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