Как настроить регламентное задание в 1С с автоматическим переносом запуска на ближайший рабочий день?

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

В процессе автоматизации бизнес-процессов в 1С часто возникает задача регулярной отправки отчетов или выполнения обменов данными в строго определенные даты. Классический пример — отправка данных по ключевым показателям эффективности (КПЭ) во внешнюю систему (например, в SAP) строго 26-го числа каждого месяца. Однако бизнес-логика накладывает важное ограничение: если 26-е число выпадает на выходной или праздничный день, запуск процесса должен быть перенесен на первый последующий рабочий день (27-е или 28-е число).

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

Постановка задачи и анализ архитектуры

Для реализации этой задачи нам потребуется задействовать несколько механизмов платформы 1С:Предприятие 8:

  1. Регламентные задания (Scheduled Jobs) — метаданные, определяющие расписание и привязку к процедуре общего модуля.
  2. Общий модуль (Common Module) — контейнер для хранения исполняемого кода, который будет запускаться сервером 1С.
  3. Производственный календарь (регистр сведений) — источник данных для проверки статуса каждого дня (рабочий, предпраздничный, выходной или праздничный).

Главная архитектурная сложность заключается в том, что регламентное задание выполняется в фоновом режиме на сервере 1С. У него нет визуального интерфейса, нет открытых форм и нет интерактивного пользователя. Весь код должен быть полностью автономным и не зависеть от клиентского контекста.

Создание и настройка общего модуля

Прежде чем писать код, подготовим для него место в конфигурации. Создадим новый общий модуль, в котором будет располагаться наша процедура запуска.

Рассмотрим ключевые свойства общего модуля, которые необходимо настроить в палитре свойств:

Реализация функции проверки выходного дня

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

Напишем функцию, которая принимает проверяемую дату, делает запрос к регистру и возвращает Истина, если день является выходным или праздничным, и Ложь, если день рабочий или предпраздничный.


Функция ЭтоВыходнойДень(ПроверяемаяДата) Экспорт
    
    Запрос = Новый Запрос;
    Запрос.Текст = 
        "ВЫБРАТЬ
        |    Календарь.ВидДня
        |ИЗ
        |    РегистрСведений.РегламентированныйПроизводственныйКалендарь КАК Календарь
        |ГДЕ
        |    Календарь.ДатаКалендаря = &ПроверяемаяДата
        |    И Календарь.ВидДня В (
        |        ЗНАЧЕНИЕ(Перечисление.ВидыДнейПроизводственногоКалендаря.Рабочий),
        |        ЗНАЧЕНИЕ(Перечисление.ВидыДнейПроизводственногоКалендаря.Предпраздничный)
        |    )";
    
    Запрос.УстановитьПараметр("ПроверяемаяДата", НачалоДня(ПроверяемаяДата));
    Результат = Запрос.Выполнить();
    
    // Если запрос вернул пустой результат, значит, день НЕ рабочий и НЕ предпраздничный.
    // Соответственно, это выходной или праздничный день.
    Возврат Результат.Пустой();
    
КонецФункции

Обратите внимание на использование оператора В и перечисления видов дней. Мы объединили проверку на Рабочий и Предпраздничный дни через скобки, чтобы корректно обрабатывать сокращенные рабочие дни перед государственными праздниками.

Универсальный алгоритм сдвига даты запуска

На форумах часто предлагают решать задачу «в лоб», прописывая жесткие условия для каждого возможного дня смещения (например, отдельно проверять 26, 27 и 28 числа). Этот подход крайне хрупок. Если праздничные дни продлятся дольше (например, новогодние каникулы или майские праздники), жестко закодированные условия не сработают.

Мы применим более элегантный и универсальный алгоритм с использованием цикла Пока. Система будет брать базовую дату (26-е число) и сдвигать ее вперед на один день до тех пор, пока не встретит рабочий день.

Проанализируем этот алгоритм на примере кода:


// Определяем базовую дату — 26 число текущего месяца
БазоваяДата = Дата(Год(ТекущаяДата()), Месяц(ТекущаяДата()), 26);
ФактическаяДатаЗапуска = БазоваяДата;

// Сдвигаем дату вперед на сутки (86400 секунд), пока она является выходной
Пока ЭтоВыходнойДень(ФактическаяДатаЗапуска) Цикл
    ФактическаяДатаЗапуска = ФактическаяДатаЗапуска + 86400; 
КонецЦикла;

// Если сегодняшняя дата не совпадает с вычисленной рабочей датой запуска — выходим
Если НачалоДня(ТекущаяДата()) <> НачалоДня(ФактическаяДатаЗапуска) Тогда
    Возврат;
КонецЕсли;

Этот алгоритм полностью автоматизирует расчет. Если 26-е число — это рабочий день, цикл завершится сразу, и задание выполнится 26-го числа. Если 26-е выпадет на субботу, цикл прибавит день и проверит воскресенье 27-го (тоже выходной), затем прибавит еще день и остановится на понедельнике 28-го. В этот день условие совпадения выполнится, и код обмена запустится.

Решение проблемы с передачей параметров (Ошибка: Переменная не определена)

Начинающие разработчики часто пытаются перенести логику интерактивной формы в регламентное задание «как есть». В кодовой базе форм часто фигурируют переменные вроде СтатФорма или Организация, которые заполняются пользователем на клиенте. При переносе такого кода на сервер возникает ошибка компиляции: Переменная не определена (СтатФорма).

Поскольку регламентное задание работает автономно, оно должно получать параметры из информационной базы. Для этого мы можем использовать:

Разберем готовый вариант процедуры регламентного задания, где параметры обмена считываются динамически из базы данных, а все ключевые события фиксируются в системном журнале:


