Интеграция подсистемы печати Библиотеки стандартных подсистем (БСП) в конфигурацию, создаваемую «с нуля», — задача, с которой сталкивается практически каждый разработчик 1С. Современные версии БСП (начиная с 3.0 и выше) используют механизм подключаемых команд, который существенно упрощает жизнь пользователям, но требует от программиста предельной аккуратности при настройке элементов формы и написании кода в модулях.
В этой статье мы подробно разберем, как правильно организовать печать на БСП, выясним причину популярной ошибки «Значение не является значением объектного типа (АдресТаблицыКоманд)» и рассмотрим корректные шаблоны кода для модуля управляемой формы и модуля менеджера объекта.
При попытке запустить форму документа с кодом интеграции БСП разработчики часто сталкиваются с системным сбоем в общем модуле ПодключаемыеКомандыКлиент:
{ОбщийМодуль.ПодключаемыеКомандыКлиент.Модуль(20)}: Значение не является значением объектного типа (АдресТаблицыКоманд)
АдресНастроек = Форма.ПараметрыПодключаемыхКоманд.АдресТаблицыКоманд;
Проанализируем ситуацию. Механизм подключаемых команд БСП работает следующим образом: при создании формы на сервере вызывается метод ПодключаемыеКоманды.ПриСозданииНаСервере(ЭтотОбъект). Система динамически опрашивает менеджеры объектов, собирает доступные команды печати, заполнения или отчетов, формирует служебную таблицу команд и помещает ее во временное хранилище. Адрес этого хранилища записывается в структуру внутри реквизита формы ПараметрыПодключаемыхКоманд.
Если реквизит ПараметрыПодключаемыхКоманд был добавлен на форму вручную с типом данных Строка (или любым другим, кроме Произвольный), платформа не сможет записать в него структуру с адресом хранилища и прочими метаданными подключаемых команд. На клиенте это приводит к ошибке обращения к свойству несуществующего объекта.
Решение проблемы: откройте редактор управляемой формы вашего документа, найдите в списке реквизитов формы ПараметрыПодключаемыхКоманд и измените его тип на Произвольный. Это моментально устранит ошибку инициализации.
Рассмотрим, какие именно элементы и обработчики должны присутствовать в модуле управляемой формы документа для корректной работы печати БСП.
Для начала настроим саму форму в конфигураторе:
ПараметрыПодключаемыхКоманд с типом данных Произвольный.ПодменюПечать. Установим для нее тип Группа - Подменю. Рекомендуется настроить отображение как «Картинка и текст» и выбрать стандартную пиктограмму печати. БСП автоматически найдет эту группу по имени и заполнит ее доступными командами печати при открытии формы.Теперь перейдем к заполнению модуля формы. Нам необходимо подключить обработку создания формы, чтение объекта, открытие и выполнение команд на клиенте и сервере. Разберем шаблон кода по шагам:
&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
// СтандартныеПодсистемы.ПодключаемыеКоманды
ПодключаемыеКоманды.ПриСозданииНаСервере(ЭтотОбъект);
// Конец СтандартныеПодсистемы.ПодключаемыеКоманды
КонецПроцедуры
&НаСервере
Процедура ПриЧтенииНаСервере(ТекущийОбъект)
// СтандартныеПодсистемы.ПодключаемыеКоманды
ПодключаемыеКомандыКлиентСервер.ОбновитьКоманды(ЭтотОбъект, Объект);
// Конец СтандартныеПодсистемы.ПодключаемыеКоманды
КонецПроцедуры
&НаКлиенте
Процедура ПриОткрытии(Отказ)
// СтандартныеПодсистемы.ПодключаемыеКоманды
ПодключаемыеКомандыКлиент.НачатьОбновлениеКоманд(ЭтотОбъект);
// Конец СтандартныеПодсистемы.ПодключаемыеКоманды
КонецПроцедуры
// СтандартныеПодсистемы.ПодключаемыеКоманды
&НаКлиенте
Процедура Подключаемый_ВыполнитьКоманду(Команда)
ПодключаемыеКомандыКлиент.ВыполнитьКоманду(ЭтотОбъект, Команда, Объект);
КонецПроцедуры
&НаСервере
Процедура Подключаемый_ВыполнитьКомандуНаСервере(Контекст, Результат)
ПодключаемыеКоманды.ВыполнитьКоманду(ЭтотОбъект, Контекст, Объект, Результат);
КонецПроцедуры
&НаКлиенте
Процедура Подключаемый_ОбновитьКоманды()
ПодключаемыеКомандыКлиентСервер.ОбновитьКоманды(ЭтотОбъект, Объект);
КонецПроцедуры
// Конец СтандартныеПодсистемы.ПодключаемыеКоманды
Обратите внимание, что все обработчики с префиксом Подключаемый_ должны быть явно назначены в свойствах соответствующих элементов формы или событий (например, событие нажатия для динамически создаваемых кнопок автоматически перенаправляется на Подключаемый_ВыполнитьКоманду через механизмы БСП).
Вся основная логика генерации печатных форм в БСП должна быть сосредоточена в модуле менеджера объекта (документа или справочника). Нам необходимо реализовать две обязательные экспортные процедуры: ДобавитьКомандыПечати и Печать.
Рассмотрим подробнее процедуру добавления команд печати. Именно здесь мы регистрируем наши печатные формы, указываем их идентификаторы, представления и то, где именно (в каких формах) они должны отображаться.
#Область ПрограммныйИнтерфейс
// Заполняет список команд печати.
//
// Параметры:
// КомандыПечати – ТаблицаЗначений – состав полей см. в функции УправлениеПечатью.СоздатьКоллекциюКомандПечати.
//
Процедура ДобавитьКомандыПечати(КомандыПечати) Экспорт
// Регистрация печатной формы "Путевой лист"
КомандаПечати = КомандыПечати.Добавить();
КомандаПечати.МенеджерПечати = "Документ.ПутевойЛист";
КомандаПечати.Идентификатор = "ПФ_ПутевойЛист";
КомандаПечати.Представление = НСтр("ru = 'Путевой лист (легковой)'");
КомандаПечати.ПроверкаПроведенияПередПечатью = Истина;
КомандаПечати.СписокФорм = "ФормаСписка,ФормаДокумента";
КонецПроцедуры
Теперь проанализируем процедуру Печать. Ее задача — определить, какие именно макеты запросил пользователь (ведь в БСП можно выбрать несколько печатных форм одновременно), сформировать табличные документы и передать их обратно в систему.
// Формирует печатные формы.
//
// Параметры:
// МассивОбъектов – Массив – ссылки на объекты, которые нужно распечатать;
// ПараметрыПечати – Структура – дополнительные настройки печати;
// КоллекцияПечатныхФорм – ТаблицаЗначений – сформированные табличные документы (выходной параметр)
// ОбъектыПечати – СписокЗначений – значение – ссылка на объект;
// представление – имя области, в которой был выведен объект (выходной параметр);
// ПараметрыВывода – Структура – дополнительные параметры сформированных табличных документов (выходной параметр).
//
Процедура Печать(МассивОбъектов, ПараметрыПечати, КоллекцияПечатныхФорм, ОбъектыПечати, ПараметрыВывода) Экспорт
// Проверяем, выбрана ли пользователем наша печатная форма
Если УправлениеПечатью.НужноПечататьМакет(КоллекцияПечатныхФорм, "ПФ_ПутевойЛист") Тогда
// Формируем табличный документ с помощью нашей функции
ТабличныйДокумент = СформироватьПечатнуюФормуПутевогоЛиста(МассивОбъектов, ОбъектыПечати);
// Выводим полученный табличный документ в коллекцию БСП
УправлениеПечатью.ВывестиТабличныйДокументВКоллекцию(
КоллекцияПечатныхФорм,
"ПФ_ПутевойЛист",
НСтр("ru = 'Путевой лист (легковой)'"),
ТабличныйДокумент,
,
"Документ.ПутевойЛист.ПФ_ПутевойЛист" // Путь к макету в конфигурации
);
КонецЕсли;
КонецПроцедуры
#КонецОбласти
Разработчики часто совершают две серьезные архитектурные ошибки при написании функции формирования табличного документа. Посмотрим на некорректный пример кода, который часто встречается на форумах:
// Пример кода С ОШИБКАМИ (так делать НЕ надо)
Функция ПечатьПутевогоЛиста(МассивОбъектов, ОбъектыПечати)
Ссылка = МассивОбъектов[0]; // Ошибка №1: жесткая привязка к первому элементу массива
...
Макет = Документы.ПутевойЛист.ПолучитьМакет("ПФ_ПутевойЛист");
ОбластьШапка = Макет.ПолучитьОбласть("ОбластьШапка");
ЗаполнитьЗначенияСвойств(ОбластьШапка.Параметры, ОбъектыПечати); // Ошибка №2: ОбъектыПечати пуст!
...
КонецФункции
Выясним причины этих ошибок и разберем, как написать код правильно:
МассивОбъектов[0]). Команды печати БСП доступны не только на форме документа, но и в форме списка. Пользователь может выделить десять документов и нажать кнопку «Печать». Если ваш код завязан на первый элемент массива, система распечатает десять копий первого документа, проигнорировав остальные. Необходимо всегда обходить массив в цикле или использовать запрос, обрабатывающий весь массив документов целиком.ОбъектыПечати. Параметр ОбъектыПечати является выходным параметром БСП. Изначально он пуст. Он предназначен для того, чтобы разработчик зафиксировал в нем связь между выведенными областями табличного документа и ссылками на объекты метаданных. Заполнение параметров областей макета должно производиться исключительно данными, полученными запросом из базы данных по переданному МассивОбъектов.Рассмотрим правильный вариант реализации функции формирования табличного документа с учетом пакетной групповой печати и правильной ассоциации областей:
Функция СформироватьПечатнуюФормуПутевогоЛиста(МассивОбъектов, ОбъектыПечати)
ТабДокумент = Новый ТабличныйДокумент;
ТабДокумент.КлючПараметровПечати = "ПараметрыПечати_ПутевойЛист";
ТабДокумент.АвтоМасштаб = Истина;
Макет = Документы.ПутевойЛист.ПолучитьМакет("ПФ_ПутевойЛист");
// Получаем данные для печати одним запросом ко всей выборке объектов
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| ПутевойЛист.Ссылка КАК Ссылка,
| ПутевойЛист.Номер КАК Номер,
| ПутевойЛист.Дата КАК Дата,
| ПутевойЛист.Организация КАК Организация,
| ПутевойЛист.Водитель КАК Водитель
|ИЗ
| Документ.ПутевойЛист КАК ПутевойЛист
|ГДЕ
| ПутевойЛист.Ссылка В(&МассивОбъектов)";
Запрос.УстановитьПараметр("МассивОбъектов", МассивОбъектов);
Выборка = Запрос.Выполнить().Выбрать();
ПервыйДокумент = Истина;
Пока Выборка.Следующий() Цикл
// Разделяем документы при печати на новые страницы
Если Не ПервыйДокумент Тогда
ТабДокумент.ВывестиГоризонтальныйРазделительСтраниц();
КонецЕсли;
ПервыйДокумент = Ложь;
// Запоминаем начальную строку для текущего документа
НомерСтрокиНачало = ТабДокумент.ВысотаТаблицы + 1;
// Выводим шапку
ОбластьШапка = Макет.ПолучитьОбласть("ОбластьШапка");
ОбластьШапка.Параметры.Заполнить(Выборка);
ТабДокумент.Вывести(ОбластьШапка);
// Выводим организацию
ОбластьОрганизация = Макет.ПолучитьОбласть("ОбластьОрганизация");
ОбластьОрганизация.Параметры.Заполнить(Выборка);
ТабДокумент.Вывести(ОбластьОрганизация);
// Ассоциируем выведенную область с конкретным объектом для механизмов БСП
// (это нужно для корректной отправки по почте, сохранения файлов и разбиения по копиям)
УправлениеПечатью.ЗадатьОбластьПечатиДокумента(
ТабДокумент,
НомерСтрокиНачало,
ОбъектыПечати,
Выборка.Ссылка
);
КонецЦикла;
Возврат ТабДокумент;
КонецФункции
Для того чтобы система БСП знала, что у вашего документа вообще существуют команды печати, его менеджер необходимо зарегистрировать. Если этого не сделать, процедура ДобавитьКомандыПечати в менеджере вашего документа никогда не будет вызвана ядром подсистемы.
Перейдем в общий модуль УправлениеПечатьюПереопределяемый и найдем процедуру ПриОпределенииОбъектовСКомандамиПечати. Добавим туда наш новый документ:
// Определяет объекты метаданных, в менеджерах которых настроены команды печати.
//
// Параметры:
// СписокОбъектов - Массив - объекты метаданных с командами печати.
//
Процедура ПриОпределенииОбъектовСКомандамиПечати(СписокОбъектов) Экспорт
СписокОбъектов.Добавить(Метаданные.Документы.ПутевойЛист);
КонецПроцедуры
В некоторых версиях БСП (в зависимости от настроек интеграции конкретной конфигурации) аналогичная регистрация может происходить через общий модуль ИнтеграцияПодсистемБСП.ПриОпределенииОбъектовСКомандамиПечати. Если вы разрабатываете конфигурацию с нуля на чистой БСП, убедитесь, что вы заполнили коллекцию именно в том переопределяемом модуле, который активен в вашей редакции библиотеки.
Важным преимуществом правильного развертывания печати на БСП является автоматическая поддержка механизма дополнительных отчетов и обработок. Создав команды печати один раз по описанному выше стандарту, вы получаете следующие возможности без изменения кода конфигурации в будущем:
ПодменюПечать на форме документа и списка.Соблюдение этих стандартов гарантирует стабильную работу вашей конфигурации, легкую обновляемость БСП в будущем и полное отсутствие непредвиденных ошибок при работе пользователей с печатными формами.