Как изменить количество товара в зависимости от номенклатуры при выгрузке через 1С:Конвертация данных 2?

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

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

В этой статье мы подробно рассмотрим, как решить эту задачу с помощью программных механизмов конфигурации «1С:Конвертация данных 2» (КД 2). Мы проанализируем базовое решение, разберем его скрытые подводные камни (такие как проблемы с иерархией справочников, производительностью и согласованностью сумм документа) и изучим альтернативные, более профессиональные подходы.

Базовое решение: Использование обработчика «Перед выгрузкой» в ПКС

Для изменения конкретного реквизита (в нашем случае — количества в табличной части документа) в КД 2 традиционно используются Правила Конвертации Свойств (ПКС). Давайте разберем, как обратиться к данным текущей строки табличной части источника.

При выгрузке табличной части КД 2 циклически обходит каждую строку. В контексте обработчиков ПКС для реквизитов табличной части нам доступна специальная переменная ОбъектКоллекции. Она представляет собой текущую строку выгружаемой табличной части (строку типа СтрокаТабличнойЧасти).

Чтобы изменить выгружаемое значение, мы можем написать следующий код в обработчике «Перед выгрузкой» для ПКС Количество:


// Проверяем код родительской группы номенклатуры
Если ОбъектКоллекции.Номенклатура.Родитель.Код = "000001056" Тогда
    // Умножаем исходное количество на коэффициент 1.2
    Значение = ОбъектКоллекции.Количество * 1.2;
Иначе
    // Оставляем исходное количество без изменений
    Значение = ОбъектКоллекции.Количество;
КонецЕсли;

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

Подводные камни и архитектурные проблемы базового решения

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

  1. Проблема иерархии справочника (проверка только первого уровня). Конструкция ОбъектКоллекции.Номенклатура.Родитель.Код извлекает код только непосредственного родителя элемента. Если в базе-источнике целевой товар лежит глубже в иерархии (например, в подпапке внутри папки с кодом "000001056"), проверка вернет ложь, и количество не изменится. Использовать в этой точке метод ПринадлежитЭлементу() затруднительно, так как для него требуется предварительно получить ссылку на группу-родитель из базы данных.
  2. Критическое падение производительности (разыменование ссылок через точку). Обращение вида ОбъектКоллекции.Номенклатура.Родитель.Код заставляет платформу 1С выполнять неявные SQL-запросы к базе данных на каждой строке каждого выгружаемого документа. Если выгружается документ со многими сотнями строк или большой массив документов, процесс обмена данными может затянуться на часы из-за тысяч лишних запросов к СУБД. Это классическая ошибка разработки под названием «запрос в цикле».
  3. Нарушение математической логики документа. Изменение только количества ломает формулу Количество * Цена = Сумма. В результате в базу-приемник загрузится строка, где количество увеличилось, а сумма и НДС остались старыми (соответствующими старому количеству). Это приведет к некорректному заполнению движений регистров накопления и ошибкам в отчетах по взаиморасчетам и продажам.

Способ 1. Использование ПКГС и временной таблицы (Лучшая практика)

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

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

Проанализируем следующий пример кода:


// Выгружаем табличную часть источника во временную таблицу для безопасного изменения
КоллекцияОбъектов = Источник.Товары.Выгрузить();

// Чтобы избежать запросов к базе в цикле, находим целевую группу один раз
ГруппаРодитель = Справочники.Номенклатура.НайтиПоКоду("000001056");

Если ЗначениеЗаполнено(ГруппаРодитель) Тогда
    Для Каждого СтрокаТЧ Из КоллекцияОбъектов Цикл
        // Проверяем вхождение элемента в группу с учетом любой глубины вложенности
        Если СтрокаТЧ.Номенклатура.ПринадлежитЭлементу(ГруппаРодитель) Тогда
            // Корректируем количество
            СтрокаТЧ.Количество = СтрокаТЧ.Количество * 1.2;
            
            // Сразу пересчитываем сумму, чтобы сохранить математику документа
            СтрокаТЧ.Сумма = СтрокаТЧ.Количество * СтрокаТЧ.Цена;
            
            // При необходимости пересчитываем сумму НДС (например, по ставке 20%)
            СтрокаТЧ.СуммаНДС = СтрокаТЧ.Сумма * 20 / 120; 
        КонецЕсли;
    КонецЦикла;
