При работе со старыми конфигурациями или специфическими задачами часто возникает необходимость доработки отчетов, построенных на классическом выводе в макет (без использования Системы компоновки данных). Одной из наиболее сложных задач в этом случае является создание динамических колонок, количество которых заранее неизвестно — например, вывод сумм платежей в разрезе месяцев года. Разберем подробно, как реализовать такой механизм программно.
Для вывода данных в таблицу, где колонки формируются динамически, нам необходимо отойти от стандартного последовательного вывода строк. Рассмотрим ключевую разницу между двумя основными методами табличного документа:
Вывести() — этот метод берет область макета и добавляет ее в табличный документ снизу, всегда начиная новую строку.Присоединить() — этот метод добавляет область макета справа от уже выведенной области в той же самой строке.Проанализируем алгоритм работы: сначала мы выводим фиксированную левую часть шапки (например, "Номенклатура" или "Контрагент") методом Вывести(), а затем в цикле по количеству месяцев используем Присоединить(), чтобы достроить шапку вправо.
Прежде всего, нам нужно правильно подготовить макет в конфигураторе. Разберем структуру областей:
ШапкаВерх).КолонкаПериод).Строка и вертикальную область ЯчейкаСуммы, которая находится на пересечении строки и динамической колонки.В ячейках области КолонкаПериод установим параметр МесяцГод, а в ЯчейкаСуммы — параметр СуммаПлатежа.
Чтобы отчет выглядел профессионально, нам нужно преобразовать стандартную дату 1С в читаемый формат месяца. Посмотрим на пример кода, который обсуждался в теме:
// Пример формирования строки месяца
ДатаПлатежа = Выборка.Дата;
МесяцСтрокой = Формат(ДатаПлатежа, "ДФ='MMMM (yyyy)'");
// Результат: "Март (2020)"
Выясним причину, по которой у автора темы данные "уходили в разнос". Это происходит из-за отсутствия синхронизации. Если у одного контрагента есть платеж в марте, а у другого нет, то при простом переборе выборки колонки сместятся. Чтобы этого избежать, сначала подготовим массив всех уникальных периодов, которые будут в отчете.
// Сначала соберем все уникальные месяцы из данных запроса
ТаблицаПериодов = Запрос.Выполнить().Выгрузить();
ТаблицаПериодов.Свернуть("ПериодМесяц"); // ПериодМесяц должен быть началом месяца
ТаблицаПериодов.Сортировать("ПериодМесяц Возр");
Рассмотрим по шагам процесс сборки таблицы в коде. Сначала выводим шапку:
// Выводим статичную часть шапки
ОбластьШапкаЛево = Макет.ПолучитьОбласть("Шапка|ЛеваяЧасть");
ТабДок.Вывести(ОбластьШапкаЛево);
// Присоединяем динамические колонки в шапку
ОбластьКолонка = Макет.ПолучитьОбласть("Шапка|КолонкаПериод");
Для Каждого СтрокаПериода Из ТаблицаПериодов Цикл
ОбластьКолонка.Параметры.МесяцГод = Формат(СтрокаПериода.ПериодМесяц, "ДФ='MMMM (yyyy)'");
ТабДок.Присоединить(ОбластьКолонка);
КонецЦикла;
Теперь проанализируем ситуацию с выводом строк данных. Важно для каждой строки данных итерироваться по **полному** списку периодов, который мы подготовили ранее:
Пока ВыборкаКонтрагенты.Следующий() Цикл
// Выводим начало строки (ФИО или Название)
ОбластьСтрокаЛево = Макет.ПолучитьОбласть("Строка|ЛеваяЧасть");
ОбластьСтрокаЛево.Параметры.Заполнить(ВыборкаКонтрагенты);
ТабДок.Вывести(ОбластьСтрокаЛево);
// Выводим суммы по каждому месяцу
ОбластьЯчейка = Макет.ПолучитьОбласть("Строка|ЯчейкаСуммы");
Для Каждого СтрокаПериода Из ТаблицаПериодов Цикл
// Ищем сумму по конкретному контрагенту за конкретный месяц
ПараметрыОтбора = Новый Структура("Контрагент, ПериодМесяц", ВыборкаКонтрагенты.Контрагент, СтрокаПериода.ПериодМесяц);
СтрокиДанных = ТЗРезультат.НайтиСтроки(ПараметрыОтбора);
Если СтрокиДанных.Количество() > 0 Тогда
ОбластьЯчейка.Параметры.СуммаПлатежа = СтрокиДанных[0].Сумма;
Иначе
ОбластьЯчейка.Параметры.СуммаПлатежа = 0; // Обязательно заполняем нулем для красоты
КонецЕсли;
ТабДок.Присоединить(ОбластьЯчейка);
КонецЦикла;
КонецЦикла;
Для того чтобы отчет был удобен для пользователя, рекомендуем обратить внимание на следующие моменты:
ТабДок.ФиксацияСлева = ШиринаЛевойКолонки; и ТабДок.ФиксацияСверху = ВысотаШапки;, чтобы при прокрутке названия контрагентов и месяцев оставались на экране.ТабДок.АвтоМасштаб = Истина;, чтобы отчет автоматически подгонялся под ширину страницы при печати.Формат() можно использовать встроенную функцию ПредставлениеПериода(НачалоМесяца, КонецМесяца, "Л=ru_RU"), которая также дает корректное строковое описание.Таким образом, мы разобрали, как с помощью методов Вывести() и Присоединить() создать гибкий и понятный отчет в 1С без использования СКД. Главное в этом процессе — предварительная подготовка списка всех колонок и строгая синхронизация данных при выводе каждой строки.