Как рассчитать крайний срок оплаты в рабочих днях по производственному календарю в 1С?

Программист 1С v8.3 (Управляемые формы) Управленческий учет IT и автоматизация бизнеса
← На главную

При разработке конфигураций, отчетов и механизмов контроля задолженности часто возникает необходимость вычислить дату окончания срока оплаты в рабочих днях на основании даты выписки первичного документа (например, счета-фактуры) и допустимого срока оплаты по договору. Стандартная функция языка запросов 1С РАЗНОСТЬДАТ работает только с календарными днями, поэтому для правильного учета выходных и праздничных дней необходимо привлекать данные производственного календаря.

Рассмотрим несколько эффективных способов решения этой задачи: использование встроенных программных интерфейсов Библиотеки Стандартных Подсистем (БСП), алгоритмический перебор в цикле и выполнение расчетов непосредственно в языке запросов.

Способ 1. Использование готовых функций БСП (модуль КалендарныеГрафики)

Если разработка ведется на базе БСП, нет необходимости писать собственную логику обхода дат вручную. В составе БСП присутствует программный модуль КалендарныеГрафики, предоставляющий все необходимые функции.

Разберем ключевые функции модуля:

  1. КалендарныеГрафики.ДатаПоКалендарю(ГрафикРаботыИлиКалендарь, ДатаОт, КоличествоДней) — возвращает новую дату, полученную смещением от исходной на переданное число рабочих дней.
  2. КалендарныеГрафики.ДатаЗавершенияСрока(ГрафикРаботыИлиКалендарь, ДатаНачала, СрокВРабочихДнях) — возвращает дату окончания срока. Если передан параметр со значением 0, функция возвращает исходную дату (если это рабочий день) либо ближайший следующий рабочий день.
  3. КалендарныеГрафики.РазностьДатПоКалендарю(ГрафикРаботыИлиКалендарь, ДатаНачала, ДатаОкончания) — рассчитывает количество рабочих дней между двумя датами.
  4. КалендарныеГрафики.ОсновнойПроизводственныйКалендарь() — возвращает ссылку на производственный календарь по умолчанию (СправочникСсылка.ПроизводственныеКалендари).

Проанализируем пример программного кода для расчета предельной даты оплаты:


Календарь = КалендарныеГрафики.ОсновнойПроизводственныйКалендарь();
ДатаСчетаФактуры = Объект.Дата;
СрокВРабочихДнях = Объект.Контракт.СрокОплаты;

// Получаем дату последнего дня для оплаты
КрайняяДатаОплаты = КалендарныеГрафики.ДатаПоКалендарю(Календарь, ДатаСчетаФактуры, СрокВРабочихДнях);

Способ 2. Программный перебор дат в цикле

Если функционал БСП недоступен или требуется реализовать собственную универсальную процедуру, можно применить алгоритм с перебором дней в цикле. В качестве источника сведений о рабочих и праздничных днях используется регистр сведений ДанныеПроизводственногоКалендаря.

Разберем алгоритм по шагам:

  1. Устанавливаем начальную дату расчета равной дате документа.
  2. Заводим счетчик пройденных рабочих дней со значением 0.
  3. В цикле прибавляем к дате по одному дню (86400 секунд).
  4. Проверяем вид текущего дня в регистре сведений ДанныеПроизводственногоКалендаря.
  5. Если день является рабочим или предпраздничным, увеличиваем счетчик на 1.
  6. Когда значение счетчика достигнет требуемого срока оплаты, цикл завершается, а полученная дата будет являться крайним днем оплаты.

Посмотрим на пример реализации данного алгоритма:


ТекущаяДатаРасчета = ДатаСчетаФактуры;
СчетчикРабочихДней = 0;

Пока СчетчикРабочихДней < СрокВРабочихДнях Цикл
    ТекущаяДатаРасчета = ТекущаяДатаРасчета + 86400; // Прибавляем 1 день
    
    ВидДня = РегистрыСведений.ДанныеПроизводственногоКалендаря.ВидДня(ТекущаяДатаРасчета, Календарь);
    
    // Учитываем рабочие и предпраздничные дни
    Если ВидДня = Перечисления.ВидыДнейПроизводственногоКалендаря.Рабочий
       Или ВидДня = Перечисления.ВидыДнейПроизводственногоКалендаря.Предпраздничный Тогда
        СчетчикРабочихДней = СчетчикРабочихДней + 1;
    КонецЕсли;
КонецЦикла;

КрайняяДатаОплаты = ТекущаяДатаРасчета;

Способ 3. Вычисление рабочих дней в запросе (для отчетов и СКД)

При построении отчетов на базе Системы компоновки данных (СКД) или при написании сложных запросов вычисления выполняются прямо в базе данных через обращение к регистру РегистрСведений.ДанныеПроизводственногоКалендаря.

Для подсчета количества рабочих дней за период между датой выписки и датой отчета используется агрегатная функция КОЛИЧЕСТВО с фильтрацией видов дней:


ВЫБРАТЬ
    КОЛИЧЕСТВО(ПроизводственныйКалендарь.Дата) КАК КоличествоРабочихДней
ИЗ
    РегистрСведений.ДанныеПроизводственногоКалендаря КАК ПроизводственныйКалендарь
ГДЕ
    ПроизводственныйКалендарь.Дата МЕЖДУ &ДатаНачала И &ДатаОкончания
    И (ПроизводственныйКалендарь.ВидДня = ЗНАЧЕНИЕ(Перечисление.ВидыДнейПроизводственногоКалендаря.Рабочий)
        ИЛИ ПроизводственныйКалендарь.ВидДня = ЗНАЧЕНИЕ(Перечисление.ВидыДнейПроизводственногоКалендаря.Предпраздничный))

Для получения крайней даты оплаты в запросе формируется временная таблица рабочих дней из регистра сведений, начиная от даты выписки. С помощью соединения таблицы с самой собой по условию Дата <= Дата рассчитывается нарастающий итог (порядковый номер рабочего дня). Искомой датой оплаты станет запись, где нарастающий итог равен заданному сроку оплаты из контракта.

Важные методические особенности

При реализации расчета сроков оплаты обратим внимание на следующие критически важные моменты:

  1. Заполнение производственного календаря: Регистр сведений ДанныеПроизводственногоКалендаря должен быть заполнен на все проверяемые годы вперед. Если данные за текущий или следующий период отсутствуют, запросы вернут пустые значения (NULL), а механизмы БСП могут вызвать исключение.
  2. Учет предпраздничных дней: При настройке отборов по полю ВидДня обязательно следует учитывать значение Предпраздничный, поскольку законодательно эти дни являются рабочими и засчитываются в общий срок оплаты.
  3. Региональные календари: Если контрагент или организация располагаются в регионе с региональными праздничными днями, в качестве параметра функций БСП или отбора в запросе следует указывать соответствующий региональный календарь из справочника ПроизводственныеКалендари.
← На главную