Skip to content

Пример простого обмена двух баз через файл с квитированием

В общем виде обмен с квитированием осущетвляется в несколько шагов:

  1. Создание сообщения обмена в источнике
  2. Чтение и обработка сообщения обмена в приемнике
  3. Создание подтверждающего сообщения в приемнике (квитирование)
  4. Чтение и удаление успешно переданного из плана обмена в источнике

Сообщение обмена Источник-Приемник

Создание сообщения

Создаем план обмена, реализуем выгрузку. В примере в плане обмена источника зарегистрирован один справочник “Номенклатура”

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

В результате получим xml вида:

<!--Начало блока, добавляемого методом ЗаписьСообщения.НачатьЗапись()-->
<v8msg:Message xmlns:v8msg="http://v8.1c.ru/messages">
<v8msg:Header>
<v8msg:ExchangePlan>СН_ОбменСПриемником</v8msg:ExchangePlan>
<v8msg:To>ПБ</v8msg:To>
<v8msg:From>ИБ</v8msg:From>
<v8msg:MessageNo>16</v8msg:MessageNo>
<v8msg:ReceivedNo>0</v8msg:ReceivedNo>
</v8msg:Header>
<v8msg:Body>
<!--конец блока, добавляемого методом ЗаписьСообщения.НачатьЗапись()-->
<!--Начало блока, который формируется нами вручную-->
<СписокНоменклатуры>
<Номенклатура>
<Код>000000006</Код>
...
<ПометкаУдаления>Нет</ПометкаУдаления>
</Номенклатура>
<Номенклатура>
...
</Номенклатура>
...
<Номенклатура>
...
</Номенклатура>
</СписокНоменклатуры>
<!--Конец блока, который формируется нами вручную-->
<!--Начало блока, добавляемого методом ЗаписьСообщения.ЗакончитьЗапись()-->
</v8msg:Body>
</v8msg:Message>
<!--Конец блока, добавляемого методом ЗаписьСообщения.ЗакончитьЗапись()-->

Чтение сообщения в базе-приемнике

ВАЖНО! В приемнике должен быть план обмена с таким же именем, что и в источнике. Также нужно, чтобы код узла базы приемника совпадал с кодом, указанным в шапке сообщения в блоке <v8msg:To> . Это необходимо для того, чтобы методы чтения сообщения корректно сработали

Считываем данные для обработки в приемнике

// ПолноеИмяФайла - путь к файлу обмена, созданному источником
// ТаблицаДляЗагрузки - промежуточная таблица для последующей загрузки в запрос
Процедура ЗаполнитьТаблицуДляЗагрузки(ПолноеИмяФайла, ТаблицаДляЗагрузки)
СоответствиеКолонокУзлам = Новый Соответствие;
СоответствиеКолонокУзлам.Вставить("Наименование", "Наименование");
...
СоответствиеКолонокУзлам.Вставить("ПометкаУдаления", "ПометкаУдаления");
// Создаем объект чтения сообщения
ЧтениеСообщения = ПланыОбмена.СоздатьЧтениеСообщения();
// Создаем объект, который будет использоваться чтением сообщения
ЧтениеXML = Новый ЧтениеXML;
ЧтениеXML.ОткрытьФайл(ПолноеИмяФайла);
// Считываем служебную информацию сообщения. Код узла, номера сообщений и пр.
ЧтениеСообщения.НачатьЧтение(ЧтениеXML);
// Проверяем, что отправитель это именно та база, откуда мы ожидаем сообщение
Если ЧтениеСообщения.Отправитель <> "ИБ" Тогда
//Обработка ошибки
Возврат;
КонецЕсли;
// Считываем данные, записанные в <body> узле сообщения
Пока ЧтениеXML.Прочитать() Цикл
// Мы должны закончить чтение на узле </v8msg:Body>,
// иначе метод ЧтениеСообщения.ЗакончитьЧтение() завершится с ошибкой
Если ЧтениеXML.ТипУзла = ТипУзлаXML.КонецЭлемента
И ЧтениеXML.Имя = "v8msg:Body" Тогда
Прервать;
КонецЕсли;
Если ЧтениеXML.ТипУзла = ТипУзлаXML.НачалоЭлемента Тогда
ИмяТекущегоУзла = ЧтениеXML.Имя;
Если ИмяТекущегоУзла = "Номенклатура" Тогда
СтрокаТаблицы = ТаблицаДляЗагрузки.Добавить();
КонецЕсли;
ИначеЕсли ЧтениеXML.ТипУзла = ТипУзлаXML.Текст Тогда
ИмяКолонкиТаблицы = СоответствиеКолонокУзлам.Получить(ИмяТекущегоУзла);
Если ИмяКолонкиТаблицы <> Неопределено Тогда
СтрокаТаблицы[ИмяКолонкиТаблицы] = ЧтениеXML.Значение;
КонецЕсли;
КонецЕсли;
КонецЦикла;
// Считываем закрывающие служебные тэги сообщения
ЧтениеСообщения.ЗакончитьЧтение();
// завершаем чтение файла
ЧтениеXML.Закрыть();
КонецПроцедуры

