Почему внешняя печатная форма в 1С не выводит строки и как исправить пустой результат запроса

Программист 1С v8.3 (Обычные формы) IT и автоматизация бизнеса
← На главную

При разработке внешних печатных форм программисты нередко сталкиваются с ситуацией: при интерактивном открытии обработки и нажатии на кнопку печати макет формируется корректно, со всеми строками и суммами. Однако стоит зарегистрировать эту же форму в информационной базе (через справочник внешних обработок или печатных форм) и запустить ее штатно из документа, как табличная часть перестает заполняться — печатная форма выходит пустой либо без единой строки товаров. Разберем по шагам, почему возникает такое поведение, как устроена передача данных в различных конфигурациях и как сделать внешнюю печатную форму универсальной.

Анализ исходного кода и проявления проблемы

Посмотрим на типовой фрагмент запроса, который разработчики размещают в процедуре формирования печатного листа:


Запрос = Новый Запрос;
Запрос.УстановитьПараметр("Ссылка", СсылкаНаОбъект.Ссылка);
Запрос.Текст = "ВЫБРАТЬ
               |    СчетНаОплатуТовары.Ссылка,
               |    СчетНаОплатуТовары.НомерСтроки,
               |    СчетНаОплатуТовары.Номенклатура,
               |    СчетНаОплатуТовары.Количество,
               |    СчетНаОплатуТовары.Цена,
               |    СчетНаОплатуТовары.Сумма
               |ИЗ
               |    Документ.СчетНаОплату.Товары КАК СчетНаОплатуТовары
               |ГДЕ
               |    СчетНаОплатуТовары.Ссылка = &Ссылка";

Выборка = Запрос.Выполнить().Выбрать();
Пока Выборка.Следующий() Цикл
    // Вывод строк в табличный документ
КонецЦикла;

С точки зрения языка запросов 1С код написан синтаксически верно. Если при выполнении отчета цикл Пока Выборка.Следующий() Цикл не выполняется ни разу, это однозначно указывает на то, что условие в секции ГДЕ СчетНаОплатуТовары.Ссылка = &Ссылка не нашло соответствий. Выясним, почему параметр Ссылка оказался пустым или некорректным.

Причина 1: Различия механизмов передачи параметров (типовые конфигурации vs Альфа-Авто)

В типовых решениях (например, «Управление торговлей 10.3», «Комплексная автоматизация 1.1» или «Управление производственным предприятием 1.3») при вызове внешней обработки механизм подсистемы печати выполняет следующую последовательность действий:

  1. Создает объект обработки через ВнешниеОбработки.Создать(...).
  2. Находит в нем реквизит с именем СсылкаНаОбъект и заполняет его ссылкой на текущий документ.
  3. Вызывает экспортную функцию Печать() без параметров, которая возвращает сформированный ТабличныйДокумент.

Однако в отраслевых конфигурациях (в частности, в линейке «Альфа-Авто») механизм подключения внешних печатных форм реализован совершенно иначе. Проанализируем строку вызова из модуля управления внешними формами:


ТабДокумент = ВнешниеОбработки.Создать(ИмяФайлаПечатнойФормы).Печать(ДокументОбъект, ТабДокумент);

В этой схеме система не заполняет реквизит обработки СсылкаНаОбъект. Вместо этого объект документа передается напрямую в качестве первого аргумента экспортной функции Печать модуля объекта. В результате при обращении к СсылкаНаОбъект.Ссылка код пытается прочитать свойство у незаполненного реквизита, параметр &Ссылка получает значение Неопределено или пустую ссылку, и запрос возвращает пустую выборку.

Причина 2: Печать нового или несохраненного объекта

Обратите внимание на тип передаваемого значения в «Альфа-Авто»: в процедуру передается переменная с типом ДокументОбъект, а не ДокументСсылка. Если пользователь нажал кнопку печати в форме документа, в который только что внесли изменения или который еще не был записан в базу данных:

  1. У нового документа свойство ДокументОбъект.Ссылка является пустой ссылкой (Ссылка.Пустая() = Истина). В таблицах базы данных таких записей еще нет, поэтому запрос не возвратит ни одной строки.
  2. Если документ уже был записан, но пользователь отредактировал табличную часть на форме и не нажал «Записать», запрос к базе данных вернет старые сохраненные строки, а не те, что пользователь видит на экране.

Причина 3: Кэширование файлов внешних обработок на платформе 8.1

Платформа 1С:Предприятие при запуске обработок из справочника выгружает двоичные данные во временную папку пользователя (каталог Temp). Если вы вносите правки в файл обработки на диске и заново загружаете его в справочник, платформа может продолжать исполнять закэшированный файл из временного хранилища. Чтобы исключить влияние кэша, рекомендуется очищать каталог временных файлов сеанса или перезапускать клиентское приложение при отладке внешних форм.

Решение: Разработка универсальной функции печати

Чтобы внешняя печатная форма корректно отрабатывала и при ручном запуске через Файл - Открыть, и при подключении через типовые механизмы, и при работе в «Альфа-Авто», напишем универсальный обработчик в модуле объекта внешней обработки.

Реализуем проверку входящего контекста:


