В практической работе разработчика на платформе 1С:Предприятие 7.7 (в сообществе известной как «клюшки») часто возникает задача пакетной печати. Например, когда создается комплексный документ (путевой лист, реестр документов или спецификация), в табличной части которого содержатся ссылки на другие документы (накладные, счета, акты). Бухгалтеру или оператору требуется распечатать весь этот пакет документов одним нажатием кнопки.
Давайте подробно проанализируем ситуацию, выясним причину ограничений платформы 1С 7.7 и рассмотрим три надежных способа реализации этой задачи.
В отличие от платформы 1С:Предприятие 8.х, где у объектов метаданных могут быть свои экспортные методы в модуле менеджера или объекта, в версии 7.7 у объектов типа Документ нет встроенного метода Печать(), доступного извне.
Если мы попытаемся написать прямой код обхода табличной части следующего вида:
// Этот код вызовет ошибку!
ВыбратьСтроки();
Пока ПолучитьСтроку() = 1 Цикл
ДокСсылка = РеквизитДокументТЧ; // Ссылка на документ в табличной части
ДокСсылка.Печать(); // Ошибка: Значение не представляет агрегатный объект (Печать)
КонецЦикла;
Платформа выдаст критическую ошибку выполнения, так как метод Печать() обычно объявляется в модуле формы конкретного документа и недоступен напрямую из контекста ссылки. Чтобы обойти это ограничение, программисты используют проверенные временем архитектурные приемы.
---
Это самый популярный и изящный способ, который позволяет использовать уже существующий код печати внутри формы целевого документа без его дублирования и без визуального мерцания окон на экране пользователя.
Разберем этот метод по шагам.
Шаг 1. Код в ведущем (групповом) документе.
В модуле формы документа, из которого мы запускаем печать, пишем процедуру обхода строк табличной части. Для передачи команды "печатай скрыто" мы будем использовать специальный параметр типа СписокЗначений.
Процедура ВыполнитьПечатьПакета()
// Создаем список значений для передачи параметров управления
ПараметрыОткрытия = СоздатьОбъект("СписокЗначений");
ПараметрыОткрытия.Установить("РежимПечати", "Тихий"); // Флаг скрытой печати
// Обходим строки табличной части ведущего документа
ВыбратьСтроки();
Пока ПолучитьСтроку() = 1 Цикл
ДокСсылка = РеквизитДокументТЧ; // Получаем ссылку на документ из строки
// Обязательно проверяем, заполнен ли реквизит в строке
Если ДокСсылка.Выбран() = 1 Тогда
// Программно открываем форму подчиненного документа
ОткрытьФорму(ДокСсылка, ПараметрыОткрытия);
КонецЕсли;
КонецЦикла;
КонецПроцедуры
Шаг 2. Доработка модуля формы подчиненного документа.
Теперь нам нужно научить подчиненный документ (тот, который лежит внутри реквизита ТЧ) правильно обрабатывать этот параметр при открытии. Переходим в модуль формы этого документа и дорабатываем предопределенную процедуру ПриОткрытии():
Процедура ПриОткрытии()
// Получаем переданный параметр
Парам = Форма.Параметр;
Если ТипЗначенияСтр(Парам) = "СписокЗначений" Тогда
// Проверяем, пришла ли команда скрытой печати
Если Парам.Получить("РежимПечати") = "Тихий" Тогда
// Вызываем стандартную процедуру печати, которая есть в форме документа
Печать();
// КРИТИЧЕСКИ ВАЖНО: Отменяем открытие формы на экране!
СтатусВозврата(0);
Возврат;
КонецЕсли;
КонецЕсли;
// Стандартное открытие формы (если открывает пользователь вручную)
// ...
КонецПроцедуры
Почему это работает? Метод СтатусВозврата(0) сообщает платформе, что открытие формы нужно прервать. При этом процедура Печать() успевает отработать, отправить документ на принтер или вывести его на экран (в зависимости от логики процедуры), а сама форма так и не появляется перед пользователем, экономя ресурсы компьютера.
---
Если в табличной части могут быть документы самых разных видов (например, и "Счета", и "Реализации", и "Приходные ордера"), то внедрять код обработки в форму каждого документа может быть трудоемко. В таком случае логику формирования печатных форм целесообразно вынести в Глобальный модуль.
Рассмотрим подробнее реализацию этого подхода.
Шаг 1. Создание процедуры в Глобальном модуле.
В Глобальном модуле конфигурации пишем экспортную процедуру, которая принимает объект документа, анализирует его вид и запускает соответствующий алгоритм печати:
Процедура глПечатьДокументаИзТЧ(КонтекстДокумента) Экспорт
ВидДока = КонтекстДокумента.Вид();
Если ВидДока = "Реализация" Тогда
// Вызов логики формирования печатной формы накладной
// (передаем объект документа в соответствующую процедуру)
глПечатьРеализации(КонтекстДокумента);
ИначеЕсли ВидДока = "Счет" Тогда
// Вызов печати счета
глПечатьСчета(КонтекстДокумента);
Иначе
Сообщить("Печать для документа вида " + ВидДока + " не поддерживается!", "!");
КонецЕсли;
КонецПроцедуры
Шаг 2. Вызов печати из ведущего документа.
В модуле формы ведущего документа при обходе табличной части мы должны инициализировать объект документа через СоздатьОбъект(), спозиционировать его методом НайтиДокумент() и передать в глобальную функцию:
Процедура ПечатьПакетаЧерезГлобальныйМодуль()
ВыбратьСтроки();
Пока ПолучитьСтроку() = 1 Цикл
ДокСсылка = РеквизитДокументТЧ;
Если ДокСсылка.Выбран() = 1 Тогда
// Создаем пустой объект нужного типа документа
ОболочкаДокумента = СоздатьОбъект("Документ." + ДокСсылка.Вид());
// Находим документ в базе данных по ссылке
Если ОболочкаДокумента.НайтиДокумент(ДокСсылка) = 1 Тогда
// Вызываем экспортную процедуру
глПечатьДокументаИзТЧ(ОболочкаДокумента);
КонецЕсли;
КонецЕсли;
КонецЦикла;
КонецПроцедуры
Этот способ позволяет держать весь код печати в одном месте, что существенно упрощает дальнейшую поддержку и обновление конфигурации.
---
Если вы работаете в типовой конфигурации (например, «Торговля и Склад 9.2» или «Бухгалтерский учет 4.5»), в них уже заложен механизм внешних печатных форм (файлы с расширением .ert, хранящиеся в каталоге ExtForms\PrnForms).
Мы можем программно вызвать внешнюю обработку печати напрямую, передав ей контекст найденного документа:
Процедура ПечатьЧерезВнешнийФайл()
ВыбратьСтроки();
Пока ПолучитьСтроку() = 1 Цикл
ДокСсылка = РеквизитДокументТЧ;
Если ДокСсылка.Выбран() = 1 Тогда
ДокОбъект = СоздатьОбъект("Документ." + ДокСсылка.Вид());
Если ДокОбъект.НайтиДокумент(ДокСсылка) = 1 Тогда
// Путь к файлу внешней печатной формы
ПутьКФорме = КаталогИБ() + "ExtForms\PrnForms\nakl.ert";
// Открываем форму отчета (ВПФ), передавая контекст документа в качестве параметра
ОткрытьФорму("Отчет", ДокОбъект, ПутьКФорме);
EndIf;
КонецЕсли;
КонецЦикла;
КонецПроцедуры
Во внешней обработке nakl.ert в процедуре ПриОткрытии() мы считываем контекст из Форма.Параметр, формируем табличный документ, отправляем его на печать и закрываем обработку с помощью СтатусВозврата(0). Это позволяет избежать изменения метаданных конфигурации.
---
Если ДокСсылка.Выбран() = 1 Тогда. Если строка окажется пустой (документ не выбран), обращение к его свойствам вызовет ошибку системы.Показать() только для отладки, а для автоматической печати применяйте метод Напечатать(0) (параметр 0 отключает вывод диалогового окна настройки печати).Состояние().