Как объединить и свернуть строки табличной части при переносе данных в Конвертации данных 2.0?

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

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

В этой статье мы подробно разберем, как решить проблему дублирования строк, проанализируем типичные ошибки при использовании встроенных методов платформы и рассмотрим три практических способа свертки табличной части средствами КД 2.0.

Почему возникает ошибка и почему стандартный метод Свернуть() не всегда работает?

Первое, что приходит на ум разработчику — выгрузить табличную часть в объект ТаблицаЗначений и применить к ней стандартный метод платформы 1С Свернуть(). Однако на этом пути часто возникают две критические ошибки, которые мы детально разберем.

Ошибка 1. «Слишком много фактических параметров»

Эта ошибка возникает, когда разработчик пытается передать нечисловые типы данных (например, даты начала и окончания периода, даты события или строки) во второй параметр метода Свернуть(). Рассмотрим некорректный пример:


// ОШИБОЧНЫЙ КОД
времТЗ.Свернуть("ВидРасчета, ПодразделениеОрганизации, Сотрудник", 
                "Результат, ОтработаноДней, ОтработаноЧасов, ДатаНачала, ДатаОкончания");

Выясним причину: метод ТаблицаЗначений.Свернуть(КолонкиГруппировки, КолонкиСуммирования) принимает строго два параметра. Во втором параметре (колонки суммирования) допускается указывать только колонки с числовыми типами данных. Попытка просуммировать даты или ссылки приводит к аварийному завершению работы платформы.

Ошибка 2. Строки не сворачиваются из-за различий в датах

Если мы перенесем даты в первый параметр (колонки группировки), то синтаксической ошибки не возникнет:


// Код выполнится, но не решит задачу
времТЗ.Свернуть("ВидРасчета, ПодразделениеОрганизации, Сотрудник, ДатаНачала, ДатаОкончания", 
                "Результат, ОтработаноДней, ОтработаноЧасов");

Проанализируем ситуацию: метод Свернуть() группирует строки только при 100% совпадении всех значений в группировочных колонках. Если у сотрудника в одной строке «Дата начала» указана как 01.10.2023 08:00:00, а во второй строке — 01.10.2023 09:00:00, эти строки **не будут объединены**. На выходе мы получим те же дублирующиеся записи, и база-приемник снова выдаст ошибку.

---

Где правильнее обрабатывать данные: в Источнике или Приемнике?

В Конвертации данных 2.0 у нас есть возможность изменить структуру ТЧ как на этапе выгрузки (в базе-источнике), так и на этапе загрузки (в базе-приемнике).

Вариант на стороне Приемника (в ПКО «После загрузки») — Не рекомендуется

Иногда разработчики пишут код свертки в обработчике ПослеЗагрузки Правила Конвертации Объектов (ПКО), принудительно вызывая метод Объект.Записать(). Внимание: это грубая архитектурная ошибка! Принудительная запись объекта внутри обработчиков загрузки КД 2.0 ломает транзакционность обмена, удваивает нагрузку на СУБД (так как объект записывается дважды) и может приводить к взаимоблокировкам базы данных.

Вариант на стороне Источника (в ПКГС «Перед обработкой») — Рекомендуется

Правильнее всего сворачивать данные еще на этапе выгрузки из источника. В XML-файл обмена попадет уже «чистая», корректно сгруппированная табличная часть. Это уменьшит размер файла выгрузки и ускорит процесс интеграции.

---

Способ 1. Универсальный алгоритм ручной свертки с вычислением крайних дат (Рекомендуемый)

Чтобы корректно объединить строки, у которых могут отличаться даты начала/окончания работы, нам необходимо написать алгоритм ручного суммирования показателей и поиска минимальной даты начала периода и максимальной даты окончания периода. Мы реализуем это через коллекцию Соответствие.

Рассмотрим по шагам реализацию этого кода в правилах конвертации группы свойств (ПКГС) для табличной части «Начисления» в обработчике «Перед обработкой»:


// Шаг 1. Выгружаем исходную табличную часть во временную Таблицу Значений
ТаблицаИсходная = Источник.Начисления.Выгрузить();

// Шаг 2. Создаем Соответствие для группировки. 
// Ключом будет уникальная комбинация: Сотрудник + Подразделение + ВидРасчета
СвернутыеСтроки = Новый Соответствие;

