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