Как вывести контрагента во внешнюю печатную форму в 1С

Программист 1С v8.3 (Управляемые формы) 1С:Управление торговлей Управленческий учет Торговля и дистрибуция
← На главную

При разработке и модификации внешних печатных форм (ВПФ) в конфигурациях на базе 1С:Управление торговлей, ред. 11 (а также отраслевых решениях, таких как 1С:Управление аптечной сетью (УАС)) разработчики часто сталкиваются с техническими трудностями. Типичный пример — необходимость добавить коммерческую информацию (например, покупателя или контрагента) во внутренний складской документ, такой как Задание на отбор (размещение) товаров.

В этой статье мы подробно разберем, почему возникает популярная ошибка Поле объекта не обнаружено, почему ручное создание реквизитов ВПФ часто оказывается бесполезным и как правильно, быстро и с соблюдением стандартов производительности 1С вывести нужные данные в макет печатной формы.


Разбор типичных ошибок при разработке ВПФ

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

Ошибка №1: Создание реквизита СсылкаНаОбъект во внешней обработке

В старых версиях Библиотеки Стандартных Подсистем (БСП 1.x) для работы механизма внешних печатных форм действительно требовалось создавать в объекте обработки реквизит с именем СсылкаНаОбъект. Система автоматически записывала туда ссылку на печатаемый документ перед выполнением модуля.

В современных конфигурациях на БСП 2.x/3.x (включая актуальные версии УТ 11, КА 2, ERP 2 и УАС) этот механизм давно изменен. Теперь печать инициируется через экспортные функции модуля объекта (или модуля менеджера) внешней обработки, куда массив печатаемых документов передается напрямую в качестве параметра (например, МассивОбъектов). Созданный вручную реквизит ВПФ остается пустым (содержит Неопределено или пустую ссылку), из-за чего любые попытки получить из него данные (например, СсылкаНаОбъект.Контрагент) приводят к ошибкам выполнения или возвращают пустое значение.

Ошибка №2: Попытка получить реквизит напрямую из выборки без изменения запроса

Часто разработчики пытаются написать код следующего вида:

ОбластьШапка.Параметры.Покупатель = ВыборкаПоШапке.Контрагент;

При выполнении этого кода система выдает ошибку: Поле объекта не обнаружено (Контрагент). Это происходит потому, что данные для печатной формы подготавливаются в специальном запросе внутри менеджера объекта (метод ПолучитьДанныеДляПечатнойФормыОтборРазмещениеТоваров). Поскольку «Задание на отбор» является внутренним складским документом, разработчики типового решения изначально не включали коммерческое поле Контрагент в выборку запроса шапки. В результате в таблице данных ДанныеПоШапке колонка с контрагентом просто отсутствует.


Решение проблемы: Простой способ («через точку»)

Выясним, как быстро решить проблему, если время на разработку ограничено. Нам нужно найти место в коде, где происходит обход выборки шапки документа, и обратиться к реквизиту через ссылку на сам документ.

Проанализируем структуру кода. В цикле обхода документов у нас есть переменная ВыборкаПоШапке.Ссылка (или ТекущаяСсылка), которая содержит полноценную ссылку на документ-основание (например, Реализация товаров и услуг или Заказ клиента).

Пошаговый алгоритм быстрого решения:

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

ОбластьШапка.Параметры.ПредставлениеСклада = ПредставлениеСклада;
ОбластьШапка.Параметры.ПредставлениеРаспоряжения = ПредставлениеРаспоряжения;

// Добавляем заполнение нашего нового параметра "Покупатель"
// Используем обращение к контрагенту через ссылку на документ-основание
ОбластьШапка.Параметры.Покупатель = ВыборкаПоШапке.Ссылка.Контрагент;

ТабличныйДокумент.Вывести(ОбластьШапка);

Этот код будет успешно работать, поскольку платформа 1С автоматически произведет неявное получение данных (разыменование ссылки) и извлечет значение контрагента из базы данных.


Важно: Опасность использования неявных запросов в цикле (Антипаттерн)

Хотя решение с обращением «через точку» (ВыборкаПоШапке.Ссылка.Контрагент) простое и рабочее, оно скрывает в себе серьезную опасность для производительности базы данных. Это классическая проблема N+1 запросов.

