В начало

Обмен регистра «Цены»

 

            Есть независимый регистр сведений «Цены», есть две как бы различные конфигурации, нужно организовать обмен данными, находящимися в регистре сведений между этими конфигурациями. Первая – это центральная база «ЦБ» на обычных формах, вторая – база некого филиала «ФЛ» на управляемых формах.

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

Рис. Структура регистра «Цены» в дереве метаданных

 

            Итак, создаём новый план обмена, называем его «ОбменЦенами», далее настраиваем его состав, а именно включаем в него наш регистр сведений «Цены».

Рис. План обмена «ОбменЦенами», установка состава

 

            Затем переходим в раздел «Данные» свойств объекта план обмена «ОбменЦенами», где добавляем реквизит «ЭтоГлавныйУзел» с типом «Булево».

            Далее переходим на вкладку «Формы» и добавляем форму узла.

Рис. Форма узла плана обмена

 

            Затем, аналогичным образом, добавляем форму списка в план обмена «ОбменЦенами». На форму кидаем кнопку, которую называем «ЗарегистрироватьИзменения».

Рис. Форма списка плана обмена «ОбменЦенами»

 

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

 

Листинг. Модуль объекта плана обмена

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

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

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

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

            Каталог = КаталогВременныхФайлов();

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

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

            "Сообщение_ОбменЦенами_" +

            СокрЛП(ПланыОбмена.ОбменЦенами.ЭтотУзел().Код) + "-" +

            СокрЛП(Ссылка.Код) + ".xml";

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

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

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

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

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

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

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

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

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

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

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

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

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

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

            Получатель,ЗаписьСообщения.НомерСообщения);

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

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

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

            КонецЦикла;

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

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

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

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

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

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

 

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

            Каталог = КаталогВременныхФайлов();

            // Сформировать имя файла.

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

            "Сообщение_ОбменЦенами_" + СокрЛП(Ссылка.Код) + "-" +

            СокрЛП(ПланыОбмена.ОбменЦенами.ЭтотУзел().Код) + ".xml";

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

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

                        Возврат;

            КонецЕсли;

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

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

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

            Попытка

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

            Исключение

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

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

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

                        Возврат;

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

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

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

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

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

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

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

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

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

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

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

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

            // Сообщение предназначено не для этого узла.

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

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

            КонецЕсли;

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

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

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

            ЧтениеСообщения.НомерПринятого);

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

                        // Читаем очередное значение.

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

                        // Не переносим изменение, полученное в главный из неглавного,

                        // если есть регистрация изменения.

                        Если Не ЧтениеСообщения.Отправитель.ЭтоГлавныйУзел И

                                   ПланыОбмена.ИзменениеЗарегистрировано(

                                   ЧтениеСообщения.Отправитель, Данные) Тогда

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

                                   Сообщение.Текст = " – Изменения отклонены";

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

                                   Продолжить;

                        КонецЕсли;

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

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

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

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

            КонецЦикла;

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

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

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

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

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

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

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

 

            Потом в модуль формы узла добавляем обработчик «ПередОткрытием».

 

Листинг. Модуль формы узла плана обмена

Процедура ПередОткрытием(Отказ, СтандартнаяОбработка)

            Если ЭтотОбъект.Ссылка = ПланыОбмена.ОбменЦенами.ЭтотУзел() Тогда

                        ЭлементыФормы.ЭтоГлавныйУзел.Доступность = Ложь;

            КонецЕсли;

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

 

            Затем переходим на форму списка плана обмена. Для кнопки «ЗарегистрироватьИзменения» добавляем событие, а для списка – обработчик «ПриАктивизацииСтроки».

 

Листинг. Модуль формы списка плана обмена

Процедура Кнопка1Нажатие(Элемент)

            Запрос = Новый Запрос;

            Запрос.Текст =

            "ВЫБРАТЬ

            |          ЦеныИзменения.Номенклатура

            |ИЗ

            |          РегистрСведений.Цены.Изменения КАК ЦеныИзменения";

           

            Результат = Запрос.Выполнить();

            Выборка = Результат.Выбрать();

            ТекУзел = ЭлементыФормы.ПланОбменаСписок.ТекущаяСтрока;

            НЗ = РегистрыСведений.Цены.СоздатьНаборЗаписей();

           

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

                        НЗ.Отбор.Номенклатура.Установить(Выборка.Номенклатура);

                        НЗ.Прочитать();

                       

                        ПланыОбмена.ЗарегистрироватьИзменения(ТекУзел, НЗ);

            КонецЦикла;

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

 

