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