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

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

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

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

Почему не работают стандартные попытки заполнения?

Для начала разберем по шагам ошибки в коде автора темы. Рассмотрим его первую попытку:


Пока Перечень.Следующий() Цикл
    Если Перечень.Проведен = Истина Тогда
        Продолжить;
    КонецЕсли;
    Документ = Перечень.ПолучитьОбъект();
    Форма = Документ.ПолучитьФорму("ФормаДокумента");
    Форма.ОткрытьМодально(15);
    Форма.ЭлементыФормы.СуммаОплаты.Значение = Документ.СуммаДокумента;
КонецЦикла;

Причина ошибки №1: Блокировка выполнения модальным окном. Метод ОткрытьМодально() полностью останавливает выполнение текущего потока кода во внешней обработке. Строка присвоения значения реквизиту формы выполнится только тогда, когда модальное окно будет закрыто пользователем или закроется по таймауту (через 15 секунд). К моменту закрытия формы её контекст и элементы управления уже уничтожены, поэтому присвоение значения не имеет никакого смысла.

Поняв эту ошибку, автор попытался перенести заполнение до момента открытия формы:


Документ = Перечень.ПолучитьОбъект();
Форма = Документ.ПолучитьФорму("ФормаДокумента");
Форма.ЭлементыФормы.СуммаОплаты.Значение = Документ.СуммаДокумента;
Форма.ОткрытьМодально(15);
Документ.Провести();

Причина ошибки №2: Очистка данных при инициализации формы. Назначение значения элементу формы до её открытия часто оказывается бесполезным. При вызове метода ОткрытьМодально() внутри формы срабатывают стандартные обработчики событий ПередОткрытием и ПриОткрытии. В типовых конфигурациях в этих процедурах обычно прописан код инициализации, который заполняет элементы формы значениями по умолчанию или рассчитывает их заново. В результате переданное значение просто затирается стандартными алгоритмами формы.

Причина ошибки №3: Разделение контекстов формы и объекта. Автор упоминает, что реквизит СуммаОплаты влияет на проведение документа. Важно понимать, что процедура ОбработкаПроведения выполняется исключительно в модуле объекта документа на стороне сервера (или в транзакции базы данных). Модуль объекта физически ничего не знает о существовании формы, её элементах управления или реквизитах формы. Если проверка суммы действительно завязана на реквизит формы, то объект получает это значение обходным путем (например, через глобальные переменные или свойства), либо проверка реализована в самой форме в событии ПередЗаписью. В последнем случае вызов метода Документ.Провести() напрямую из обработки вообще обойдет форму и все её проверки.


Способ 1. Использование экспортных переменных формы (Рекомендуемый вариант с визуальным открытием)

Если бизнес-процесс требует, чтобы пользователь обязательно видел форму документа на экране, лучшим решением будет передача значения через экспортную переменную модуля формы. Это позволит избежать затирания данных при инициализации.

Шаг 1. Модификация модуля формы документа. В самом верху модуля формы документа (вне процедур и функций) объявим экспортную переменную:

Перем ВходящаяСуммаОплаты Экспорт;

Шаг 2. Обработка события при открытии. В процедуре ПриОткрытии() модуля формы пропишем логику установки значения из этой переменной:


Процедура ПриОткрытии()
    // Стандартные процедуры инициализации формы...
    
    // Если переменная была заполнена извне, переносим её в реквизит формы
    Если ЗначениеЗаполнено(ВходящаяСуммаОплаты) Тогда
        СуммаОплаты = ВходящаяСуммаОплаты;
        // Если это связано с элементом формы напрямую:
        ЭлементыФормы.СуммаОплаты.Значение = ВходящаяСуммаОплаты;
    КонецЕсли;
КонецПроцедуры

Шаг 3. Код во внешней обработке. Теперь мы можем безопасно передавать значение в форму до её открытия:


ДокументОбъект = Перечень.ПолучитьОбъект();
Форма = ДокументОбъект.ПолучитьФорму("ФормаДокумента");

// Заполняем экспортную переменную формы
Форма.ВходящаяСуммаОплаты = ДокументОбъект.СуммаДокумента;

// Открываем форму модально. Пользователь видит заполненное поле.
Форма.ОткрытьМодально();

Способ 2. Использование дополнительных свойств объекта (Без открытия формы)

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

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

Шаг 1. Передача значения из внешней обработки:


ДокументОбъект = Перечень.ПолучитьОбъект();

// Записываем значение в дополнительные свойства объекта
ДокументОбъект.ДополнительныеСвойства.Вставить("ПрограммнаяСуммаОплаты", ДокументОбъект.СуммаДокумента);

// Проводим документ напрямую без открытия формы
ДокументОбъект.Записать(РежимЗаписиДокумента.Проведение);

Шаг 2. Обработка значения в модуле объекта документа: В процедуре проведения или перед записью считываем переданное свойство:


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

Способ 3. Автоматический режим работы формы (Гибридный метод)

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

Шаг 1. Настройка модуля формы документа: Объявим управляющий флаг:


Перем АвтоматическийРежим Экспорт;

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

Шаг 2. Вызов из внешней обработки:


ДокументОбъект = Перечень.ПолучитьОбъект();
Форма = ДокументОбъект.ПолучитьФорму("ФормаДокумента");

// Включаем автоматический режим работы формы
Форма.АвтоматическийРежим = Истина;

// Запускаем процесс. Форма откроется, сама заполнит поле, проведет документ и закроется.
Форма.ОткрытьМодально();

Рассмотренные подходы позволяют гибко и безопасно обходить ограничения платформы 1С при работе с модальными окнами, разделяя зоны ответственности между экранным интерфейсом и бизнес-логикой проведения документов.

← На главную