Функция Печать(ПараметрОбъект = Неопределено, ТабДокумент = Неопределено) Экспорт

    // 1. Определяем источник данных
    ТекущийОбъект = Неопределено;
    
    Если ПараметрОбъект <> Неопределено Тогда
        // Вызов из системы Альфа-Авто (передан объект или ссылка через аргумент)
        ТекущийОбъект = ПараметрОбъект;
    ИначеЕсли ЗначениеЗаполнено(СсылкаНаОбъект) Тогда
        // Интерактивный запуск или типовой механизм (заполнен реквизит обработки)
        ТекущийОбъект = СсылкаНаОбъект;
    КонецЕсли;

    Если ТекущийОбъект = Неопределено Тогда
        Сообщить("Не указан документ для формирования печатной формы!");
        Возврат Неопределено;
    КонецЕсли;

    // 2. Получаем ссылку для запроса
    СсылкаДляЗапроса = Неопределено;
    Если Метаданные.Документы.Содержит(ТекущийОбъект.Метаданные()) Тогда
        СсылкаДляЗапроса = ТекущийОбъект.Ссылка;
    Иначе
        СсылкаДляЗапроса = ТекущийОбъект;
    КонецЕсли;

    // 3. Инициализируем табличный документ, если он не был передан извне
    Если ТабДокумент = Неопределено Тогда
        ТабДокумент = Новый ТабличныйДокумент;
    КонецЕсли;

    // 4. Проверяем, записан ли документ в базе данных
    Если СсылкаДляЗапроса.Пустая() Тогда
        // Если документ не записан, данные табличной части берем напрямую из объекта
        ЗаполнитьНапрямуюИзОбъекта(ТекущийОбъект, ТабДокумент);
    Иначе
        // Если документ сохранен, выполняем выборку через запрос
        ЗаполнитьЧерезЗапрос(СсылкаДляЗапроса, ТабДокумент);
    КонецЕсли;

    Возврат ТабДокумент;

КонецФункции

Формирование данных через запрос и напрямую из коллекции

Разберем реализацию вспомогательных процедур. Для сохраненных документов выполним запрос к базе данных, передав вычисленную ссылку:


Процедура ЗаполнитьЧерезЗапрос(СсылкаНаДокумент, ТабДокумент)

    Запрос = Новый Запрос;
    Запрос.УстановитьПараметр("Ссылка", СсылкаНаДокумент);
    Запрос.Текст = 
        "ВЫБРАТЬ
        |    СчетТовары.НомерСтроки КАК НомерСтроки,
        |    СчетТовары.Номенклатура.Наименование КАК Номенклатура,
        |    СчетТовары.Количество КАК Количество,
        |    СчетТовары.Цена КАК Цена,
        |    СчетТовары.Сумма КАК Сумма
        |ИЗ
        |    Документ.СчетНаОплату.Товары КАК СчетТовары
        |ГДЕ
        |    СчетТовары.Ссылка = &Ссылка
        |УПОРЯДОЧИТЬ ПО
        |    НомерСтроки";

    Выборка = Запрос.Выполнить().Выбрать();

    Макет = ПолучитьМакет("Печать");
    ОбластьСтрока = Макет.ПолучитьОбласть("Строка");

    Пока Выборка.Следующий() Цикл
        ЗаполнитьЗначенияСвойств(ОбластьСтрока.Параметры, Выборка);
        ТабДокумент.Вывести(ОбластьСтрока);
    КонецЦикла;

КонецПроцедуры

Для случаев, когда документ передан в виде несохраненного экземпляра ДокументОбъект, организуем обход коллекции строк без обращения к базе данных:


Процедура ЗаполнитьНапрямуюИзОбъекта(ДокументОбъект, ТабДокумент)

    Макет = ПолучитьМакет("Печать");
    ОбластьСтрока = Макет.ПолучитьОбласть("Строка");

    Для Каждого СтрТовар Из ДокументОбъект.Товары Цикл
        ОбластьСтрока.Параметры.НомерСтроки   = СтрТовар.НомерСтроки;
        ОбластьСтрока.Параметры.Номенклатура  = СтрТовар.Номенклатура.Наименование;
        ОбластьСтрока.Параметры.Количество    = СтрТовар.Количество;
        ОбластьСтрока.Параметры.Цена          = СтрТовар.Цена;
        ОбластьСтрока.Параметры.Сумма         = СтрТовар.Сумма;
        ТабДокумент.Вывести(ОбластьСтрока);
    КонецЦикла;

КонецПроцедуры

Памятка для отладки внешних форм

При возникновении трудностей с регистрацией внешних печатных форм рекомендуем придерживаться следующего чек-листа:

  1. Проверяйте сигнатуру функции: Функция Печать обязательно должна иметь признак Экспорт и находиться в модуле объекта обработки, а не в модуле формы.
  2. Контролируйте параметры вызова: Убедитесь, принимает ли функция параметры (в «Альфа-Авто» это (ДокументОбъект, ТабДокумент), а в типовых конфигурациях 1С — вызов без параметров). Делайте параметры функции необязательными по умолчанию (= Неопределено).
  3. Проверяйте запись объекта: Перед формированием печатной формы убедитесь, что документ физически записан в информационную базу, иначе выборка по реальным таблицам вернет нулевое количество записей.
← На главную