Почему не работает ПередЗаписью при создании документа регламентным заданием?

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

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

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

Главная причина: Путаница между модулем формы и модулем объекта

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

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

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

Если ваш обработчик ПередЗаписью объявлен в модуле формы документа, он никогда не выполнится при программном создании. Форма просто не участвует в этом процессе! Любые алгоритмы автоматического заполнения реквизитов (например, расчет суммы табличной части по колонке) должны быть реализованы исключительно в модуле объекта документа.

Пример правильного переноса кода в модуль объекта

Рассмотрим, как должен выглядеть правильный обработчик в модуле объекта документа. Перейдем в конфигуратор, откроем свойства нужного документа, выберем вкладку «Прочие» и нажмем кнопку «Модуль объекта».

Напишем процедуру расчета суммы по табличной части:


Процедура ПередЗаписью(Отказ, РежимЗаписи, РежимПроведения)
    
    // Важно! Проверяем, не выполняется ли загрузка данных (например, при обмене)
    Если ОбменДанными.Загрузка Тогда
        Возврат;
    КонецЕсли;
    
    // Рассчитываем итоговую сумму по колонке табличной части "Товары"
    ЭтотОбъект.СуммаДокумента = ЭтотОбъект.Товары.Итог("Сумма");
    
КонецПроцедуры

Обратите внимание на ключевое различие в сигнатуре процедур. В модуле формы процедура ПередЗаписью принимает только параметр Отказ (а также ПараметрыЗаписи в управляемых формах), тогда как в модуле объекта она имеет три параметра: Отказ, РежимЗаписи и РежимПроведения. Это позволяет тонко управлять поведением системы в зависимости от того, проводится документ или просто записывается.

Влияние свойства ОбменДанными.Загрузка

Очень часто разработчики забывают проверить состояние свойства ОбменДанными.Загрузка или, напротив, устанавливают его принудительно перед записью документа в фоновом задании. Если в вашем коде регламентного задания написано следующее:


НовыйДокумент = Документы.РеализацияТоваровУслуг.СоздатьДокумент();
НовыйДокумент.ОбменДанными.Загрузка = Истина;
// Заполнение данных...
НовыйДокумент.Записать();

То платформа применит режим "загрузки". Это означает, что большинство стандартных проверок и обработчиков (включая расчеты в ПередЗаписью) будут полностью пропущены, если в начале процедур модуля объекта стоит стандартная заглушка Если ОбменДанными.Загрузка Тогда Возврат; КонецЕсли;. Это необходимо, чтобы при переносе данных из других систем бизнес-логика не выполнялась повторно.

Правило: При обычном программном создании документов регламентным заданием свойство ОбменДанными.Загрузка должно оставаться в значении Ложь (это значение по умолчанию), чтобы все процедуры обработки данных отработали корректно.

Параметры сеанса в фоновых заданиях: подводные камни

Еще одна частая причина падения фонового задания при записи документов — обращение к параметрам сеанса (например, к текущему пользователю) внутри модуля объекта. В интерактивном режиме параметр сеанса ТекущийПользователь всегда заполнен. Но когда документ создается регламентным заданием, код выполняется в рамках специального фонового сеанса, у которого нет интерактивного пользователя.

Попытка обратиться к неинициализированному параметру сеанса вызовет критическую ошибку, транзакция откатится, и документ не запишется. Выясним, как правильно решить эту проблему.

Во-первых, в процедуре ПередЗаписью модуля объекта следует избегать жесткой привязки к параметрам сеанса без предварительной проверки. Во-вторых, в модуле сеанса в процедуре УстановкаПараметровСеанса необходимо предусмотреть корректное заполнение параметров для фоновых заданий:


Процедура УстановкаПараметровСеанса(ТребуемыеПараметры)
    
    Если Найти(СтрокаСоединенияИнформационнойБазы(), "Srvr=") > 0 Тогда
        // Серверный вариант работы
        Если ИмяПользователя() = "" Тогда
            // Сеанс запущен фоновым/регламентным заданием
            ПараметрыСеанса.ТекущийПользователь = Справочники.Пользователи.НайтиПоРеквизиту("ИмяВхода", "SystemRobot");
            Возврат;
        КонецЕсли;
    КонецЕсли;
    
    // Стандартная инициализация для обычных пользователей...
    
КонецПроцедуры

Как правильно передать контекст из регламентного задания

Иногда возникает необходимость передать специфическую информацию из регламентного задания напрямую в обработчик ПередЗаписью модуля объекта. Использовать глобальные переменные для этого нельзя, так как контексты выполнения изолированы.

Для решения этой задачи у любого прикладного объекта 1С существует встроенное свойство-коллекция ДополнительныеСвойства. Это структура, которая существует в памяти до тех пор, пока жив сам объект документа. Разберем пример передачи флага "Создано в фоне":

В модуле регламентного задания:


НовыйДокумент = Документы.СписаниеТоваров.СоздатьДокумент();
// Заполняем реквизиты...
НовыйДокумент.ДополнительныеСвойства.Вставить("СозданоРегламентнымЗаданием", Истина);
НовыйДокумент.Записать(РежимЗаписиДокумента.Проведение);

В модуле объекта документа:


Процедура ПередЗаписью(Отказ, РежимЗаписи, РежимПроведения)
    Если ОбменДанными.Загрузка Тогда
        Возврат;
    КонецЕсли;
    
    // Проверяем, пришел ли флаг из фонового задания
    Если ЭтотОбъект.ДополнительныеСвойства.Свойство("СозданоРегламентнымЗаданием") Тогда
        // Выполняем специфическую логику, предназначенную только для автоматического списания
        ЭтотОбъект.Комментарий = "Создано автоматически регламентным заданием.";
    КонецЕсли;
КонецПроцедуры

Настройка отладки для фоновых и регламентных заданий

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

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

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

← На главную