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