Как вывести ссылку на документ и сумму в строку итогов при обходе запроса в 1С?

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

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

Анализ проблемы: почему пропадают итоги или ссылки на документы

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

В коде могут возникать следующие ключевые ошибки:

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

Шаг 1. Оптимизация текста запроса и расчет суммы

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

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


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

Запрос.УстановитьПараметр("ДатНач", ДатНач);
Запрос.УстановитьПараметр("ДатКон", ДатКон);
Запрос.УстановитьПараметр("Пров", Истина);
Запрос.УстановитьПараметр("Контр", Контр);

В этом запросе поле Сумма вычисляется для каждой строки, а в секции ИТОГИ платформа автоматически суммирует количество и сумму по каждому документу (ПО Док).

Шаг 2. Реализация двухуровневого обхода по группировкам

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

Разберем программный код обхода:


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

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

Обратим внимание на то, что для строки документа значения берутся из объекта ВыборкаДокумент, а для строк с номенклатурой — из объекта ВыборкаТовар. Это исключает затирание детальных цен и гарантирует заполнение итоговой строки.

Шаг 3. Оптимизация работы с табличным полем

При использовании вызовов ЭлементыФормы.ПолеОтчёт.ДобавитьСтроку() и обращения к ТекущаяСтрока интерфейс платформы выполняет визуальное обновление и смену фокуса на каждой итерации цикла. При формировании отчетов за большой период это приводит к существенному замедлению работы интерфейса.

Проанализируем более эффективный подход: если элемент управления связан с реквизитом формы типа ТаблицаЗначений или ДеревоЗначений, все операции следует выполнять напрямую с коллекцией строк прикладного объекта. Если требуется иерархическое отображение с возможностью сворачивания и разворачивания узлов, рекомендуется использовать выгрузку в ДеревоЗначений:


ДеревоРезультата = Запрос.Выполнить().Выгрузить(ОбходРезультатаЗапроса.ПоГруппировкам);
// Если реквизит формы является Деревом Значений:
ЗначениеВРеквизитФормы(ДеревоРезультата, "ДеревоОтчета");

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

← На главную