Как реализовать групповую печать документов М-11 по данным за период?

Программист 1С v8.3 (Обычные формы) Управленческий учет Промышленность, строительство и АПК
← На главную

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

Анализируем структуру запроса и параметры

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

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


Запрос.УстановитьПараметр("КонецПериода", КонецДня(ЭтотОбъект.КонецПериода));
Запрос.УстановитьПараметр("НачалоПериода", НачалоДня(ЭтотОбъект.НачалоПериода));    
// Вместо .УстановитьПараметр("Статья", Справочники.СтатьиЗатрат.Название.Указатель)
// Лучше использовать:
Запрос.УстановитьПараметр("СтатьяАрбитраж", Справочники.СтатьиЗатрат.НайтиПоНаименованию("Арбитраж"));

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

Организация цикла обхода и формирования макета

Одной из главных ошибок в исходном коде было создание объекта ТабличныйДокумент внутри цикла. Если мы пишем ТабДокумент = Новый ТабличныйДокумент при каждой итерации, то на каждом шаге мы создаем чистый лист, стирая всё, что было сформировано ранее. В итоге пользователь либо не видит ничего, либо видит только последнюю строку.

Выясним причину, почему данные не попадали в макет. Рассмотрим правильную структуру, где один общий табличный документ наполняется данными постепенно:


// Создаем документ ОДИН раз перед циклом
ТабДокумент = Новый ТабличныйДокумент;
Макет = ПолучитьМакет("Арбитраж");

Выборка = Результат.Выбрать();
ПервыйДокумент = Истина;

Пока Выборка.Следующий() Цикл
    
    // Проверяем условия (Арбитраж или Стабильность)
    Если Выборка.АрбитражИСтабильность = 0 Тогда
        Продолжить;
    КонецЕсли;

    // Если это не первый документ в пачке, добавляем разделитель страниц
    Если Не ПервыйДокумент Тогда
        ТабДокумент.ВывестиГоризонтальныйРазделительСтраниц();
    КонецЕсли;
    ПервыйДокумент = Ложь;

    // Выводим шапку, строки и подвал
    ОбластьШапка = Макет.ПолучитьОбласть("Шапка");
    ОбластьШапка.Параметры.Заполнить(Выборка);
    ТабДокумент.Вывести(ОбластьШапка);

    ОбластьСтрока = Макет.ПолучитьОбласть("Строка");
    ОбластьСтрока.Параметры.Заполнить(Выборка);
    ТабДокумент.Вывести(ОбластьСтрока);

    ОбластьПодвал = Макет.ПолучитьОбласть("Подвал");
    ТабДокумент.Вывести(ОбластьПодвал);

КонецЦикла;

Использование группировок для разделения Арбитража и Стабильности

Если задача требует вывести сначала все документы по Арбитражу, а затем по Стабильности (или в разные окна), эффективнее всего использовать итоги в запросе. Проанализируем ситуацию: в запросе есть поле АрбитражИСтабильность, которое принимает значения 1 или 2. Мы можем добавить в текст запроса ИТОГИ ПО АрбитражИСтабильность.

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


ВыборкаГрупп = Результат.Выбрать(ОбходРезультатаЗапроса.ПоГруппировкам);

Пока ВыборкаГрупп.Следующий() Цикл
    // Здесь мы можем решить: создавать ли новый ТабДокумент 
    // для каждой группы или печатать всё в один.
    
    ВыборкаДетали = ВыборкаГрупп.Выбрать();
    Пока ВыборкаДетали.Следующий() Цикл
        // Вывод конкретных строк накладной
    КонецЦикла;
КонецЦикла;

Почему форма не открывается: возвращаемое значение и метод Показать

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

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

  1. Вызов метода .Показать() внутри функции печати: это самый быстрый способ. Вместо простого завершения функции мы принудительно открываем окно просмотра.
    
    // В конце функции ПечатьМ11()
    ТабДокумент.Показать("Печать накладных М-11");
    
  2. Возврат значения в процедуру формы: если мы хотим следовать стандартам, то в модуле формы нужно принять результат функции.
    
    // В модуле формы
    Процедура ОсновныеДействияФормыВыполнить(Кнопка)
        Таб = ЭтотОбъект.ПечатьМ11();
        Если Таб <> Неопределено Тогда
            Таб.Показать();
        КонецЕсли;
    КонецПроцедуры
    

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

Отладка пустой выборки

Если вы уверены, что Показать() на месте, но окно всё равно пустое, разберем по шагам диагностику данных. Проблема может быть в том, что Выборка.Следующий() возвращает Ложь сразу. Это происходит, даже если запрос верный, но данные не соответствуют типам в параметрах.

Рекомендуем использовать в отладчике метод Результат.Выгрузить(). Это позволит мгновенно увидеть содержимое результата запроса в виде таблицы значений. Если таблица пуста — ищите ошибку в параметрах даты или условиях ЗНАЧЕНИЕ(Перечисление...). Если данные есть, но Выборка.АрбитражИСтабильность всегда равна 0, проверьте логику оператора ВЫБОР в тексте запроса.

Также проверьте работу функции ПредставлениеСерий(Выборка). Если она ожидает конкретный объект (например, Ссылка), а вы передаете ей всю строку выборки, код может аварийно завершаться, не успев вывести макет. Используйте конструкцию Попытка...Исключение при вызове сложных внешних функций формирования строк.

Следуя этим рекомендациям, мы получим надежный механизм групповой печати, который корректно обрабатывает данные за период и предоставляет пользователю удобный интерфейс для работы с документами М-11.

← На главную