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

Программист IT и автоматизация бизнеса
← На главную

При настройке обмена данными часто возникает задача, когда связанные объекты должны создаваться с учетом контекста основного объекта. Классический пример: при выгрузке документа "Реализация товаров и услуг" нужно, чтобы у связанного с ним договора в базе-приемнике владельцем стал контрагент из самого документа, а не тот, который был указан в договоре в базе-источнике.

Проанализируем ситуацию: у нас есть Правило Конвертации Объекта (ПКО) для документа и отдельное ПКО для справочника "Договоры". Задача — передать информацию о контрагенте из ПКО документа в ПКО договора. Разберем, как это сделать правильно с помощью штатных механизмов "Конвертации данных 2.0".

Решение через "ИсходящиеДанные" и "ВходящиеДанные" — основной способ

Самый правильный и управляемый способ для передачи контекста между связанными правилами — это использование специальных переменных ИсходящиеДанные и ВходящиеДанные. Этот механизм позволяет "пробросить" любую структуру с нужной информацией из вызывающего правила в вызываемое.

Разберем реализацию по шагам.

  1. Шаг 1. Передача данных из ПКО Документа

    Нам нужно передать контрагента из документа в тот момент, когда система начнет конвертировать связанный с ним договор. Этот момент наступает при обработке правила конвертации свойства (ПКС) для реквизита "Договор" внутри ПКО нашего документа.

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

    Посмотрим на пример кода:

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

    Теперь, когда КД будет вызывать ПКО для договора, в нем будет доступна переменная ВходящиеДанные с нашей информацией.

  2. Шаг 2. Получение данных в ПКО Договора и подмена владельца

    Теперь откроем ПКО для справочника "Договоры". У нас есть два хороших варианта, где использовать полученные данные для подмены владельца. Рассмотрим оба.

Вариант А: Подмена владельца в ПКС "Владелец" (рекомендуемый)

Это наиболее элегантный и правильный подход. Мы определяем нужного владельца еще на этапе выгрузки данных, и объект в базе-приемнике создается сразу с верными реквизитами. Это избавляет от необходимости дополнительно записывать объект после загрузки.

В ПКО "Договоры" найдем ПКС для реквизита "Владелец". В обработчике события "Перед выгрузкой" напишем следующий код:


// Событие "Перед выгрузкой" в ПКС "Владелец" (внутри ПКО "Договоры")

// Сначала проверяем, были ли вообще переданы данные из ПКО документа.
// Это нужно, чтобы правило корректно работало и при переносе договоров не из документа.
Если ВходящиеДанные <> Неопределено И ВходящиеДанные.Свойство("КонтрагентИзДокумента") Тогда
    
    // Здесь ваша логика, по которой нужно решать, делать подмену или нет.
    // Например, подменять всегда, когда договор переносится в контексте документа.
    Если <УсловиеПодменыВыполняется> Тогда
        
        // Присваиваем переменной "Значение" нашего контрагента из документа.
        // КД сама сконвертирует эту ссылку из источника в ссылку приемника.
        Значение = ВходящиеДанные.КонтрагентИзДокумента;
        
    Иначе
        
        // Если условие не выполнено, оставляем стандартного владельца из договора-источника.
        Значение = Источник.Владелец;
        
    КонецЕсли;

Иначе
    // Если ВходящиеДанные не переданы, значит, договор конвертируется сам по себе.
    // Оставляем стандартное поведение.
    Значение = Источник.Владелец;
КонецЕсли;

Преимущества этого способа: логика находится в правильном месте (в правиле для свойства "Владелец"), и не требуется лишних действий после загрузки объекта.

Вариант Б: Подмена владельца в ПКО "После загрузки"

Этот способ тоже рабочий и часто используется. Его суть в том, чтобы сначала дать КД создать объект со стандартными значениями, а потом, в событии "После загрузки", изменить нужные реквизиты и принудительно записать объект.

В ПКО "Договоры" перейдем в обработчик события "После загрузки".


// Событие "После загрузки" в ПКО "Договоры"

// Проверяем, что данные были переданы.
Если ВходящиеДанные <> Неопределено И ВходящиеДанные.Свойство("КонтрагентИзДокумента") Тогда

    // Получаем ссылку на нового владельца.
    // На этапе "После загрузки" ВходящиеДанные.КонтрагентИзДокумента уже будет 
    // ссылкой на объект в базе-приемнике (если он был найден или создан).
    НовыйВладелец = ВходящиеДанные.КонтрагентИзДокумента;

    // Сравниваем текущего владельца с тем, который должен быть.
    Если Объект.Владелец <> НовыйВладелец Тогда
        
        // Производим подмену.
        Объект.Владелец = НовыйВладелец;
        
        // Важно! Так как мы меняем уже созданный объект, его нужно явно записать.
        Объект.Записать();
        
    КонецЕсли;
    
КонецЕсли;

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

Альтернативный способ: использование "Параметров"

В КД 2.0 есть механизм глобальных переменных — коллекция Параметры. Значения, помещенные в нее, доступны во всех обработчиках на протяжении всего сеанса обмена. Его тоже можно использовать, но для локальных задач, как наша, он избыточен.

Когда стоит использовать Параметры? Когда одни и те же данные нужны во многих, не связанных напрямую, правилах. В нашем случае, когда связь "документ -> договор" прямая, использование ИсходящиеДанные является более чистым и предсказуемым решением, так как оно не "загрязняет" глобальную область видимости и упрощает отладку.

← На главную