Добавить в корзинуПозвонить
Найти в Дзене
Блокнот интегратора

Как вычислить дату выставления счёта с учётом рабочих дней и не вылететь за пределы месяца: разбор бизнес-кейса в Битрикс24

Ко мне обратился клиент с задачей, которая на первый взгляд звучит просто, а на деле заставляет посидеть и подумать. Суть такая: в компании есть регламентная дата выставления счёта клиенту. Она привязана к конкретному числу месяца. Но если это число выпадает на выходной или праздник, система должна перенести дату на ближайший рабочий день. При этом есть жёсткое условие: нельзя выходить за границы календарного месяца. Разберу на конкретных примерах, чтобы было понятнее: Казалось бы, бери функцию addworkdays и не мучайся. Но есть нюанс с границами месяца, из-за которого всё становится интереснее. Рассказываю, как я решил эту задачу средствами Бизнес-процессов Битрикс24. Я вынес логику в отдельный внешний Бизнес-процесс. Почему не робот на стадии сделки? В статье я не буду расписывать весь процесс целиком — только выжимку по вычислению нужной даты. Если понадобится полная схема или захотите обсудить альтернативные подходы — добро пожаловать в комментарии. В начале процесса создаю две стро
Оглавление

Ко мне обратился клиент с задачей, которая на первый взгляд звучит просто, а на деле заставляет посидеть и подумать. Суть такая: в компании есть регламентная дата выставления счёта клиенту. Она привязана к конкретному числу месяца. Но если это число выпадает на выходной или праздник, система должна перенести дату на ближайший рабочий день. При этом есть жёсткое условие: нельзя выходить за границы календарного месяца.

Разберу на конкретных примерах, чтобы было понятнее:

  • Счёт нужно выставить 1 мая. Это выходной. Ближайший рабочий день — 4 мая (после длинных праздников). Счёт должен быть выставлен именно на 4-е число.
  • Счёт нужно выставить 4 апреля. Это суббота. Ближайший рабочий день перед этой датой — 3 апреля (пятница). Счёт должен выставлен 3-его числа.

Казалось бы, бери функцию addworkdays и не мучайся. Но есть нюанс с границами месяца, из-за которого всё становится интереснее. Рассказываю, как я решил эту задачу средствами Бизнес-процессов Битрикс24.

Где живёт логика

Я вынес логику в отдельный внешний Бизнес-процесс. Почему не робот на стадии сделки?

  • Внешний БП удобнее редактировать и отлаживать.
  • Его можно дёргать из любого места: из сделки, из другого процесса, даже по REST API.
  • Если логика поменяется, вы правите один шаблон, а не десяток роботов в разных воронках.

В статье я не буду расписывать весь процесс целиком — только выжимку по вычислению нужной даты. Если понадобится полная схема или захотите обсудить альтернативные подходы — добро пожаловать в комментарии.

Шаг 1. Подготовка переменных

В начале процесса создаю две строковые переменные:

  • Дата — в ней будем хранить и вычислять итоговую дату.
  • Месяц — для контроля, не вышли ли мы за границы календарного месяца.

Исходная дата приходит из сделки. В моём примере поле называется Дата начала.

Шаг 2. Проверяем, рабочий ли день

-2

Использую активити Изменение переменной. Меняю значение переменной Дата на результат проверки:

{{=if(isworkday({{Дата начала}}), 'Да', 'Нет')}}

Функция isworkday сверяется с производственным календарём, который настроен в вашем Битрикс24, и возвращает «Да» или «Нет». Результат записываю в переменную Дата.

-3

Шаг 3. Первая развилка

Ставлю активити Условие. Проверяю значение переменной Дата:

  • Если Да — всё хорошо, исходная дата рабочая. Просто присваиваю переменной Дата значение поля {{Дата начала}}. Процесс идёт дальше по своим делам.
  • Если Нет — переходим к вычислениям.
-4

Шаг 4. Определяем порядковый номер дня в месяце

-5

Нужно понять, первое число у нас или нет. От этого зависит, в какую сторону двигаться — вперёд или назад. Использую активити Изменение переменной для переменной Дата:

