В торговых компаниях часто возникает задача ограничить объем продаж определенных товаров для менеджеров. Например, в рамках одного спецпредложения (Договор 2) менеджер может продать не более 30 единиц конкретной номенклатуры в месяц. Если лимит исчерпан, программа должна автоматически переключить условия продажи на стандартные (Договор 1). Рассмотрим, как правильно спроектировать архитектуру такого решения, какие объекты 1С использовать и каких ошибок стоит избегать.
Для реализации задачи нам необходимо хранить два типа данных: плановые показатели (сколько можно продать) и фактические (сколько уже продано). Проанализируем наиболее эффективный способ их хранения.
1. Настройка лимитов (Регистр сведений)
Для хранения информации о том, какому менеджеру и на какую номенклатуру установлен лимит, лучше всего использовать непериодический или периодический (в зависимости от частоты смены правил) РегистрСведений. Назовем его, например, ЛимитыПродажМенеджеров.
Рекомендуемая структура регистра:
Менеджер (СправочникСсылка.Пользователи), Номенклатура (СправочникСсылка.Номенклатура), ПериодЛимита (Дата, начало месяца).КоличествоЛимит (Число).Такая структура позволит гибко задавать лимиты на каждый месяц. Если запись для менеджера отсутствует, мы можем считать, что лимит не ограничен или равен нулю, в зависимости от бизнес-логики.
2. Учет фактических продаж (Регистр накопления)
Хотя на форумах часто предлагают делать запрос напрямую к документам, этот путь тупиковый для высоконагруженных систем. Рассмотрим подробнее, почему стоит выбрать РегистрНакопления с видом «Обороты».
Использование регистра оборотов позволяет системе мгновенно получать данные о накопленных продажах за период, не пересчитывая тысячи документов. Назовем его ПродажиПоЛимитируемымДоговорам.
Структура регистра оборотов:
Менеджер, Номенклатура, Договор.Количество.Разберем по шагам, как должна работать система при выборе товара в заказе или при его проведении.
Проанализируем ситуацию: менеджер добавляет строку в «Заказ клиента». В этот момент нам нужно оперативно подсказать ему, проходит ли товар по «Договору 2» или лимит уже исчерпан. Для этого в обработчике события ПриИзменении номенклатуры или количества на форме документа мы должны выполнить запрос.
Пример логики запроса:
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| ЕСТЬNULL(Лимиты.КоличествоЛимит, 0) КАК Лимит,
| ЕСТЬNULL(ПродажиОбороты.КоличествоОборот, 0) КАК Продано
|ИЗ
| РегистрСведений.ЛимитыПродажМенеджеров КАК Лимиты
| ЛЕВОЕ СОЕДИНЕНИЕ РегистрНакопления.ПродажиПоЛимитируемымДоговорам.Обороты(&НачалоПериода, &КонецПериода, , Менеджер = &Менеджер И Номенклатура = &Номенклатура И Договор = &Договор2) КАК ПродажиОбороты
| ПО Лимиты.Менеджер = &Менеджер И Лимиты.Номенклатура = &Номенклатура";
Если Продано + ТекущееКоличество > Лимит, то система должна программно подставить Договор 1. Однако здесь кроется важный нюанс: в 1С договор чаще всего указывается в шапке документа. Если в одном заказе часть товаров укладывается в лимит, а часть — нет, документ придется либо разделять на два, либо выводить менеджеру предупреждение о необходимости создать второй заказ.
Выясним причину частых ошибок при планировании отгрузок на стыке месяцев. Если менеджер оформляет заказ 25-го числа, а отгрузка планируется на 10-е число следующего месяца, то лимит должен расходоваться из квоты следующего месяца.
Для корректной работы системы необходимо ориентироваться не на Дата документа, а на реквизит ДатаОтгрузки. В движения регистра накопления данные должны попадать именно на дату планируемой отгрузки. Это позволит системе «видеть» будущие расходы лимита и не допускать перепродаж.
Рассмотрим ситуацию: два менеджера одновременно продают последнюю единицу товара по лимиту. Если проверка идет только визуально на форме, оба документа будут проведены, и возникнет превышение. Чтобы этого избежать, обязателен контроль в транзакции проведения.
В модуле объекта в обработчике ОбработкаПроведения необходимо реализовать жесткий контроль с использованием механизма БлокировкаДанных. Мы должны заблокировать комбинацию «Менеджер + Номенклатура + Период», чтобы другие сеансы не могли изменить данные, пока мы проверяем остаток и записываем свои движения.
Пример установки блокировки:
Блокировка = Новый БлокировкаДанных;
ЭлементБлокировки = Блокировка.Добавить("РегистрНакопления.ПродажиПоЛимитируемымДоговорам");
ЭлементБлокировки.УстановитьПараметр("Менеджер", Менеджер);
ЭлементБлокировки.УстановитьПараметр("Номенклатура", Номенклатура);
ЭлементБлокировки.Режим = РежимБлокировкиДанных.Исключительный;
Блокировка.Заблокировать();
Важно помнить, что управленческий учет — это не только продажи, но и возвраты. Если клиент вернул товар, лимит менеджера должен восстановиться. При использовании регистра накопления (Обороты) это решается автоматически: документ «Возврат товаров от клиента» делает запись с отрицательным значением расхода («сторно»), что увеличивает доступный остаток лимита при расчете запросом.
Чтобы сохранить конфигурацию на поддержке и не вносить изменения в типовые объекты (например, если вы работаете с 1С:УНФ или 1С:УТ), всю логику лимитирования лучше вынести в Расширение.
&После или &Перед расширяем процедуру ОбработкаПроведения заказов или реализаций.Проанализировав все подходы, можно сделать вывод: наиболее надежным методом реализации является связка из Регистра сведений для настроек и Регистра накопления (обороты) для контроля факта. Это обеспечит высокую производительность, корректный учет будущих периодов и исключит ошибки при одновременной работе пользователей.