КонецЕсли;

Преимущества данного метода:

Способ 2. Отказ от жесткого кодирования (Использование параметров)

Прописывание конкретного кода папки ("000001056") прямо в программном коде правил обмена (хардкод) считается плохой практикой разработки. Если в одной из баз код группы изменится или потребуется применить правила для другой группы товаров, вам придется заново открывать КД 2, править правила и перевыгружать их.

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

Выполним следующие шаги:

  1. В конфигурации «Конвертация данных» перейдите на вкладку «Параметры» и добавьте новый параметр с именем ГруппаДляНаценки (тип значения — СправочникСсылка.Номенклатура).
  2. В коде выгрузки замените жесткий поиск по коду на обращение к этому параметру.

Посмотрим на пример измененного кода в обработчике ПКГС:


КоллекцияОбъектов = Источник.Товары.Выгрузить();

// Получаем группу напрямую из параметров обмена, заданных пользователем
ГруппаРодитель = Параметры.ГруппаДляНаценки;

Если ЗначениеЗаполнено(ГруппаРодитель) Тогда
    Для Каждого СтрокаТЧ Из КоллекцияОбъектов Цикл
        Если СтрокаТЧ.Номенклатура.ПринадлежитЭлементу(ГруппаРодитель) Тогда
            СтрокаТЧ.Количество = СтрокаТЧ.Количество * 1.2;
            СтрокаТЧ.Сумма = СтрокаТЧ.Количество * СтрокаТЧ.Цена;
        КонецЕсли;
    КонецЦикла;
КонецЕсли;

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

Способ 3. Пересчет данных при загрузке в базу-приемник

Иногда логику изменения данных гораздо выгоднее и проще реализовать не при выгрузке, а в момент загрузки в базу-приемник. Это позволяет задействовать встроенные механизмы и бизнес-логику самой целевой конфигурации (например, механизмы пересчета табличных частей в «1С:Управление торговлей 10»).

Для этого мы можем использовать обработчик «После загрузки» в Правилах Конвертации Объектов (ПКО) для нашего документа.

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


// Код выполняется на стороне базы-приемника
ГруппаПриемника = Справочники.Номенклатура.НайтиПоКоду("000001056");

Если ЗначениеЗаполнено(ГруппаПриемника) Тогда
    Для Каждого СтрокаТовары Из Объект.Товары Цикл
        Если СтрокаТовары.Номенклатура.ПринадлежитЭлементу(ГруппаПриемника) Тогда
            // Корректируем количество
            СтрокаТовары.Количество = СтрокаТовары.Количество * 1.2;
            
            // Используем штатные модули конфигурации "Управление торговлей" 
            // для автоматического и корректного пересчета сумм, скидок и НДС
            ОбработкаТабличныхЧастей.РассчитатьСуммуТабЧасти(СтрокаТовары, Объект);
            ОбработкаТабличныхЧастей.РассчитатьСуммуНДСТабЧасти(СтрокаТовары, Объект);
        КонецЕсли;
    КонецЦикла;
КонецЕсли;

Преимущества переноса логики на загрузку:

Выбор конкретного метода зависит от архитектуры вашей интеграционной системы. Если базы полностью идентичны и нет необходимости нагружать базу-приемник лишними вычислениями при импорте, оптимальным выбором будет Способ 1 (использование ПКГС на этапе выгрузки). Если же требуется гарантировать идеальную математическую точность сумм по правилам приемника, лучше применить Способ 3.

← На главную