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

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

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

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

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

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


Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
|   ЗаказКлиента.Ссылка,
|   ЗаказКлиента.Номер,
|   ЗаказКлиента.Дата
|ИЗ
|   Документ.ЗаказКлиента КАК ЗаказКлиента";
// Параметр вставлен, но в тексте запроса он не используется!
Запрос.Параметры.Вставить("Ссылка", ТекущийДокумент); 
Выборка = Запрос.Выполнить().Выбрать();

Выясним причину ошибки: в тексте запроса отсутствует инструкция, ограничивающая выборку. Для исправления ситуации необходимо добавить условие. Если мы обрабатываем один документ в цикле, используем оператор =. Если же мы передаем сразу массив документов (что более правильно с точки зрения производительности), используем оператор В.

Исправленный фрагмент запроса должен выглядеть так:


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

Запрос.УстановитьПараметр("МассивОбъектов", МассивОбъектов);

Ошибки при передаче параметров и несоответствие типов

Часто при добавлении условия ГДЕ Ссылка = &Ссылка возникает ошибка: "Неверные параметры в операции сравнения. Нельзя сравнивать поля неограниченной длины и поля несовместимых типов". Разберем по шагам, почему это происходит.

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

Важный момент: всегда проверяйте, что именно вы передаете в запрос. Если вам нужен массив ссылок конкретного типа, извлекайте его из структуры или используйте исходный МассивОбъектов, который приходит в процедуру Печать.

Оптимизация: отказ от запроса в цикле

В коде, который мы анализируем, цикл Для Каждого ТекущийДокумент Из МассивОбъектов содержит внутри себя создание и выполнение запроса. Это является критической ошибкой производительности. Если пользователь выделит 50 заказов и нажмет "Печать", система сделает 50 обращений к базе данных, что существенно замедлит работу.

Рассмотрим правильный алгоритм формирования печатной формы:

  1. Выносим формирование запроса за пределы цикла.
  2. Передаем в запрос сразу весь МассивОбъектов.
  3. Выполняем запрос один раз и получаем все необходимые данные.
  4. Обходим результат запроса и для каждого документа формируем свою область в ТабличныйДокумент.

Пример оптимизированной структуры кода:


Процедура Печать(МассивОбъектов, КоллекцияПечатныхФорм, ОбъектыПечати, ПараметрыВывода) Экспорт
    ТабДок = СформироватьПечатнуюФорму(МассивОбъектов, ОбъектыПечати);
    УправлениеПечатью.ВывестиТабличныйДокументВКоллекцию(КоллекцияПечатныхФорм, "Идентификатор", "Наименование", ТабДок);
КонецПроцедуры

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

Как отладить внешнюю печатную форму

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

Способ 1: Использование вспомогательной формы. Добавьте в обработку форму, на которой разместите список значений (для выбора документов) и кнопку "Тест". В коде кнопки вызовите основную экспортную процедуру Печать. После этого вы сможете открывать обработку через меню "Файл -> Открыть" и точки останова будут срабатывать.

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

Способ 3: Отладочные сообщения. Если нет возможности менять структуру, используйте метод Сообщить() для вывода содержимого переменных. Например, Сообщить("Количество объектов: " + МассивОбъектов.Количество()); поможет быстро понять, какие данные пришли на вход процедуры Печать.

Нюансы работы с методом Очистить()

В предоставленном в теме коде внутри цикла по документам встречался вызов ТабличныйДокумент.Очистить(). Это грубая логическая ошибка: при каждой итерации цикла (при формировании каждого следующего документа) весь накопленный ранее результат будет удаляться. В итоге пользователь увидит только последний документ из списка выбранных. Метод Очистить() следует вызывать один раз в самом начале функции формирования табличного документа.

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

← На главную