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

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

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

Понимание основной задачи: динамические единицы измерения

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

Таким образом, перед нами стоит две основные подзадачи:

  1. Программно сформировать или модифицировать схему компоновки данных таким образом, чтобы она учитывала динамические поля (количество в различных единицах измерения).
  2. Передать эту динамически сформированную схему в отчет так, чтобы она стала его текущей схемой, и пользователь мог в дальнейшем изменять настройки отчета, сохранять варианты и т.д.

Решение 1: Прямая передача программно сформированной схемы в отчет

Самый прямой способ, который был найден в ходе обсуждения, это присвоение программно созданной схемы свойству СхемаКомпоновкиДанных объекта отчета. Давайте рассмотрим этот подход подробнее.

Программное создание схемы компоновки данных

Прежде чем передавать схему, ее необходимо создать или модифицировать программно. Этот процесс включает в себя несколько шагов:

  1. Создание объекта схемы: Мы начинаем с создания нового экземпляра объекта СхемаКомпоновкиДанных.
  2. Добавление источников данных: Определяем, откуда СКД будет брать данные. Чаще всего это база данных, но может быть и внешний источник.
  3. Добавление наборов данных: Наборы данных могут быть двух типов:
    • НаборДанныхЗапрос: Если данные можно получить SQL-запросом. В этом случае мы формируем текст запроса, который может быть динамическим и включать в себя все необходимые поля для различных единиц измерения.
    • НаборДанныхОбъект: Если данные формируются программно в виде таблицы значений (ТЗ). Этот подход идеально подходит для динамических сценариев, когда набор полей или сами данные зависят от сложной логики. Мы можем программно сформировать ТЗ с колонками для каждой выбранной единицы измерения и загрузить ее в этот набор данных.

    Для нашей задачи с динамическими единицами измерения, использование НаборДанныхОбъект выглядит очень перспективным. Мы можем создать ТЗ, где будут поля для основной номенклатуры и, например, поля КоличествоВШтуках, КоличествоВПачках, КоличествоВКилограммах, если эти единицы были выбраны. Если единицы измерения могут быть произвольными, мы можем генерировать имена колонок для ТЗ на основе выбранных единиц (например, Количество_Штуки, Количество_КГ).

  4. Добавление вычисляемых полей: Если часть расчетов удобно выполнять на уровне СКД, мы можем добавлять вычисляемые поля. Например, для пересчета количества из одной единицы в другую с использованием коэффициента.
  5. Определение ресурсов: Ресурсы используются для агрегирования данных (суммы, средние значения и т.д.). Для динамических полей количества нам также потребуется определить для них ресурсы.
  6. Формирование настроек СКД: Здесь мы определяем, как данные будут отображаться: группировки строк и колонок, отборы, сортировки, условное оформление. Это очень важный шаг, так как именно здесь мы можем управлять динамическим отображением полей.

Передача схемы в объект отчета

После того как мы программно сформировали объект СхемаКомпоновкиДанных, мы можем присвоить его свойству отчета:


// Предположим, что СКД уже программно сформирована
// (см. шаги выше)
// ...
// Создаем или получаем объект СхемаКомпоновкиДанных
ПеременнаяСКД = Новый СхемаКомпоновкиДанных;
// Здесь мы наполняем ПеременнаяСКД всеми необходимыми элементами:
// ИсточникиДанных, НаборыДанных, Поля, Ресурсы, Параметры...
// ...
// И теперь передаем эту схему в текущий объект отчета
ЭтотОбъект.СхемаКомпоновкиДанных = ПеременнаяСКД;

Этот метод работает, особенно для обычных форм. Однако для управляемых форм и более сложных сценариев важно учитывать, что компоновщик настроек на форме отчета при открытии получает схему из конфигурации как новый экземпляр. Поэтому, чтобы пользователь мог взаимодействовать с программно созданной схемой, необходимо обеспечить, чтобы компоновщик настроек на форме отчета инициализировался именно вашей динамически сформированной схемой. Это может потребовать дополнительной обвязки для сохранения и восстановления схемы или ее настроек.

Важно понимать, что макет отчета (часть метаданных) программно изменить нельзя, поскольку он является частью конфигурации. То, что мы меняем, это объект схемы компоновки данных, который может быть загружен из макета или создан полностью программно. Мы фактически подменяем схему, с которой будет работать компоновщик на форме отчета, а не меняем сам метаданный "макет".

Решение 2: Использование обработчика "ПриКомпоновкеРезультата"

Обработчик события ПриКомпоновкеРезультата в модуле отчета предоставляет мощный механизм для управления процессом компоновки данных. Мы можем использовать его для тонкой настройки схемы или ее настроек непосредственно перед формированием отчета.

Принцип работы

  1. Мы получаем текущую схему компоновки данных (которая может быть изначально загружена из макета отчета).
  2. Загружаем пользовательские настройки компоновщика (если они были сохранены).
  3. Модифицируем схему компоновки данных или ее настройки (группировки, отборы, выводимые поля, параметры) в зависимости от условий.
  4. Выполняем компоновку и выводим результат в табличный документ.

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


