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