Как очистить движения регистра, записанные в событии ПередЗаписью, при пометке документа на удаление?

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

Иногда при разработке нестандартных механизмов в 1С возникает необходимость формировать движения в регистрах накопления еще до проведения документа — непосредственно в момент его записи. Например, это может требоваться для фиксации предварительных резервов, фиксации статусов или контроля очередей по непроведенным черновикам документов. Однако при таком подходе разработчики часто сталкиваются с неожиданным поведением платформы: при установке на документ пометки на удаление сформированные движения не исчезают и продолжают искажать остатки в отчетах.

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

Выясним причину: почему платформа не очищает движения автоматически

Штатный механизм платформы по автоматическому удалению записей в регистрах (свойство документа Удаление движений в конфигураторе) жестко привязан к процессу отмены проведения. Платформа очищает таблицы движений в следующих случаях:

  1. Когда для уже проведенного документа вызывается отмена проведения (в обработчиках режима РежимЗаписиДокумента.ОтменаПроведения).
  2. Когда документ физически удаляется из базы данных через процедуру Удаление помеченных объектов — в этот момент СУБД удаляет все записи во всех таблицах, где документ выступает регистратором.

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

Способ 1. Очистка движений через коллекцию документа в событии ПередЗаписью

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

Для очистки записей регистра нам достаточно проверить признак ПометкаУдаления и вызвать метод очистки коллекции движений. Рассмотрим пример кода:


Процедура ПередЗаписью(Отказ, РежимЗаписи, РежимПроведения)
    
    // Если документ помечается на удаление, очищаем сформированные движения
    Если ПометкаУдаления Тогда
        Движения.ОстаткиНаСкладах.Очистить();
        Движения.ОстаткиНаСкладах.Записывать = Истина;
    КонецЕсли;

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

Обратим особое внимание на установку флага Записывать = Истина. Если просто вызвать метод Очистить(), коллекция очистится только в оперативной памяти объекта. Чтобы платформа перенесла эти изменения в базу данных и удалила строки из таблицы регистра, свойство Записывать набора движений обязательно должно быть установлено в значение Истина.

Способ 2. Очистка через явную запись пустого набора записей

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

Посмотрим на пример реализации:


Процедура ПередЗаписью(Отказ, РежимЗаписи, РежимПроведения)

    // Проверяем, что документ уже существует в базе и помечается на удаление
    Если Не ЭтоНовый() И ПометкаУдаления Тогда
        НаборЗаписей = РегистрыНакопления.ОстаткиНаСкладах.СоздатьНаборЗаписей();
        НаборЗаписей.Отбор.Регистратор.Установить(Ссылка);
        
        // Запись набора без добавления строк удаляет все движения регистратора
        НаборЗаписей.Записать();
    КонецЕсли;

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

В данном варианте обязательно используется проверка Не ЭтоНовый(). В событии ПередЗаписью новый документ еще не имеет постоянной ссылки в базе данных (если не использовался метод УстановитьСсылкуНового()), и попытка установить отбор по пустой ссылке вызовет ошибку либо некорректную выборку.

Важное предостережение: если применяется метод с явной записью набора НаборЗаписей.Записать(), ни в коем случае нельзя одновременно взводить флаг Движения.ОстаткиНаСкладах.Записывать = Истина в том же событии, чтобы не вызвать конфликт транзакционных блокировок и повторную перезапись пустых данных.

Архитектурные альтернативы и стандарты разработки 1С

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

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