Как ограничить количество регистраций в документе 1С на основе лимита мест

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

При разработке прикладных решений на платформе 1С часто возникает задача контроля количественных показателей. Типичный пример — ограничение записи слушателей на учебные курсы, когда количество мест строго лимитировано. Если просто хранить лимит в справочнике, это может привести к архитектурным ошибкам и низкой производительности. В этой статье мы подробно разберем, как правильно реализовать механизм контроля лимитов, используя регистры и транзакционную логику проведения документов.

Почему нельзя хранить оперативную информацию в справочнике?

Начнем с анализа исходной ситуации. Изначально предлагалось хранить количество мест в реквизите справочника Предметы. Рассмотрим подробнее, почему это плохая практика. Справочники предназначены для хранения условно-постоянной информации. Как только мы начинаем записывать туда данные, которые часто меняются или на основе которых строятся оперативные отчеты (например, сколько мест осталось), мы сталкиваемся с проблемами блокировок и отсутствием истории изменений.

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

Шаг 1: Настройка структуры данных

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

  1. Регистр сведений "КвотыКурсов": Здесь мы будем хранить информацию о том, сколько человек может записаться на конкретный курс. Сделаем его Непериодическим (если лимит не меняется часто) или Периодическим (если в следующем месяце мест может быть больше). В качестве измерения укажем Курс (ссылка на справочник), а в качестве ресурса — КоличествоМест (число).
  2. Регистр накопления "ЗанятыеМеста": Вид регистра выберем Остатки. Измерение — Курс, ресурс — Количество. Этот регистр позволит нам мгновенно получать информацию о том, сколько человек уже записано на курс на текущий момент.

Шаг 2: Реализация логики проведения документа

Проанализируем ситуацию: документ Регистрация должен при проведении проверять, не превышен ли лимит. Самое важное правило разработки в 1С — проверка должна происходить в процедуре ОбработкаПроведения в модуле документа. Это гарантирует, что проверка выполняется внутри транзакции записи в базу данных.

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


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

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

Шаг 3: Обеспечение параллельной работы (Блокировки)

Рассмотрим подробнее важный нюанс. Если два менеджера одновременно нажмут кнопку "Провести" на последнем свободном месте, может возникнуть ситуация, когда оба документа проведутся одновременно. Это происходит потому, что в момент выполнения запроса оба документа "видят", что место еще есть.

Для решения этой проблемы мы должны использовать объект БлокировкаДанных. Мы заблокируем ресурс "Курс" в регистре накопления на время проведения транзакции. Тогда вторая транзакция будет ждать, пока первая завершится, и увидит уже обновленные (правильные) остатки.


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

Этот фрагмент кода следует вставить в самое начало процедуры ОбработкаПроведения.

Шаг 4: Работа с изменениями "задним числом"

Посмотрим на ситуацию, которую затронули в обсуждении: что делать, если лимит в регистре сведений изменили с 10 на 5, а уже проведено 8 документов? 1С не будет автоматически отменять проведение старых документов. Это правильно, так как система не должна самостоятельно принимать решения о "выселении" уже зарегистрированных студентов.

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

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

Подведем итог нашей совместной работы. Для качественной реализации ограничения записей необходимо:

Такой подход делает систему надежной, масштабируемой и соответствующей стандартам разработки 1С. Мы не просто ограничиваем запись, а создаем полноценный механизм контроля ресурсов предприятия.

← На главную