При организации обмена данными между несколькими информационными базами 1С разработчики часто сталкиваются с нестандартными требованиями со стороны бизнеса или конечных пользователей. Типичный пример такой задачи — необходимость собрать документы (например, «Реализации товаров и услуг») из трех периферийных баз, объединить их в один файл обмена и загрузить в четвертую (центральную) базу, но при этом применить жесткий фильтр: загружать только те документы, которые оформлены по определенному контрагенту.
В этой статье мы подробно разберем, почему стандартные механизмы «Конвертации данных 2.1» (КД 2.1) и обработки «Универсальный обмен данными в формате XML» не позволяют решить эту задачу «в лоб», какие опасности таит в себе идея слияния файлов и как правильно реализовать фильтрацию данных на этапе загрузки без вреда для производительности и целостности вашей информационной базы.
Давайте проанализируем архитектуру XML-файла, который формируется обработкой «Универсальный обмен данными». Этот файл имеет строго определенную древовидную структуру, соответствующую стандартам XML. Он обязательно содержит:
ФайлОбмена).Данные), внутри которой последовательно идут узлы с выгруженными объектами (документами, справочниками, регистрами).Если мы попытаемся физически дописывать выгрузки из трех разных баз в один файл (например, простым текстовым сложением), мы гарантированно получим невалидный XML-документ. В нем окажется либо несколько корневых тегов, либо нарушится вложенность элементов. Попытка прочитать такой файл стандартными средствами 1С (через объект ЧтениеXML) приведет к ошибке синтаксического анализатора, и загрузка полностью аварийно завершится.
Кроме того, при механическом объединении данных из разных баз возникает критическая опасность коллизии уникальных идентификаторов (UUID). Если в базах-источниках существуют разные объекты (например, разные договоры или элементы номенклатуры) с одинаковыми UUID (что часто бывает, если базы создавались копированием или развивались независимо), то при загрузке в центральную базу они просто перезапишут друг друга, безвозвратно испортив учетные данные.
Вместо того чтобы тратить время на написание сложных парсеров для склеивания XML, мы можем автоматизировать последовательную обработку файлов. Для пользователя этот процесс должен выглядеть максимально просто — «нажал одну кнопку и все загрузилось». Достичь этого можно следующими путями:
base1.xml, base2.xml, base3.xml) и поочередно запускать для них стандартную обработку обмена в программном режиме.Рассмотрим пример кода для программного вызова обработки «Универсальный обмен данными в формате XML» для последовательной загрузки нескольких файлов:
Процедура ВыполнитьПоследовательнуюЗагрузку() Экспорт
МассивФайлов = Новый Массив;
МассивФайлов.Добавить("C:\Exchange\Export_Base1.xml");
МассивФайлов.Добавить("C:\Exchange\Export_Base2.xml");
МассивФайлов.Добавить("C:\Exchange\Export_Base3.xml");
ОбработкаОбмена = Обработки.УниверсальныйОбменДаннымиВФорматеXML.Создать();
ОбработкаОбмена.РежимОбмена = "Загрузка";
ОбработкаОбмена.ЗаписыватьРегистрыНаборамиЗаписей = Истина;
ОбработкаОбмена.ЗаписыватьВЗамещаемомРежиме = Истина;
Для Каждого ПутьКФайлу Из МассивФайлов Цикл
ФайлНаДиске = Новый Файл(ПутьКФайлу);
Если Не ФайлНаДиске.Существует() Тогда
ЗаписьЖурналаРегистрации("Обмен данными", УровеньЖурналаРегистрации.Предупреждение, , , "Файл не найден: " + ПутьКФайлу);
Продолжить;
КонецЕсли;
ОбработкаОбмена.ИмяФайлаОбмена = ПутьКФайлу;
Попытка
ОбработкаОбмена.ВыполнитьЗагрузку();
ЗаписьЖурналаРегистрации("Обмен данными", УровеньЖурналаРегистрации.Информация, , , "Успешно загружен файл: " + ПутьКФайлу);
Исключение
ИнформацияОбОшибке = ОписаниеОшибки();
ЗаписьЖурналаРегистрации("Обмен данными", УровеньЖурналаРегистрации.Ошибка, , , "Ошибка загрузки файла " + ПутьКФайлу + ": " + ИнформацияОбОшибке);
КонецПопытки;
КонецЦикла;
КонецПроцедуры
Участники форумов часто предлагают решать задачу отбора документов по контрагенту самым очевидным, но крайне неэффективным способом — использовать обработчик события ПослеЗагрузки в правилах конвертации объектов (ПКО). Давайте разберем, почему этот подход ошибочен и опасен.
Пример нерекомендуемого кода в обработчике ПослеЗагрузки:
// НЕ РЕКОМЕНДУЕТСЯ ИСПОЛЬЗОВАТЬ!
Если Объект.Контрагент.Наименование <> "Василек ООО" Тогда
Отказ = Истина;
КонецЕсли;
В чем опасность этого подхода?
ПослеЗагрузки срабатывает в тот момент, когда XML-парсер уже полностью прочитал объект, заполнил его свойства в памяти и подготовил транзакцию для записи в базу данных. В зависимости от версии платформы 1С и релиза обработки обмена, установка флага Отказ = Истина на этом этапе может отменить запись самого документа «Реализация», но при этом сопутствующие новые элементы справочников (например, новые контрагенты, договоры или номенклатурные позиции, которые были указаны в табличной части документа) уже будут записаны в базу данных, так как они обрабатываются и записываются до завершения загрузки основного объекта. Это приводит к быстрому засорению информационной базы «мусорными» данными.Для того чтобы избежать загрузки лишних связанных данных и не тратить ресурсы сервера на обработку ненужных объектов, отбор необходимо выполнять в обработчике события ПКО ПриЗагрузке. На этом этапе сам объект 1С еще не создан в оперативной памяти приемника, но у нас уже есть доступ к свойствам, считываемым непосредственно из XML-узла файла обмена.
Давайте разберем по шагам, как настроить такую фильтрацию в КД 2.1.
Никогда не зашивайте конкретные названия контрагентов или их ИНН прямо в программный код правил обмена. Это сделает ваши правила негибкими, и при малейшем изменении условий вам придется снова открывать Конвертацию данных, менять код и перевыгружать правила. Правильный подход — использовать параметры.
ИННКонтрагентаДляОтбора.Строка.Теперь перейдем к настройке ПКО (Правила конвертации объектов) для нашего документа «РеализацияТоваровУслуг». Нам нужно проанализировать реквизиты контрагента до того, как документ начнет создаваться.
Для этого откройте свойства ПКО вашего документа и перейдите на вкладку «Обработчики событий». Нам понадобится обработчик ПриЗагрузке. В этом обработчике нам доступны параметры алгоритма, среди которых есть специальная структура ПараметрыОбъекта, хранящая переданные из источника значения свойств.
Однако, по умолчанию свойства контрагента могут не передаваться отдельно от самого объекта. Чтобы иметь возможность легко прочитать ИНН контрагента, мы можем при выгрузке документа в базе-источнике передать ИНН его контрагента как входящее текстовое свойство документа.
Для этого в ПКО документа в обработчике ПриВыгрузке (в базе-источнике) напишем следующий код:
// Передаем ИНН контрагента в свойствах самого документа для быстрого анализа при загрузке
Если ЗначениеЗаполнено(Источник.Контрагент) Тогда
ПередатьОдинРеквизитВПараметры = Источник.Контрагент.ИНН;
ПараметрыВыгрузки.Вставить("ИННКонтрагентаДокумента", ПередатьОдинРеквизитВПараметры);
КонецЕсли;
Теперь в базе-приемнике в обработчике ПриЗагрузке нашего документа мы можем легко перехватить это значение и сравнить его с параметром, который ввел пользователь на форме:
// Проверяем, задан ли параметр отбора контрагента
ИННОтбора = "";
Если Параметры.Свойство("ИННКонтрагентаДляОтбора", ИННОтбора) И ЗначениеЗаполнено(ИННОтбора) Тогда
// Получаем переданный ИНН контрагента из параметров загружаемого объекта
ИННДокумента = "";
Если ПараметрыОбъекта.Свойство("ИННКонтрагентаДокумента", ИННДокумента) Тогда
// Если ИНН документа не совпадает с ИНН отбора, отменяем загрузку объекта на ранней стадии
Если СокрЛП(ИННДокумента) <> СокрЛП(ИННОтбора) Тогда
Отказ = Истина;
// Дополнительно можно вывести информационное сообщение в журнал обмена
// Сообщить("Документ пропущен по отбору контрагента.");
КонецЕсли;
Иначе
// Если ИНН контрагента не был передан, но отбор установлен — безопаснее пропустить документ
Отказ = Истина;
КонецЕсли;
КонецЕсли;
Проанализируем частую ошибку начинающих разработчиков — сопоставление и фильтрацию по наименованию контрагента (например, Объект.Контрагент.Наименование). Делать так крайне не рекомендуется по следующим причинам:
Подводя итоги нашего разбора, сформулируем основные правила, которые помогут вам создавать надежные и быстрые обмены данными между конфигурациями 1С:
ПриЗагрузке, а не ПослеЗагрузки, чтобы не засорять базу данных ненужными элементами справочников и ссылками-фантомами.