Как реализовать механизм временного бронирования товаров или мест в 1С

Программист 1С v8.3 (Управляемые формы) Управленческий учет Сфера услуг, туризм и социальный сектор
← На главную

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

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

Вариант 1: Использование независимого регистра сведений

Это один из самых гибких подходов. Мы создаем независимый РегистрСведений (например, ВременныеБрони), в котором фиксируем факт выбора объекта. Рассмотрим структуру такого регистра:

  1. Измерения: ОбъектБронирования (СправочникСсылка или любая уникальная комбинация), Склад (если актуально).
  2. Ресурсы: ВремяОкончанияБрони (Дата), Менеджер (СправочникСсылка.Пользователи).
  3. Свойства: Регистр должен быть независимым, чтобы запись в него не требовала фиксации основного документа.

Рассмотрим логику работы. При выборе товара в форме подбора мы выполняем запись в этот регистр. Чтобы система работала корректно, нам необходимо реализовать механизм очистки «протухших» броней.


// Пример записи временной брони
Процедура ЗафиксироватьБронирование(ТоварСсылка, ТекущийПользователь)
    МенеджерЗаписи = РегистрыСведений.ВременныеБрони.СоздатьМенеджерЗаписи();
    МенеджерЗаписи.ОбъектБронирования = ТоварСсылка;
    МенеджерЗаписи.Менеджер = ТекущийПользователь;
    МенеджерЗаписи.ВремяОкончанияБрони = ТекущаяДата() + 600; // Бронь на 10 минут
    МенеджерЗаписи.Записать();
КонецПроцедуры

Для автоматического снятия брони проанализируем использование Регламентного задания. Раз в несколько минут (например, раз в минуту) задание должно удалять записи, у которых ВремяОкончанияБрони меньше ТекущаяДата(). Также важно предусмотреть очистку записи в момент проведения документа реализации или закрытия формы подбора без сохранения.

Вариант 2: Регистр накопления с «хитрой» записью набора

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

Мы можем создать документ «Заказ» и при интерактивном подборе записывать движения по регистру накопления (например, ТоварыВРезерве), устанавливая Регистратор, но не проводя сам документ. Для этого используется объект НаборЗаписей.


// Запись в регистр накопления без проведения документа
Набор = РегистрыНакопления.ТоварыВРезерве.СоздатьНаборЗаписей();
Набор.Отбор.Регистратор.Установить(СсылкаНаДокумент);

НоваяЗапись = Набор.Добавить();
НоваяЗапись.ВидДвижения = ВидДвиженияНакопления.Приход;
НоваяЗапись.Номенклатура = ВыбранныйТовар;
НоваяЗапись.Количество = 1;
НоваяЗапись.Период = ТекущаяДата();

Набор.Записать(); // Запись физически попадет в БД

Важный нюанс: при окончательном проведении документа реализации необходимо убедиться, что свойство Записывать у набора записей в обработке проведения установлено в Истина, но сам набор пуст (или содержит уже окончательные данные), чтобы временная бронь «схлопнулась» и заместилась реальным резервом или списанием.

Вариант 3: Атомарные документы бронирования

Проанализируем ситуацию, когда нагрузка на базу очень высокая. В этом случае запись каждой строки в общий регистр может вызвать конфликты блокировок. Решением может стать создание отдельного легкого документа БронированиеМеста. Каждое нажатие кнопки в интерфейсе порождает новый документ. Это позволяет избежать блокировок всей таблицы регистра, так как каждый пользователь работает со своим объектом. После оплаты или истечения времени документ либо помечается на удаление, либо меняет статус.

Вариант 4: Управляемые блокировки на виртуальные ресурсы

Если нам нужно запретить выбор места на уровне транзакции, не создавая лишних записей в таблицах, мы можем использовать механизм управляемых блокировок. Мы можем заблокировать «виртуальное имя», которое соответствует нашему объекту.

Разберем пример кода для установки блокировки:


Блокировка = Новый БлокировкаДанных;
ЭлементБлок = Блокировка.Добавить("РегистрСведений.ВременныеБрони");
ЭлементБлок.УстановитьПараметр("ОбъектБронирования", ВыбранноеМесто);
ЭлементБлок.Режим = РежимБлокировкиДанных.Исключительный;
Блокировка.Заблокировать();
// Если другой пользователь попробует выполнить этот же код, 
// система выдаст ошибку блокировки, пока транзакция не завершится

Вариант 5: Использование Системы взаимодействия и кэширования

Для создания современного и отзывчивого интерфейса (как на сайтах авиакомпаний) рассмотрим использование Системы взаимодействия. Когда оператор №1 выбирает место, сервер 1С отправляет оповещение всем остальным клиентам через метод СистемаВзаимодействия.ОтправитьСообщение(). В форме подбора у других операторов срабатывает обработчик оповещения, который программно «закрашивает» это место серым цветом, предотвращая даже попытку клика.

Это значительно снижает количество обращений к базе данных и конфликтов, так как пользователи видят актуальное состояние «почти в реальном времени».

Рекомендации по реализации интерфейса

При разработке формы подбора рекомендуем придерживаться следующих правил:

  1. Визуальный таймер: Используйте метод ПодключитьОбработчикОжидания, чтобы показывать оператору, сколько секунд осталось до снятия брони.
  2. Валидация при выборе: Даже если место кажется свободным на форме, перед записью брони всегда выполняйте быструю проверку в транзакции через Запрос к регистру броней с установкой исключительной блокировки.
  3. Идентификация сеанса: Записывайте в регистр НомерСеансаИнформационнойБазы. Если пользователь внезапно закрыл программу (вылетела ошибка, пропал интернет), регламентное задание сможет мгновенно очистить брони этого сеанса, так как сеанс в списке активных пользователей пропадет.

Подводя итог, выбор механизма зависит от требований к нагрузке. Для большинства задач оптимальным является использование независимого регистра сведений с хранением времени жизни записи и идентификатора сеанса пользователя. Это обеспечивает баланс между производительностью и простотой поддержки кода.

← На главную