Как в Конвертации данных 2.1 выгрузить строки табличной части в отдельные документы?

Программист 1С v8.3 (Обычные формы) Управленческий учет IT и автоматизация бизнеса
← На главную

В процессе разработки обменов данными между конфигурациями 1С часто возникает задача трансформации структуры данных. Типичный пример: в исходной базе (например, «Альфа-Авто») банковская выписка содержит строки по эквайрингу в общей табличной части, а в целевой базе (УПП или КА 1.1) эти строки должны превратиться в отдельные документы ОплатаОтПокупателяПлатежнойКартой. Рассмотрим подробнее, как реализовать такой механизм с помощью конфигурации «Конвертация данных 2.1».

Архитектура решения: ПВД и ПКО

Для решения задачи нам не подойдет стандартная выгрузка «объект в объект», так как одному объекту источника соответствует множество объектов приемника. Проанализируем правильный алгоритм настройки:

  1. Создание ПКО (Правила конвертации объекта): Создадим правило, где Источник будет пустым, а Приемник — документом ОплатаОтПокупателяПлатежнойКартой. Это позволит нам генерировать документы «из воздуха», наполняя их данными программно.
  2. Настройка ПКС (Правил конвертации свойств): Внутри ПКО создадим правила для всех необходимых реквизитов (Контрагент, Сумма, Договор и т.д.). Поскольку источник пуст, в каждом ПКС в качестве источника ничего не указываем. Данные мы будем передавать через структуру ВходящиеДанные или напрямую в Источник (в зависимости от способа вызова).
  3. Создание ПВД (Правила выгрузки данных): Здесь и будет сосредоточена основная логика. Выберем тип выгрузки «Произвольный алгоритм».

Реализация логики в ПВД

Разберем, как написать обработчик ПередВыгрузкой в ПВД. Нам необходимо выбрать данные из табличной части исходного документа с помощью запроса, а затем в цикле инициировать выгрузку для каждой строки. Посмотрим на пример кода:


Запрос = Новый Запрос;
Запрос.Текст = "
|ВЫБРАТЬ
|    ВыпискаСостав.Ссылка,
|    ВыпискаСостав.СтатьяДДС,
|    ВыпискаСостав.Контрагент,
|    ВыпискаСостав.СуммаПриход КАК Сумма,
|    ВыпискаСостав.НазначениеПлатежа,
|    ВыпискаСостав.Ссылка.Дата КАК Дата,
|    ВыпискаСостав.Ссылка.Организация КАК Организация
|ИЗ
|    Документ.Выписка.Состав КАК ВыпискаСостав
|ГДЕ
|    ВыпискаСостав.Ссылка.Дата МЕЖДУ &НачДата И &КонДата
|    И ВыпискаСостав.Ссылка.Проведен";

Запрос.УстановитьПараметр("НачДата", ДатаНачала);
Запрос.УстановитьПараметр("КонДата", ДатаОкончания);

Выборка = Запрос.Выполнить().Выбрать();

Пока Выборка.Следующий() Цикл
    // Фильтруем только нужные строки (например, по эквайрингу)
    Если Найти(Выборка.НазначениеПлатежа, "Эквайринг") = 0 Тогда
        Продолжить;
    КонецЕсли;

    // Формируем структуру данных для выгрузки
    ДанныеДляПКО = Новый Структура;
    ДанныеДляПКО.Вставить("СтатьяДДС", Выборка.СтатьяДДС);
    ДанныеДляПКО.Вставить("Контрагент", Выборка.Контрагент);
    ДанныеДляПКО.Вставить("Сумма", Выборка.Сумма);
    ДанныеДляПКО.Вставить("Дата", Выборка.Дата);
    ДанныеДляПКО.Вставить("Организация", Выборка.Организация);
    
    // Вызываем выгрузку по правилу
    // Передаем структуру в качестве Источника (первый параметр)
    ВыгрузитьПоПравилу(ДанныеДляПКО, , , , "СтрокаВыписки_ОплатаКартой");
КонецЦикла;

