Как настроить отбор документов при загрузке в Конвертации данных 2.1 и правильно объединить данные из нескольких баз 1С

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

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

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

Проблема первая: Почему нельзя просто «склеить» три XML-файла в один

Давайте проанализируем архитектуру XML-файла, который формируется обработкой «Универсальный обмен данными». Этот файл имеет строго определенную древовидную структуру, соответствующую стандартам XML. Он обязательно содержит:

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

Кроме того, при механическом объединении данных из разных баз возникает критическая опасность коллизии уникальных идентификаторов (UUID). Если в базах-источниках существуют разные объекты (например, разные договоры или элементы номенклатуры) с одинаковыми UUID (что часто бывает, если базы создавались копированием или развивались независимо), то при загрузке в центральную базу они просто перезапишут друг друга, безвозвратно испортив учетные данные.

Как правильно организовать процесс без слияния файлов

Вместо того чтобы тратить время на написание сложных парсеров для склеивания XML, мы можем автоматизировать последовательную обработку файлов. Для пользователя этот процесс должен выглядеть максимально просто — «нажал одну кнопку и все загрузилось». Достичь этого можно следующими путями:

  1. Программный запуск пакетной загрузки. Мы можем написать небольшую внешнюю обработку в центральной базе. Она будет обращаться к определенному каталогу на сервере или локальном диске, находить там все файлы выгрузки (например, base1.xml, base2.xml, base3.xml) и поочередно запускать для них стандартную обработку обмена в программном режиме.
  2. Использование регламентных заданий. Если обмен происходит регулярно, оптимальным решением будет отказаться от ручного запуска. Мы можем настроить регламентное задание, которое будет автоматически забирать файлы из сетевой папки или FTP-хранилища и загружать их в фоне.

Рассмотрим пример кода для программного вызова обработки «Универсальный обмен данными в формате XML» для последовательной загрузки нескольких файлов:


Процедура ВыполнитьПоследовательнуюЗагрузку() Экспорт
    
    МассивФайлов = Новый Массив;
    МассивФайлов.Добавить("C:\Exchange\Export_Base1.xml");
    МассивФайлов.Добавить("C:\Exchange\Export_Base2.xml");
    МассивФайлов.Добавить("C:\Exchange\Export_Base3.xml");
    
    ОбработкаОбмена = Обработки.УниверсальныйОбменДаннымиВФорматеXML.Создать();
    ОбработкаОбмена.РежимОбмена = "Загрузка";
    ОбработкаОбмена.ЗаписыватьРегистрыНаборамиЗаписей = Истина;
    ОбработкаОбмена.ЗаписыватьВЗамещаемомРежиме = Истина;
    
    Для Каждого ПутьКФайлу Из МассивФайлов Цикл
        ФайлНаДиске = Новый Файл(ПутьКФайлу);
        Если Не ФайлНаДиске.Существует() Тогда
            ЗаписьЖурналаРегистрации("Обмен данными", УровеньЖурналаРегистрации.Предупреждение, , , "Файл не найден: " + ПутьКФайлу);
            Продолжить;
        КонецЕсли;
        
        ОбработкаОбмена.ИмяФайлаОбмена = ПутьКФайлу;
        Попытка
            ОбработкаОбмена.ВыполнитьЗагрузку();
            ЗаписьЖурналаРегистрации("Обмен данными", УровеньЖурналаРегистрации.Информация, , , "Успешно загружен файл: " + ПутьКФайлу);
        Исключение
            ИнформацияОбОшибке = ОписаниеОшибки();
            ЗаписьЖурналаРегистрации("Обмен данными", УровеньЖурналаРегистрации.Ошибка, , , "Ошибка загрузки файла " + ПутьКФайлу + ": " + ИнформацияОбОшибке);
        КонецПопытки;
    КонецЦикла;

КонецПроцедуры

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

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

Пример нерекомендуемого кода в обработчике ПослеЗагрузки:


// НЕ РЕКОМЕНДУЕТСЯ ИСПОЛЬЗОВАТЬ!
Если Объект.Контрагент.Наименование <> "Василек ООО" Тогда
    Отказ = Истина;
КонецЕсли;

В чем опасность этого подхода?

Правильное решение: Фильтрация на этапе «ПриЗагрузке»

Для того чтобы избежать загрузки лишних связанных данных и не тратить ресурсы сервера на обработку ненужных объектов, отбор необходимо выполнять в обработчике события ПКО ПриЗагрузке. На этом этапе сам объект 1С еще не создан в оперативной памяти приемника, но у нас уже есть доступ к свойствам, считываемым непосредственно из XML-узла файла обмена.

Давайте разберем по шагам, как настроить такую фильтрацию в КД 2.1.

Шаг 1. Передача ИНН контрагента через параметры обмена

Никогда не зашивайте конкретные названия контрагентов или их ИНН прямо в программный код правил обмена. Это сделает ваши правила негибкими, и при малейшем изменении условий вам придется снова открывать Конвертацию данных, менять код и перевыгружать правила. Правильный подход — использовать параметры.

  1. Откройте ваши правила обмена в конфигурации «Конвертация данных 2.1».
  2. Перейдите на вкладку «Параметры».
  3. Добавьте новый параметр, например, с именем ИННКонтрагентаДляОтбора.
  4. Установите для него тип данных Строка.
  5. Обязательно установите флаг «Диалог». Это позволит пользователю вводить ИНН контрагента непосредственно в интерфейсе обработки «Универсальный обмен данными» перед началом загрузки.

Шаг 2. Написание кода фильтрации в правилах обмена

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

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

Однако, по умолчанию свойства контрагента могут не передаваться отдельно от самого объекта. Чтобы иметь возможность легко прочитать ИНН контрагента, мы можем при выгрузке документа в базе-источнике передать ИНН его контрагента как входящее текстовое свойство документа.

Для этого в ПКО документа в обработчике ПриВыгрузке (в базе-источнике) напишем следующий код:


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

Теперь в базе-приемнике в обработчике ПриЗагрузке нашего документа мы можем легко перехватить это значение и сравнить его с параметром, который ввел пользователь на форме:


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

Почему для идентификации нужно использовать ИНН, а не наименование

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

Резюме и лучшие практики организации обмена

Подводя итоги нашего разбора, сформулируем основные правила, которые помогут вам создавать надежные и быстрые обмены данными между конфигурациями 1С:

  1. Избегайте ручной склейки файлов обмена. XML-формат КД 2.1 чувствителен к структуре. Вместо слияния файлов настройте автоматическую последовательную загрузку нескольких XML-файлов программными средствами платформы 1С.
  2. Переносите фильтрацию на этап выгрузки, если это возможно. Лучший способ ускорить загрузку — вообще не выгружать лишние данные из баз-источников. Настройте отборы в правилах выгрузки данных (ПВД) на стороне баз-источников.
  3. Используйте правильные обработчики для отборов на загрузке. Если отбор при загрузке неизбежен, выполняйте его в обработчике ПриЗагрузке, а не ПослеЗагрузки, чтобы не засорять базу данных ненужными элементами справочников и ссылками-фантомами.
  4. Привязывайте фильтры к уникальным реквизитам. Проводите проверки контрагентов по ИНН/КПП или уникальным идентификаторам (UUID), но не по текстовому наименованию.
← На главную