Как связать контактное лицо с контрагентом и в чем разница между родителем и владельцем в 1С?

Программист 1С v8.3 (Обычные формы) IT и автоматизация бизнеса
← На главную

При проектировании структуры справочников в 1С разработчики часто сталкиваются с задачей сопоставления нескольких объектов, например, контрагентов и контактных лиц. На начальном этапе нередко возникает путаница в терминологии платформы 1С:Предприятие относительно понятий Родитель, Владелец и ссылочных реквизитов. Разберем по шагам, как устроены эти механизмы платформы, в каких случаях они применяются и как правильно организовать связь между объектами.

Проанализируем базовые механизмы и ограничения платформы, а затем рассмотрим типовые архитектурные и программные решения.

Разница между родителем, владельцем и ссылочным реквизитом

Выясним причину частых ошибок проектирования. В платформе 1С:Предприятие каждый из этих терминов имеет строго определенное техническое назначение:

  1. Иерархия (реквизит Родитель): механизм предназначен исключительно для выстраивания иерархических связей (групп и элементов или элементов и элементов) внутри одного и того же справочника. Реквизит Родитель не может ссылаться на элемент другого справочника. Например, папкой для элемента справочника КонтактныеЛица может быть только другой элемент или группа справочника КонтактныеЛица.
  2. Подчинение (реквизит Владелец): настраивается на уровне метаданных через свойство «Владельцы». Подчиненный справочник (например, КонтактныеЛица) ссылается на справочник-владелец (например, Контрагенты). Однако стандартный механизм подчинения платформы поддерживает отношение «один-ко-многим»: у одного контрагента может быть несколько контактных лиц, но у конкретного контактного лица владельцем может быть строго один контрагент.
  3. Связь через реквизит: если в справочнике Контрагенты создан реквизит КонтактноеЛицо с типом СправочникСсылка.КонтактныеЛица, то контрагент хранит ссылку на конкретного человека (например, основного представителя). При этом сам человек не подчинен контрагенту жестко через метаданные.

Способ 1. Программное назначение контактного лица контрагенту (Обычные формы)

Рассмотрим ситуацию, когда в карточке контактного лица необходимо предоставить пользователю возможность выбрать контрагента из справочника и сразу записать текущее контактное лицо в соответствующий реквизит выбранного контрагента.

Разберем пример обработчика нажатия кнопки на обычной форме:


Процедура ОсновныеДействияФормыНазначитьКонтрагента(Кнопка)
    // Проверяем, записан ли текущий объект
    Если Модифицированность = Истина Тогда
        Сообщить("Необходимо записать контактное лицо перед его назначением контрагенту");
        Возврат;
    КонецЕсли;

    // Получаем форму выбора справочника Контрагенты
    ФормаВыбора = Справочники.Контрагенты.ПолучитьФормуВыбора(, ЭтаФорма);
    ФормаВыбора.Заголовок = "Выберите контрагента!";
    
    // Открываем форму для интерактивного выбора
    ВыбранныйКонтрагент = ФормаВыбора.ОткрытьМодально();
    
    // Если контрагент выбран, обновляем его реквизит
    Если ЗначениеЗаполнено(ВыбранныйКонтрагент) Тогда
        ОбъектКонтрагент = ВыбранныйКонтрагент.ПолучитьОбъект();
        ОбъектКонтрагент.КонтактноеЛицо = Ссылка;
        ОбъектКонтрагент.Записать();
    КонецЕсли;
КонецПроцедуры

Обратите внимание на важные детали реализации:

  1. Перед передачей ссылки через свойство Ссылка текущий элемент обязательно должен быть записан в базу данных, иначе ссылка будет пустой (Ссылка.Пустая()).
  2. Метод ОткрытьМодально() используется в обычных формах и при отключенном режиме запрета модальности. В управляемом интерфейсе следует использовать асинхронные методы открытия форм и обработку оповещения.

Способ 2. Архитектура отношения «многие-ко-многим» через Регистр сведений

Если требуется, чтобы одно и то же контактное лицо могло представлять интересы сразу нескольких различных контрагентов (например, один представитель работает с группой компаний), использование стандартного подчинения через свойство Владелец не подойдет. В этом случае наиболее надежным и расширяемым решением является использование независимого регистра сведений.

Разберем по шагам построение такой структуры:

  1. Создаем непериодический независимый регистр сведений (например, СвязиКонтрагентовИКонтактныхЛиц).
  2. Добавляем измерения:
    1. Контрагент с типом СправочникСсылка.Контрагенты.
    2. КонтактноеЛицо с типом СправочникСсылка.КонтактныеЛица (или СправочникСсылка.ФизическиеЛица).
  3. Добавляем необходимые ресурсы или реквизиты: Должность, ДействуетНаОсновании, ОсновнойКонтакт (тип Булево).

Преимущество использования регистра сведений заключается в том, что оно устраняет взаимные блокировки при одновременной работе пользователей и позволяет хранить дополнительные свойства связи (роль, полномочия, контактные телефоны в рамках конкретной организации) без дублирования личных данных человека.

Способ 3. Использование табличной части

Если создание отдельного регистра сведений избыточно, связь «многие-ко-многим» можно реализовать через табличную часть:

  1. В справочнике КонтактныеЛица создаем табличную часть Контрагенты с реквизитом Контрагент (тип СправочникСсылка.Контрагенты).
  2. В карточке контактного лица размещаем эту табличную часть, куда пользователь сможет добавлять неограниченное количество организаций, к которым привязано данное лицо.

Организация динамического отбора на управляемых формах

Если справочники уже связаны через подчинение или реквизиты, при открытии формы выбора контактного лица для конкретного контрагента полезно сразу наложить фильтр. Посмотрим, как передать структуру отбора на управляемых формах:


&НаКлиенте
Процедура ВыбратьКонтактноеЛицо(Команда)
    ПараметрыФормы = Новый Структура;
    ПараметрыФормы.Вставить("Отбор", Новый Структура("Владелец", Объект.Контрагент));
    
    ОткрытьФорму("Справочник.КонтактныеЛица.ФормаВыбора", ПараметрыФормы, Элементы.КонтактноеЛицо);
КонецПроцедуры

Также для полей ввода в управляемом интерфейсе можно настроить свойство метаданных СвязиПараметровВыбора, указав отбор по реквизиту Отбор.Владелец(Объект.Контрагент), что позволит фильтровать список без написания программного кода.

← На главную