При интеграции устаревших конфигураций на обычных формах (таких как 1С:Комплексная автоматизация 1.1) с современными базами (например, 1С:Бухгалтерия предприятия 3.0) разработчики часто сталкиваются с необходимостью настройки надежного автоматического обмена. Стандартное COM-соединение постепенно уходит в прошлое из-за проблем с производительностью, требовательности к лицензиям и привязки к платформе Windows.
В этой статье мы подробно разберем, как построить архитектурно правильный («по феншую») односторонний обмен данными. Мы исключим использование COM-соединения, задействуем планы обмена для регистрации изменений, организуем передачу через современные HTTP-сервисы и реализуем надежную схему гарантированной доставки данных (квитирование).
Чтобы обмен работал стабильно, не терял данные при сбоях сети и не нагружал систему избыточной выгрузкой, мы должны опираться на три важных столпа:
План обмена необходим для фиксации измененных объектов. Разберем, как его правильно настроить. Создадим новый план обмена в конфигураторе КА 1.1 (например, ПланОбменаОбменСБухгалтерией). В составе плана обмена укажем те документы и справочники, которые мы планируем переносить в БП 3.0. Авторегистрацию для этих объектов можно установить в режим «Разрешить».
Главная ошибка начинающих разработчиков — очищать регистрацию изменений сразу после генерации файла выгрузки. Если в этот момент произойдет сбой сети, данные в приемник не попадут, а источник будет «думать», что всё отправлено. Правильный алгоритм строится на номерах сообщений.
Проанализируем программный код выгрузки изменений с использованием номеров сообщений на стороне КА 1.1:
// Определяем узел обмена
УзелОбмена = ПланыОбмена.НайтиПоКоду("БП");
Если УзелОбмена.Пустая() Тогда
ВызватьИсключение "Не найден узел обмена для Бухгалтерии!";
КонецЕсли;
// Увеличиваем номер отправляемого сообщения на 1
НовыйНомерСообщения = УзелОбмена.НомерОтправленного + 1;
// Начинаем выборку измененных данных
ВыборкаИзменений = ПланыОбмена.ВыбратьИзменения(УзелОбмена, НовыйНомерСообщения);
// Создаем объект для выгрузки по правилам КД2
ОбработкаОбмена = Обработки.УниверсальныйОбменДаннымиXML.Создать();
ОбработкаОбмена.ИмяФайлаПравилОбмена = "C:\Rules\Rules_KA_BP.xml"; // Путь к правилам конвертации
ОбработкаОбмена.РежимОбмена = "Выгрузка";
// Вместо записи в файл на диск, пишем XML-данные прямо в строку
ЗаписьXML = Новый ЗаписьXML;
ЗаписьXML.УстановитьСтроку();
// Выполняем выгрузку зарегистрированных изменений
ОбработкаОбмена.ВыполнитьВыгрузку(ЗаписьXML, ВыборкаИзменений);
СтрокаXML = ЗаписьXML.Закрыть();
Обратите внимание: метод ПланыОбмена.ВыбратьИзменения() не просто выбирает данные, но и закрепляет за каждым выгруженным объектом переданный НовыйНомерСообщения. Если объект изменится снова во время сеанса обмена, платформа зарегистрирует его повторно, но уже без привязки к текущему номеру сообщения.
Передавать «сырой» XML-текст большого объема по сети неэффективно. Намного правильнее сжать его в ZIP-архив. Рассмотрим, как упаковать полученную XML-строку в архив и отправить её получателю с помощью объекта HTTPСоединение:
// Сжатие данных в ZIP-архив во временный файл
ИмяВременногоФайлаXML = ПолучитьИмяВременногоФайла("xml");
ТекстовыйДокумент = Новый ТекстовыйДокумент;
ТекстовыйДокумент.УстановитьТекст(СтрокаXML);
ТекстовыйДокумент.Записать(ИмяВременногоФайлаXML, КодировкаТекста.UTF8);
ИмяВременногоАрхива = ПолучитьИмяВременногоФайла("zip");
Архив = Новый ЗаписьZipФайла(ИмяВременногоАрхива);
Архив.Добавить(ИмяВременногоФайлаXML, МетодСжатияZIP.Сжатие, КодированиеИменФайловZIP.UTF8);
Архив.Записать();
// Читаем архив в двоичные данные для отправки
ДвоичныеДанныеАрхива = Новый ДвоичныеДанные(ИмяВременногоАрхива);
// Удаляем временные файлы с диска источника
УдалитьФайлы(ИмяВременногоФайлаXML);
УдалитьФайлы(ИмяВременногоАрхива);
// Настройка HTTP-соединения с БП 3.0
Сервер = "192.168.1.100"; // Адрес сервера БП
Порт = 80;
Пользователь = "ExchangeUser";
Пароль = "StrongPassword";
Соединение = Новый HTTPСоединение(Сервер, Порт, Пользователь, Пароль);
Запрос = Новый HTTPЗапрос("/bp_base/hs/exchange/v1/import");
Запрос.УстановитьТелоИзДвоичныхДанных(ДвоичныеДанныеАрхива);
Попытка
Ответ = Соединение.ОтправитьДляОбработки(Запрос); // Отправляем POST-запрос
Если Ответ.КодСостояния = 200 Тогда
// Квитирование: Сервер успешно обработал пакет
// Только теперь мы можем очистить регистрацию изменений в источнике!
ПланыОбмена.УдалитьРегистрациюИзменений(УзелОбмена, НовыйНомерСообщения);
// Фиксируем новый номер отправленного сообщения в узле
ОбъектУзла = УзелОбмена.ПолучитьОбъект();
ОбъектУзла.НомерОтправленного = НовыйНомерСообщения;
ОбъектУзла.Записать();
ЗаписьЖурналаРегистрации("Обмен данными", УровеньЖурналаРегистрации.Информация, , ,
"Обмен успешно завершен. Номер сообщения: " + НовыйНомерСообщения);
Иначе
ЗаписьЖурналаРегистрации("Обмен данными", УровеньЖурналаРегистрации.Ошибка, , ,
"Ошибка отправки данных. Код ответа сервера: " + Ответ.КодСостояния);
КонецЕсли;
Исключение
ЗаписьЖурналаРегистрации("Обмен данными", УровеньЖурналаРегистрации.Ошибка, , ,
"Не удалось связаться с базой-приемником: " + ОписаниеОшибки());
КонецПопытки;
Метод ПланыОбмена.УдалитьРегистрациюИзменений() удалит регистрацию только для тех объектов, чей номер сообщения меньше или равен переданному НовыйНомерСообщения. Если во время загрузки произошел сбой, очистка не выполнится, и при следующем запуске регламентного задания все эти данные будут повторно выгружены.
Теперь переместимся в базу-приемник 1С:Бухгалтерия предприятия 3.0. Здесь нам необходимо создать HTTP-сервис, который будет принимать ZIP-архив, распаковывать его и загружать данные через встроенную обработку УниверсальныйОбменДаннымиXML.
Выполним следующие шаги в конфигураторе БП 3.0:
ОбменДанными.exchange.Импорт и шаблоном пути: /v1/import.POST и назначим ему обработчик (функцию в модуле HTTP-сервиса).Проанализируем код обработчика POST-запроса на стороне БП 3.0:
Функция ИмпортДанныхPOST(Запрос)
// Получаем двоичные данные архива из тела запроса
ДвоичныеДанныеАрхива = Запрос.ПолучитьТелоКакДвоичныеДанные();
Если ДвоичныеДанныеАрхива = Неопределено Или ДвоичныеДанныеАрхива.Размер() = 0 Тогда
Ответ = Новый HTTPСервисОтвет(400);
Ответ.УстановитьТелоИспользуяСтроку("Пустой запрос");
Возврат Ответ;
КонецЕсли;
// Сохраняем пришедший архив во временный файл
ИмяВременногоАрхива = ПолучитьИмяВременногоФайла("zip");
ДвоичныеДанныеАрхива.Записать(ИмяВременногоАрхива);
// Распаковываем архив во временный каталог
КаталогРаспаковки = ПолучитьИмяВременногоФайла("");
Архив = Новый ЧтениеZipФайла(ИмяВременногоАрхива);
Архив.ИзвлечьВсе(КаталогРаспаковки, РежимВосстановленияПутейФайловZIP.НеВосстанавливать);
Архив.Закрыть();
// Полагаем, что внутри архива один файл данных XML
НайденныеФайлы = НайтиФайлы(КаталогРаспаковки, "*.xml");
Если НайденныеФайлы.Количество() = 0 Тогда
УдалитьФайлы(ИмяВременногоАрхива);
УдалитьФайлы(КаталогРаспаковки);
Ответ = Новый HTTPСервисОтвет(400);
Ответ.УстановитьТелоИспользуяСтроку("Файл данных не найден внутри архива");
Возврат Ответ;
КонецЕсли;
ПутьКФайлуДанных = НайденныеФайлы[0].ПолноеИмя;
// Инициализируем обработку УниверсальныйОбменДаннымиXML в режиме загрузки
ОбработкаЗагрузки = Обработки.УниверсальныйОбменДаннымиXML.Создать();
ОбработкаЗагрузки.РежимОбмена = "Загрузка";
ОбработкаЗагрузки.ИмяФайлаОбмена = ПутьКФайлуДанных;
Попытка
ОбработкаЗагрузки.ВыполнитьЗагрузку();
// Очищаем временные папки и файлы
УдалитьФайлы(ИмяВременногоАрхива);
УдалитьФайлы(КаталогРаспаковки);
// Возвращаем успешный ответ источнику
Ответ = Новый HTTPСервисОтвет(200);
Ответ.УстановитьТелоИспользуяСтроку("Пакет успешно обработан и загружен");
Возврат Ответ;
Исключение
// В случае ошибки логируем ее и удаляем временные файлы
ЗаписьЖурналаРегистрации("Загрузка данных", УровеньЖурналаРегистрации.Ошибка, , ,
"Ошибка при загрузке XML: " + ОписаниеОшибки());
УдалитьФайлы(ИмяВременногоАрхива);
УдалитьФайлы(КаталогРаспаковки);
Ответ = Новый HTTPСервисОтвет(500);
Ответ.УстановитьТелоИспользуяСтроку("Внутренняя ошибка сервера при записи объектов: " + ОписаниеОшибки());
Возврат Ответ;
КонецПопытки;
КонецФункции
Если вы хотите избежать написания правил обмена в Конвертации Данных 2.0 и последующей их поддержки при обновлениях конфигурации 1С:Бухгалтерия 3.0, имеет смысл посмотреть в сторону формата EnterpriseData.
Начиная с релизов серии 1.1.110, фирма «1С» встроила базовую поддержку универсального формата обмена данными (EnterpriseData версии 1.5) прямо в старую конфигурацию «Комплексная автоматизация 1.1».
Рассмотрим особенности этого подхода:
Подводя итог, можно сказать, что связка План обмена (с квитированием) + КД 2.0 + HTTP-сервис (с ZIP-архивацией в памяти) является наиболее производительным, надежным и контролируемым решением для одностороннего обмена данными. Это позволяет полностью отказаться от нестабильных COM-соединений и гарантирует доставку каждого документа.