При разработке отчетов на системе компоновки данных (СКД) часто возникает задача распределения определенных показателей (например, процентов наценки, скидок или коэффициентов) в зависимости от принадлежности номенклатуры к той или иной группе. Типичная ситуация: для одной группы товаров наценка составляет 5%, для другой — 10%, а для третьей — все 30%. В этой статье мы разберем несколько эффективных способов реализации этой задачи, проанализируем их плюсы и минусы, и выберем наиболее подходящий вариант для вашей конфигурации.
Рассмотрим ситуацию, когда мы не хотим жестко прописывать группы и проценты в коде или настройках отчета. Самым гибким решением будет создание специального регистра сведений (например, НаценкиНоменклатуры). Это позволит пользователям самостоятельно управлять правилами ценообразования через интерфейс программы.
Проанализируем структуру такого регистра:
ОбъектНастройки (тип СправочникСсылка.Номенклатура) — здесь может быть как конкретный товар, так и группа.ПроцентНаценки (тип Число).Теперь разберем, как правильно составить запрос в СКД, чтобы учесть иерархию. Нам нужно соединить основную таблицу товаров с этим регистром. Важным моментом здесь является использование оператора В ИЕРАРХИИ, однако в классическом левом соединении запроса это сделать напрямую сложно. Поэтому мы часто используем следующий алгоритм в запросе:
ВЫБРАТЬ
Товары.Ссылка КАК Номенклатура,
ЕСТЬNULL(Наценки.ПроцентНаценки, 0) КАК Процент
ИЗ
Справочник.Номенклатура КАК Товары
ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.НаценкиНоменклатуры.СрезПоследних(&Период, ) КАК Наценки
ПО Товары.Ссылка В ИЕРАРХИИ (Наценки.ОбъектНастройки)
Важное примечание: Использование В ИЕРАРХИИ в условии соединения может существенно замедлить отчет на больших справочниках. Если производительность критична, рекомендуется предварительно подготовить таблицу соответствий в коде или использовать дополнительные реквизиты.
Выясним причину, по которой авторы на форумах часто склоняются к подготовке данных в коде. Метод внешнего набора данных (Object DataSet) позволяет реализовать любую, даже самую сложную логику распределения процентов, используя всю мощь языка 1С, прежде чем данные попадут в компоновщик.
Рассмотрим по шагам, как это реализовать:
Набор данных - объект и назовем его ТаблицаНаценок.Номенклатура и ПроцентНаценки.Пример программного кода для инициализации компоновки:
// Подготовим таблицу данных
ТЗНаценок = Новый ТаблицаЗначений;
ТЗНаценок.Колонки.Добавить("Номенклатура", Новый ОписаниеТипов("СправочникСсылка.Номенклатура"));
ТЗНаценок.Колонки.Добавить("ПроцентНаценки", Новый ОписаниеТипов("Число"));
// Логика заполнения таблицы (например, обход дерева групп)
// ... затычка для логики заполнения ...
ВнешниеНаборыДанных = Новый Структура;
ВнешниеНаборыДанных.Вставить("ТаблицаНаценок", ТЗНаценок);
КомпоновщикМакета = Новый КомпоновщикМакетаКомпоновкиДанных;
МакетКомпоновки = КомпоновщикМакета.Выполнить(СхемаКомпоновкиДанных, НастройкиКомпоновки, ДанныеРасшифровки);
ПроцессорКомпоновки = Новый ПроцессорКомпоновкиДанных;
ПроцессорКомпоновки.Инициализировать(МакетКомпоновки, ВнешниеНаборыДанных, ДанныеРасшифровки);
Этот метод идеален, если у вас сложная иерархия и правила "перекрытия" наценок (когда у подгруппы одна наценка, а у родительской группы — другая).
Если количество групп ограничено и они меняются редко, мы можем воспользоваться оператором ВЫБОР непосредственно в тексте запроса СКД. Это самый быстрый метод с точки зрения производительности СУБД.
Разберем пример такого запроса:
ВЫБРАТЬ
Номенклатура.Ссылка,
ВЫБОР
КОГДА Номенклатура.Ссылка В ИЕРАРХИИ (&Группа_30) ТОГДА 30
КОГДА Номенклатура.Ссылка В ИЕРАРХИИ (&Группа_20) ТОГДА 20
КОГДА Номенклатура.Ссылка В ИЕРАРХИИ (&Группа_10) ТОГДА 10
ИНАЧЕ 0
КОНЕЦ КАК ПроцентНаценки
ИЗ
Справочник.Номенклатура КАК Номенклатура
В данном случае &Группа_30, &Группа_20 и т.д. — это параметры СКД с типом Список значений или СправочникСсылка.Номенклатура. Система компоновки данных очень эффективно транслирует оператор В ИЕРАРХИИ в SQL-запрос, что обеспечивает высокую скорость выполнения.
Современные конфигурации на базе БСП (Библиотеки стандартных подсистем) позволяют добавлять дополнительные реквизиты к объектам без изменения метаданных. Мы можем добавить реквизит Процент наценки прямо к элементам справочника Номенклатура.
В СКД этот реквизит будет доступен через стандартный механизм характеристик. Если наценка указана только у папок, мы можем настроить получение значения от родителя. Посмотрим, как это упрощает работу:
Номенклатура.ПроцентНаценки доступно для группировок, отборов и вычислений.ЕСТЬNULL(ПроцентНаценки, Родитель.ПроцентНаценки).Проанализируем ситуацию: что делать, если товар входит в группу "Электроника" (наценка 10%), которая в свою очередь входит в группу "Импорт" (наценка 5%)? Какой процент должен примениться?
При использовании метода с ВЫБОР в запросе, приоритет определяется порядком условий КОГДА. Первое сработавшее условие "выигрывает". Если мы хотим, чтобы приоритет имела максимально близкая к товару группа (самая глубокая в иерархии), нам необходимо:
Рассмотрим вариант решения через Вычисляемые поля СКД. Хотя это может быть медленнее, чем запрос, иногда это удобнее для настройки. В выражении вычисляемого поля можно использовать функции общего модуля для определения принадлежности к группе, но будьте осторожны: это приведет к выполнению функции для каждой строки отчета.
Мы рассмотрели различные способы реализации дифференцированных наценок. Для небольших задач отлично подойдет Метод 3 (ВЫБОР в запросе). Для серьезных систем автоматизации торговли наиболее правильным решением будет Метод 1 (Регистр сведений), так как он обеспечивает прозрачность для пользователя и гибкость настроек без участия программиста.
Если же логика распределения наценок слишком сложна для описания одним запросом (например, зависит от сезона, склада и группы одновременно), то Метод 2 (Внешний набор данных) станет вашим спасением, позволяя подготовить идеальную таблицу данных средствами встроенного языка 1С.