Как программно пометить документ на удаление, если в модуле объекта срабатывают контроли и проверки?

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

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

В этой статье мы подробно разберем, почему возникает популярная ошибка «Действие не может выполняться в режиме загрузки данных», проанализируем опасные «костыли», которые часто используют новички, и рассмотрим три правильных, безопасных способа обхода проверок при программном удалении документов.

Почему возникает ошибка «Действие не может выполняться в режиме загрузки данных»?

Для обхода проверок в модуле объекта разработчики часто используют стандартный механизм платформы — отключение бизнес-логики через режим загрузки данных. Код выглядит следующим образом:


ДокументОбъект = СсылкаНаДокумент.ПолучитьОбъект();
ДокументОбъект.ОбменДанными.Загрузка = Истина;
ДокументОбъект.УстановитьПометкуУдаления(Истина);

При выполнении этого кода для проведенного документа система выдает ошибку: «Действие не может выполняться в режиме загрузки данных». Выясним причину такого поведения платформы.

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

Анализ «опасного» решения (Антипаттерн)

Некоторые разработчики пытаются обойти это ограничение «хитрым» кодом в самом обработчике ПередЗаписью:


Если ОбменДанными.Загрузка Тогда
    ОбменДанными.Загрузка = Ложь;
    Возврат;
КонецЕсли;

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


Правильные способы решения задачи

Рассмотрим безопасные и архитектурно верные варианты обхода проверок.

Способ 1. Разделение операции на два этапа (Рекомендуемый платформенный подход)

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


// Шаг 1. Отменяем проведение в обычном режиме
Если ДокументОбъект.Проведен Тогда
    ДокументОбъект.Записать(РежимЗаписиДокумента.ОтменаПроведения);
КонецЕсли;

// Шаг 2. Устанавливаем пометку удаления в режиме загрузки
ДокументОбъект.ОбменДанными.Загрузка = Истина;
ДокументОбъект.ПометкаУдаления = Истина;
ДокументОбъект.Записать(РежимЗаписиДокумента.Запись);

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

Способ 2. Прямая запись и ручное удаление движений

Если бизнес-логика в модуле объекта настолько жесткая, что блокирует даже стандартную отмену проведения (например, запрещает любые действия с документами закрытого периода), мы можем применить ручной обход:

  1. Сразу переводим документ в режим загрузки данных.
  2. Вручную снимаем флаг проведения и устанавливаем пометку удаления.
  3. Записываем объект в режиме простой записи (без проведения).
  4. Вручную очищаем все движения документа по регистрам, так как платформа в режиме загрузки не делает этого автоматически.

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


ДокументОбъект = СсылкаНаДокумент.ПолучитьОбъект();

// Включаем режим загрузки для обхода ПередЗаписью
ДокументОбъект.ОбменДанными.Загрузка = Истина;
ДокументОбъект.Проведен = Ложь;
ДокументОбъект.ПометкаУдаления = Истина;
ДокументОбъект.Записать(РежимЗаписиДокумента.Запись);

// Очищаем движения по всем регистрам, где документ является регистратором
Для Каждого НаборЗаписей Из ДокументОбъект.Движения Цикл
    Если НаборЗаписей.Количество() > 0 Тогда
        НаборЗаписей.Очистить();
        НаборЗаписей.Записать();
    КонецЕсли;
КонецЦикла;

Способ 3. Использование коллекции «ДополнительныеСвойства» (Best Practice)

Использование глобального флага ОбменДанными.Загрузка — это тяжелая артиллерия, которая отключает вообще все контроли в системе. Более профессиональным и точечным решением является передача параметров через коллекцию ДополнительныеСвойства объекта.

Разберем этот метод по шагам.

Шаг 1. В месте программного удаления документа (например, во внешней обработке) мы получаем объект и записываем в его дополнительные свойства специальный маркер-флаг:


ДокументОбъект = СсылкаНаДокумент.ПолучитьОбъект();
// Передаем персональный флаг обхода проверок
ДокументОбъект.ДополнительныеСвойства.Вставить("ОбойтиПроверкиПриУдалении", Истина);
// Вызываем штатный метод (он автоматически и распроведет, и пометит на удаление)
ДокументОбъект.УстановитьПометкуУдаления(Истина);

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


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

Использование коллекции ДополнительныеСвойства позволяет сохранить целостность базы данных, избежать платформенных ошибок блокировки транзакций и гибко управлять логикой проведения документов на уровне кода.

← На главную