Важный нюанс: Если вы передаете структуру первым параметром в ВыгрузитьПоПравилу, то в ПКО в обработчиках ПКС эти данные будут доступны через переменную Источник. Например, в ПКС для суммы можно написать: Значение = Источник.Сумма;.

Критическая настройка ПКО: Кэширование объектов

Выясним одну из самых частых причин ошибок при такой выгрузке. Если в ПКО для создаваемого документа не установлена галочка «Не запоминать выгруженные объекты», система обмена при выгрузке второй и последующих строк одной и той же выписки может решить, что объект уже был выгружен (так как формально «источник» один и тот же — пустой или сама ссылка на выписку). В результате вместо создания разных документов в файл будут записываться ссылки на самый первый созданный документ. Обязательно устанавливайте этот флаг в настройках ПКО на вкладке «Настройки выгрузки».

Настройка поиска и обновление существующих документов

Рассмотрим ситуацию, когда документы в базе-приемнике уже созданы (например, вручную) и нам нужно их обновить, а не плодить дубли. Стандартный поиск по уникальному идентификатору (GUID) здесь не сработает, так как в источнике нет реального объекта-документа. Нам нужно реализовать поиск по полям (Организация, Контрагент, Сумма, Дата).

Проанализируем алгоритм поиска в обработчике Поля поиска в ПКО. Выясним причину ошибки «Номер не уникален»: она возникает, если система не нашла объект и пытается создать новый с тем же номером, который уже есть в базе. Чтобы этого избежать, напишем гибкий поиск через запрос.

Пример кода в обработчике Поля поиска:


// Если номер передан, ищем по номеру и дате
Если Не ПустаяСтрока(СвойстваПоиска["Номер"]) Тогда
    СтрокаИменСвойствПоиска = "Номер, Дата";
Иначе
    // Если номера нет, ищем по совокупности признаков в пределах дня
    Запрос = Новый Запрос;
    Запрос.Текст = "
    |ВЫБРАТЬ
    |    Док.Ссылка
    |ИЗ
    |    Документ.ОплатаОтПокупателяПлатежнойКартой КАК Док
    |ГДЕ
    |    Док.Дата МЕЖДУ &НачДата И &КонДата
    |    И Док.Организация = &Организация
    |    И Док.Контрагент = &Контрагент
    |    И Док.СуммаДокумента = &СуммаДокумента";

    Запрос.УстановитьПараметр("НачДата", НачалоДня(СвойстваПоиска.Получить("Дата")));
    Запрос.УстановитьПараметр("КонДата", КонецДня(СвойстваПоиска.Получить("Дата")));
    Запрос.УстановитьПараметр("Организация", СвойстваПоиска.Получить("Организация"));
    Запрос.УстановитьПараметр("Контрагент", СвойстваПоиска.Получить("Контрагент"));
    Запрос.УстановитьПараметр("СуммаДокумента", СвойстваПоиска.Получить("Сумма"));

    Выборка = Запрос.Выполнить().Выбрать();
    Если Выборка.Следующий() Тогда
        СсылкаНаОбъект = Выборка.Ссылка;
    КонецЕсли;
КонецЕсли;

Обратите внимание на использование СсылкаНаОбъект. Если в этом обработчике мы явно присвоим значение этой переменной, стандартный поиск по полям выполняться не будет — система сразу использует найденную нами ссылку.

Рекомендации по сохранению данных при обновлении

Проанализируем ситуацию: если документ в приемнике найден (ОбъектНайден = Истина), нам может потребоваться сохранить его старую дату или ответственного. Это делается в обработчике ПослеЗагрузки в ПКО:


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

Важный совет: При выгрузке из ТЧ в ПВД рекомендуется добавлять хотя бы одну секунду к времени каждого следующего документа (ДатаВыписки + ИндексСтроки). Это позволит документам корректно выстроиться в журнале и избежать проблем с последовательностью при проведении в один и тот же момент времени.

Подведем итог: использование ВыгрузитьПоПравилу внутри цикла в ПВД в сочетании с ПКО без источника — это мощный инструмент трансформации данных. Главное — не забывать про отключение кэширования объектов и тщательную настройку алгоритмов поиска существующих документов в целевой базе.

← На главную