Почему не выводятся детальные поля в печатную форму отчета при обходе по группировкам в 1С?

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

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

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

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

Проанализируем структуру запроса и циклов вывода. В тексте запроса указана секция итогов:


ИТОГИ
    СУММА(Количество),
    СУММА(Сумма)
ПО
    Контрагент,
    Номенклатура

Когда мы выполняем обход с параметром ОбходРезультатаЗапроса.ПоГруппировкам, метод РезультатЗапроса.Выбрать(Обход, "ИмяГруппировки") возвращает выборку только итоговых строк указанного разреза. В строке итогов по группировке Номенклатура присутствуют только само поле группировки и поля, указанные в секции ИТОГИ с агрегатными функциями.

Поля детальных записей (такие как ДокОплаты, СчетНаОплату, Цена, Менеджер) на уровне итоговой записи номенклатуры не определены, поэтому обращение к ним возвращает Неопределено или пустые значения.

Решение: добавление вложенного цикла для обхода детальных записей

Разберем по шагам, как правильно организовать обход выборки с тремя уровнями: Контрагент → Номенклатура → Детальные строки (документы оплаты и цены).

  1. На верхнем уровне получаем выборку группировки Контрагент.
  2. Внутри первого цикла открываем подчиненную выборку по группировке Номенклатура.
  3. Внутри цикла по номенклатуре вызываем метод Карты.Выбрать() без указания имени группировки, чтобы получить выборку детальных записей.
  4. Заполняем параметры области макета из свойств полученной детальной выборки.

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


ТабДок.НачатьАвтогруппировкуСтрок();
РезультатЗапроса = Запрос.Выполнить();

ИтСумма = 0;
ИтКол = 0;

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

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

Важные нюансы при подсчете итогов и соединении таблиц

При реализации подобных отчетов обратим внимание на типичные ошибки в логике расчетов:

  1. Накопление итогов в цикле: Переменные ИтКол и ИтСумма необходимо увеличивать на значения из ВыборкаДетали.Количество и ВыборкаДетали.Сумма. Если внутри детального цикла ошибочно прибавлять поля родительской группировки Карты.Количество, итоговая сумма многократно завысится.
  2. Задвоение сумм шапки документов: В запросе поле шапки (СуммаДокументаПриход или СуммаДокумента) соединяется с табличной частью СчетНаОплату.Товары. Если в счете указано несколько позиций номенклатуры, сумма всего платежного документа дублируется для каждой строки счета. Для корректных расчетов распределяйте оплату по строкам счета пропорционально либо объединяйте выборки без дублирования связи 1:N.
  3. Оптимизация обращений через точку: Конструкции вроде СчетНаОплатуТовары.Ссылка.Контрагент.Менеджер создают неявные левые соединения в СУБД. В высоконагруженных отчетах рекомендуется соединять таблицы явно.
  4. Общие итоги запросом: Чтобы не накапливать общие суммы вручную в коде, укажите в тексте запроса конструкцию ИТОГИ ПО ОБЩИЕ, Контрагент, Номенклатура. Это позволит получить финальные итоги напрямую из корневой выборки.

Альтернативный вариант: прямой линейный обход или СКД

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


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

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

← На главную