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