Как передать ссылку на созданный документ из модуля объекта в управляемую форму и использовать ее перед закрытием

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

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

Разберем подробно, почему стандартные попытки «прочитать» данные из формы часто заканчиваются неудачей, и рассмотрим наиболее надежные и архитектурно правильные способы решения этой задачи.

Разбор проблемы: почему ДополнительныеСвойства оказываются пустыми?

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

Проанализируем правильный цикл событий при записи управляемой формы:

  1. Обработчик формы ПередЗаписьюНаСервере.
  2. Модуль объекта: ПередЗаписью.
  3. Модуль объекта: ПриЗаписи (здесь мы создаем вспомогательный документ).
  4. Обработчик формы ПослеЗаписиНаСервере (здесь мы должны «поймать» ссылку).

Способ №1: Связка ДополнительныхСвойств и обработчика ПослеЗаписиНаСервере

Это самый «чистый» и рекомендуемый способ. Он основан на том, что в процедуру ПослеЗаписиНаСервере передается параметр ТекущийОбъект, который является именно тем экземпляром, с которым велась работа в модуле объекта внутри транзакции.

Рассмотрим реализацию. Сначала в модуле объекта основного документа в процедуре ПриЗаписи создадим вспомогательный документ и сохраним ссылку:


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

Теперь в модуле управляемой формы нам нужно перехватить эту ссылку. Для этого используем предопределенный обработчик событий формы:


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

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

Способ №2: Использование параметров записи (WriteParameters)

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

В обработчике ПередЗаписью (на клиенте) или ПередЗаписьюНаСервере мы можем инициализировать структуру. Хотя модуль объекта напрямую не видит ПараметрыЗаписи, мы можем использовать их для хранения результата в ПослеЗаписиНаСервере, если данные были получены через ДополнительныеСвойства.

Если же мы хотим передать данные в ПередЗакрытием, мы можем использовать глобальную переменную модуля формы (на клиенте), заполнив её в процедуре ПослеЗаписи (на клиенте).


&НаКлиенте
Перем СсылкаДляПроведения; // Переменная в начале модуля формы

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

Способ №3: Механизм временного хранилища

Проанализируем ситуацию, когда передать нужно не одну ссылку, а массив документов или сложную структуру данных. В этом случае ДополнительныеСвойства могут стать громоздкими. Посмотрим на алгоритм с использованием временного хранилища:

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

Этот метод гарантирует, что даже большие объемы данных будут переданы корректно без лишней нагрузки на память ТекущегоОбъекта.

Почему поиск запросом — это плохое решение?

Выясним, почему решение автора темы (использование простого запроса для поиска созданного документа) не является оптимальным, несмотря на кажущуюся простоту:

Реализация финальной задачи: проведение перед закрытием

Теперь, когда мы научились передавать ссылку в форму и хранить её, разберем, как выполнить финальное требование — провести созданный документ перед закрытием формы. Используем накопленные знания и реализуем обработчик ПередЗакрытием:


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

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

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

← На главную