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

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

При разработке в среде 1С:Предприятие часто возникает задача кастомизации типовых документов без изменения их структуры в метаданных. Популярный способ решения — программное добавление колонок в табличные части на форме документа. Однако при попытке обработать эти данные в модуле объекта или в подписке на проведение разработчики сталкиваются с серьезным препятствием: динамических реквизитов формы нет в самом объекте базы данных. При записи объекта форма уничтожается, а данные программной колонки бесследно теряются.

В этой статье мы подробно разберем, как передать программно добавленные реквизиты табличной части в модуль объекта или подписку на проведение, детально проанализируем архитектурные риски этого подхода и рассмотрим альтернативные, более надежные варианты реализации.

Решение проблемы: Передача данных через ДополнительныеСвойства

Поскольку программно добавленные реквизиты существуют только в контексте формы, нам необходимо принудительно «перекинуть» их в объект до того, как форма закроется, а объект уйдет на запись в базу данных. Для этого идеально подходит стандартное свойство прикладных объектов — ДополнительныеСвойства.

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

Давайте разберем пошагово код, который решает эту задачу:


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

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

Теперь в подписке на проведение (или в самом модуле объекта) мы можем легко извлечь эти данные следующим образом:


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

Как это работает: Лайфхак с РеквизитФормыВЗначение

Давайте выясним причину, почему этот код работает, хотя в метаданных конфигурации у табличной части нет реквизита СтатусЗаявки.

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

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

Критический архитектурный риск: Программное проведение

Описанный выше метод прекрасно работает при интерактивных действиях пользователя. Но рассмотрим крайне важный нюанс: что произойдет, если документ будет проводиться программно?

Примеры программного проведения:

  1. Групповое перепроведение документов (например, обработкой «Групповое изменение реквизитов» или при восстановлении последовательности расчетов).
  2. Проведение документа из фонового задания или регламентной процедуры.
  3. Проведение документа при обмене данными (РИБ, интеграции через API).

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

Разберем, как минимизировать этот риск.

Способ 1: Безопасная обработка в подписке (Обходной путь)

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


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

Способ 2: Использование расширений конфигурации (Рекомендуемый подход)

Поскольку речь идет о современной конфигурации ERP, самым надежным, чистым и архитектурно верным решением будет отказаться от программного добавления колонок на форму в пользу Расширений конфигурации.

Рассмотрим этот алгоритм по шагам:

  1. Создаем новое расширение конфигурации (или используем существующее корпоративное расширение).
  2. Добавляем целевой документ в расширение.
  3. Добавляем табличную часть документа (например, Товары) в расширение.
  4. В расширении добавляем новый реквизит табличной части (например, СтатусЗаявки).
  5. Выводим данный реквизит на форму документа (форму также заимствуем в расширение).

Преимущества этого подхода очевидны:

Способ 3: Независимый регистр сведений и запись напрямую из формы

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

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

← На главную