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