Как настроить совместное действие скидки по купону и подарка в «1С:Розница», чтобы сумма скидки не «сгорала» на бесплатном товаре?

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

При автоматизации розничной торговли часто возникают ситуации, когда маркетинговые активности накладываются друг на друга. Классический пример из практики — совместное проведение акции «Купи 6 товаров Х и получи товар Y в подарок» (то есть со скидкой 100%) и одновременное применение купона на фиксированную сумму (например, 100 рублей) на весь чек.

В конфигурации «1С:Розница» (начиная с версии 2.2) пользователи часто сталкиваются с неприятным эффектом: программа распределяет (пропорционально «размазывает») фиксированную сумму купона по всем строкам чека, включая и подарочный товар Y. Поскольку подарок и так отпускается со 100% скидкой (его стоимость для клиента равна 0 рублей), то часть купонной скидки, которая пришлась на эту строку, просто аннулируется. В итоге вместо положенных 100 рублей скидки по купону покупатель получает, например, только 80 рублей. Выясним причину этого поведения и подробно разберем, как исправить эту логику штатными и программными средствами.

Почему происходит «сгорание» скидки: математика распределения в 1С

Давайте проанализируем ситуацию на конкретном примере чека, чтобы понять внутреннюю логику системы:

Если в системе настроено совместное применение скидок по принципу «Максимум» или «Сложение» без жестких приоритетов, система производит расчет параллельно:

Сначала алгоритм распределяет купон в 100 рублей на общую сумму чека (1200 + 300 = 1500 руб.):

  1. Доля товара X в чеке составляет: 1200 / 1500 = 80%. На него распределяется 80 рублей от купона. Конечная стоимость товара X становится равной 1120 руб.
  2. Доля товара Y (подарка) составляет: 300 / 1500 = 20%. На него распределяется 20 рублей от купона. Стоимость товара Y уменьшается до 280 руб.

Затем срабатывает акция «Подарок», которая должна предоставить 100% скидку на товар Y. Программа рассчитывает скидку на товар Y от его текущей стоимости. Но максимальная скидка на товар не может превышать его цену. Поскольку на товар Y уже распределилось 20 рублей купона, скидка-подарок дает оставшиеся 280 рублей. В итоге товар Y уходит за 0 рублей, но из 100 рублей купона реально применились только 80 рублей, распределенные на товар X. Оставшиеся 20 рублей бесследно «сгорают».

Ниже мы подробно рассмотрим три практических способа решения этой проблемы.

---

Решение 1. Настройка последовательного применения и правильных приоритетов (Штатный способ №1)

Наиболее простым и правильным решением без изменения метаданных является настройка правильной иерархии в справочнике «Группы совместного действия скидок, наценок и ограничений». Нам необходимо заставить систему рассчитывать скидки строго по очереди: сначала полностью обнулить стоимость подарка, а затем распределить купон только на те строки, которые имеют положительную стоимость.

Давайте разберем настройку по шагам:

  1. Перейдем в раздел Маркетинг и откроем справочник Скидки (наценки).
  2. Создадим новую группу совместного действия (или отредактируем существующую), выбрав для нее вариант совместного действия «Последовательное применение».
  3. Поместим внутрь этой группы две наши скидки: акцию с подарком и скидку по купону.
  4. Это критически важно: установим приоритеты применения скидок. Акция, дающая подарок (товар Y со скидкой 100%), должна иметь более высокий приоритет, чем скидка по купону. Например, установим приоритет для подарка равным «10», а для купона — «5». В системе последовательного применения скидка с большим приоритетом рассчитывается первой.

Проанализируем, как изменится математика расчета при такой настройке:

Таким образом, покупатель получает товар Y бесплатно, а за товары X платит 1100 рублей вместо 1200. Скидка по купону применилась в полном объеме!

---

Решение 2. Исключение сегмента подарков из области действия купона (Штатный способ №2)

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

