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