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