Когда вы обращаетесь к реквизиту ссылочного поля «через точку» внутри цикла, платформа 1С вынуждена при каждой итерации выполнять отдельный скрытый SQL-запрос к СУБД для получения значения этого реквизита. Если кладовщик отправляет на печать одно задание, система сделает всего один дополнительный микрозапрос, что останется незамеченным. Но если на складе выполняется пакетная печать (например, выделено 100 или 200 документов одновременно), система выполнит 100–200 отдельных запросов к базе данных в цикле. Это приведет к существенным задержкам, зависанию интерфейса и лишней нагрузке на сервер.


Правильное решение: Оптимальное получение данных одним запросом

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

Рассмотрим по шагам реализацию этого подхода:

Шаг 1. Создаем запрос для предварительного сбора контрагентов

В самом начале процедуры формирования печатной формы, где нам доступен массив всех отправленных на печать документов (МассивОбъектов), мы напишем запрос, который соберет контрагентов и поместит их в быстрое кэш-соответствие.


// Создаем соответствие для кэширования контрагентов
СоответствиеКонтрагентов = Новый Соответствие;

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

Шаг 2. Заполнение параметров в цикле без обращения к СУБД

Теперь внутри цикла обхода выборки шапки мы просто извлекаем контрагента из нашего соответствия по ключу ссылки. СУБД при этом не нагружается, так как все данные уже находятся в оперативной памяти сервера приложений 1С.


Пока ВыборкаПоШапке.Следующий() Цикл
    
    // ... Инициализация областей макета и расчет стандартных параметров ...
    
    // Безопасное и быстрое получение контрагента из кэша
    НайденныйКонтрагент = СоответствиеКонтрагентов.Получить(ВыборкаПоШапке.Ссылка);
    
    Если ЗначениеЗаполнено(НайденныйКонтрагент) Тогда
        ОбластьШапка.Параметры.Покупатель = НайденныйКонтрагент;
    Иначе
        ОбластьШапка.Параметры.Покупатель = "Не указан";
    КонецЕсли;
    
    // Выводим заполненную шапку в итоговый табличный документ
    ТабличныйДокумент.Вывести(ОбластьШапка);
    
    // ... Дальнейший вывод строк и табличной части ...
    
КонецЦикла;

Дополнительно: Красивый вывод реквизитов контрагента по стандартам БСП

Если мы просто передадим ссылку на контрагента в параметр макета (как в примере выше), то в печатной форме выведется его рабочее наименование из справочника (например, "Ромашка ООО"). Для официальных документов или более информативных заданий часто требуется выводить полное юридическое наименование, ИНН, КПП или юридический адрес.

Для решения этой задачи в современных конфигурациях 1С предусмотрен специальный общий модуль БСП — ФормированиеПечатныхФорм. Проанализируем, как с его помощью получить и красиво вывести подробные юридические данные покупателя:


// Получаем контрагента из нашего оптимизированного кэша
ТекущийКонтрагент = СоответствиеКонтрагентов.Получить(ВыборкаПоШапке.Ссылка);

Если ЗначениеЗаполнено(ТекущийКонтрагент) Тогда
    
    // 1. Получаем структуру сведений о контрагенте на дату документа
    СведенияОПокупателе = "ФормированиеПечатныхФорм".СведенияОЮрФизЛице(ТекущийКонтрагент, ВыборкаПоШапке.Ссылка.Дата);
    
    // 2. Формируем красивое текстовое описание с нужными реквизитами
    // Доступные поля для сборки: ПолноеНаименование, ИНН, КПП, ЮридическийАдрес, Телефоны
    ТекстПокупателя = "ФормированиеПечатныхФорм".ОписаниеОрганизации(
        СведенияОПокупателе, 
        "ПолноеНаименование,ИНН,ФактическийАдрес"
    );
    
    ОбластьШапка.Параметры.Покупатель = ТекстПокупателя;
    
КонецЕсли;

Использование встроенных функций БСП гарантирует единообразие оформления печатных форм вашей информационной системы и исключает ошибки ручного форматирования строк контрагентов.

Резюме

Подведем итоги совместной работы по доработке внешней печатной формы:

  1. Не создавайте лишних реквизитов в объекте внешней обработки для хранения ссылки на документ — современная БСП передает массив объектов напрямую в параметры экспортной функции печати.
  2. Для быстрого решения можно обратиться к реквизитам «через точку» от ссылки (ВыборкаПоШапке.Ссылка.Контрагент), но помните про риски снижения производительности при пакетной печати документов.
  3. Используйте предварительный пакетный запрос для сбора всех необходимых коммерческих данных в кэш-соответствие перед запуском цикла формирования макетов.
  4. Для формирования красивых юридических реквизитов контрагента применяйте типовые функции общего модуля ФормированиеПечатныхФорм.
← На главную