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