При разработке фоновых и регламентных заданий в 1С можно столкнуться с ситуацией, когда код, прекрасно работающий в обычном режиме, падает с ошибкой при выполнении на сервере. Одна из таких распространенных ошибок — «Ошибка инициализации модуля: Документ.<ИмяДокумента>.МодульОбъекта», которая возникает в момент программного создания документа.
Давайте подробно разберем, почему возникает эта ошибка и какие существуют способы ее диагностики и исправления.
Основная причина этой проблемы кроется в архитектуре платформы 1С и разделении кода на тот, что выполняется на клиенте (в пользовательском интерфейсе), и тот, что выполняется на сервере (в фоновом режиме, без участия пользователя). Для более глубокого понимания этих механизмов можно использовать руководство по управлению местом выполнения кода в управляемых формах.
Регламентное задание — это процесс, который всегда выполняется на сервере. У этого процесса нет доступа к экрану, клавиатуре, мыши и, соответственно, ко всем функциям, которые требуют взаимодействия с пользователем. Когда в регламентном задании вызывается команда Документы.Переоценка.СоздатьДокумент(), платформа пытается подготовить (инициализировать) объект документа. Для этого она компилирует его модуль объекта в серверном контексте.
Если в этом модуле (Документ.Переоценка.МодульОбъекта) окажется код, который предназначен только для клиента, сервер не сможет его выполнить, и произойдет сбой. К такому коду относятся:
Предупреждение(), Вопрос(), ВвестиЗначение().ОткрытьФорму(), обращение к реквизитам и элементам формы.Часто такой код размещают в стандартных обработчиках, например, ОбработкаЗаполнения или ПриЗаписи, забывая, что эти обработчики могут вызываться не только при интерактивной работе пользователя, но и программно на сервере. Чтобы разобраться в логике работы платформы в таких случаях, пригодится инструмент для изучения последовательности вызова событий.
Самый быстрый и надежный способ найти "запрещенный" код — воспользоваться встроенным инструментом проверки конфигурации. Этот метод позволяет автоматически проанализировать все модули и указать на строки, которые не могут быть выполнены на сервере.
Разберем по шагам, как это сделать:
Документ.Переоценка.МодульОбъекта). Платформа точно укажет на строку кода и причину, по которой она не может быть выполнена на сервере.Этот способ является предпочтительным, так как он исключает человеческий фактор и быстро локализует все потенциальные проблемы в конфигурации.
Если по какой-то причине автоматическая проверка не дала результата или вы хотите глубже понять проблему, можно найти проблемный код вручную. Как и поступил автор темы, можно использовать метод последовательного комментирования.
Шаг 1. Локализация проблемы.
Закомментируйте весь код в модуле объекта проблемного документа, оставив только пустые процедуры. Попробуйте запустить регламентное задание. Если ошибка исчезла, значит, проблема точно в коде модуля. Далее раскомментируйте процедуры и функции по одной, пока ошибка не появится снова. Так вы найдете конкретную процедуру, содержащую ошибку.
Шаг 2. Исправление кода.
После того как проблемная строка найдена, ее нужно исправить. В примере из темы это был вызов процедуры Предупреждение(). Решение — обернуть этот вызов в директивы препроцессора.
Директивы препроцессора — это специальные инструкции для компилятора, которые указывают, какой фрагмент кода нужно включать в сборку для определенного контекста (клиента или сервера).
Чтобы код выполнялся только при интерактивной работе пользователя (на клиенте), используйте конструкцию #Если Клиент Тогда ... #КонецЕсли.
Посмотрим на пример. Исходный код, вызывающий ошибку:
Процедура ОбработкаЗаполнения(ДанныеЗаполнения, СтандартнаяОбработка)
// ... какой-то код ...
Предупреждение("Документ заполнен по умолчанию!");
// ... еще какой-то код ...
КонецПроцедуры
Правильный вариант:
Процедура ОбработкаЗаполнения(ДанныеЗаполнения, СтандартнаяОбработка)
// ... какой-то код ...
#Если Клиент Тогда
Предупреждение("Документ заполнен по умолчанию!");
#КонецЕсли
// ... еще какой-то код ...
КонецПроцедуры
Теперь при компиляции модуля для сервера компилятор просто проигнорирует блок кода между #Если Клиент Тогда и #КонецЕсли. Ошибки инициализации больше не будет, а регламентное задание выполнится корректно.
В ходе обсуждения на форуме возник спор о методе Сообщить(). Важно понимать его особенности:
Сообщить() технически доступен на сервере и не вызовет ошибку компиляции или выполнения в регламентном задании.СообщениеПользователю. Он позволяет "привязать" сообщение к конкретному объекту данных (например, к созданному документу), и пользователь увидит его, когда откроет форму этого объекта.Поэтому, хотя Сообщить() не вызывает падения, его использование в модуле объекта для информирования пользователя из регламентного задания неэффективно. Вся логика взаимодействия с пользователем должна быть вынесена в модули форм.
Ошибка «Ошибка инициализации модуля» при создании документа в регламентном задании — это сигнал о том, что в серверном контексте выполняется клиентский код. Лучшая практика — это разделять бизнес-логику (которая находится в модуле объекта) и логику интерфейса (которая находится в модуле формы). Модуль объекта должен быть "чистым" от интерактивных вызовов. Если же такой код необходим для интерактивной работы, его следует изолировать с помощью директив препроцессора #Если Клиент Тогда ... #КонецЕсли.