Функция ЭтоПредопределенныйУзел(Узел)

            Возврат Узел = ПланыОбмена.ОбменЦенами.ЭтотУзел();

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

 

Процедура ПланОбменаСписокПриАктивизацииСтроки(Элемент)

            Если ЭтоПредопределенныйУзел(Элемент.ТекущаяСтрока) Тогда

                        ЭлементыФормы.ЗарегистрироватьИзменения.Доступность = Ложь;

            Иначе

                        ЭлементыФормы.ЗарегистрироватьИзменения.Доступность = Истина;

            КонецЕсли;

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

 

            После этого добавляем новую обработку «ОбменДаннымиЦен». Создаём форму обработки. Добавляем действие для кнопки.

Рис. Форма обработки «ОбменДаннымиЦен»

 

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

 

Листинг. Модуль формы обработки «Обмен данными цен»

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

            ВыборкаУзлов = ПланыОбмена.ОбменЦенами.Выбрать();

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

                        // Произвести обмен данными со всеми узлами,

                        //кроме текущего (ЭтотУзел)

                        Если ВыборкаУзлов.Ссылка <> ПланыОбмена.ОбменЦенами.ЭтотУзел() Тогда

                                   УзелОбъект = ВыборкаУзлов.ПолучитьОбъект();

                                  

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

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

                        КонецЕсли;

            КонецЦикла;

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

 

            Теперь можно протестировать центральную базу в режиме отладки. Открываем план обмена «ОбменЦенами», настраиваем список узлов плана обмена. Имеющийся незаполненный предопределённый узел – это центральная база «ЦБ». Добавляем еще один узел для базы филиала «ФЛ».

Рис. Форма списка плана обмена в центральной базе

 

            Чтобы было что регистрировать, перейдём в регистр сведений «Цены» и сделаем некоторые изменения.

Рис. Изменения в регистре сведений «Цены»

 

            Далее возвращаемся в план обмена, выделяем строку с узлом «ФЛ» и нажимаем кнопку «Зарегистрировать изменения». Вылетает ошибка.

Рис. Ошибка «Ошибка при вызове метода контекста», снизу подробности ошибки

 

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

 

Листинг. Исправление ошибки при вызове метода контекста

Процедура Кнопка1Нажатие(Элемент)

            Запрос = Новый Запрос;

            Запрос.Текст =

            "ВЫБРАТЬ

            |          ЦеныИзменения.Период,

            |          ЦеныИзменения.Номенклатура

            |ИЗ

            |          РегистрСведений.Цены.Изменения КАК ЦеныИзменения";

           

            Результат = Запрос.Выполнить();

            Выборка = Результат.Выбрать();

            ТекУзел = ЭлементыФормы.ПланОбменаСписок.ТекущаяСтрока;

            НЗ = РегистрыСведений.Цены.СоздатьНаборЗаписей();

           

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

                        НЗ.Отбор.Номенклатура.Установить(Выборка.Номенклатура);

                        НЗ.Отбор.Период.Установить(Выборка.Период);

                        НЗ.Прочитать();

                       

                        ПланыОбмена.ЗарегистрироватьИзменения(ТекУзел, НЗ);

            КонецЦикла;

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

 

            Далее открываем обработку «Обмен данными цен», жмем кнопку «Выполнить обмен».

Рис. Выполнение обмена данными

 

            При этом на экран выводятся системные сообщения, а в каталоге временных файлов создается файл-сообщение «Сообщение_ОбменЦенами_ЦБ-ФЛ.xml» с данными для обмена из центральной базы «ЦБ» в базу филиала «ФЛ».

 

Листинг. Содержимое файла «Сообщение_ОбменЦенами_ЦБ-ФЛ.xml»

<?xml version="1.0" encoding="UTF-8"?>

<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>1</v8msg:MessageNo>

                               <v8msg:ReceivedNo>0</v8msg:ReceivedNo>

                </v8msg:Header>

                <v8msg:Body>

                               <InformationRegisterRecordSet.Цены>

                                               <Filter>

                                                               <Period>2022-03-20T12:09:12</Period>

                                                               <Номенклатура>ab4f277a-a55b-11ec-9fae-001eec3547a4</Номенклатура>

                                               </Filter>

                                               <Records>

                                                              <Record>

                                                                              <Period>2022-03-20T12:09:12</Period>

                                                                              <Номенклатура>ab4f277a-a55b-11ec-9fae-001eec3547a4</Номенклатура>

                                                                              <Цена>100</Цена>

                                                               </Record>

                                               </Records>

                               </InformationRegisterRecordSet.Цены>

                </v8msg:Body>

