Резервирование товаров — это одна из фундаментальных задач при автоматизации торговых операций. С технической точки зрения, задача заключается в том, чтобы «отложить» товар для конкретного покупателя так, чтобы другие менеджеры не могли его продать, хотя фактически товар все еще находится на складе. Разберем подробно, как выстроить архитектуру такой системы, какие объекты использовать и как прописать алгоритмы проведения документов.
Для реализации полноценного резервирования в 1С традиционно используется схема с двумя регистрами накопления остаточного типа. Давайте проанализируем, зачем это нужно и какие функции выполняет каждый регистр.
Рассмотрим формулу, по которой рассчитывается доступный к продаже товар: СвободныйОстаток = ОбщийОстаток - Зарезервировано. Однако на практике удобнее использовать регистр СвободныеОстатки, где при поступлении товара делается «Приход», а при резервировании — «Расход».
Проанализируем жизненный цикл товара от поступления до отгрузки. Рассмотрим, какие движения должен делать каждый документ в нашей системе.
1. Документ «Приходная накладная»
Когда товар поступает на склад, мы должны увеличить как фактический остаток, так и свободный для продажи. В процедуре ОбработкаПроведения() записываем:
Движения.ТоварыНаСкладах.Записывать = Истина;
Движения.СвободныеОстатки.Записывать = Истина;
Для Каждого ТекСтрокаТовары Из Товары Цикл
// Увеличиваем физический остаток
Движение = Движения.ТоварыНаСкладах.Добавить();
Движение.ВидДвижения = ВидДвиженияНакопления.Приход;
Движение.Период = Дата;
Движение.Номенклатура = ТекСтрокаТовары.Номенклатура;
Движение.Склад = Склад;
Движение.Количество = ТекСтрокаТовары.Количество;
// Увеличиваем свободный остаток
Движение = Движения.СвободныеОстатки.Добавить();
Движение.ВидДвижения = ВидДвиженияНакопления.Приход;
Движение.Период = Дата;
Движение.Номенклатура = ТекСтрокаТовары.Номенклатура;
Движение.Количество = ТекСтрокаТовары.Количество;
КонецЦикла;
2. Документ «Заказ покупателя»
Это ключевой момент резервирования. На этом этапе товар физически не перемещается. Мы должны проверить, есть ли свободный остаток, и если есть — уменьшить его. Выясним, почему здесь используется именно «Расход» по регистру СвободныеОстатки: мы как бы «тратим» право на продажу этого товара другим лицам.
// Сначала проверяем остатки (упрощенно)
Запрос = Новый Запрос;
Запрос.Текст = "ВЫБРАТЬ СвободныеОстаткиОстатки.КоличествоОстаток ИЗ РегистрНакопления.СвободныеОстатки.Остатки(&Момент, Номенклатура = &Номенклатура) КАК СвободныеОстаткиОстатки";
// ... установка параметров и выполнение запроса ...
// Если товара достаточно, делаем движение
Движения.СвободныеОстатки.Записывать = Истина;
Движение = Движения.СвободныеОстатки.Добавить();
Движение.ВидДвижения = ВидДвиженияНакопления.Расход;
Движение.Период = Дата;
Движение.Номенклатура = ТекСтрокаТовары.Номенклатура;
Движение.Количество = ТекСтрокаТовары.Количество;
3. Документ «Расходная накладная»
Когда товар реально уезжает со склада, мы должны уменьшить остаток в регистре ТоварыНаСкладах. Важный нюанс: свободный остаток мы уже уменьшили документом «Заказ покупателя», поэтому повторно его трогать не нужно (если расходная накладная делается на основании заказа). Если же накладная выписывается без заказа, то она должна уменьшить оба регистра.
Рассмотрим более сложную ситуацию, когда резерв должен быть «жестким», то есть привязанным к конкретному заказу. В простых системах (мягкое резервирование) мы просто знаем, что 10 штук из 100 заняты. Но мы не знаем, кем именно. В профессиональных конфигурациях типа 1С:ERP или УТ 11 используется аналитика «Назначение» или измерение «Заказ» в регистрах.
В этом случае в регистр ТоварыНаСкладах (или отдельный регистр РезервыТоваров) добавляется измерение ДокументРезерва. Это позволяет системе точно понимать: «Эти 5 мониторов стоят здесь специально для Иванова по Заказу №1».
Выясним причину, по которой системы резервирования могут давать сбой при одновременной работе нескольких пользователей. Представим: на складе 1 единица товара. Два менеджера одновременно открывают «Заказ покупателя». Оба видят остаток «1» и нажимают «Провести». Если не использовать механизм блокировок, система может позволить провести оба документа, и свободный остаток станет «-1».
Для предотвращения таких ситуаций в 1С 8.3 используется объект БлокировкаДанных. Разберем пример кода, который нужно вставить перед проверкой остатков:
Блокировка = Новый БлокировкаДанных;
ЭлементБлокировки = Блокировка.Добавить("РегистрНакопления.СвободныеОстатки");
ЭлементБлокировки.УстановитьЗначение("Номенклатура", ТекСтрокаТовары.Номенклатура);
ЭлементБлокировки.Режим = РежимБлокировкиДанных.Исключительный;
Блокировка.Заблокировать();
Это гарантирует, что пока один документ проверяет остаток и делает движение, второй будет ждать завершения транзакции.
В реальном бизнесе резерв не может висеть вечно. Посмотрим на алгоритм автоматического снятия резервов. Обычно в документ «Заказ покупателя» добавляется реквизит ДатаАктуальностиРезерва. Разберем по шагам, как организовать очистку:
СвободныеОстатки, тем самым возвращая товар в свободную продажу.Продвинутая модель учета предполагает, что мы можем зарезервировать товар, которого еще нет на складе, но который уже заказан у поставщика. В этом случае алгоритм усложняется:
ЗаказыПоставщикам.Подводя итог, отметим, что для учебной задачи достаточно реализовать схему с двумя регистрами и контролем остатков при проведении. В реальных же проектах всегда стоит учитывать вопросы блокировок, сроков жизни резерва и возможности обособленного учета под конкретную сделку.