Почему при отмене проведения документа реквизит "Проведен" равен Истина и как это правильно обработать?

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

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

Суть проблемы: почему Проведен всё ещё Истина?

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

С проведением всё работает как ожидается, но при отмене проведения возникает аномалия: при срабатывании события ОбработкаУдаленияПроведения реквизит Проведен равен Истина! При этом движения по регистрам уже очищены. Проанализируем ситуацию и выясним причину такого поведения платформы.

В системе 1С необходимо строго разделять состояние документа (значение реквизита Проведен) и сам процесс отмены проведения. Отмена проведения — это частный, специфический случай записи объекта, который протекает в рамках одной общей транзакции.

Событие ОбработкаУдаленияПроведения вызывается платформой до того, как в базу данных будет физически записано новое состояние документа (где Проведен станет Ложь). В момент срабатывания этого обработчика (и связанной с ним подписки на событие) система всё ещё работает с объектом, который с точки зрения базы данных является проведённым. Платформа сначала инициирует событие отмены, давая нам возможность выполнить необходимые проверки или каскадные действия, и только если не будет установлен параметр Отказ = Истина, она завершит транзакцию и зафиксирует новый непроведенный статус.

Куда пропадают записи из регистров?

Возникает закономерный вопрос: если документ формально еще проведен, почему наборы записей его регистров оказываются пустыми? Разберем этот нюанс.

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

Решение 1: Разделение подписок на разные процедуры

Самый простой и надежный способ обойти эту иллюзию статусов — перестать полагаться на реквизит Проведен внутри этих конкретных транзакций. Вместо одной универсальной процедуры создадим две разные:

  1. Процедуру для подписки на ОбработкаПроведения, которая точно знает, что документ проводится.
  2. Процедуру для подписки на ОбработкаУдаленияПроведения, которая точно знает, что документ отменяет проведение.

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

Решение 2: Использование событий ПередЗаписью и ПриЗаписи

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

Посмотрим на пример, как это можно реализовать:


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

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

Важно: При использовании ПередЗаписью следует помнить, что в последующих обработчиках (в том же модуле объекта) может случиться Отказ = Истина. Поэтому, если вы делаете записи во внешние системы напрямую из этого обработчика, вы рискуете получить расхождение данных.

Особенности регистрации изменений для обмена

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

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

Нюанс с пометкой на удаление

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

В этом случае последовательность событий такова: сначала вызовется ОбработкаУдаленияПроведения, очистятся регистры, а затем документ будет записан с измененными свойствами (Проведен = Ложь, ПометкаУдаления = Истина). Если наша самописная логика обмена опирается только на анализ события отмены проведения, она может некорректно передать в другую систему статус документа: она передаст его как просто "отмененный", а не "помеченный на удаление". Использование системных механизмов планов обмена и обработчиков ПриЗаписи позволяет избежать таких коллизий, так как регистрация будет учитывать итоговое состояние объекта после завершения всех транзакций.

← На главную