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