Для Каждого СтрокаТЧ Из ТаблицаИсходная Цикл
    
    // Формируем уникальный текстовый ключ на основе идентификаторов объектов
    КлючСтроки = Строка(СтрокаТЧ.Сотрудник.УникальныйИдентификатор()) + "_" 
               + Строка(СтрокаТЧ.ПодразделениеОрганизации.УникальныйИдентификатор()) + "_" 
               + Строка(СтрокаТЧ.ВидРасчета.УникальныйИдентификатор());
               
    НайденнаяСтрока = СвернутыеСтроки.Получить(КлючСтроки);
    
    Если НайденнаяСтрока = Неопределено Тогда
        // Если такой строки еще нет в соответствии, создаем структуру и заполняем первичные данные
        НоваяСтрока = Новый Структура;
        НоваяСтрока.Вставить("Сотрудник", СтрокаТЧ.Сотрудник);
        НоваяСтрока.Вставить("ПодразделениеОрганизации", СтрокаТЧ.ПодразделениеОрганизации);
        НоваяСтрока.Вставить("ВидРасчета", СтрокаТЧ.ВидРасчета);
        НоваяСтрока.Вставить("Результат", СтрокаТЧ.Результат);
        НоваяСтрока.Вставить("ОтработаноДней", СтрокаТЧ.ОтработаноДней);
        НоваяСтрока.Вставить("ОтработаноЧасов", СтрокаТЧ.ОтработаноЧасов);
        НоваяСтрока.Вставить("ДатаНачала", СтрокаТЧ.ДатаНачала);
        НоваяСтрока.Вставить("ДатаОкончания", СтрокаТЧ.ДатаОкончания);
        НоваяСтрока.Вставить("ДатаНачалаСобытия", СтрокаТЧ.ДатаНачалаСобытия);
        
        СвернутыеСтроки.Вставить(КлючСтроки, НоваяСтрока);
    Иначе
        // Если строка уже существует, суммируем числовые показатели
        НайденнаяСтрока.Результат = НайденнаяСтрока.Результат + СтрокаТЧ.Результат;
        НайденнаяСтрока.ОтработаноДней = НайденнаяСтрока.ОтработаноДней + СтрокаТЧ.ОтработаноДней;
        НайденнаяСтрока.ОтработаноЧасов = НайденнаяСтрока.ОтработаноЧасов + СтрокаТЧ.ОтработаноЧасов;
        
        // Вычисляем самую раннюю Дату Начала периода
        Если ЗначениеЗаполнено(СтрокаТЧ.ДатаНачала) Тогда
            Если НЕ ЗначениеЗаполнено(НайденнаяСтрока.ДатаНачала) Или СтрокаТЧ.ДатаНачала < НайденнаяСтрока.ДатаНачала Тогда
                НайденнаяСтрока.ДатаНачала = СтрокаТЧ.ДатаНачала;
            КонецЕсли;
        КонецЕсли;
        
        // Вычисляем самую позднюю Дату Окончания периода
        Если ЗначениеЗаполнено(СтрокаТЧ.ДатаОкончания) Тогда
            Если НЕ ЗначениеЗаполнено(НайденнаяСтрока.ДатаОкончания) Или СтрокаТЧ.ДатаОкончания > НайденнаяСтрока.ДатаОкончания Тогда
                НайденнаяСтрока.ДатаОкончания = СтрокаТЧ.ДатаОкончания;
            КонецЕсли;
        КонецЕсли;
        
        // Для реквизита "ДатаНачалаСобытия" также берем наиболее раннее значение
        Если ЗначениеЗаполнено(СтрокаТЧ.ДатаНачалаСобытия) Тогда
            Если НЕ ЗначениеЗаполнено(НайденнаяСтрока.ДатаНачалаСобытия) Или СтрокаТЧ.ДатаНачалаСобытия < НайденнаяСтрока.ДатаНачалаСобытия Тогда
                НайденнаяСтрока.ДатаНачалаСобытия = СтрокаТЧ.ДатаНачалаСобытия;
            КонецЕсли;
        КонецЕсли;
    КонецЕсли;
КонецЦикла;

// Шаг 3. Переносим свернутые данные из Соответствия обратно в чистую Таблицу Значений
ТаблицаРезультат = ТаблицаИсходная.СкопироватьКолонки();
Для Каждого Элемент Из СвернутыеСтроки Цикл
    ЗаполнитьЗначенияСвойств(ТаблицаРезультат.Добавить(), Элемент.Value);
КонецЦикла;

// Шаг 4. Подменяем стандартную коллекцию выгрузки КД на нашу подготовленную ТЗ
КоллекцияОбъектов = ТаблицаРезультат;

Этот способ является наиболее надежным, так как мы гарантируем корректное заполнение всех обязательных реквизитов (таких как ДатаНачала и ДатаОкончания), избегая при этом дублирования аналитики.

---

Способ 2. Использование механизма «Входящие данные»

Если мы хотим максимально разделить логику подготовки данных и саму выгрузку, в КД 2.0 предусмотрен штатный механизм передачи параметров через ВходящиеДанные.

Разберем, как настроить этот вариант по шагам:

  1. В ПКО документа (например, НачислениеЗарплаты) в обработчике «Перед выгрузкой» мы выполняем программную подготовку и свертку таблицы по алгоритму, описанному в Способе 1.
  2. Результат свертки (нашу подготовленную ТаблицуЗначений) мы записываем во временную структуру передачи параметров:
    
    ИсходящиеДанные = Новый Структура;
    ИсходящиеДанные.Вставить("СвернутаяТЧНачисления", ТаблицаРезультат);
    
  3. В правилах конвертации группы свойств (ПКГС) для нашей табличной части «Начисления» взводим флаг «Получать из входящих данных».
  4. В обработчике ПКГС «Перед обработкой» пишем всего одну строчку кода, которая автоматически подставит переданную таблицу в качестве источника выгрузки: КоллекцияОбъектов = ВходящиеДанные.СвернутаяТЧНачисления;

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

---

Резюме и рекомендации

Мы проанализировали проблему дублирования строк при переносе табличных частей в КД 2.0. Подводя итоги, дадим несколько важных рекомендаций для успешной разработки правил обмена:

← На главную