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