Процедура ПриКомпоновкеРезультата(ДокументРезультат, ДанныеРасшифровки, СтандартнаяОбработка)
    СтандартнаяОбработка = Ложь;

    // Получаем схему компоновки данных
    Схема = ЭтотОбъект.ПолучитьМакет("ОсновнаяСхемаКомпоновкиДанных"); 
    // Или, если схему уже подменили, то: Схема = ЭтотОбъект.СхемаКомпоновкиДанных;

    // Создаем компоновщик макета
    КомпоновщикМакета = Новый КомпоновщикМакетаКомпоновкиДанных;
    МакетКомпоновки = КомпоновщикМакета.Выполнить(Схема, ЭтотОбъект.КомпоновщикНастроек.Настройки, ДанныеРасшифровки);

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

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

    // Выводим результат
    ПроцессорВывода.НачатьВывод();
    ПроцессорКомпоновки.Обработать(ПроцессорВывода);
    ПроцессорВывода.ЗакончитьВывод();

КонецПроцедуры

Использование этого обработчика позволяет нам гибко реагировать на выбор пользователя, не меняя при этом "основной" макет отчета. Мы можем модифицировать настройки для конкретного сеанса работы пользователя.

Решение 3: Альтернативные подходы к динамическому отображению полей без полной замены схемы

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

Использование набора данных "Объект"

Мы уже упоминали этот подход, но давайте рассмотрим его подробнее. Если у нас есть основной набор данных (например, по продажам), и нам нужны динамические данные по единицам измерения, мы можем добавить второй набор данных типа НаборДанныхОбъект.

  1. Создаем основной запрос, который выбирает все базовые данные по продажам (номенклатура, склад, сумма, НДС и т.д.).
  2. В коде отчета формируем таблицу значений (ТЗ), которая будет содержать информацию о выбранных пользователем единицах измерения, их коэффициентах и, возможно, уже рассчитанные количества.
  3. Загружаем эту ТЗ во вспомогательный набор данных типа Объект.
  4. Соединяем основной запрос с этим вспомогательным набором данных по ключевым полям (например, по номенклатуре) на уровне СКД.
  5. Используем вычисляемые поля для расчета количества в выбранных единицах измерения, опираясь на данные из вспомогательного набора.

Этот метод позволяет нам инкапсулировать логику выбора и расчета единиц измерения в программный код, а СКД будет использовать уже подготовленные данные.

Использование группировок в табличном отчете СКД

Это очень мощный и часто недооцениваемый инструмент СКД, который может решить проблему динамического отображения единиц измерения без каких-либо программных изменений структуры схемы. Идея заключается в следующем:

  1. В запросе выбираем все возможные единицы измерения для номенклатуры и их коэффициенты, а также количество в базовой единице.
  2. Настраиваем структуру отчета СКД как "Таблица".
  3. Определяем строки отчета: Например, Номенклатура, Склад, и другие базовые поля, которые не должны зависеть от единиц измерения.
  4. Определяем колонки отчета: Здесь кроется ключевое решение. Мы можем добавить группировку по полю ЕдиницаИзмерения (или аналогичному полю, которое будет содержать наименование выбранной единицы) в колонках. Но это поле должно влиять только на вывод поля Количество.
  5. Разделяем поля на две категории:
    • Поля, зависящие от единицы измерения: Например, Количество. Для этого поля мы добавляем его в детальные записи или в ресурсы, которые будут агрегироваться в колонках по единице измерения.
    • Поля, не зависящие от единицы измерения: Например, СуммаПродажи, СуммаНДС, Стоимость. Эти поля мы выводим как обычные поля в строках отчета или в детальных записях, но без привязки к колонкам, сгруппированным по единице измерения.

Пример настройки структуры СКД:


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

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

Использование отборов СКД для фильтрации подзапросов

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

Использование нескольких вариантов отчета

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

Дополнительные аспекты и рекомендации

Работа с вычисляемыми полями и выражениями представления

Для динамического отображения данных можно активно использовать вычисляемые поля в СКД. Например, для каждого типа единицы измерения можно создать отдельное вычисляемое поле. Также для колонок с количеством можно задать "Выражение представления", объединяющее числовое значение с выбранной единицей измерения (например, "Количество в " + ЕдиницаИзмерения).

Копирование настроек СКД

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

Локализация

При использовании строковых литералов в запросах и заголовках полей, которые будут видны пользователю, всегда рекомендуем выносить их в параметры и использовать функцию НСтр() для корректной локализации.

Оптимизация запросов

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

Вспомогательные модули

Для упрощения программного создания СКД существуют общие модули-обертки (например, СКДБилдер), которые могут значительно сократить объем кода и повысить его читаемость.

Заключение

Мы рассмотрели различные подходы к формированию структуры отчета СКД программно и передаче ее в макет, а также альтернативные решения, которые могут быть более подходящими для специфической задачи с динамическими единицами измерения. Прямая подмена схемы через ЭтотОбъект.СхемаКомпоновкиДанных = СКД; является рабочим решением, но требует дополнительного внимания к управляемым формам. Однако, для задачи с динамическими единицами измерения, часто более эффективными и поддерживаемыми являются подходы с использованием НаборДанныхОбъект или, что особенно удобно, грамотная настройка группировок в табличном отчете СКД, позволяющая отображать динамические поля в колонках, сохраняя при этом статические поля в строках. Выбор конкретного метода будет зависеть от сложности задачи, требований к гибкости и удобству поддержки.

← На главную