При интеграции различных конфигураций 1С (например, когда источником выступает 1С:Документооборот, а приемником — 1С:Управление нашей фирмой) часто возникает задача онлайн-синхронизации справочников. Рассмотрим подробно, как правильно спроектировать и реализовать передачу измененных и новых контрагентов с использованием механизмов платформы: веб-сервисов (SOAP/HTTP), планов обмена и подтверждения доставки данных (квитирования).
Разберем общую схему передачи данных. Веб-сервер публикует базу-приемник, предоставляя точку входа для внешних запросов. База-источник по регламентному заданию или событию выбирает зарегистрированные изменения и отправляет их в веб-сервис.
Стандартный цикл обмена состоит из следующих этапов:
Справочники.Контрагенты.Выясним требования к развертыванию веб-сервера для работы с 1С:
default.vrd) и временную папку %TEMP%.В конфигурации-приемнике создадим объект метаданных Web-сервисы (или HTTP-сервисы). Для SOAP-сервиса потребуется предварительно объявить XDTO-пакеты со структурой контрагента либо принимать сериализованную строку JSON/XML.
Рассмотрим пример программной обработки входящего пакета контрагентов в модуле веб-сервиса. Реализуем поиск по уникальному идентификатору и ключевым реквизитам (ИНН, КПП):
Функция ЗаписатьКонтрагентов(ДанныеJSON, НомерСообщения) Экспорт
ЧтениеJSON = Новый ЧтениеJSON;
ЧтениеJSON.УстановитьСтроку(ДанныеJSON);
МассивКонтрагентов = ПрочитатьJSON(ЧтениеJSON);
ЧтениеJSON.Закрыть();
Для Каждого СтрКонтрагент Из МассивКонтрагентов Цикл
СсылкаGUID = Справочники.Контрагенты.ПолучитьСсылку(Новый УникальныйИдентификатор(СтрКонтрагент.Идентификатор));
НайденныйОбъект = СсылкаGUID.ПолучитьОбъект();
Если НайденныйОбъект = Неопределено Тогда
// Поиск по ИНН и КПП при отсутствии объекта по GUID
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ ПЕРВЫЕ 1
| Контрагенты.Ссылка КАК Ссылка
|ИЗ
| Справочник.Контрагенты КАК Контрагенты
|ГДЕ
| Контрагенты.ИНН = &ИНН
| И Контрагенты.КПП = &КПП";
Запрос.УстановитьПараметр("ИНН", СтрКонтрагент.ИНН);
Запрос.УстановитьПараметр("КПП", СтрКонтрагент.КПП);
Выборка = Запрос.Выполнить().Выбрать();
Если Выборка.Следующий() Тогда
НайденныйОбъект = Выборка.Ссылка.ПолучитьОбъект();
Иначе
НайденныйОбъект = Справочники.Контрагенты.СоздатьЭлемент();
НайденныйОбъект.УстановитьСсылкуНового(СсылкаGUID);
КонецЕсли;
КонецЕсли;
НайденныйОбъект.Наименование = СтрКонтрагент.Наименование;
НайденныйОбъект.ИНН = СтрКонтрагент.ИНН;
НайденныйОбъект.КПП = СтрКонтрагент.КПП;
НайденныйОбъект.ЮридическоеФизическоеЛицо = Перечисления.ЮридическоеФизическоеЛицо[СтрКонтрагент.ЮрФизЛицо];
НайденныйОбъект.ОбменДанными.Загрузка = Истина;
НайденныйОбъект.Записать();
КонецЦикла;
// Возвращаем квитанцию с номером принятого сообщения
Возврат НомерСообщения;
КонецФункции
В базе-источнике создадим план обмена (например, ПланОбмена.ОбменСУНФ), в состав которого включим справочник Справочники.Контрагенты с авторегистрацией изменений.
Разберем процедуру регламентного задания, которая выбирает измененные объекты, формирует выгрузку и обращается к веб-сервису через WSПрокси:
Процедура ВыгрузитьИзмененныхКонтрагентов() Экспорт
УзелОбмена = ПланыОбмена.ОбменСУНФ.НайтиПоКоду("УНФ");
Если Не ЗначениеЗаполнено(УзелОбмена) Тогда
Возврат;
КонецЕсли;
ВыборкаИзменений = ПланыОбмена.ВыбратьИзменения(УзелОбмена, УзелОбмена.НомерОтправленного + 1);
МассивДанных = Новый Массив;
Пока ВыборкаИзменений.Следующий() Цикл
ОбъектДанных = ВыборкаИзменений.Получить();
Если ТипЗнч(ОбъектДанных) = Тип("СправочникСсылка.Контрагенты") Тогда
КонтрагентОбъект = ОбъектДанных.ПолучитьОбъект();
СтруктураКонтрагента = Новый Структура;
СтруктураКонтрагента.Вставить("Идентификатор", Строка(КонтрагентОбъект.Ссылка.УникальныйИдентификатор()));
СтруктураКонтрагента.Вставить("Наименование", КонтрагентОбъект.Наименование);
СтруктураКонтрагента.Вставить("ИНН", КонтрагентОбъект.ИНН);
СтруктураКонтрагента.Вставить("КПП", КонтрагентОбъект.КПП);
СтруктураКонтрагента.Вставить("ЮрФизЛицо", Строка(КонтрагентОбъект.ЮридическоеФизическоеЛицо));
МассивДанных.Добавить(СтруктураКонтрагента);
КонецЕсли;
КонецЦикла;
Если МассивДанных.Количество() = 0 Тогда
Возврат;
КонецЕсли;
ЗаписьJSON = Новый ЗаписьJSON;
ЗаписьJSON.УстановитьСтроку();
ЗаписатьJSON(ЗаписьJSON, МассивДанных);
СтрокаОтправки = ЗаписьJSON.Закрыть();
// Подключение к сервису
Определения = Новый WSОпределения("http://server-unf/unf_base/ws/ExchangeService.1cws?wsdl", "WSUser", "Password123");
Прокси = Новый WSПрокси(Определения, "http://www.company.ru/exchange", "ExchangeService", "ExchangeServiceSoap");
Прокси.Пользователь = "WSUser";
Прокси.Пароль = "Password123";
НомерПакета = УзелОбмена.НомерОтправленного + 1;
Попытка
ПодтвержденныйНомер = Прокси.ЗаписатьКонтрагентов(СтрокаОтправки, НомерПакета);
// Квитирование: очистка регистрации изменений
ПланыОбмена.УдалитьРегистрациюИзменений(УзелОбмена, ПодтвержденныйНомер);
УзелОбъект = УзелОбмена.ПолучитьОбъект();
УзелОбъект.НомерОтправленного = НомерПакета;
УзелОбъект.НомерПринятого = ПодтвержденныйНомер;
УзелОбъект.Записать();
Исключение
ЗаписьЖурналаРегистрации("ОбменКонтрагентами", УровеньЖурналаРегистрации.Ошибка,,, ОписаниеОшибки());
КонецПопытки;
КонецПроцедуры
Проанализируем важные технические нюансы при промышленной эксплуатации веб-сервисов:
ОбменДанными.Загрузка = Истина: обязательно устанавливайте этот флаг перед записью объекта в базе-приемнике. Это отключает лишние проверки и платформенные обработчики проведения/записи, ускоряя импорт и предотвращая блокировки.