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