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