Как запретить проведение документа, но разрешить его запись в 1С 8.2

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

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

Постановка задачи и анализ механизмов платформы

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

Решение через обработчик ПередЗаписью

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

Рассмотрим по шагам, как это реализовать:

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

Проанализируем пример кода, который решает эту задачу:


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

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

В данном примере, если условие (заполнение кода ТН ВЭД) не выполнено, документ не вызовет процедуру ОбработкаПроведения, а просто сохранится в базе данных как незакрытый черновик.

Важный нюанс: Состояние проведенности документа

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

Сценарий 1: Документ новый или еще не был проведен. В этом случае все работает идеально. Мы меняем режим на Запись, документ сохраняется, флаг Проведен остается в значении Ложь.

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

Чтобы избежать этой проблемы, давайте усовершенствуем наш алгоритм. Если документ уже проведен и данные некорректны, нам следует либо полностью запретить запись, либо принудительно сделать отмену проведения.

Посмотрим на расширенный пример кода:


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

Альтернативный подход: Использование формы документа

Иногда полезно взаимодействовать с пользователем интерактивно. Если мы реализуем логику в модуле объекта, пользователь может не понять, почему он нажал «Провести», а документ просто записался. Рассмотрим, как сделать это в модуле формы.

В обработчике ПередЗаписью на форме мы можем задать вопрос:


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

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

Использование подписок на события

Если вам нужно запретить проведение для целого списка различных документов (например, для всех складских накладных), не обязательно прописывать код в каждом модуле. Проанализируем объект ПодпискаНаСобытие.

  1. Создадим новую подписку в дереве метаданных.
  2. В качестве источника выберем типы документов, которые нас интересуют.
  3. Событие — ПередЗаписью.
  4. В обработчике подписки (в общем модуле) напишем логику, аналогичную той, что мы разбирали выше.

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

Заключение

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

← На главную