</v8msg:Message>

 

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

            Переходим в конфигуратор конфигурации филиала и добавляем новый план обмена «ОбменЦенами».

            Процедуры в модуле объекта плана обмена точно такие же, как и в конфигурации центральной базы.

            Создаем форму узла в плане обмена.

Рис. Форма узла плана обмена «ОбменЦенами» в конфигураторе филиала

 

            Переходим в модуль формы узла и добавляем обработчик «ПриСозданииНаСервере», добавляем в него код.

 

Листинг. Модуль формы узла в конфигурации филиала

&НаСервере

Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)

            Если Объект.Ссылка = ПланыОбмена.ОбменЦенами.ЭтотУзел() Тогда

                        Элементы.ЭтоГлавныйУзел.Доступность = Ложь;

            КонецЕсли;

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

 

            Далее создаем форму списка плана обмена. Добавляем команду «ЗарегистрироватьИзменения».

Рис. Форма списка плана обмена в конфигураторе филиала

           

            Для команды «ЗарегистрироватьИзменения» добавляем действие, а для списка узлов – обработчик «ПриАктивизацииСтроки». Описываем содержимое процедур в модуле формы списка.

 

Листинг. Модуль формы списка плана обмена в конфигурации филиала

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

Процедура ЗарегистрироватьИзмененияНаСервере(ТекУзел)

            Запрос = Новый Запрос;

            Запрос.Текст =

            "ВЫБРАТЬ

            |          ЦеныИзменения.Период,

            |          ЦеныИзменения.Номенклатура

            |ИЗ

            |          РегистрСведений.Цены.Изменения КАК ЦеныИзменения";

           

            Результат = Запрос.Выполнить();

            Выборка = Результат.Выбрать();

            НЗ = РегистрыСведений.Цены.СоздатьНаборЗаписей();

           

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

                        НЗ.Отбор.Период.Установить(Выборка.Период);

                        НЗ.Отбор.Номенклатура.Установить(Выборка.Номенклатура);

                        НЗ.Прочитать();

                       

                        ПланыОбмена.ЗарегистрироватьИзменения(ТекУзел, НЗ);

            КонецЦикла;

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

 

&НаКлиенте

Процедура ЗарегистрироватьИзменения(Команда)

            ТекУзел = Элементы.Список.ТекущаяСтрока;

            ЗарегистрироватьИзмененияНаСервере(ТекУзел);

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

 

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

Функция ЭтоПредопределенныйУзел(Узел)

            Возврат Узел = ПланыОбмена.ОбменЦенами.ЭтотУзел();

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

 

&НаКлиенте

Процедура СписокПриАктивизацииСтроки(Элемент)

            Если ЭтоПредопределенныйУзел(Элемент.ТекущаяСтрока) Тогда

                        Элементы.ЗарегистрироватьИзменения.Доступность = Ложь;

            Иначе

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

            КонецЕсли;

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

 

            Создаем обработку «Обмен данными цен», добавляем форму обработки, на форме размещаем кнопку.

Рис. Форма обработки «ОбменДаннымиЦен»

 

            Для команды кнопки добавляем действие.

 

Листинг. Модуль формы обработки

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

Процедура ВыполнитьОбменНаСервере()

            ВыборкаУзлов = ПланыОбмена.ОбменЦенами.Выбрать();

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

                        // Произвести обмен данными со всеми узлами,

                        //кроме текущего (ЭтотУзел)

                        Если ВыборкаУзлов.Ссылка <> ПланыОбмена.ОбменЦенами.ЭтотУзел() Тогда

                                   УзелОбъект = ВыборкаУзлов.ПолучитьОбъект();

                                  

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

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

                        КонецЕсли;

            КонецЦикла;

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

 

&НаКлиенте

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

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

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

 

            Запускаемся в режиме отладки. Настраиваем список узлов для плана обмена базы филиала.

Рис. Настройка списка плана обмена базы филиала

 

            В базе филиала предопределенный узел будет «ФЛ». Нужно добавить еще один узел для центральной базы.

            Поскольку у нас уже есть файл-сообщение из центральной базы, то можно выполнить обмен при помощи обработки «Обмен данными цен».

 

Рис. Выполнение обмена

 

            По идее данные из файла «Сообщение_ОбменЦенами_ЦБ-ФЛ.xml» прочитались и изменения должны были перенестись в регистр сведений «Цены». В служебном сообщении указано, что файл прочитан.  Проверим, так ли это. Для этого открываем регистр сведений «Цены».

Рис. Изменения в регистре сведений «Цены»

 

            Все нормально, изменения перенесены. Далее можно проверить обратный обмен, из филиала «ФЛ» в центральную базу «ЦБ».