Рассмотрим этот вариант по шагам:

  1. Создадим новый сегмент номенклатуры. Для этого перейдем в раздел Маркетинг -> Сегменты номенклатуры.
  2. Создадим сегмент с названием ТоварыПодарки. Сформируем его состав — добавим туда товар Y (и любые другие товары, которые могут выступать в качестве бесплатных подарков по акциям). Настройку можно сделать как вручную, так и динамически (например, по определенной группе номенклатуры или свойству).
  3. Перейдем в настройки скидки по купону (на 100 рублей).
  4. Откроем вкладку Уточнения и ограничения (в зависимости от релиза название вкладки может звучать как «Область предоставления» или «Номенклатурные группы»).
  5. Настроим правило предоставления: укажем, что скидка действует на всю номенклатуру, за исключением сегмента ТоварыПодарки.

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

---

Решение 3. Программный расчет через внешнюю обработку (Для разработчиков)

В конфигурации «1С:Розница 2.2» предусмотрен крайне гибкий механизм расширения возможностей расчета скидок с помощью механизма внешних обработок. Если маркетинговая политика компании очень сложная (например, состав подарков постоянно меняется, или сегменты пересекаются), стандартных настроек совместного действия может не хватить. В таком случае мы можем использовать внешнюю обработку для расчета условий или самой скидки.

При вызове внешней обработки система передает в нее объект, содержащий полную таблицу товаров чека. Мы можем программно проанализировать строки чека, определить строки-подарки и корректно перераспределить скидку.

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


// Процедура рассчитывает скидку по купону, распределяя ее только на платные товары
Процедура РассчитатьСкидку(ПараметрыРасчета) Экспорт
    
    ТаблицаТоваров = ПараметрыРасчета.ТаблицаТоваров;
    СуммаКупона = 100; // Фиксированная сумма купона
    
    // Шаг 1. Найдем строки, которые не являются подарками (цена > 0 после применения других скидок)
    МассивПлатныхСтрок = Новый Массив;
    ОбщаяСтоимостьПлатныхТоваров = 0;
    
    Для Каждого СтрокаТовара Из ТаблицаТоваров Цикл
        // Проверяем текущую стоимость строки с учетом уже примененных скидок
        ТекущаяСтоимостьСтроки = СтрокаТовара.Сумма - СтрокаТовара.СуммаСкидки;
        
        Если ТекущаяСтоимостьСтроки > 0 Тогда
            МассивПлатныхСтрок.Добавить(СтрокаТовара);
            ОбщаяСтоимостьПлатныхТоваров = ОбщаяСтоимостьПлатныхТоваров + ТекущаяСтоимостьСтроки;
        КонецЕсли;
    КонецЦикла;
    
    Если МассивПлатныхСтрок.Количество() = 0 Или ОбщаяСтоимостьПлатныхТоваров = 0 Тогда
        Возврат; // Не на что распределять скидку
    КонецЕсли;
    
    // Шаг 2. Распределяем сумму купона пропорционально стоимости платных товаров
    ОстатокСкидки = СуммаКупона;
    КоличествоСтрок = МассивПлатныхСтрок.Количество();
    
    Для Индекс = 0 По КоличествоСтрок - 1 Цикл
        СтрокаТовара = МассивПлатныхСтрок[Индекс];
        ТекущаяСтоимостьСтроки = СтрокаТовара.Сумма - СтрокаТовара.СуммаСкидки;
        
        Если Индекс = КоличествоСтрок - 1 Тогда
            // В последнюю строку пишем весь остаток, чтобы избежать копеечных погрешностей округления
            ТекущаяСкидкаСтроки = ОстатокСкидки;
        Иначе
            ТекущаяСкидкаСтроки = ОкруглитьДоКопеек(СуммаКупона * (ТекущаяСтоимостьСтроки / ОбщаяСтоимостьПлатныхТоваров));
            ОстатокСкидки = ОстатокСкидки - ТекущаяСкидкаСтроки;
        EndЕсли;
        
        // Записываем рассчитанную скидку обратно в структуру данных 1С:Розницы
        СтрокаТовара.СуммаСкидки = СтрокаТовара.СуммаСкидки + ТекущаяСкидкаСтроки;
    КонецЦикла;

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

Функция ОкруглитьДоКопеек(Значение)
    Возврат Окр(Значение, 2, РежимОкругления.Окр15_21);
КонецФункции

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

Резюме и рекомендации

Мы проанализировали проблему распределения скидок в «1С:Розница 2.2» и рассмотрели три метода борьбы с потерей скидки по купону:

← На главную