Как отменить создание документа в 1С при вводе на основании, если он уже был создан?

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

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

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

Причина поведения платформы при использовании оператора Возврат

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

Когда в коде срабатывает конструкция:


Сообщить("На основании этой заявки уже создана реализация!");    
Возврат;

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

Способ 1. Использование генерации исключения в ОбработкаЗаполнения

Для гарантированного предотвращения создания нового документа и отмены открытия его формы непосредственно из модуля объекта применяется оператор ВызватьИсключение. Этот подход прерывает транзакцию создания объекта на сервере, и форма документа не открывается.

Проанализируем пример кода в процедуре ОбработкаЗаполнения модуля объекта документа:


Процедура ОбработкаЗаполнения(ДанныеЗаполнения, СтандартнаяОбработка)
    
    ТипДанныхЗаполнения = ТипЗнч(ДанныеЗаполнения);
    
    Если ТипДанныхЗаполнения = Тип("ДокументСсылка.ЗаявкаНаПеревозку") Тогда
        
        Запрос = Новый Запрос;
        Запрос.Текст = 
            "ВЫБРАТЬ Первые 1
            |   РеализацияТоваровУслуг.Ссылка КАК Ссылка
            |ИЗ
            |   Документ.РеализацияТоваровУслуг КАК РеализацияТоваровУслуг
            |ГДЕ
            |   РеализацияТоваровУслуг.ЗаказКлиента = &ЗаявкаНаПеревозку
            |   И НЕ РеализацияТоваровУслуг.ПометкаУдаления";
            
        Запрос.УстановитьПараметр("ЗаявкаНаПеревозку", ДанныеЗаполнения);
        
        РезультатЗапроса = Запрос.Выполнить();
        
        Если Не РезультатЗапроса.Пустой() Тогда
            ВызватьИсключение "На основании этой заявки уже создана реализация!";
        Иначе
            ЗаполнитьДокументНаОснованииЗаявкиНаПеревозку(ДанныеЗаполнения);
            ЗаполненНаОснованииДокумента = Истина;
        КонецЕсли;
        
    КонецЕсли;
    
КонецПроцедуры

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

Способ 2. Проверка в форме документа при создании на сервере

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

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

Разберем реализацию проверки в форме документа:


&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
    
    // Проверяем, что документ новый и передан параметр основания
    Если Параметры.Ключ.Пустая() И Параметры.Свойство("ЗначениеЗаполнения") Тогда
        
        ДанныеЗаполнения = Параметры.ЗначениеЗаполнения;
        
        Если ТипЗнч(ДанныеЗаполнения) = Тип("ДокументСсылка.ЗаявкаНаПеревозку") Тогда
            
            Запрос = Новый Запрос;
            Запрос.Текст = 
                "ВЫБРАТЬ Первые 1
                |   РеализацияТоваровУслуг.Ссылка КАК Ссылка
                |ИЗ
                |   Документ.РеализацияТоваровУслуг КАК РеализацияТоваровУслуг
                |ГДЕ
                |   РеализацияТоваровУслуг.ЗаказКлиента = &ЗаявкаНаПеревозку
                |   И НЕ РеализацияТоваровУслуг.ПометкаУдаления";
                
            Запрос.УстановитьПараметр("ЗаявкаНаПеревозку", ДанныеЗаполнения);
            
            Если Не Запрос.Выполнить().Пустой() Тогда
                ОбщегоНазначенияКлиентСервер.СообщитьПользователю("На основании этой заявки уже создана реализация!");
                Отказ = Истина;
            КонецЕсли;
            
        КонецЕсли;
        
    КонецЕсли;
    
КонецПроцедуры

Установка параметра Отказ = Истина в событии ПриСозданииНаСервере предотвращает открытие формы документа без вызова критических исключений системы.

Способ 3. Связка ДополнительныеСвойства и формы документа

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

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

Сравним предложенные решения:

← На главную