Процедура ВыполнитьОбменСSAP() Экспорт
    
    // 1. Проверяем, наступил ли день отправки с учетом выходных
    БазоваяДата = Дата(Год(ТекущаяДата()), Месяц(ТекущаяДата()), 26);
    ФактическаяДата = БазоваяДата;
    
    Пока ЭтоВыходнойДень(ФактическаяДата) Цикл
        ФактическаяДата = ФактическаяДата + 86400;
    КонецЦикла;
    
    Если НачалоДня(ТекущаяДата()) <> НачалоДня(ФактическаяДата) Тогда
        Возврат; // Сегодня не день обмена, тихо выходим
    КонецЕсли;
    
    // 2. Получаем параметры обмена, которые раньше выбирались на форме.
    // В данном примере мы считываем форму из настроек или находим по коду.
    СтатФорма = ПолучитьНастройкуИДФормы(); 
    
    Если Не ЗначениеЗаполнено(СтатФорма) Тогда
        ЗаписьЖурналаРегистрации(
            "ОбменSAP.Ошибка",
            УровеньЖурналаРегистрации.Ошибка,
            ,
            ,
            "Не удалось запустить обмен: не заполнен идентификатор статистической формы!"
        );
        Возврат;
    КонецЕсли;
    
    Организация = Справочники.Организации.НайтиПоКоду("000000001");
    
    // 3. Формируем структуру параметров и перезаполняем отчетность
    ПараметрыОтчета = Новый Структура;
    ПараметрыОтчета.Вставить("ИДФормы", СтатФорма);
    ПараметрыОтчета.Вставить("Организация", Организация);
    ПараметрыОтчета.Вставить("НачалоПериода", НачалоМесяца(ТекущаяДата()));
    ПараметрыОтчета.Вставить("КонецПериода", КонецМесяца(ТекущаяДата()));
    
    Попытка
        // Вызываем логику перезаполнения данных в информационной базе
        РегистрыСведений.тн_СтатистическаяОтчетностьДляSAP.ПерезаполнитьОтчетность(ПараметрыОтчета);
        
        КодФормы = РегистрыСведений.тн_СтатистическаяОтчетностьДляSAP.ПолучитьКодФормыПоИДФормы(СтатФорма);
        
        Если ЗначениеЗаполнено(КодФормы) Тогда
            // Непосредственная передача подготовленных данных во внешнюю систему SAP
            тн_ОбменSAP.ПередатьВSAP(КодФормы, НачалоМесяца(ТекущаяДата()), КонецМесяца(ТекущаяДата()));
            
            ЗаписьЖурналаРегистрации(
                "ОбменSAP.Успех",
                УровеньЖурналаРегистрации.Информация,
                ,
                ,
                "Обмен успешно выполнен для формы: " + Сокращенно(КодФормы)
            );
        КонецЕсли;
        
    Исключение
        // Обязательно перехватываем любые ошибки, чтобы задание не "вешало" рабочий процесс сервера
        ЗаписьЖурналаРегистрации(
            "ОбменSAP.Ошибка",
            УровеньЖурналаРегистрации.Ошибка,
            ,
            ,
            "Произошла ошибка при выполнении обмена: " + ОписаниеОшибки()
        );
    КонецПопытки;
    
КонецПроцедуры

Функция ПолучитьНастройкуИДФормы()
    // Вспомогательная функция получения настройки.
    // Здесь может быть запрос к константе или регистру настроек.
    Возврат Справочники.тн_СтатистическиеФормы.НайтиПоРеквизиту("КодДляSAP", "KPI_FORM_01");
КонецФункции

Настройка расписания регламентного задания в Конфигураторе

После написания кода перейдем к настройке метаданных в дереве конфигурации:

  1. Найдем ветку Общие -> Регламентные задания и добавим новое задание.
  2. В поле Имя метода укажем нашу процедуру: ОбщийМодуль.ИмяМодуля.ВыполнитьОбменСSAP.
  3. Установим флажок Предопределенное. Это гарантирует автоматический запуск задания после обновления конфигурации базы данных без необходимости ручного создания в режиме Предприятия.
  4. Перейдем к настройке Расписания.

Важное правило настройки расписания: поскольку логика сдвига дат полностью реализована программно внутри нашей процедуры, расписание в Конфигураторе нужно настроить на запуск Каждый день, один раз в день (например, в 23:00).

Если настроить запуск только на 26-е число, то в месяце, где 26-е окажется субботой, задание запустится в субботу, увидит выходной день и завершит работу без отправки. При этом 27-го (в воскресенье) и 28-го (в понедельник) задание просто не запустится, так как расписание жестко ограничивало работу только 26-м числом.

Правильная отладка и логирование серверного кода

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

Для надежного контроля работы регламентных заданий используйте два инструмента:

1. Запись в журнал регистрации

Используйте метод ЗаписьЖурналаРегистрации() для фиксации каждого шага. Это позволит администраторам базы данных оперативно диагностировать любые сбои в процессе обмена без привлечения разработчика и запуска конфигуратора.

2. Настройка отладки фоновых заданий

Для того чтобы зайти отладчиком в процедуру регламентного задания и пройтись по коду по шагам:

  1. Убедитесь, что сервер 1С:Предприятия запущен в режиме отладки (с ключом -debug).
  2. В Конфигураторе откройте меню Отладка -> Подключение...
  3. В открывшемся окне нажмите кнопку Автоматическое подключение... и установите флажок напротив пункта Фоновые задания.
  4. Установите точку останова в коде вашей процедуры общего модуля. При очередном срабатывании расписания (или принудительном запуске через консоль регламентных заданий) отладчик автоматически перехватит управление.
← На главную