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