В процессе разработки платежных календарей или систем автоматического планирования оплат в среде 1С:Предприятие 7.7 часто возникает задача определения следующей корректной даты. Например, если контрагент принимает платежи только по понедельникам и средам, системе нужно вычислить ближайший такой день, начиная от текущей даты или даты документа.
В данной статье мы разберем несколько способов решения этой задачи: от простого циклического перебора до оптимизированных алгоритмов с использованием списков значений и математических формул.
Это самый наглядный и надежный способ для версии 7.7. Логика заключается в том, что мы берем начальную дату и в цикле прибавляем к ней по одному дню до тех пор, пока номер дня недели не совпадет с одним из разрешенных дней платежа.
Рассмотрим реализацию функции, которая принимает исходную дату и список разрешенных дней недели. В 1С 7.7 для работы с днями недели используется функция НомерДняНедели(), которая возвращает значения от 1 (понедельник) до 7 (воскресенье).
Пример кода с использованием объекта СписокЗначений:
Функция ПолучитьБлижайшийДеньПлатежа(ВыбДата, СписокДнейОплаты)
// Определяем номер дня недели для текущей даты
ТекДеньНедели = НомерДняНедели(ВыбДата);
БлижайшаяДата = ВыбДата;
// Запускаем цикл поиска.
// Метод Принадлежит() вернет 1, если день найден в списке
Пока СписокДнейОплаты.Принадлежит(ТекДеньНедели) = 0 Цикл
// В 7.7 прибавление 1 к дате означает прибавление одного дня
БлижайшаяДата = БлижайшаяДата + 1;
ТекДеньНедели = НомерДняНедели(БлижайшаяДата);
КонецЦикла;
Возврат БлижайшаяДата;
КонецФункции
Важное замечание: Перед запуском такого цикла обязательно проверьте, что СписокДнейОплаты не пуст. Если в настройках контрагента не указано ни одного платежного дня, программа уйдет в бесконечный цикл. Рекомендуется добавить условие Если СписокДнейОплаты.РазмерСписка() = 0 Тогда Возврат '00.00.00'; КонецЕсли;.
Если нам известен только один конкретный день недели (например, мы всегда платим по четвергам), можно обойтись без цикла, вычислив разницу по формуле. Для этого используется оператор остатка от деления %.
Проанализируем алгоритм расчета:
(ЦелевойДень - ТекущийДень + 7) % 7.Этот метод работает быстрее, так как не требует итераций, но он сложнее в реализации, если платежных дней в неделю несколько (например, вторник и пятница).
Довольно элегантный способ для 1С 7.7 — хранение графика в виде строки из 7 символов, где "1" означает платежный день, а "0" — выходной. Например, "1010000" (Пн и Ср).
Чтобы найти ближайший день, мы можем "удвоить" эту строку: "10100001010000". Затем, начиная с позиции, соответствующей текущему дню недели, мы ищем первую единицу с помощью функции Найти(). Количество символов до найденной единицы и будет количеством дней, которые нужно прибавить к текущей дате.
При реализации любого из выбранных методов следует учитывать технические нюансы старой платформы:
ТекущаяДата + 1 вернет завтрашний день.ВыбратьДаты() или через прямое обращение к периодическим реквизитам, если календарь заполнен в базе.Дата в 7.7 не содержит времени в явном виде (время хранится отдельно в документах). Поэтому расчеты всегда ведутся с точностью до дня.Разберем ситуацию, когда у контрагента в реквизитах справочника стоят флажки Пн, Вт, Ср, Чт, Пт. Нам нужно собрать их в список и найти дату платежа:
СписокДней = СоздатьОбъект("СписокЗначений");
Если Контрагент.ПлатПонедельник = 1 Тогда СписокДней.ДобавитьЗначение(1); КонецЕсли;
Если Контрагент.ПлатСреда = 1 Тогда СписокДней.ДобавитьЗначение(3); КонецЕсли;
Если СписокДней.РазмерСписка() > 0 Тогда
ДатаПлатежа = ПолучитьБлижайшийДеньПлатежа(РабочаяДата(), СписокДней);
Сообщить("Ближайшая оплата: " + ДатаПлатежа);
Иначе
Сообщить("У контрагента не настроен график платежей!");
КонецЕсли;
Использование СпискаЗначений в данном контексте является наиболее гибким подходом, так как позволяет легко изменять набор платежных дней без переписывания основной логики функции поиска.