В типовой конфигурации 1С:Розница 2.3 многие пользователи и предприниматели сталкиваются с логической дилеммой при работе с программами лояльности. Ситуация выглядит так: клиент покупает товар, часть суммы оплачивает накопленными бонусами, а остаток — наличными или картой. Программа, согласно стандартным правилам, часто начисляет новые бонусы на всю сумму чека, включая ту часть, которая была оплачена баллами. С точки зрения бизнеса это выглядит как «бонусы на бонусы», что ведет к необоснованным затратам.
В этой статье мы подробно разберем, почему так происходит и какими способами можно заставить программу рассчитывать бонусную базу только из «живых» денег.
Начнем с самого простого и неочевидного метода, который помогает во многих релизах, начиная с 2.3.10. Проанализируем настройки бонусной программы лояльности. В 1С оплата бонусами технически может трактоваться системой по-разному: как скидка или как платежное средство.
Рассмотрим порядок действий:
Важный нюанс: Несмотря на название, эта настройка во многих конфигурациях регулирует базу начисления. Если флаг установлен, программа при расчете новых баллов вычитает из общей суммы документа все примененные скидки и, в некоторых случаях, оплаты, приравненные к ним. Посмотрим на результат: если настройка активна, система должна увидеть оплату бонусами как фактор, уменьшающий базу для расчета последующих начислений. Однако стоит учитывать, что в некоторых старых релизах этот механизм может работать некорректно, так как оплата бонусами фискализируется как встречное предоставление (вид оплаты), а не как скидка в чистом виде.
Если штатные флаги не помогают, разберем более гибкий, но технически сложный вариант. В 1С:Розница правила начисления бонусов могут использовать Произвольные схемы компоновки данных.
Проанализируем ситуацию: нам нужно, чтобы система при расчете суммы бонуса обращалась не к полю СуммаДокумента, а к разности между общей суммой и суммой, оплаченной конкретным видом оплаты (Бонусами).
Рассмотрим алгоритм настройки:
ЧекиККМ с таблицей ЧекиККМОплата.ТипОплаты НЕ равен БонусныеБаллы.Такой подход позволяет на лету вычислять корректную базу для начисления, не изменяя программный код конфигурации. Это наиболее «чистый» способ с точки зрения поддержки системы.
Рассмотрим ситуацию, когда стандартные механизмы начисления в момент пробития чека не подходят (например, если требуется сложная логика разделения бонусов по типам оплаты: 2% за наличные и 1% за карту). В этом случае мы можем отключить автоматическое начисление в чеке и реализовать его через внешнюю обработку, запускаемую по расписанию.
Разберем пример кода, который обходит чеки за текущий день, анализирует виды оплат и создает документ НачислениеИСписаниеБонусныхБаллов. Выясним причину использования такого метода: он позволяет полностью исключить тип оплаты ЗачетАванса (бонусы) из расчета.
Посмотрим на пример реализации серверной части такой обработки:
// Фрагмент кода для выборки данных из чеков и расчета бонусов
Запрос = Новый Запрос;
Запрос.Текст = "ВЫБРАТЬ
| ЧекККМ.Ссылка КАК Ссылка,
| ЧекККМ.ДисконтнаяКарта КАК ДисконтнаяКарта,
| ЧекККМОплата.Сумма КАК СуммаОплаты,
| ЧекККМОплата.ВидОплаты.ТипОплаты КАК ТипОплаты
|ИЗ
| Документ.ЧекККМ КАК ЧекККМ
| ЛЕВОЕ СОЕДИНЕНИЕ Документ.ЧекККМ.Оплата КАК ЧекККМОплата
| ПО ЧекККМ.Ссылка = ЧекККМОплата.Ссылка
|ГДЕ
| ЧекККМ.Дата МЕЖДУ &НачалоПериода И &КонецПериода
| И ЧекККМ.Проведен = ИСТИНА
| И ЧекККМОплата.ВидОплаты.ТипОплаты <> ЗНАЧЕНИЕ(Перечисление.ТипыОплатЧекаККМ.ЗачетАванса)";
Запрос.УстановитьПараметр("НачалоПериода", НачалоДня(ТекущаяДата()));
Запрос.УстановитьПараметр("КонецПериода", КонецДня(ТекущаяДата()));
Результат = Запрос.Выполнить();
Выборка = Результат.Выбрать();
Начисление = Документы.НачислениеИСписаниеБонусныхБаллов.СоздатьДокумент();
Начисление.Дата = ТекущаяДата();
Начисление.БонуснаяПрограммаЛояльности = Справочники.БонусныеПрограммыЛояльности.НайтиПоНаименованию("Основная");
Пока Выборка.Следующий() Цикл
Если ЗначениеЗаполнено(Выборка.ДисконтнаяКарта) Тогда
НоваяСтрока = Начисление.Начисление.Добавить();
НоваяСтрока.ДисконтнаяКарта = Выборка.ДисконтнаяКарта;
// Логика: 2% на наличные, 1% на остальные (кроме бонусов, которые мы отсекли в запросе)
Если Выборка.ТипОплаты = Перечисления.ТипыОплатЧекаККМ.Наличные Тогда
НоваяСтрока.Баллы = Цел(Выборка.СуммаОплаты * 0.02);
Иначе
НоваяСтрока.Баллы = Цел(Выборка.СуммаОплаты * 0.01);
КонецЕсли;
КонецЕсли;
КонецЦикла;
Начисление.Записать(РежимЗаписиДокумента.Проведение);
Для того чтобы эта обработка работала автоматически, её необходимо зарегистрировать в системе как дополнительную. Для этого используем стандартную функцию СведенияОВнешнейОбработке:
Функция СведенияОВнешнейОбработке() Экспорт
ПараметрыРегистрации = Новый Структура;
ПараметрыРегистрации.Вставить("Вид", "ДополнительнаяОбработка");
ПараметрыРегистрации.Вставить("Наименование", "Регламентное начисление бонусов (без учета баллов)");
ПараметрыРегистрации.Вставить("Версия", "1.0");
ПараметрыРегистрации.Вставить("БезопасныйРежим", Ложь);
ТаблицаКоманд = Новый ТаблицаЗначений;
ТаблицаКоманд.Колонки.Добавить("Представление", Новый ОписаниеТипов("Строка"));
ТаблицаКоманд.Колонки.Добавить("Идентификатор", Новый ОписаниеТипов("Строка"));
ТаблицаКоманд.Колонки.Добавить("Использование", Новый ОписаниеТипов("Строка"));
НоваяКоманда = ТаблицаКоманд.Добавить();
НоваяКоманда.Представление = "Выполнить начисление";
НоваяКоманда.Идентификатор = "НачислитьБонусы";
НоваяКоманда.Использование = "ВызовСерверногоМетода";
ПараметрыРегистрации.Вставить("Команды", ТаблицаКоманд);
Возврат ПараметрыРегистрации;
КонецФункции
Проанализируем плюсы и минусы каждого метода:
Резюмируем: Для большинства типовых задач в 1С:Розница 2.3 достаточно правильно настроить бонусную программу через интерфейс или создать корректную схему компоновки данных. Если же условия акции требуют разграничения по типам оплат (нал/безнал), то программный метод через документ НачислениеИСписаниеБонусныхБаллов станет наиболее надежным решением.