При разработке сложных систем на платформе 1С:Предприятие 8.3 часто возникает ситуация, когда функционал разнесен по разным расширениям. Например, в расширении "МодульЛогистики" создан справочник ТранспортныеСредства, а в расширении "МодульПродаж" нам необходимо добавить реквизит в документ, который бы ссылался на этот справочник. Однако разработчики часто сталкиваются с тем, что в конфигураторе при выборе типа реквизита объекты из других расширений просто не отображаются. Проанализируем, почему так происходит, и разберем все доступные способы решения этой задачи.
Важно понимать архитектурную особенность: каждое расширение в 1С проектируется как автономный модуль, который «знает» только о составе основной конфигурации. Механизм расширений изначально задумывался для дополнения основной конфигурации, а не для создания сложной иерархии зависимостей между самими расширениями. Рассмотрим основные пути решения этой проблемы, начиная от самых надежных и заканчивая обходными программными маневрами.
Самый простой и логичный способ, который рекомендует большинство опытных разработчиков — это объединение связанных объектов в рамках одного расширения. Если расширение «А» не может существовать без объектов расширения «Б», то их разделение зачастую избыточно.
Преимущества этого подхода:
В современных версиях платформы (начиная с 8.3.24) разработчики 1С добавили штатный механизм управления зависимостями. Теперь в свойствах расширения можно явно указать, от каких других расширений оно зависит.
Проанализируем алгоритм действий:
Важное уточнение: хотя этот механизм гарантирует, что расширение "YYY" будет загружено раньше вашего, он не всегда решает проблему «невидимости» типов в графическом интерфейсе конфигуратора. Часто это служит лишь сигналом для платформы правильно выстроить порядок применения метаданных в режиме предприятия.
Если нам нужно отобразить справочник из другого расширения на форме документа или справочника, мы можем обойти ограничения конфигуратора с помощью встроенного языка. В рантайме (в режиме «1С:Предприятие») программный контекст видит все типы всех подключенных расширений.
Рассмотрим, как это реализовать через метод ИзменитьРеквизиты. Выясним последовательность действий в модуле формы:
&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
// Описываем новый реквизит. Имя типа должно включать префикс, если он есть.
ДобавляемыеРеквизиты = Новый Массив;
ТипСправочника = "СправочникСсылка.ХХХ"; // ХХХ - имя справочника из расширения YYY
НовыйРеквизит = Новый РеквизитФормы("ДополнительныйОбъект", Новый ОписаниеТипов(ТипСправочника), , "Выбранный объект", Истина);
ДобавляемыеРеквизиты.Добавить(НовыйРеквизит);
// Добавляем реквизит на форму
ЭтаФорма.ИзменитьРеквизиты(ДобавляемыеРеквизиты);
// Теперь добавим поле ввода для этого реквизита
Элемент = ЭтаФорма.Элементы.Добавить("ДекоративноеПолеОбъекта", Тип("ПолеФормы"), ЭтаФорма.Элементы.ГруппаШапка);
Элемент.Вид = ВидПоляФормы.ПолеВвода;
Элемент.ПутьКДанным = "ДополнительныйОбъект";
КонецПроцедуры
При таком подходе пользователь увидит полноценное поле выбора, сможет открывать форму выбора справочника из другого расширения и выбирать значения. Единственный минус — данные этого реквизита не будут сохраняться автоматически в объекте базы данных, так как реквизит существует только на форме.
Чтобы данные сохранялись в базе, мы можем создать в своем расширении реквизит с типом Строка (длиной 36 символов) или УникальныйИдентификатор. Мы будем записывать туда GUID ссылки из чужого расширения.
Разберем пример получения ссылки по сохраненному идентификатору:
// Получение ссылки из GUID для работы в коде
ИмяСправочника = "XXX";
ТекGUID = Новый УникальныйИдентификатор(СтрокаСИдентификатором);
СсылкаНаОбъект = Справочники[ИмяСправочника].ПолучитьСсылку(ТекGUID);
Если Не СсылкаНаОбъект.Пустая() Тогда
// Работаем с объектом как обычно
КонецЕсли;
Этот метод позволяет обойти жесткую типизацию конфигуратора. Однако при работе с запросами возникнут сложности: вы не сможете напрямую обращаться к полям этого справочника через точку (например, Документ.МойРеквизитGUID.Наименование).
Если вы используете метод с хранением идентификаторов или программным формированием данных, работа с запросами потребует особого подхода. Рассмотрим, как эффективно работать с данными из «чужого» расширения в отчетах и обработках:
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| ТЗ.СсылкаОбъекта КАК Ссылка
|ПОМЕСТИТЬ ВТ_Объекты
|ИЗ
| &ВнешняяТЗ КАК ТЗ;
|
|ВЫБРАТЬ
| ВТ.Ссылка.Наименование КАК Наименование,
| ВТ.Ссылка.Код КАК Код
|ИЗ
| ВТ_Объекты КАК ВТ";
// Предварительно получаем массив ссылок через Справочники[...].ПолучитьСсылку()
Запрос.УстановитьПараметр("ВнешняяТЗ", ТаблицаСОбъектами);
Результат = Запрос.Выполнить();
Иногда даже внутри одного расширения возникают проблемы с отображением типов (как в 15-м сообщении обсуждения). Проанализируем ситуацию: вы добавили справочник, применили изменения, но не видите его в списке доступных типов для другого реквизита.
Как это лечится:
Подводя итог, можно сказать: если у вас есть возможность объединить расширения — сделайте это. Это избавит вас от 90% проблем с типами и запросами.
Если же архитектура требует строгого разделения, используйте механизм зависимостей (на новых платформах) в сочетании с программным созданием реквизитов на форме. Хранение через GUID оправдано только в исключительных случаях, когда ссылки могут динамически указывать на объекты разных, заранее неизвестных расширений.