Книга: Технологии интеграции "1С:Предприятия 8.3""
Назад: Пример реализации универсального обмена
Дальше: Стратегия распространения данных

Стандартные процедуры обмена

Для выполнения обмена данными добавим в конфигурацию обработку ОбменСУдаленнымиСкладами и откроем ее основную форму.

Добавим в форму реквизит УзелОбмена типа ПланОбменаСсылка.УдаленныеСклады, в котором будет содержаться ссылка на выбранный узел обмена. А также добавим в форму команды ВыгрузитьДанные и ЗагрузитьДанные. Перетащим эти команды и реквизит в окно элементов формы.

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

Для того чтобы обеспечить такое поведение кнопок, поместим в модуле формы функцию ПолучитьДоступностьПоУзлу(), в которую передается ссылка на выбранный узел (листинг 3.53).

Листинг 3.53. Функция «ПолучитьДоступностьПоУзлу»

&НаСервереБезКонтекста

Функция ПолучитьДоступностьПоУзлу(Узел)

 

ДоступностьКнопок = Ложь;

 

// Определить наличие установленного непредопределенного узла.

Если Узел <> ПланыОбмена.УдаленныеСклады.ПустаяСсылка()

И Узел <> ПланыОбмена.УдаленныеСклады.ЭтотУзел()

И Узел.ПолучитьОбъект() <> Неопределено Тогда

ДоступностьКнопок = Истина;

 

КонецЕсли;

 

Возврат ДоступностьКнопок;

 

КонецФункции

Эта функция будет возвращать Истина, в случае если ссылка, содержащаяся в параметре Узел, не пустая и не равна ссылке на предопределенный узел, соответствующий текущей информационной базе. Для получения ссылки на текущий узел используется метод менеджера узла плана обмена ЭтотУзел(). В противном случае функция вернет Ложь.

После этого создадим обработчик события ПриИзменении для поля формы УзелОбмена, в котором доступность кнопок будет зависеть от значения, возвращенного описанной ранее функцией (листинг 3.54).

Листинг 3.54. Обработчик события «ПриИзменении» поля «УзелОбмена»

&НаКлиенте

Процедура УзелОбменаПриИзменении(Элемент)

 

ДоступностьКнопок = ПолучитьДоступностьПоУзлу(УзелОбмена);

 

// Установить доступность кнопок в зависимости от установленного узла обмена.

Элементы.ЗагрузитьДанные.Доступность = ДоступностьКнопок;

Элементы.ВыгрузитьДанные.Доступность = ДоступностьКнопок;

 

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

Теперь создадим обработчик команды ВыгрузитьДанные и заполним следующим образом (листинг 3.55).

Листинг 3.55. Обработчик команды «ВыгрузитьДанные»

&НаКлиенте

Процедура ВыполнитьВыгрузку(Команда)

 

ВыполнитьВыгрузкуНаСервере(УзелОбмена);

 

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

В этом обработчике мы вызываем процедуру ВыполнитьВыгрузкуНаСервере(), в которую передаем ссылку на узел обмена, выбранный в поле обработки. В реквизите УзелОбмена будет содержаться ссылка на узел, для которого будет производиться запись изменений (листинг 3.56).

Листинг 3.56. Процедура «ВыполнитьВыгрузкуНаСервере»

&НаСервереБезКонтекста

Процедура ВыполнитьВыгрузкуНаСервере(Узел)

 

// Получить объект узла обмена.

УзелОбмена = Узел.ПолучитьОбъект();

 

// Записать новое сообщение обмена.

УзелОбмена.ЗаписатьСообщениеСИзменениями();

 

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

В этой процедуре мы получаем объект от ссылки на узел плана обмена и выполняем процедуру ЗаписатьСообщенияСИзменениями(), которую мы поместим в модуле плана обмена УдаленныеСклады (см. листинг 3.59).

Теперь создадим обработчик команды ЗагрузитьДанные и заполним следующим образом (листинг 3.57).

Листинг 3.57. Обработчик команды «ЗагрузитьДанные»

