Как при конвертации данных установить основной договор контрагента в приемнике и избежать создания дублей?

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

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

Проблема стандартного механизма поиска

Если мы просто настроим поиск договора по наименованию и владельцу, велика вероятность создания дублей. Ситуация осложняется тем, что в источнике и приемнике идентификаторы (УИД) договоров могут не совпадать. Если Контрагент нашелся по коду, а Договор по заданным полям поиска — нет, система по умолчанию создаст новый объект. Наша цель — перехватить этот процесс и заставить систему взять ОсновнойДоговор у найденного контрагента.

Решение 1: Использование параметров и обработчика ПослеЗагрузки

Этот метод считается наиболее гибким. Мы откажемся от прямой передачи ссылки на договор в соответствующий реквизит документа и передадим его как вспомогательную информацию. Проанализируем шаги реализации:

  1. В правилах конвертации свойств (ПКС) для документа найдем реквизит Договор.
  2. Установим флаг Передавать в параметр. Это предотвратит попытку стандартного создания объекта при загрузке реквизита.
  3. В обработчике ПослеЗагрузки ПКО документа напишем код, который проверит, заполнен ли договор, и при необходимости подставит основной договор владельца.

Пример кода в обработчике ПослеЗагрузки:


Если НЕ ЗначениеЗаполнено(Объект.ДоговорКонтрагента) Тогда
    // Если контрагент найден (не новый), подставляем его основной договор
    Если ЗначениеЗаполнено(Объект.Контрагент) И ЗначениеЗаполнено(Объект.Контрагент.ОсновнойДоговорКонтрагента) Тогда
        Объект.ДоговорКонтрагента = Объект.Контрагент.ОсновнойДоговорКонтрагента;
    Иначе
        // Логика создания нового договора, если контрагент новый или договора нет
        // Здесь можно использовать данные из ПараметрыОбъекта["ДоговорКонтрагента"]
    КонецЕсли;
КонецЕсли;

Решение 2: Определение статуса «Новый объект» через ДополнительныеСвойства

Чтобы точно понимать, был ли контрагент создан в текущем сеансе загрузки или он уже существовал, воспользуемся обработчиками ПКО контрагента. Разберем этот алгоритм по шагам:

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


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

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

Решение 3: Управление поиском через ПКО договора

Для предотвращения создания лишних сущностей в ПКО договора (например, ДоговорыКонтрагентов) следует активировать опцию Не создавать новый объект в приемнике, если он не найден. В этом случае, если стандартный поиск не дал результатов, реквизит в документе останется пустым, и мы сможем заполнить его программно.

Проанализируем работу обработчика ПередОбработкой в ПКС Договор у документа:


// Проверяем, существует ли уже контрагент в базе-приемнике
// Если поиск контрагента по коду дает результат, принудительно берем его договор
КонтрагентСсылка = Справочники.Контрагенты.НайтиПоКоду(Источник.Контрагент.Код);

Если НЕ КонтрагентСсылка.Пустая() Тогда
    Значение = КонтрагентСсылка.ОсновнойДоговорКонтрагента;
    // Отключаем стандартную обработку, так как значение уже установлено
    Отказ = Истина; 
КонецЕсли;

Важно: Данный подход (поиск через НайтиПоКоду) может замедлить выгрузку, если документов очень много. В таких случаях лучше использовать кэширование или передачу данных через параметры, как описано в первом решении.

Рекомендации по оптимизации

Рассмотрим несколько важных моментов, которые помогут избежать ошибок при реализации:

Выясним причину, почему договор может не подставляться: часто это происходит из-за того, что в базе-приемнике реквизит ОсновнойДоговор у контрагента просто не заполнен. Перед запуском обмена рекомендуется убедиться, что в приемнике справочник Контрагенты корректно настроен, либо добавить в код проверку: если основной договор не найден даже у существующего контрагента, создавать его принудительно.

← На главную