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