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