В режиме "Конфигуратор"
страницаВ режиме «Конфигуратор»
В конфигураторе центральной базы создадим новый объект конфигурации Обработка с именем ОбменСОтделениями.
На закладке Формы создадим основную форму обработки. В окне редактора форм на закладке Реквизиты добавим реквизит формы ПолеВводаОтделение с типом ПланОбменаСсылка.Отделения и перетащим его в окно элементов формы.
В открывшейся палитре свойств этого поля зададим заголовок — Отделение, вид поля (Поле ввода) оставим по умолчанию (рис. 24.27).

Рис. 24.27. Редактирование формы обработки
Затем на закладке Команды поочередно создадим команды СоздатьНачальныйОбраз, ЗаписатьИзменения и ПрочитатьИзменения. Нажмем кнопку открытия в строке Действие для каждой команды.
Создадим клиентские обработчики этих команд в модуле формы, но заполнять их пока не будем, а перейдем на закладку Форма и поочередно перетащим эти команды в окно элементов формы.
В результате форма обработки примет вид (рис. 24.28).

Рис. 24.28. Форма обработки
Откроем палитру свойств кнопки СоздатьНачальныйОбраз и снимем флажок у свойства Доступность.
Таким образом, при открытии обработки кнопка будет недоступной, пока не выбран узел плана обмена в поле ПолеВводаОтделение. Эта кнопка также будет недоступной в случае выбора предопределенного узла нашей информационной базы, то есть создание начального образа невозможно, если выбранный узел является предопределенным.
Чтобы обеспечить такое поведение кнопки, создадим в модуле формы обработки функцию, выполняющуюся на сервере и возвращающую истину, если переданный в функцию узел является предопределенным (листинг 24.25).
Листинг 24.25. Функция «ПредопределенныйУзел()»
&НаСервереБезКонтекста
Функция ПредопределенныйУзел(Узел)
Возврат Узел = ПланыОбмена.Отделения.ЭтотУзел();
КонецФункции
Затем в окне элементов формы выделим элемент ПолеВводаОтделение, вызовем его палитру свойств и создадим клиентский обработчик события ОбработкаВыбора.
Заполним обработчик следующим образом (листинг 24.26).
Листинг 24.26. Процедура «ПолеВводаОтделениеОбработкаВыбора()»
&НаКлиенте
Процедура ПолеВводаОтделениеОбработкаВыбора(Элемент, ВыбранноеЗначение, СтандартнаяОбработка)
Если ПредопределенныйУзел(ВыбранноеЗначение)Тогда
Элементы.СоздатьНачальныйОбраз.Доступность = Ложь;
Иначе
Элементы.СоздатьНачальныйОбраз.Доступность = Истина;
КонецЕсли;
КонецПроцедуры
В этой процедуре доступность кнопки СоздатьНачальныйОбраз определяется в зависимости от значения функции ПредопределенныйУзел(), в которую передается ссылка на выбранный узел (ВыбранноеЗначение).
Теперь заполним обработчик команды СоздатьНачальныйОбраз следующим образом (листинг 24.27).
Листинг 24.27. Обработчик нажатия кнопки «Создать начальный образ»
&НаКлиенте
Асинх Процедура СоздатьНачальныйОбраз(Команда)
Диалог = Новый ДиалогВыбораФайла(РежимДиалогаВыбораФайла.ВыборКаталога);
Диалог.Заголовок = "Укажите каталог информационной базы:";
Если Ждать Диалог.ВыбратьАсинх() <> Неопределено Тогда
СоздатьНачальныйОбразНаСервере(ПолеВводаОтделение, Диалог.Каталог);
Сообщение = Новый СообщениеПользователю;
Сообщение.Текст = "Создание начального образа узла завершено.";
Сообщение.Сообщить();
КонецЕсли;
КонецПроцедуры
В начале процедуры мы асинхронно (подробнее об этом рассказывается в разделе «Особенности разработки в режиме без использования модальности») вызываем диалог выбора каталога, куда будет помещен образ информационной базы, и затем вызываем процедуру СоздатьНачальныйОбразНаСервере(), исполняющуюся на сервере без контекста, в которой вызывается метод СоздатьНачальныйОбраз() объекта ПланыОбменаМенеджер.
Именно этот метод и позволяет нам создать образ для подчиненного узла распределенной информационной базы. В первом параметре метода передается ссылка на узел (реквизит формы ПолеВводаОтделение), для которого мы хотим создать начальный образ, а во втором — строка соединения, указывающая информационную базу (листинг 24.28).
Листинг 24.28. Процедура «СоздатьНачальныйОбразНаСервере»
&НаСервереБезКонтекста
Процедура СоздатьНачальныйОбразНаСервере(Узел, КаталогСоединения)
ПланыОбмена.СоздатьНачальныйОбраз(Узел, "File =""" + КаталогСоединения + """");
КонецПроцедуры
Теперь создадим обработчик команды Записать изменения.
Текст обработчика будет выглядеть следующим образом (листинг 24.29).
Листинг 24.29. Обработчик нажатия кнопки «Записать изменения»
&НаКлиенте
Асинх Процедура ЗаписатьИзменения(Команда)
Диалог = Новый ДиалогВыбораФайла(РежимДиалогаВыбораФайла.Сохранение);
Диалог.Заголовок = "Укажите файл обмена:";
Если Ждать Диалог.ВыбратьАсинх() <> Неопределено Тогда
ЗаписатьИзмененияНаСервере(ПолеВводаОтделение, Диалог.ПолноеИмяФайла);
Сообщение = Новый СообщениеПользователю;
Сообщение.Текст = "Запись изменений завершена.";
Сообщение.Сообщить();
КонецЕсли;
КонецПроцедуры
В начале процедуры мы асинхронно вызываем диалог ввода имени файла, в который будут записаны изменения, и затем вызываем процедуру ЗаписатьИзмененияНаСервере(), исполняющуюся на сервере без контекста. В первом параметре метода передается ссылка на узел (реквизит формы ПолеВводаОтделение), для которого будет производиться запись изменений.
В этой процедуре мы создаем объект ЗаписьXML для работы с этим файлом.
Затем создаем объект ЗаписьСообщенияОбмена, с помощью которого будем делать сообщение обмена. В методе НачатьЗапись(), во втором параметре, мы указываем, для какого узла обмена будет создаваться это сообщение.
После этого мы выполняем метод ЗаписатьИзменения() объекта ПланыОбменаМенеджер, который и записывает изменения, предназначенные для передачи в выбранный узел, в указанное сообщение обмена.
В заключение мы, как обычно, заканчиваем запись сообщения обмена и закрываем файл (листинг 24.30).
Листинг 24.30. Процедура «ЗаписатьИзмененияНаСервере»
&НаСервереБезКонтекста
Процедура ЗаписатьИзмененияНаСервере(Узел, ИмяФайла)
// Создать и проинициализировать объект ЗаписьXML.
ЗаписьXML = Новый ЗаписьXML;
ЗаписьXML.ОткрытьФайл(ИмяФайла);
// Создать объект ЗаписьСообщенияОбмена и начать запись сообщения.
ЗаписьСообщения = ПланыОбмена.СоздатьЗаписьСообщения();
ЗаписьСообщения.НачатьЗапись(ЗаписьXML, Узел);
// Записать содержимое тела сообщения обмена данными распределенной ИБ.
ПланыОбмена.ЗаписатьИзменения(ЗаписьСообщения);
// Закончить запись сообщения и запись XML.
ЗаписьСообщения.ЗакончитьЗапись();
ЗаписьXML.Закрыть();
КонецПроцедуры
Узнай больше!
Следует отметить, что метод «ЗаписатьИзменения()» позволяет задать максимальное число элементов данных, которые помещаются в сообщение в рамках одной транзакции базы данных. По умолчанию все данные помещаются в сообщение в рамках одной транзакции.
Такой режим является рекомендуемым, так как гарантирует согласованность данных, помещаемых в сообщение.
Но при создании сообщения в многопользовательском режиме могут быть конфликты блокировок между транзакцией, в которой данные помещаются в сообщение, и транзакциями, выполняемыми другими пользователями. Для снижения вероятности возникновения таких конфликтов можно задать значение этого параметра, отличное от значения по умолчанию. Чем меньше значение параметра, тем меньше вероятность конфликта блокировок, но выше вероятность помещения в сообщение несогласованных данных.
Учитывая все вышесказанное, идеальным вариантом является выполнение обмена данными в монопольном режиме. Однако такой вариант не всегда приемлем в силу специфики организации работы конкретных информационных баз.
И последним мы создадим обработчик команды Прочитать изменения.
Текст обработчика будет выглядеть следующим образом (листинг 24.31).
Листинг 24.31. Обработчик нажатия кнопки «Прочитать изменения»
&НаКлиенте
Асинх Процедура ПрочитатьИзменения(Команда)
Диалог = Новый ДиалогВыбораФайла(РежимДиалогаВыбораФайла.Открытие);
Диалог.Заголовок = "Укажите файл обмена:";
Если Ждать Диалог.ВыбратьАсинх() <> Неопределено Тогда
ПрочитатьИзмененияНаСервере(Диалог.ПолноеИмяФайла);
Сообщение = Новый СообщениеПользователю;
Сообщение.Текст = "Чтение изменений завершено.";
Сообщение.Сообщить();
КонецЕсли;
КонецПроцедуры
В начале процедуры мы снова асинхронно вызываем диалог выбора имени файла, который будет прочитан, и затем вызываем процедуру ПрочитатьИзмененияНаСервере(), исполняющуюся на сервере без контекста.
В этой процедуре мы создаем объект ЧтениеXML для работы с этим файлом. Затем создаем объект ЧтениеСообщенияОбмена для чтения сообщения, содержащегося в указанном файле.
Затем методом ПрочитатьИзменения() объекта ПланыОбменаМенеджер мы читаем полученное сообщение.
В заключение процедуры мы завершаем чтение сообщения обмена и закрываем файл (листинг 24.32).
Листинг 24.32. Процедура «ПрочитатьИзмененияНаСервере»
&НаСервереБезКонтекста
Процедура ПрочитатьИзмененияНаСервере(ИмяФайла)
// Создать и проинициализировать объект ЧтениеXML.
ЧтениеXML = Новый ЧтениеXML;
ЧтениеXML.ОткрытьФайл(ИмяФайла);
// Создать объект ЧтениеСообщенияОбмена и начать чтение сообщения.
ЧтениеСообщения = ПланыОбмена.СоздатьЧтениеСообщения();
ЧтениеСообщения.НачатьЧтение(ЧтениеXML);
// Прочитать содержимое тела сообщения.
ПланыОбмена.ПрочитатьИзменения(ЧтениеСообщения);
// Закончить чтение сообщения и чтение XML.
ЧтениеСообщения.ЗакончитьЧтение();
ЧтениеXML.Закрыть();
КонецПроцедуры
В заключение на закладке Подсистемы укажем принадлежность обработки ОбменСОтделениями к подсистеме Предприятие. Затем настроим командный интерфейс этой подсистемы, чтобы доступ к команде открытия обработки имел только Администратор.
Теперь настроим командный интерфейс основного раздела для администратора. Вызовем окно настройки командного интерфейса (Открыть командный интерфейс основного раздела) из контекстного меню корня дерева объектов конфигурации. Добавим команды для открытия форм Общие настройки, Обмен данными и Обмен с отделениями в список команд основного раздела и зададим видимость этих форм только для роли Администратор (рис. 24.29).

Рис. 24.29. Настройка командного интерфейса основного раздела для администратора
А также расположим формы списка планов обмена Филиалы и Отделения на начальной странице администратора. Вызовем настройку начальной страницы (Открыть рабочую область начальной страницы) из контекстного меню корня дерева объектов конфигурации.
Создадим форму списка плана обмена Отделения. Добавим формы списка планов обмена Филиалы и Отделения в левую часть начальной страницы и зададим видимость этих форм только для роли Администратор (рис. 24.30).

Рис. 24.30. Настройка начальной страницы для администратора
Теперь выполним пример программного обмена данными.
подсказка
При выполнении примера обмена данными нужно правильно задавать узел, в который записываются и от которого принимаются изменения. Например, после изменения данных в центральной базе в списке узлов плана обмена нужно выбрать подчиненный узел, которому будут передаваться данные (например, Отделение), и нажать кнопку Записать изменения. А в базе узла, в который будут загружаться данные, в списке узлов плана обмена нужно выбрать узел, из которого данные были выгружены (например, Центральная база), и нажать кнопку Прочитать изменения.
Запустим «1С:Предприятие» для пользователя с ролью Администратор. Откроется начальная страница приложения (рис. 24.31).

Рис. 24.31. Начальная страница «1С:Предприятия» для администратора
Из командной панели раздела Главное, из подменю Сервис откроем форму обработки Обмен с отделениями. Выберем в поле ввода Отделение узел обмена Отделение, для которого мы хотим создать начальный образ нашей информационной базы (рис. 24.32).

Рис. 24.32. Пример программного обмена с отделениями
Затем выполним команду Создать начальный образ. Создадим каталог, куда будет выгружен начальный образ информационной базы, и укажем его в диалоге выбора каталога.
Теперь создадим в центральной базе нового сотрудника. В форме Обмен с отделениями выберем в поле ввода Отделение узел обмена Отделение, в который мы хотим передать изменения. Нажмем кнопку Записать изменения и укажем имя файла сообщения с изменениями.
Затем откроем базу отделения (куда был выгружен начальный образ центральной базы) в конфигураторе. Создадим в ней пользователя с ролью Администратор и запустим «1С:Предприятие». На начальной странице вызовем из подменю Сервис обработку Обмен с отделениями выберем в поле ввода Отделение узел обмена Центральная база, от которого мы хотим принять изменения. Нажмем кнопку Прочитать изменения и укажем имя файла сообщения с изменениями.
Убедимся, что сотрудник центральной базы (с префиксом кода ЦБ) присутствует в базе отделения.
Следует лишь сделать несколько заключительных замечаний.
При использовании механизма распределенных информационных баз становятся доступными четыре события объекта встроенного языка ПланОбменаОбъект.<имя>, которые позволяют управлять отправкой и приемом данных на уровне отдельных элементов данных:
- ПриОтправкеДанныхГлавному(),
- ПриОтправкеДанныхПодчиненному(),
- ПриПолученииДанныхОтГлавного(),
- ПриПолученииДанныхОтПодчиненного().
Эти события будут вызываться для каждого элемента данных, включаемого в сообщение.
Работу этих событий можно увидеть, добавив в модуль объекта План обмена Отделения следующий текст (листинг 24.33).
Листинг 24.33. Просмотр работы событий объекта «ПланОбменаОбъект»
Процедура ПриОтправкеДанныхГлавному(ЭлементДанных, ОтправкаЭлемента)
Сообщение = Новый СообщениеПользователю;
Сообщение.Текст = "ПриОтправкеДанныхГлавному " + ЭлементДанных;
Сообщение.Сообщить();
КонецПроцедуры
Процедура ПриОтправкеДанныхПодчиненному(ЭлементДанных, ОтправкаЭлемента)
Сообщение = Новый СообщениеПользователю;
Сообщение.Текст = "ПриОтправкеДанныхПодчиненному " + ЭлементДанных;
Сообщение.Сообщить();
КонецПроцедуры
Процедура ПриПолученииДанныхОтГлавного(ЭлементДанных, ПолучениеЭлемента, ОтправкаНазад)
Сообщение = Новый СообщениеПользователю;
Сообщение.Текст = "ПриПолученииДанныхОтГлавного " + ЭлементДанных;
Сообщение.Сообщить();
КонецПроцедуры
Процедура ПриПолученииДанныхОтПодчиненного(ЭлементДанных, ПолучениеЭлемента, ОтправкаНазад)
Сообщение = Новый СообщениеПользователю;
Сообщение.Текст = "ПриПолученииДанныхОтПодчиненного " + ЭлементДанных;
Сообщение.Сообщить();
КонецПроцедуры
В первом параметре всех перечисленных событий находится тот элемент данных, для которого вызвано это событие.
Параметр ОтправкаЭлемента позволяет управлять тем, какая информация будет помещена в сообщение. Он может принимать три значения:
Авто— значение по умолчанию. Указывает на то, что элемент данных будет помещен в сообщение;Удалить— в сообщение будет помещено значение, предназначенное для удаления этого элемента данных;Игнорировать— в сообщение не будет помещено ничего, связанного с этим элементом данных.
Параметр ПолучениеЭлемента позволяет указать, будет ли прочитанный элемент данных записан в базу данных или нет. Параметр также может принимать три значения:
Авто— значение по умолчанию. Если элемент данных получен от главного узла, он будет записан всегда. Если элемент данных получен от подчиненного узла, он будет записан, только если не зарегистрированы изменения для этого элемента данных;Принять— полученный элемент данных будет записан всегда;Игнорировать— проигнорировать получение элемента данных и ничего не записывать.
Также в событиях получения данных существует третий параметр — ОтправкаНазад, имеющий тип Булево.
Этот параметр позволяет выполнять принудительную регистрацию изменений для полученного элемента данных в базе-получателе.
Такая необходимость может возникнуть, например, когда при приеме данных от узла-отправителя обнаружено, что полученные данные противоречивы (например, в узле-отправителе была допущена ошибка при изменении данных).
Тогда мы можем проигнорировать присланные изменения и, установив флажок ОтправкаНазад, вызвать принудительную регистрацию изменений полученного элемента данных в нашей базе для узла-отправителя.
В результате последующего обмена состояние этого элемента данных в узле-отправителе будет установлено таким же, как и в нашей базе.