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