&НаКлиенте

Процедура ВыполнитьЗагрузку(Команда)

 

ВыполнитьЗагрузкуНаСервере(УзелОбмена);

 

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

В этом обработчике мы вызываем процедуру ВыполнитьЗагрузкуНаСервере(), в которую передаем ссылку на узел обмена, выбранный в поле обработки. В реквизите УзелОбмена будет содержаться ссылка на узел, от которого будет производиться чтение изменений (листинг 3.58).

Листинг 3.58. Процедура «ВыполнитьЗагрузкуНаСервере»

&НаСервереБезКонтекста

Процедура ВыполнитьЗагрузкуНаСервере(Узел)

 

// Получить объект узла обмена.

УзелОбмена = Узел.ПолучитьОбъект();

 

// Прочитать новое сообщение обмена.

УзелОбмена.ПрочитатьСообщениеСИзменениями();

 

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

В этой процедуре мы получаем объект от ссылки на узел плана обмена и выполняем процедуру ПрочитатьСообщенияСИзменениями(), которую мы поместим в модуле плана обмена УдаленныеСклады (см. листинг 3.61).

Процедуру ЗаписатьСообщенияСИзменениями() в модуле плана обмена заполним следующим образом (листинг 3.59).

Листинг 3.59. Процедура для записи данных обмена

Процедура ЗаписатьСообщениеСИзменениями() Экспорт

 

Сообщение = Новый СообщениеПользователю;

Сообщение.Текст = "-------- Выгрузка в узел " + Строка(ЭтотОбъект) + " ------------";

Сообщение.Сообщить();

 

// Получить имя файла обмена.

ИмяФайла = ОбменСУдаленнымиСкладами.ПолучитьИмяФайлаОбмена(ПланыОбмена.УдаленныеСклады.ЭтотУзел(), Ссылка);

 

// Создать объект записи XML.

// *** ЗаписьXML-документов.

ЗаписьXML = Новый ЗаписьXML;

ЗаписьXML.ОткрытьФайл(ИмяФайла);

ЗаписьXML.ЗаписатьОбъявлениеXML();

 

// *** Инфраструктура сообщений.

ЗаписьСообщения = ПланыОбмена.СоздатьЗаписьСообщения();

ЗаписьСообщения.НачатьЗапись(ЗаписьXML, Ссылка);

// Записать соответствие пространств имен для сокращения размера файла сообщения

ЗаписьXML.ЗаписатьСоответствиеПространстваИмен("xsd", "http://www.w3.org/2001/XMLSchema");

ЗаписьXML.ЗаписатьСоответствиеПространстваИмен("xsi", "http://www.w3.org/2001/XMLSchema-instance");

ЗаписьXML.ЗаписатьСоответствиеПространстваИмен("v8", "http://v8.1c.ru/data");

 

Сообщение = Новый СообщениеПользователю;

Сообщение.Текст = " Номер сообщения: " + ЗаписьСообщения.НомерСообщения;

Сообщение.Сообщить();

 

// Получить выборку измененных данных.

// *** Механизм регистрации изменений.

ВыборкаИзменений = ПланыОбмена.ВыбратьИзменения(ЗаписьСообщения.Получатель, ЗаписьСообщения.НомерСообщения);

Пока ВыборкаИзменений.Следующий() Цикл

// Записать данные в сообщение *** XML-сериализация.

ЗаписатьXML(ЗаписьXML, ВыборкаИзменений.Получить());

КонецЦикла;

 

ЗаписьСообщения.ЗакончитьЗапись();

ЗаписьXML.Закрыть();

 

Сообщение = Новый СообщениеПользователю;

Сообщение.Текст = "-------- Конец выгрузки ------------";

Сообщение.Сообщить();

 

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

В этой процедуре сначала мы сообщаем пользователю о начале выгрузки данных в узел обмена.

Затем с помощью функции ПолучитьИмяФайлаОбмена(), расположенной в общем модуле ОбменСУдаленнымиСкладами, мы формируем имя файла, в который будет записано сообщение обмена.

