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

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

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

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

Для начала проанализируем архитектуру платформы. Модуль объекта работает на сервере и оперирует данными, которые хранятся в базе данных или передаются в экземпляр объекта. Реквизиты формы — это элементы контекста формы, которые "живут" только пока открыто окно документа. Когда мы нажимаем кнопку "Записать", данные из формы передаются на сервер, создается экземпляр объекта базы данных, и управление передается в его программный модуль. Напрямую обратиться из модуля объекта к элементам формы невозможно, так как форма может вообще не существовать (например, если документ записывается программно или через групповую обработку).

Основное решение: Использование структуры ДополнительныеСвойства

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

Рассмотрим по шагам, как реализовать передачу значения реквизита ДокументПолучен в модуль объекта.

Шаг 1. Подготовка данных в модуле формы

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


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

В данном примере мы создаем в структуре ключ "ПризнакДокументПолучен" и присваиваем ему значение нашего экранного реквизита. Теперь эти данные "приклеены" к объекту на время текущей транзакции записи.

Шаг 2. Получение данных в модуле объекта

Теперь перейдем в модуль объекта (например, документа). Нам нужно извлечь переданное значение. Рассмотрим это на примере процедуры ОбработкаПроведения.


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

КонецПроцедуры

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

Альтернативный подход: Обработка в событии ПослеЗаписиНаСервере

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

В модуле формы после успешной записи объекта мы можем вызвать серверную процедуру:


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

&НаСервере
Процедура ЗаписатьСтатусВРегистр(СсылкаНаДокумент, ЗначениеПризнака)
    
    МенеджерЗаписи = РегистрыСведений.СтатусыДокументов.СоздатьМенеджерЗаписи();
    МенеджерЗаписи.Документ = СсылкаНаДокумент;
    МенеджерЗаписи.СтатусПолучен = ЗначениеПризнака;
    МенеджерЗаписи.Записать();
    
КонецПроцедуры

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

Нюансы работы с расширениями и сохранением данных

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

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

Важные рекомендации по транзакционности

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

Рассмотрим пример в ОбработкаПроведения:


Движение = Движения.СтатусыДокументов.Добавить();
Движение.Период = Дата;
Движение.Регистратор = Ссылка;
Движение.СтатусПолучен = ?(ДополнительныеСвойства.Свойство("ПризнакДокументПолучен"), ДополнительныеСвойства.ПризнакДокументПолучен, Ложь);

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

Подведем итог: Для передачи временного контекста "Форма -> Модуль объекта" всегда используйте ДополнительныеСвойства. Это делает ваш код чистым, предсказуемым и безопасным с точки зрения программного взаимодействия с объектами базы данных.

← На главную