Как полностью запретить изменение и отмену проведения документа в 1С?

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

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

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

Почему проверка в событии ПриЗаписи не блокирует отмену проведения

Проанализируем механику работы платформы при записи объектов. Когда пользователь нажимает «Отменить проведение» (интерактивно из формы или списка, либо при вызове метода программно), платформа выполняет определенную цепочку действий:

  1. Объект документа считывается и инициализируется процедура отмены проведения.
  2. Свойство документа Проведен в оперативной памяти сразу же сбрасывается в значение Ложь.
  3. Вызываются обработчики ПередЗаписью, очищаются движения по регистрам, отрабатывает ОбработкаУдаленияПроведения, и только затем вызывается событие ПриЗаписи.

Когда в обработчике ПриЗаписи проверяется свойство объекта через Источник.Проведен, платформа сообщает, что флаг проведения уже снят. В итоге условие проверки не срабатывает, транзакция фиксируется, и проведение успешно отменяется.

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

Способ 1. Реализация через подписку на событие ПередЗаписью (Рекомендуемый)

Рассмотрим правильный подход к глобальному контролю состояния документа. Чтобы определить реальный статус документа до начала текущей транзакции записи, необходимо обратиться к его состоянию, сохраненному непосредственно в базе данных. Для этого используется обращение через ссылку: Источник.Ссылка.Проведен.

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

Создадим подписку на события в конфигурации со следующими параметрами:

  1. Источник: ДокументОбъект.ИмяВашегоДокумента (или несколько документов).
  2. Событие: ПередЗаписью.
  3. Обработчик: процедура в общем серверном модуле.

Посмотрим на пример кода процедуры-обработчика подписки:


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

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

    // Проверяем статус проведения документа непосредственно в базе данных
    Если Источник.Ссылка.Проведен Тогда
        Отказ = Истина;
        ВызватьИсключение "Редактирование, перепроведение и отмена проведения данного документа запрещены!";
    КонецЕсли;

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

Разберем по шагам, как отрабатывает данный алгоритм в разных сценариях:

  1. Создание нового документа: метод Источник.ЭтоНовый() возвращает Истина, проверка пропускается, документ успешно проводится первый раз.
  2. Попытка изменения реквизитов проведенного документа: в базе данных документ уже проведен (Источник.Ссылка.Проведен = Истина). Срабатывает отказ, запись отменяется.
  3. Попытка отмены проведения: в памяти свойство Источник.Проведен уже равно Ложь, однако в базе данных документ всё еще числится проведенным (Источник.Ссылка.Проведен = Истина). Платформа устанавливает Отказ = Истина, транзакция откатывается, и отмена проведения блокируется.

Способ 2. Защита от прямого удаления документа через событие ПередУдалением

Если мы полностью запретили перезапись и отмену проведения, документ все еще могут попытаться удалить напрямую (например, через удаление помеченных объектов или программно вызовом метода Удалить()). При этом событие ПередЗаписью не вызывается.

Для полной изоляции документа создадим вторую подписку на событие ПередУдалением:


Процедура ЗапретитьУдалениеПроведенныхПередУдалением(Источник, Отказ) Экспорт

    Если Источник.Проведен Тогда
        Отказ = Истина;
        ВызватьИсключение "Удаление проведенного документа запрещено!";
    КонецЕсли;

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

Способ 3. Перехват отмены проведения в модуле объекта

Если блокировку требуется реализовать только для конкретного вида документа без создания общих подписок, можно задействовать предопределенные процедуры модуля объекта документа.

Для перехвата именно операции отмены проведения в модуле объекта существует специальный обработчик ОбработкаУдаленияПроведения. Посмотрим на пример кода:


Процедура ОбработкаУдаленияПроведения(Отказ)
    
    // Блокируем отмену проведения документа
    Отказ = Истина;
    Сообщить("Отмена проведения для данного документа запрещена правилами учета.");

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

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


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

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

Важные технические нюансы реализации

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

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