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