Для упрощения примера мы будем обмениваться сообщениями через заранее известный каталог обмена, путь к которому хранится в константе Каталог обмена. Значение этой константы (например, e:\Exchange), наряду с префиксом номеров, можно задать в форме настроек информационной базы (см. рис. 3.15).

Имена файлов сообщений стандартизованы и имеют вид: Message_<КодУзлаОтправителя>_<КодУзлаПолучателя>.xml. В качестве узла-отправителя сообщения обмена в функцию ПолучитьИмяФайлаОбмена() передается ссылка на предопределенный узел информационной базы, полученный с помощью метода ЭтотУзел(), а в качестве узла-получателя – ссылка на тот узел обмена, в модуле которого мы находимся (листинг 3.60).

Листинг 3.60. Функция «ПолучитьИмяФайлаОбмена()»

Функция ПолучитьИмяФайлаОбмена(УзелИсточник, УзелПриемник) Экспорт

 

// Сформировать полное имя файла обмена.

Каталог = Константы.КаталогОбмена.Получить();

ИмяФайла = Каталог + ?(Прав(Каталог, 1) = "\","", "\") + "Message_" +

СокрЛП(УзелИсточник.Код) + "_" + СокрЛП(УзелПриемник.Код) + ".xml";

Возврат ИмяФайла;

 

КонецФункции

После этого мы обращаемся к механизмам записи XML-документов и создаем новый объект – ЗаписьXML. С помощью него открываем для записи XML-файл с полученным ранее именем и записываем в него объявление XML.

Затем мы обращаемся к механизмам инфраструктуры сообщений и создаем новый объект ЗаписьСообщенияОбмена, метод которого НачатьЗапись() позволяет, кроме всего прочего, создать очередной номер сообщения и записать заголовок сообщения в XML.

В качестве ссылки на узел обмена, который является получателем сообщения, мы используем значение стандартного реквизита Ссылка плана обмена УдаленныеСклады, в модуле которого мы находимся.

Для сокращения размера файла сообщения первоначально определяем соответствие используемым пространствам имен.

После этого, чтобы получить данные, которые необходимо сохранить в этом файле, мы обращаемся к механизму регистрации изменений и получаем выборку из записей регистрации изменений, предназначенных узлу-получателю. При формировании выборки методом менеджера планов обмена ВыбратьИзменения() мы передаем вторым параметром номер сообщения.

В цикле перебора измененных данных мы сериализуем эти данные в открытый XML-файл методом глобального контекста ЗаписатьXML.

После выхода из цикла мы заканчиваем запись методом ЗакончитьЗапись() объекта ЗаписьСообщенияОбмена. Затем закрываем файл с сообщением обмена методом Закрыть() объекта ЗаписьXML и выводим сообщение об окончании выгрузки данных.

Процедуру ПрочитатьСообщенияСИзменениями() в модуле плана обмена заполним следующим образом (листинг 3.61).

Листинг 3.61. Процедура для чтения данных обмена

Процедура ПрочитатьСообщениеСИзменениями() Экспорт

 

// Получить имя файла обмена.

ИмяФайла = ОбменСУдаленнымиСкладами.ПолучитьИмяФайлаОбмена(Ссылка, ПланыОбмена.УдаленныеСклады.ЭтотУзел());

 

Файл = Новый Файл(ИмяФайла);

Если Не Файл.Существует() Тогда

Возврат;

КонецЕсли;

 

// Попытаться открыть файл.

// *** Чтение документов XML.

ЧтениеXML = Новый ЧтениеXML;

Попытка

ЧтениеXML.ОткрытьФайл(ИмяФайла);

 

Исключение

Сообщение = Новый СообщениеПользователю;

Сообщение.Текст = "Невозможно открыть файл обмена данными.";

Сообщение.Сообщить();

 

Возврат;

 

КонецПопытки;

 

Сообщение = Новый СообщениеПользователю;

Сообщение.Текст = "-------- Загрузка из " + Строка(ЭтотОбъект) + " ------------";

Сообщение.Сообщить();

Сообщение.Текст = " – Считывается файл " + ИмяФайла;

Сообщение.Сообщить();

 

// Загрузить данные из найденного файла.

// *** Инфраструктура сообщений.

ЧтениеСообщения = ПланыОбмена.СоздатьЧтениеСообщения();

 

// Прочитать заголовок сообщения обмена данными – файла XML.

ЧтениеСообщения.НачатьЧтение(ЧтениеXML);

 

// Проверить, что сообщение предназначено для этого узла.

Если ЧтениеСообщения.Отправитель <> Ссылка Тогда

ВызватьИсключение "Неверный узел";

КонецЕсли;

 

// Удалить регистрацию изменений для узла-отправителя сообщения.

// *** Служба регистрации изменений.

ПланыОбмена.УдалитьРегистрациюИзменений(ЧтениеСообщения.Отправитель, ЧтениеСообщения.НомерПринятого);

 

// Прочитать данные из сообщения в цикле. *** XML-сериализация.

Пока ВозможностьЧтенияXML(ЧтениеXML) Цикл

 

// Прочитать очередное значение.

Данные = ПрочитатьXML(ЧтениеXML);

 

// Записать полученные данные.

Данные.ОбменДанными.Отправитель = ЧтениеСообщения.Отправитель;

Данные.ОбменДанными.Загрузка = Истина;

Данные.Записать();

 

КонецЦикла;

 

ЧтениеСообщения.ЗакончитьЧтение();

ЧтениеXML.Закрыть();

УдалитьФайлы(ИмяФайла);

 

Сообщение = Новый СообщениеПользователю;

Сообщение.Текст = "-------- Конец загрузки ------------";

Сообщение.Сообщить();

 

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

В этой процедуре с помощью функции ПолучитьИмяФайлаОбмена(), расположенной в общем модуле ОбменСУдаленнымиСкладами (см. листинг 3.60), мы формируем имя файла, из которого будет прочитано сообщение обмена.

Имена файлов сообщений стандартизованы и имеют вид: Message_<КодУзлаОтправителя>_<КодУзлаПолучателя>.xml. В качестве узла-отправителя сообщения обмена в функцию ПолучитьИмяФайлаОбмена() передается ссылка на тот узел обмена, в модуле которого мы находимся, а в качестве узла-получателя – ссылка на предопределенный узел информационной базы.

Затем на основе имени файла мы создаем объект Файл и проверяем, существует ли он. Если файл обмена найден, то мы пытаемся открыть его для чтения с помощью объекта ЧтениеXML. В случае успеха выводим сообщение о начале загрузки данных из файла.

Затем мы обращаемся к механизмам инфраструктуры сообщений планов обмена и создаем объект ЧтениеСообщенияОбмена. Используя метод этого объекта НачатьЧтение(), мы считываем заголовок XML-сообщения, в котором содержится, в том числе, информация об отправителе сообщения.

После этого проверяем, является ли отправитель сообщения тем узлом плана обмена, для которого мы в данном вызове этой процедуры производим обмен данными. В качестве ссылки на узел обмена, который является отправителем сообщения, мы используем значение стандартного реквизита Ссылка плана обмена УдаленныеСклады, в модуле которого мы находимся.

Если все в порядке, то, перед тем как начать чтение данных, мы удаляем все записи регистрации изменений, которые были сделаны для этого узла и соответствовали номерам сообщений, меньшим или равным указанному в обрабатываемом нами сообщении как номер принятого. Это делается затем, чтобы исключить дублирование данных, которые уже были ранее посланы этому узлу и им обработаны. Для этого мы обращаемся к службе регистрации изменений менеджера планов обмена и используем метод УдалитьРегистрациюИзменений().

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

Для чтения данных мы используем метод глобального контекста ПрочитатьXML(). В результате переменная Данные будет содержать объект «1С:Предприятия», полученный из сообщения обмена.

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

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

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

Назад: Пример реализации универсального обмена
Дальше: Стратегия распространения данных