Как в 1С 7.7 сформировать отчет с выводом шапки документа и списка строк табличной части

Программист 1С v7.7 Управленческий учет IT и автоматизация бизнеса
← На главную

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

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

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

Рассмотрим типичную ошибку при составлении текста запроса. Если в блоке группировок указан только документ со списком полей сортировки:


|Группировка КассовыйЧек упорядочить по КассовыйЧек.ДатаДок, КассовыйЧек.Товар, КассовыйЧек.Цена;

В такой конструкции платформа 1С 7.7 формирует выборку только верхнего уровня — по самому объекту документа. При обходе через один цикл Пока Запрос.Группировка(1) = 1 Цикл переменные табличной части (Товар, Цена, Количество) не детализируются построчно, а берутся либо как случайное первое значение, либо не заполняются вовсе, так как реквизиты строк требуют вложенной группировки.

Решение: двухуровневая группировка в объекте «Запрос»

Чтобы получить структуру «Шапка документа -> Строки табличной части -> Итоги по документу», необходимо разделить запрос на два уровня группировки:

  1. Первый уровень: Группировка КассовыйЧек; — группирует данные по конкретному документу.
  2. Второй уровень: Группировка Товар без групп; или Группировка СтрокаДокумента; — детализирует строки внутри текущего документа. Ключевое слово без групп исключает служебный вывод иерархических папок справочника.

Посмотрим на полный и рабочий пример текста процедуры формирования отчета:


//*******************************************
// Процедура генерации запроса Сформировать.
//
Процедура Сформировать()
    Перем Запрос, ТекстЗапроса, Таб;
    
    // Создание объекта типа Запрос
    Запрос = СоздатьОбъект("Запрос");
    ТекстЗапроса = 
    "//{{ЗАПРОС(Сформировать)
    |Период с ВыбНачПериода по ВыбКонПериода; 
    |КассовыйЧек = Документ.КассовыйЧек.ТекущийДокумент;
    |Основание = Документ.КассовыйЧек.Основание;
    |Товар = Документ.КассовыйЧек.Товар;
    |Количество = Документ.КассовыйЧек.Количество;
    |НомерДок = Документ.КассовыйЧек.НомерДок;
    |ДатаДок = Документ.КассовыйЧек.ДатаДок;
    |ВремяДок = Документ.КассовыйЧек.ВремяДок;
    |Цена = Документ.КассовыйЧек.Цена;   
    |Сумма = Документ.КассовыйЧек.Сумма;
    |Функция КоличествоСумма = Сумма(Количество);
    |Функция СуммаСумма = Сумма(Сумма);
    |Группировка КассовыйЧек;
    |Группировка Товар без групп;
    |Условие (КассовыйЧек.Проведен() = 1);
    |"//}}ЗАПРОС
    ;
    
    // Если ошибка в запросе, то выход из процедуры
    Если Запрос.Выполнить(ТекстЗапроса) = 0 Тогда
        Возврат;
    КонецЕсли;
    
    // Подготовка к заполнению выходных форм данными запроса
    Таб = СоздатьОбъект("Таблица");
    Таб.ИсходнаяТаблица("Сформировать");
    
    // Заполнение полей заголовка
    Таб.ВывестиСекцию("Заголовок");
    Состояние("Заполнение выходной таблицы...");
    Таб.Опции(0, 0, Таб.ВысотаТаблицы(), 0);
    
    // Внешний цикл: обход документов (чеков)
    Пока Запрос.Группировка(1) = 1 Цикл  
        Таб.ВывестиСекцию("Чек");
        
        // Внутренний цикл: обход строк табличной части (товары/услуги)
        Пока Запрос.Группировка(2) = 1 Цикл
            Таб.ВывестиСекцию("СтрокаЧека");
        КонецЦикла;
        
        // Вывод промежуточного итога по конкретному документу
        Таб.ВывестиСекцию("ИтогоПоЧеку");
    КонецЦикла;
    
    // Вывод общего подвала по всему отчету
    Таб.ВывестиСекцию("ОбщийИтог");
    
    // Вывод заполненной формы
    Таб.ТолькоПросмотр(1);
    Таб.Показать("Сформировать", "");
КонецПроцедуры

Важные особенности вывода данных и агрегатных функций

Разберем ключевые нюансы, на которые следует обратить внимание при работе с запросами по документам в 1С 7.7:

  1. Обращение к реквизиту «Цена» в ячейках таблицы: реквизит Цена не является функцией агрегации. На уровне шапки чека (Группировка(1)) значение Запрос.Цена не имеет смысла. Его следует выводить строго в секции СтрокаЧека внутри второго цикла.
  2. Схлопывание одинаковых позиций: если в документе одна и та же номенклатура добавлена двумя разными строками, запрос с Группировка Товар объединит их в одну строку таблицы и просуммирует количество. Если требуется вывести строки ровно в том виде и порядке, как они заведены в чеке, вместо номенклатуры применяют группировку по номеру строки документа: Группировка СтрокаДокумента;.
  3. Промежуточные и общие итоги: внутри внешнего цикла агрегатные функции Запрос.СуммаСумма и Запрос.КоличествоСумма возвращают сумму по текущему чеку. После выхода из всех циклов эти же функции содержат итоговые значения по всей выборке за период.
  4. Фильтрация непроведенных документов: прямой запрос к документам выбирает все объекты базы, включая непроведенные и помеченные на удаление. Для корректности финансового отчета обязательно добавление условия |Условие (КассовыйЧек.Проведен() = 1);.

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

Для небольших интервалов дат или простых отчетов не обязательно строить сложный запрос. Можно использовать стандартный перебор объекта метаданных Документ через методы платформы. Этот способ полностью сохраняет порядок строк документа:


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

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

← На главную