Как убрать пометку (проведен) в сообщениях об ошибке при отмене проведения документа?

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

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

В чем заключается проблема с ОбработкойПроведения?

Разберем ситуацию, описанную автором: в коде процедуры ОбработкаПроведения устанавливается Отказ = Истина, если реквизит СтатьяСписанияТМЦ не заполнен. Технически это работает — движения не формируются, транзакция проведения откатывается. Однако платформа выдает сообщение: "Не удалось провести Списание товаров №... (проведен)!".

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

  1. Вызывается ПередЗаписью.
  2. Вызывается ПриЗаписи.
  3. Важный момент: Платформа устанавливает свойству документа Проведен значение Истина в оперативной памяти объекта.
  4. Вызывается ОбработкаПроведения.

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

Решение №1: Использование обработчика ПередЗаписью

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

Посмотрим на пример кода, который позволяет записать документ, но "понижает" статус операции с проведения до обычной записи:


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

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

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

Разберем по шагам, что происходит в этом случае:

  1. Пользователь нажимает "Провести и закрыть".
  2. В ПередЗаписью мы видим, что РежимЗаписи равен Проведение.
  3. Обнаружив пустое поле, мы принудительно меняем РежимЗаписи на Запись.
  4. Платформа продолжает выполнение, но процедура ОбработкаПроведения даже не будет вызвана.
  5. Документ сохраняется в базе, флаг Проведен остается Ложь, и никакого сообщения с текстом "(проведен)" не возникает.

Решение №2: Использование ОбработкиПроверкиЗаполнения

Рассмотрим более "штатный" механизм платформы — использование встроенной проверки заполнения. Этот обработчик вызывается до начала записи и проведения. Мы можем динамически управлять списком проверяемых реквизитов в зависимости от того, проводится документ или просто записывается.

В модуле объекта используем следующий код:


Процедура ОбработкаПроверкиЗаполнения(Отказ, ПроверяемыеРеквизиты)

    // Если выполняется проведение, реквизит должен быть обязательным
    Если РежимЗаписи = РежимЗаписиДокумента.Проведение Тогда
        Если Не ЗначениеЗаполнено(СтатьяСписанияТМЦ) Тогда
            // Стандартный механизм выдаст ошибку и прервет операцию
            // Но в этом случае документ НЕ ЗАПИШЕТСЯ совсем.
        КонецЕсли;
    Иначе
        // Если это просто запись, исключаем реквизит из обязательных
        Позиция = ПроверяемыеРеквизиты.Найти("СтатьяСписанияТМЦ");
        Если Позиция <> Неопределено Тогда
            ПроверяемыеРеквизиты.Удалить(Позиция);
        КонецЕсли;
    КонецЕсли;

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

Важное примечание: Метод с ОбработкаПроверкиЗаполнения хорош тем, что он является стандартным для платформы 1С. Однако у него есть особенность: если проверка не пройдена (Отказ = Истина), документ не будет ни проведен, ни записан. Если же ваша цель — обязательно сохранить введенные данные в любом случае (даже без проведения), то Решение №1 (подмена режима записи в ПередЗаписью) является единственно верным.

Нюансы перепроведения уже проведенных документов

Проанализируем ситуацию, вызвавшую спор в обсуждении: что произойдет, если пользователь открывает уже проведенный документ, очищает реквизит и нажимает "Провести"?

Если мы используем подмену РежимЗаписи = РежимЗаписиДокумента.Запись, то документ останется проведенным (статус в БД не изменится), но данные внутри него обновятся. Это может привести к рассинхронизации данных в документе и его движений по регистрам.

Чтобы избежать такой "дичи" (как выразились участники форума), в ПередЗаписью следует добавить дополнительную проверку:


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

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

← На главную