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