Как программно обойти группировки в табличном документе после формирования отчета СКД?

Программист 1С v8.3 (Управляемые формы) IT и автоматизация бизнеса
← На главную

При работе с Системой Компоновки Данных (СКД) часто возникают ситуации, когда стандартных возможностей настроек отчета недостаточно для реализации сложной бизнес-логики. Иногда требуется произвести дополнительные вычисления или изменить оформление в уже сформированном ТабличныйДокумент, ориентируясь на конкретные уровни группировок. В этой статье мы подробно разберем, как программно определить уровень иерархии строк в готовом отчете и произвести их обход.

Метод 1. Использование системного поля «Уровень» и расшифровки

Проанализируем самый надежный способ идентификации строк. Чтобы не «гадать», к какому уровню относится строка в табличном документе, мы можем передать номер уровня напрямую из СКД в расшифровку ячейки. Это позволит нам при обходе документа мгновенно получать метаданные строки.

Рассмотрим пошагово, как это реализовать:

  1. В настройках СКД для нужной группировки (например, для второго уровня) перейдем в поле Выражения детальных записей или в настройки полей и добавим новое поле с выражением Уровень().
  2. Для ячеек этой группировки в параметре Расшифровка укажем наше новое поле.
  3. После формирования документа программно переберем строки и обратимся к свойству Расшифровка.

Пример кода для обхода сформированного документа (подготовить каркас подобного алгоритма поможет ИИ-помощник в консоли кода):


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

Метод 2. Поэлементный вывод через ПроцессорВывода

Выясним причину, по которой иногда лучше перехватывать данные в момент вывода, а не после. Использование ПроцессорВывода.Вывести(ПроцессорКомпоновки) сразу выдает весь результат. Однако, если мы будем использовать цикл с методом Следующий(), мы сможем контролировать каждый элемент компоновки.

Рассмотрим пример реализации поэлементного вывода:


ПроцессорКомпоновки = Новый ПроцессорКомпоновкиДанных;
ПроцессорКомпоновки.Инициализировать(МакетКомпоновки);

ПроцессорВывода = Новый ПроцессорВыводаРезультатаКомпоновкиДанныхВТабличныйДокумент;
ПроцессорВывода.УстановитьДокумент(ДокументРезультат);

Пока Истина Цикл
    ЭлементРезультата = ПроцессорКомпоновки.Следующий();
    Если ЭлементРезультата = Неопределено Тогда
        Прервать;
    КонецЕсли;
    
    // Анализируем тип элемента
    Если ЭлементРезультата.ТипЭлемента = ТипЭлементаРезультатаКомпоновкиДанных.НачалоГруппировки Тогда
        // Проверяем уровень или имя группировки
        Если ЭлементРезультата.ЗначенияПараметров.Найти("Уровень") = 2 Тогда
            // Совершаем действия для группировки 2-го уровня
        КонецЕсли;
    КонецЕсли;
    
    ПроцессорВывода.ВывестиЭлемент(ЭлементРезультата);
КонецЦикла;

Метод 3. Анализ структуры через XML-сериализацию

Если нам достался уже сформированный ТабличныйДокумент и мы не можем менять настройки СКД, воспользуемся методом анализа XML-структуры. Этот способ считается «хакерским», но он крайне эффективен, так как при сохранении документа в XML 1С записывает уровни группировок строк в атрибуты.

Посмотрим на алгоритм действий:

  1. Записываем ТабличныйДокумент во временный файл XML.
  2. Читаем файл через ЧтениеXML.
  3. Ищем узлы строк (обычно это <row>), у которых есть атрибут outlineLevel.

Значение outlineLevel="1" соответствует второму уровню иерархии (индексация в XML начинается с 0). Это позволяет быстро составить карту строк документа с привязкой к их уровням.

Метод 4. Трюк с видимостью группировок

Проанализируем интересную особенность платформы. У объекта ТабличныйДокумент есть метод ПоказатьУровеньГруппировокСтрок(Уровень). Мы можем использовать его для идентификации строк.

Алгоритм решения задачи:

  1. Программно вызываем ДокументРезультат.ПоказатьУровеньГруппировокСтрок(1). Теперь все строки ниже 1-го уровня стали невидимыми.
  2. Вызываем ДокументРезультат.ПоказатьУровеньГруппировокСтрок(2). Теперь видны строки 1-го и 2-го уровней.
  3. Перебираем строки: те, у которых свойство Видимость изменилось с Ложь на Истина при переходе от 1 к 2 уровню, гарантированно являются строками 2-го уровня.

Этот метод не требует изменения СКД и работает исключительно с визуальным представлением данных.

Метод 5. Использование фиксированных имен областей

Если структура вашего отчета фиксирована, мы можем назначить конкретным группировкам Имя области в макете компоновки. Рассмотрим, как это упрощает жизнь программисту. В некоторых случаях архитектура требует использовать две разные схемы в одном отчете, что также влияет на структуру областей.

В схеме СКД на закладке Макеты можно создать макет группировки и указать для него уникальное имя. При выводе отчета 1С пометит соответствующие области в табличном документе этими именами. В коде пост-обработки вам достаточно будет обратиться к коллекции ДокументРезультат.Области, чтобы найти все вхождения нужной группировки по имени.

Метод 6. Выгрузка в Дерево Значений для ускорения расчетов

Если основной целью обхода документа является скорость вычислений (как упоминалось в Сообщении 3), то работа напрямую с ячейками ТабличныйДокумент — не самый лучший выбор. Доступ к ячейкам через Область(нС, нК) в больших документах работает медленно.

Рекомендуем следующий подход:

  1. Выгружаем результат компоновки не в ТабличныйДокумент, а в ДеревоЗначений.
  2. В дереве иерархия представлена максимально прозрачно: Строки первого уровня, их вложенные коллекции Строки и так далее.
  3. Выполняем все необходимые математические операции в дереве.
  4. Выводим уже готовое, рассчитанное дерево в ТабличныйДокумент или используем его как источник данных для финального отчета.

Пример получения дерева:


ПроцессорВывода = Новый ПроцессорВыводаРезультатаКомпоновкиДанныхВДеревоЗначений;
ДеревоРезультат = Новый ДеревоЗначений;
ПроцессорВывода.УстановитьОбъект(ДеревоРезультат);
ПроцессорВывода.Вывести(ПроцессорКомпоновкиДанных);

// Обход 2-го уровня
Для Каждого СтрокаУр1 Из ДеревоРезультат.Строки Цикл
    Для Каждого СтрокаУр2 Из СтрокаУр1.Строки Цикл
        // Здесь мы точно на 2-м уровне группировки
        СтрокаУр2.Результат = СтрокаУр2.Параметр1 * Коэффициент;
    КонецЦикла;
КонецЦикла;

Подводя итог, можно сказать, что выбор метода зависит от того, есть ли у вас доступ к изменению схемы СКД. Если есть — используйте скрытые поля или расшифровку. Если отчет «черный ящик» — используйте анализ видимости строк или XML-парсинг. Для задач высокой производительности всегда отдавайте предпочтение Дереву Значений.

← На главную