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