При настройке правил обмена в конфигурации 1С:Конвертация данных 2.x (КД 2) разработчики часто сталкиваются с нетипичными задачами трансформации данных. Одна из самых распространенных — необходимость перенести одиночный реквизит из шапки документа источника (например, общую сумму документа, склад или контрагента) в строки новой или существующей табличной части документа приёмника. Напрямую сопоставить такие реквизиты в интерфейсе правил конвертации свойств (ПКС) нельзя, поскольку структура данных шапки и табличной части принципиально отличается. Для миграции из 1С:Бухгалтерии 3.0 в 1С:Комплексную автоматизацию 2 готовый набор правил предоставляет Перенос данных БП 3.0 — КА 2.
В этой статье мы подробно разберем, как решить эту задачу несколькими способами. Мы проанализируем частые ошибки начинающих разработчиков, подробно рассмотрим рабочий код и разберем альтернативные, более изящные методы архитектурного построения правил обмена. Для регулярного выполнения подготовленных XML-правил по расписанию применяется МС:Автообмен для автоматизации синхронизации.
Рассмотрим практическую задачу: необходимо перенести документ ПоступлениеТоваровУслуг из конфигурации «1С:Бухгалтерия предприятия» в документ ПриобретениеТоваровУслуг в «1С:Комплексная автоматизация». В базе-приёмнике у документа присутствует табличная часть ЭтапыГрафикаОплаты. Нам нужно заполнить эту табличную часть одной строкой, куда запишется общая сумма документа из шапки источника (СуммаДокумента) и некоторые статические параметры (например, вариант оплаты «Предоплата до поступления», дата платежа и процент платежа равный 100%).
---
Этот способ основан на передаче произвольной таблицы значений из обработчика правила конвертации объекта (ПКО) в правило конвертации группы свойств (ПКГС) через специальную служебную структуру ВходящиеДанные.
Давайте разберем по шагам, как настроить этот механизм и избежать критических ошибок при написании кода.
Шаг 1. Инициализация таблицы в обработчике ПКО
Откроем настройки ПКО для нашего документа. В обработчике события «Перед выгрузкой» нам необходимо программно создать и наполнить объект типа ТаблицаЗначений. Колонки этой таблицы должны строго соответствовать именам реквизитов табличной части документа-получателя. При необходимости можно воспользоваться доработанной конфигурацией «Конвертация данных» с подсказками по обработчикам.
Посмотрим на пример правильной инициализации и заполнения таблицы значений:
// Инициализируем новую таблицу значений
ТЗ = Новый ТаблицаЗначений;
// Добавляем колонки, соответствующие реквизитам ТЧ "ЭтапыГрафикаОплаты" в приёмнике
ТЗ.Колонки.Добавить("Заказ");
ТЗ.Колонки.Добавить("СверхЗаказа");
ТЗ.Колонки.Добавить("ВариантОплаты");
ТЗ.Колонки.Добавить("ДатаПлатежа");
ТЗ.Колонки.Добавить("Сдвиг");
ТЗ.Колонки.Добавить("ПроцентПлатежа");
ТЗ.Колонки.Добавить("СуммаПлатежа");
ТЗ.Колонки.Добавить("ПроцентЗалогаЗаТару");
ТЗ.Колонки.Добавить("СуммаЗалогаЗаТару");
ТЗ.Колонки.Добавить("СуммаВзаиморасчетов");
ТЗ.Колонки.Добавить("СуммаВзаиморасчетовПоТаре");
// Добавляем новую строку в таблицу значений и получаем на неё ссылку
НоваяСтрока = ТЗ.Добавить();
// Заполняем реквизиты строки ТЗ данными из шапки источника и статическими значениями
НоваяСтрока.СуммаПлатежа = Источник.СуммаДокумента;
НоваяСтрока.ВариантОплаты = "ПредоплатаДоПоступления";
НоваяСтрока.ДатаПлатежа = '20191010'; // Пример фиксированной даты
НоваяСтрока.ПроцентПлатежа = 100;
// Помещаем таблицу во "ВходящиеДанные" под именем нашей табличной части в приёмнике
ВходящиеДанные = Новый Структура;
ВходящиеДанные.Вставить("ЭтапыГрафикаОплаты", ТЗ);
Шаг 2. Настройка ПКГС (Табличной части) в правилах
Теперь перейдем к настройке структуры свойств внутри этого ПКО:
ЭтапыГрафикаОплаты.СуммаПлатежа, ВариантОплаты и т.д.). У всех дочерних ПКС поле «Источник» также оставляем пустым. Имена свойств должны в точности совпадать с именами колонок созданной нами ранее таблицы значений.Ошибка №1: Переменная не определена (ЭтапыГрафикаОплаты)
Часто в коде пишут: ВходящиеДанные.Вставить(ЭтапыГрафикаОплаты, ТЗ);. Платформа выдает ошибку компиляции. Выясним причину: КД пытается воспринять ЭтапыГрафикаОплаты как переменную, которая нигде ранее не объявлялась. Имя табличной части при вставке в структуру обязательно нужно передавать как строковый литерал в кавычках: ВходящиеДанные.Вставить("ЭтапыГрафикаОплаты", ТЗ);.
Ошибка №2: Поле объекта не обнаружено (СуммаПлатежа)
Вторая частая ошибка возникает при попытке заполнить созданную таблицу: ТЗ.СуммаПлатежа = Источник.СуммаДокумента;. Проанализируем ситуацию: объект ТаблицаЗначений сам по себе не хранит данные в колонках напрямую, он является лишь контейнером для строк. Присваивать значения свойствам нужно у конкретной строки таблицы, которую мы получаем методом Добавить(). Сначала мы пишем Стр = ТЗ.Добавить();, а затем обращаемся к свойствам полученного объекта строки: Стр.СуммаПлатежа = ....
---
Описанный выше классический метод полностью рабочий, однако он имеет один существенный архитектурный недостаток — логика заполнения табличной части выносится на уровень ПКО всего документа. Если у вас сложный документ с десятками реквизитов, код ПКО «Перед выгрузкой» превратится в трудночитаемую "свалку".
Гораздо более чистым и инкапсулированным решением будет перенос логики непосредственно внутрь самого ПКГС.
Выполним следующие настройки:
КоллекцияОбъектов:
// В обработчиках ПКГС переменная КоллекцияОбъектов используется для передачи выгружаемых строк
КоллекцияОбъектов = Новый ТаблицаЗначений;
КоллекцияОбъектов.Колонки.Добавить("Заказ");
КоллекцияОбъектов.Колонки.Добавить("СуммаПлатежа");
КоллекцияОбъектов.Колонки.Добавить("ВариантОплаты");
КоллекцияОбъектов.Колонки.Добавить("ДатаПлатежа");
КоллекцияОбъектов.Колонки.Добавить("ПроцентПлатежа");
НоваяСтрока = КоллекцияОбъектов.Добавить();
// Мы по-прежнему имеем доступ к объекту Источник (это наш документ-отправитель)
НоваяСтрока.СуммаПлатежа = Источник.СуммаДокумента;
НоваяСтрока.ВариантОплаты = "ПредоплатаДоПоступления";
НоваяСтрока.ДатаПлатежа = '20191010';
НоваяСтрока.ПроцентПлатежа = 100;
Преимущества этого подхода:
КоллекцияОбъектов является стандартным механизмом КД 2. Если она заполнена в этом обработчике, КД автоматически обходит её строки и сопоставляет их с ПКС.---
Рассмотрим другую частую ситуацию: табличная часть приёмника заполняется на основании аналогичной табличной части источника, но в каждую строку приёмника нужно дополнительно записать значение из шапки документа-источника (например, проставить общий Склад во все строки спецификации).
Для реализации этого сценария нам вообще не нужно программно создавать таблицы значений. Сделаем следующее:
Товары).Склад) и очистим у него поле «Источник».
// Переменная Источник на уровне ПКС внутри ПКГС по-прежнему ссылается на объект выгружаемого ДОКУМЕНТА
Значение = Источник.Склад;
Таким образом, при обходе стандартных строк ТЧ программа будет на каждой строке обращаться к шапке документа-источника и подставлять нужное значение.
Если же требуется программно доработать выгруженную ТЧ, то в обработчике ПКГС «Перед обработкой» можно использовать такой код:
// Выгружаем стандартную ТЧ источника в Таблицу Значений
КоллекцияОбъектов = Источник.Товары.Выгрузить();
// Добавляем новую колонку для реквизита приёмника, которой не было в источнике
КоллекцияОбъектов.Колонки.Добавить("СкладПриемник");
// Быстро заполняем всю колонку значением склада из шапки источника
КоллекцияОбъектов.ЗаполнитьЗначения(Источник.СкладШапки, "СкладПриемник");
---
В некоторых случаях заполнять табличные части на этапе выгрузки неудобно или невозможно (например, когда логика распределения сумм по этапам платежей зависит от учетной политики или настроек в самой базе-получателе). Тогда наиболее рациональным решением будет передача значения шапки через параметр документа с последующей обработкой при загрузке.
Рассмотрим по шагам реализацию этого механизма:
Шаг 1. Передача параметра при выгрузке
СуммаДокументаДляТЧ).Значение = Источник.СуммаДокумента;
Шаг 2. Заполнение ТЧ в базе-приёмнике
В ПКО документа перейдем в обработчик события «После загрузки». Напишем код, который перехватит переданный параметр и создаст строку в ТЧ уже непосредственно в базе-получателе:
СуммаИзПараметра = Неопределено;
// Проверяем наличие параметра в переданных данных
Если ПараметрыОбъекта <> Неопределено И ПараметрыОбъекта.Свойство("СуммаДокументаДляТЧ", СуммаИзПараметра) Тогда
// Если табличная часть пустая - добавим строку
Если Объект.ЭтапыГрафикаОплаты.Количество() = 0 Тогда
НоваяСтрока = Объект.ЭтапыГрафикаОплаты.Добавить();
НоваяСтрока.СуммаПлатежа = СуммаИзПараметра;
НоваяСтрока.ВариантОплаты = Перечисления.ВариантыОплатыАванса.ПредоплатаДоПоступления;
НоваяСтрока.ДатаПлатежа = ТекущаяДата(); // Или любая другая логика
НоваяСтрока.ПроцентПлатежа = 100;
КонецЕсли;
КонецЕсли;
Главный плюс этого метода: заполнение табличной части происходит внутри базы-приёмника. Это полностью решает проблемы сериализации сложных типов данных (ссылок, перечислений) при обмене, так как мы можем напрямую оперировать метаданными базы-получателя.
---
ВходящиеДанные или КоллекцияОбъектов), у всех дочерних ПКС этой ТЧ поле «Источник» должно оставаться пустым. Если там будет указан реквизит, конвертация попытается прочитать его из несуществующей ТЧ источника, что приведет к ошибкам выгрузки.ТаблицаЗначений (метод Колонки.Добавить()) всегда старайтесь явно указывать их типы, особенно для ссылочных типов (Справочники, Документы):
// Пример явного указания типа для колонки ТЗ
МассивТипов = Новый Массив;
МассивТипов.Добавить(Тип("СправочникСсылка.Контрагенты"));
ОписаниеТиповКонтрагента = Новый ОписаниеТипов(МассивТипов);
ТЗ.Колонки.Добавить("Контрагент", ОписаниеТиповКонтрагента);
Значение = ОбъектКоллекции.ИмяКолонкиИзВашейТЗ;
*(Здесь ОбъектКоллекции — служебная переменная КД, указывающая на текущую строку обрабатываемой коллекции строк).*
Используя предложенные методики, вы сможете гибко управлять переносом любых данных из шапки документов в табличные части, сохраняя при этом чистоту и поддерживаемость ваших правил обмена. Контроль результата миграции и поиск расхождений после переноса обеспечивает МС:Автовыверка для автоматической сверки проводок.