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