Чтение будет проходить следующими этапами

<!--ЧтениеСообщения.НачатьЧтение()-->
<v8msg:Message xmlns:v8msg="http://v8.1c.ru/messages">
<v8msg:Header>
<v8msg:ExchangePlan>СН_ОбменСПриемником</v8msg:ExchangePlan>
<v8msg:To>ПБ</v8msg:To>
<v8msg:From>ИБ</v8msg:From>
<v8msg:MessageNo>16</v8msg:MessageNo>
<v8msg:ReceivedNo>0</v8msg:ReceivedNo>
</v8msg:Header>
<v8msg:Body>
<!--Конец ЧтениеСообщения.НачатьЧтение()-->
<!--ЧтениеXML.Прочитать()-->
<СписокНоменклатуры>
<Номенклатура>
<Код>000000006</Код>
...
<ПометкаУдаления>Нет</ПометкаУдаления>
</Номенклатура>
<Номенклатура>
...
</Номенклатура>
<Номенклатура>
...
</Номенклатура>
...
<Номенклатура>
...
</Номенклатура>
</СписокНоменклатуры>
<!--Конец ЧтениеXML.Прочитать()-->
<!--ЧтениеСообщения.ЗакончитьЧтение()-->
</v8msg:Body>
</v8msg:Message>
<!--Конец ЧтениеСообщения.ЗакончитьЧтение()-->
<!--ЧтениеXML.Закрыть()-->

Дальше обрабатываем данные файла в приемнике как нужно.

Сообщение Приемник-Источник. Квитирование (гарантия доставки)

Формирование сообщения в базе приемнике

Квитирование необходимо для того, чтобы дать источнику данные о том, какие сообщения приемник получил и успешно обработал. Записи таблицы изменений, где номер сообщения меньше либо равен номеру, указанному в квитанции можно удалять из таблицы изменений.

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

Процедура СформироватьКвитанциюЗаписатьВКаталогОбмена()
// куда сохраняем квитанцию
ИмяФайла = "C:\путь-до-папки-обмена\Квитанция_ПБ_ИБ.xml";
// Узел в плане обмена, которому направляем квитанцию о получении
Узел = ПланыОбмена.СН_ОбменСПриемником.НайтиПоКоду("ИБ");
Если Не ЗначениеЗаполнено(Узел) Тогда
ВызватьИсключение "Неопределенный узел получателя квитанции";
КонецЕсли;
Запись = Новый ЗаписьXML;
Запись.ОткрытьФайл(ИмяФайла);
// Тут записываем шапку
ЗаписьСообщения = ПланыОбмена.СоздатьЗаписьСообщения();
ЗаписьСообщения.НачатьЗапись(Запись, Узел);
// заканчиваем запись, не записывая тело. Только шапка
ЗаписьСообщения.ЗакончитьЗапись();
// Закрываем файл
Запись.Закрыть();
КонецПроцедуры

Пример квитанции

<v8msg:Message xmlns:v8msg="http://v8.1c.ru/messages">
<v8msg:Header>
<v8msg:ExchangePlan>СН_ОбменСПриемником</v8msg:ExchangePlan>
<v8msg:To>ИБ</v8msg:To>
<v8msg:From>ПБ</v8msg:From>
<v8msg:MessageNo>4</v8msg:MessageNo>
<v8msg:ReceivedNo>20</v8msg:ReceivedNo>
</v8msg:Header>
<v8msg:Body/>
</v8msg:Message>

Чтение квитанции в базе-источнике. Удаление записей о регистрации изменений

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

Процедура ПрочитатьКвитанциюУдалитьИзмененияИзПланаОбмена(УзелОбмена) Экспорт
ПутьКФайлу = "C:\путь-до-папки-обмена\Квитанция_ПБ_ИБ.xml";
ЧтениеСообщения = ПланыОбмена.СоздатьЧтениеСообщения();
Чтение = Новый ЧтениеXML;
Чтение.ОткрытьФайл(ПутьКФайлу);
// считываем квитанцию
ЧтениеСообщения.НачатьЧтение(Чтение);
НомерПринятого = ЧтениеСообщения.НомерПринятого;
// удаляем переданное по номеру принятого, указанного в квитанции
ПланыОбмена.УдалитьРегистрациюИзменений(УзелОбмена, НомерПринятого);
ЧтениеСообщения.ЗакончитьЧтение();
Чтение.Закрыть();
// удаляем квитанции
УдалитьФайлы(ПутьКФайлу);
КонецПроцедуры