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

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

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

Почему обращение к форме из модуля объекта невозможно?

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

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

Способ 1. Использование коллекции ДополнительныеСвойства

Проанализируем наиболее правильный и стандартный метод передачи временной информации — использование свойства ДополнительныеСвойства. Это структура, которая есть у каждого прикладного объекта (справочника, документа) и которая живет ровно столько, сколько живет сам экземпляр объекта в памяти во время записи.

Рассмотрим по шагам, как реализовать этот механизм:

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

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

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

Этот метод хорош тем, что он сохраняет транзакционность. Если запись в регистр внутри подписки завершится ошибкой, вся транзакция (включая запись самого документа) будет отменена. Это гарантирует целостность данных.

Способ 2. Расширения конфигурации (Современный подход)

Выясним, как современные возможности платформы позволяют избежать проблем с обновлением конфигурации. Часто разработчики создают реквизиты на форме программно, чтобы не снимать документ с поддержки. Однако с появлением расширений в этом методе стало меньше смысла.

Мы можем создать расширение и добавить необходимые реквизиты непосредственно в документ в рамках этого расширения. Преимущества этого подхода:

Если же логика требует именно записи в отдельный регистр, в расширении можно создать метод &После("ПриЗаписиНаСервере") для формы документа. Там у нас есть доступ одновременно и к контексту формы (ее реквизитам), и к объекту документа, что позволяет легко связать их.

Способ 3. Передача через временное хранилище

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

Разберем алгоритм действий:

  1. В форме документа в процедуре ПередЗаписьюНаСервере мы помещаем данные во временное хранилище.
  2. Адрес хранилища (строку) передаем в объект через те же ДополнительныеСвойства.
  3. В модуле объекта или подписке извлекаем данные по этому адресу.

// В форме
АдресХранилища = ПоместитьВоВременноеХранилище(МояТаблицаДанных, ЭтаФорма.УникальныйИдентификатор);
ТекущийОбъект.ДополнительныеСвойства.Вставить("АдресДанных", АдресХранилища);

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

Важные нюансы работы с программными реквизитами

Проанализируем еще один важный момент, упомянутый в обсуждении. Если ваша логика завязана только на модуль формы, помните о рисках: если документ будет записан программно (например, какой-то внешней обработкой), программные реквизиты формы не будут созданы и заполнены, а значит, и данные в регистр не попадут.

Рекомендация: Если данные критически важны для бизнес-логики, всегда старайтесь хранить их в реквизитах самого документа. Если же вы хотите следовать правилам хорошего тона, добавляйте к таким реквизитам префикс (например, ит_МойРеквизит). Это гарантирует, что при обновлении типовой конфигурации от фирмы «1С» ваши поля не совпадут по имени с новыми полями от вендора и не будут затерты.

Резюме

Для решения задачи получения данных из формы на сервере мы рекомендуем придерживаться следующей иерархии решений:

  1. Самый надежный: Добавить реквизиты в расширение конфигурации. Это обеспечит доступ к данным в любом месте кода и упростит поддержку.
  2. Оптимальный для динамических данных: Передача значений через ДополнительныеСвойства в процедуре ПередЗаписьюНаСервере.
  3. Для больших объемов данных: Использование связки Временное хранилище + ДополнительныеСвойства.

Выбор метода зависит от конкретной архитектурной задачи, но помните — прямого доступа к ЭтаФорма из подписки на событие не существует по правилам платформы, и любые попытки его обойти через ПолучитьФорму приведут к логическим ошибкам.

← На главную