При разработке внешних печатных форм программисты нередко сталкиваются с ситуацией: при интерактивном открытии обработки и нажатии на кнопку печати макет формируется корректно, со всеми строками и суммами. Однако стоит зарегистрировать эту же форму в информационной базе (через справочник внешних обработок или печатных форм) и запустить ее штатно из документа, как табличная часть перестает заполняться — печатная форма выходит пустой либо без единой строки товаров. Разберем по шагам, почему возникает такое поведение, как устроена передача данных в различных конфигурациях и как сделать внешнюю печатную форму универсальной.
Посмотрим на типовой фрагмент запроса, который разработчики размещают в процедуре формирования печатного листа:
Запрос = Новый Запрос;
Запрос.УстановитьПараметр("Ссылка", СсылкаНаОбъект.Ссылка);
Запрос.Текст = "ВЫБРАТЬ
| СчетНаОплатуТовары.Ссылка,
| СчетНаОплатуТовары.НомерСтроки,
| СчетНаОплатуТовары.Номенклатура,
| СчетНаОплатуТовары.Количество,
| СчетНаОплатуТовары.Цена,
| СчетНаОплатуТовары.Сумма
|ИЗ
| Документ.СчетНаОплату.Товары КАК СчетНаОплатуТовары
|ГДЕ
| СчетНаОплатуТовары.Ссылка = &Ссылка";
Выборка = Запрос.Выполнить().Выбрать();
Пока Выборка.Следующий() Цикл
// Вывод строк в табличный документ
КонецЦикла;
С точки зрения языка запросов 1С код написан синтаксически верно. Если при выполнении отчета цикл Пока Выборка.Следующий() Цикл не выполняется ни разу, это однозначно указывает на то, что условие в секции ГДЕ СчетНаОплатуТовары.Ссылка = &Ссылка не нашло соответствий. Выясним, почему параметр Ссылка оказался пустым или некорректным.
В типовых решениях (например, «Управление торговлей 10.3», «Комплексная автоматизация 1.1» или «Управление производственным предприятием 1.3») при вызове внешней обработки механизм подсистемы печати выполняет следующую последовательность действий:
ВнешниеОбработки.Создать(...).СсылкаНаОбъект и заполняет его ссылкой на текущий документ.Печать() без параметров, которая возвращает сформированный ТабличныйДокумент.Однако в отраслевых конфигурациях (в частности, в линейке «Альфа-Авто») механизм подключения внешних печатных форм реализован совершенно иначе. Проанализируем строку вызова из модуля управления внешними формами:
ТабДокумент = ВнешниеОбработки.Создать(ИмяФайлаПечатнойФормы).Печать(ДокументОбъект, ТабДокумент);
В этой схеме система не заполняет реквизит обработки СсылкаНаОбъект. Вместо этого объект документа передается напрямую в качестве первого аргумента экспортной функции Печать модуля объекта. В результате при обращении к СсылкаНаОбъект.Ссылка код пытается прочитать свойство у незаполненного реквизита, параметр &Ссылка получает значение Неопределено или пустую ссылку, и запрос возвращает пустую выборку.
Обратите внимание на тип передаваемого значения в «Альфа-Авто»: в процедуру передается переменная с типом ДокументОбъект, а не ДокументСсылка. Если пользователь нажал кнопку печати в форме документа, в который только что внесли изменения или который еще не был записан в базу данных:
ДокументОбъект.Ссылка является пустой ссылкой (Ссылка.Пустая() = Истина). В таблицах базы данных таких записей еще нет, поэтому запрос не возвратит ни одной строки.Платформа 1С:Предприятие при запуске обработок из справочника выгружает двоичные данные во временную папку пользователя (каталог Temp). Если вы вносите правки в файл обработки на диске и заново загружаете его в справочник, платформа может продолжать исполнять закэшированный файл из временного хранилища. Чтобы исключить влияние кэша, рекомендуется очищать каталог временных файлов сеанса или перезапускать клиентское приложение при отладке внешних форм.
Чтобы внешняя печатная форма корректно отрабатывала и при ручном запуске через Файл - Открыть, и при подключении через типовые механизмы, и при работе в «Альфа-Авто», напишем универсальный обработчик в модуле объекта внешней обработки.
Реализуем проверку входящего контекста:
Функция Печать(ПараметрОбъект = Неопределено, ТабДокумент = Неопределено) Экспорт
// 1. Определяем источник данных
ТекущийОбъект = Неопределено;
Если ПараметрОбъект <> Неопределено Тогда
// Вызов из системы Альфа-Авто (передан объект или ссылка через аргумент)
ТекущийОбъект = ПараметрОбъект;
ИначеЕсли ЗначениеЗаполнено(СсылкаНаОбъект) Тогда
// Интерактивный запуск или типовой механизм (заполнен реквизит обработки)
ТекущийОбъект = СсылкаНаОбъект;
КонецЕсли;
Если ТекущийОбъект = Неопределено Тогда
Сообщить("Не указан документ для формирования печатной формы!");
Возврат Неопределено;
КонецЕсли;
// 2. Получаем ссылку для запроса
СсылкаДляЗапроса = Неопределено;
Если Метаданные.Документы.Содержит(ТекущийОбъект.Метаданные()) Тогда
СсылкаДляЗапроса = ТекущийОбъект.Ссылка;
Иначе
СсылкаДляЗапроса = ТекущийОбъект;
КонецЕсли;
// 3. Инициализируем табличный документ, если он не был передан извне
Если ТабДокумент = Неопределено Тогда
ТабДокумент = Новый ТабличныйДокумент;
КонецЕсли;
// 4. Проверяем, записан ли документ в базе данных
Если СсылкаДляЗапроса.Пустая() Тогда
// Если документ не записан, данные табличной части берем напрямую из объекта
ЗаполнитьНапрямуюИзОбъекта(ТекущийОбъект, ТабДокумент);
Иначе
// Если документ сохранен, выполняем выборку через запрос
ЗаполнитьЧерезЗапрос(СсылкаДляЗапроса, ТабДокумент);
КонецЕсли;
Возврат ТабДокумент;
КонецФункции
Разберем реализацию вспомогательных процедур. Для сохраненных документов выполним запрос к базе данных, передав вычисленную ссылку:
Процедура ЗаполнитьЧерезЗапрос(СсылкаНаДокумент, ТабДокумент)
Запрос = Новый Запрос;
Запрос.УстановитьПараметр("Ссылка", СсылкаНаДокумент);
Запрос.Текст =
"ВЫБРАТЬ
| СчетТовары.НомерСтроки КАК НомерСтроки,
| СчетТовары.Номенклатура.Наименование КАК Номенклатура,
| СчетТовары.Количество КАК Количество,
| СчетТовары.Цена КАК Цена,
| СчетТовары.Сумма КАК Сумма
|ИЗ
| Документ.СчетНаОплату.Товары КАК СчетТовары
|ГДЕ
| СчетТовары.Ссылка = &Ссылка
|УПОРЯДОЧИТЬ ПО
| НомерСтроки";
Выборка = Запрос.Выполнить().Выбрать();
Макет = ПолучитьМакет("Печать");
ОбластьСтрока = Макет.ПолучитьОбласть("Строка");
Пока Выборка.Следующий() Цикл
ЗаполнитьЗначенияСвойств(ОбластьСтрока.Параметры, Выборка);
ТабДокумент.Вывести(ОбластьСтрока);
КонецЦикла;
КонецПроцедуры
Для случаев, когда документ передан в виде несохраненного экземпляра ДокументОбъект, организуем обход коллекции строк без обращения к базе данных:
Процедура ЗаполнитьНапрямуюИзОбъекта(ДокументОбъект, ТабДокумент)
Макет = ПолучитьМакет("Печать");
ОбластьСтрока = Макет.ПолучитьОбласть("Строка");
Для Каждого СтрТовар Из ДокументОбъект.Товары Цикл
ОбластьСтрока.Параметры.НомерСтроки = СтрТовар.НомерСтроки;
ОбластьСтрока.Параметры.Номенклатура = СтрТовар.Номенклатура.Наименование;
ОбластьСтрока.Параметры.Количество = СтрТовар.Количество;
ОбластьСтрока.Параметры.Цена = СтрТовар.Цена;
ОбластьСтрока.Параметры.Сумма = СтрТовар.Сумма;
ТабДокумент.Вывести(ОбластьСтрока);
КонецЦикла;
КонецПроцедуры
При возникновении трудностей с регистрацией внешних печатных форм рекомендуем придерживаться следующего чек-листа:
Печать обязательно должна иметь признак Экспорт и находиться в модуле объекта обработки, а не в модуле формы.(ДокументОбъект, ТабДокумент), а в типовых конфигурациях 1С — вызов без параметров). Делайте параметры функции необязательными по умолчанию (= Неопределено).