Как передать данные реквизита формы документа в модуль менеджера для печати или отчета?

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

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

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

Почему нельзя получить реквизиты формы напрямую из модуля менеджера?

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

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

Рассмотрим, какими путями мы можем безопасно и красиво передать эти данные на сервер в модуль менеджера.

---

Способ 1. Прямая передача через параметры метода (для самописных механизмов)

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

Давайте разберем по шагам, как это реализовать на практике.

Во-первых, в модуле менеджера вашего документа (или отчета) определим экспортную функцию, которая принимает нужный нам параметр:


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

Во-вторых, в модуле формы документа вызовем эту функцию, передав в нее реквизит формы напрямую:


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

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

Этот способ прост и надежен, но применим только тогда, когда вы полностью контролируете процесс вызова печати.

---

Способ 2. Реализация через механизмы БСП (Библиотека Стандартных Подсистем)

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

Для передачи параметров БСП предоставляет штатный механизм — структуру ДополнительныеПараметрыПечати. Давайте посмотрим, как это настроить.

Шаг 1. В модуле формы документа перед вызовом стандартной команды печати переопределяем или дополняем параметры отправки:


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

Шаг 2. В модуле менеджера документа в стандартной экспортной процедуре Печать извлекаем переданные параметры из входящей структуры:


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

Использование этого механизма является стандартом разработки в среде 1С, так как оно не нарушает логику БСП и сохраняет совместимость при обновлениях системы.

---

Способ 3. Передача больших объемов данных через Временное хранилище

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

Выясним, как решить эту задачу с помощью механизма временного хранилища:

  1. В модуле формы на сервере преобразуем реквизит формы (табличную часть или таблицу на форме) в объект базы данных (коллекцию) и поместим его во Временное хранилище. Мы получим уникальный адрес в виде строки.
  2. Передадим эту строку-адрес в модуль менеджера.
  3. В модуле менеджера получим объект из хранилища по адресу и прочитаем данные.

Посмотрим на пример реализации этой схемы.

В модуле формы пишем следующий код:


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

В модуле менеджера принимаем адрес и извлекаем данные:


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

---

Способ 4. Работа с незаписанными данными формы (Преобразование формы в объект)

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

Как нам получить актуальные, еще не сохраненные данные из формы в модуле менеджера? Для этого мы можем преобразовать форму в объект прямо в модуле формы на сервере с помощью функции РеквизитФормыВЗначение.

Разберем по шагам, как это выглядит в коде:

В модуле формы преобразуем объект и передаем его:


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

В модуле менеджера мы отказываемся от выполнения запросов к базе данных по ссылке, а берем данные непосредственно из переданного объекта:


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

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

---

Важные правила хорошего тона (Best Practices) при проектировании печати

Когда вы проектируете связь между формой и модулем менеджера, всегда помните о следующих правилах:

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

← На главную