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