{{=substr({{Дата начала}}, 0, 2)}}

Функция substr вырезает первые два символа из строки даты. Для даты 01.05.2026 получим 01, для 04.04.2026 — 04.

Шаг 5. Проверяем, первое ли число

Ставлю Условие: {{=Variable:Date}} равно 01?

-6

Ветка «Да, первое число и оно выходное»

Это как раз случай с 1 мая. Если первое число выпало на выходной, нам нужно двигаться только вперёд, потому что назад — это уже предыдущий месяц, а за границу месяца выходить нельзя.

Делаю Изменение переменной Дата:

{{=addworkdays({{Дата начала}}, "1h")}}

Что здесь происходит: к исходной дате добавляется +1h рабочего времени. Поскольку поле Дата начала имеет тип «Дата без времени», добавление одного рабочего часа фактически сдвигает дату на следующий рабочий день. Для 1 мая 2026 (пятница, выходной) ближайший рабочий день — 4 мая (понедельник). Ровно то, что нужно.

Ветка «Нет, число не первое»

Если число больше 01 (например, 4 апреля), мы можем попробовать сдвинуться назад. Делаю Изменение переменной Дата:

{{=addworkdays({{Дата начала}}, "-1h")}}

Вычитаем один рабочий час — и получаем предыдущий рабочий день. Для 4 апреля (суббота) это будет 3 апреля (пятница).

Шаг 6. Контроль границы месяца

-7

Вот тут и кроется тот самый нюанс, о котором я говорил. Представьте: исходная дата 4 января, это выходной. Мы двигаемся назад через -1h и попадаем на последний рабочий день декабря. Это уже другой месяц, а по условию задачи так делать нельзя.

Поэтому добавляю проверку месяца.

Сначала Изменение переменной Месяц. Вырезаем номер месяца из получившейся даты:

{{=substr({=Variable:Date}, 3, 2)}}

Для даты 31.12.2025 получим 12, для 03.04.2026 — 04.

Теперь Условие: сравниваю значение переменной Месяц с номером месяца исходной даты:

{{=substr({{Дата начала}}, 3, 2)}}

Если Месяц меньше исходного — значит мы перескочили в предыдущий месяц. Например, исходный месяц был 01 (январь), а получился 12 (декабрь).

Ветка «Месяц меньше исходного»

Мы вышли за границу. Значит, двигаться назад было нельзя. Вместо этого идём вперёд. Делаю Изменение переменной Дата:

{{=addworkdays({{Дата начала}}, "1h")}}

Теперь для 4 января мы получим первый рабочий день января, а не декабря.

-8

Ветка «Месяц совпадает или больше»

Всё хорошо, граница месяца не нарушена. Переменная Дата уже содержит корректное значение, ничего не меняю.

Финальный итог

После всех проверок в переменной Дата лежит корректная рабочая дата, не выходящая за пределы нужного месяца. Дальше этот БП использует её для создания задачи, постановки напоминания или любого другого действия, которое требуется по логике клиента.

Пара заметок на полях

1. Производственный календарь. Вся магия isworkday и addworkdays работает только если в Битрикс24 настроен производственный календарь. Проверьте в настройках компании, что праздники и переносы актуальны на текущий год.

-9

2. Тип поля «Дата начала». Убедитесь, что поле, из которого вы берёте исходную дату, имеет тип «Дата» (без времени). Если там будет ещё и время, логика с добавлением часов может отработать не так, как ожидается.

3. Отладка. Если что-то идёт не так, добавьте в процесс активити Уведомление и выводите в него значения переменных на каждом шаге. Это сэкономит кучу времени при поиске ошибки.

-10
-11

А как вы решаете подобные задачи? Может, у вас есть свой подход к обходу границ месяца или вы используете другие функции? Делитесь в комментариях — интересно обсудить альтернативные варианты. Если есть вопросы по конкретным шагам или нужно больше примеров — пишите, разберём вместе. Всем продуктивных процессов и корректных дат