Как реализовать контроль остатков в 1С и запретить списание в минус

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

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

Принцип работы контроля остатков

Основная идея заключается в том, чтобы внутри процедуры ОбработкаПроведения модуля документа выполнить запрос к регистру накопления. Существует две основные стратегии проверки:

  1. Проверка перед записью: Мы сначала проверяем наличие товара, и если его хватает — записываем движения.
  2. Проверка после записи (новая стратегия): Мы сначала записываем движения документа в регистр, а затем проверяем, не стал ли остаток по этим позициям отрицательным.

Второй вариант считается более современным и надежным, так как он позволяет учесть текущие движения самого документа в одной транзакции. Если после записи движений запрос находит отрицательные остатки, транзакция проведения отменяется установкой параметра Отказ = Истина.

Программная реализация контроля

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


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

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

Важные технические нюансы

Для обеспечения корректной работы в многопользовательской среде и точности данных, необходимо учитывать несколько критических факторов:

Использование управляемых блокировок (DataLock). В современных конфигурациях крайне важно использовать объект БлокировкаДанных. Это предотвращает "состояние гонки" (Race Condition), когда два пользователя одновременно пытаются списать последнюю единицу товара. Без блокировки оба запроса на остатки могут показать наличие товара до того, как одна из транзакций завершится, что приведет к итоговому минусу.

Правильный момент времени. При получении остатков запросом важно использовать конструктор Новый Граница(МоментВремени(), ВидГраницы.Включая). Это гарантирует, что виртуальная таблица Остатки учтет изменения, внесенные текущим документом. Если просто передать дату или момент времени без границы, текущие движения могут не попасть в выборку.

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

Оптимизация производительности

Чтобы запрос работал максимально быстро, соблюдайте следующие правила:

Используя приведенную методику, вы обеспечите целостность складского учета в вашей конфигурации и исключите ошибки, связанные с некорректным списанием ТМЦ.

← На главную