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