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