Обмены в 1С: план обмена, регистрация и выгрузка изменений
План обмена — основа любых обменов в 1С: типовой синхронизации, распределённых баз и собственных выгрузок. В статье — сравнение вариантов обмена, создание плана обмена и узла, регистрация изменений, выгрузка и загрузка сообщений обмена с готовым кодом, а также краткий разбор обмена с сайтом по CommerceML.
Задача: передавать изменения данных между базами 1С
Рано или поздно одной базы становится мало: появляется филиал со своей информационной базой, интернет-магазин, учёт в другой конфигурации. Данные нужно переносить регулярно и так, чтобы каждый раз уходило только то, что изменилось. Для этого в платформе есть специальный объект метаданных — план обмена. Он хранит список участников обмена (узлов), помнит, какие изменения ещё не доставлены каждому узлу, и нумерует сообщения, чтобы подтвердить получение.
Ниже — как устроены обмены в 1С, какой вариант выбрать, как создать план обмена и написать собственный обмен: регистрация изменений, выгрузка, загрузка и очистка регистрации.
Какие бывают обмены в 1С и что выбрать
Не всякую задачу нужно решать своим кодом. Для типовых конфигураций обмен уже написан, и подключается он настройками.
| Вариант | Когда применять | Особенности |
|---|---|---|
| Типовая синхронизация данных (формат EnterpriseData, «Конвертация данных 3») | Обмен между разными типовыми конфигурациями, например торговля и бухгалтерия | Настраивается в разделе администрирования («Синхронизация данных»), правила уже есть в конфигурациях; свой код нужен только для доработок |
| «Конвертация данных» 2.x с файлами правил | Обмен с нетиповыми базами и старыми конфигурациями | Правила хранятся в XML-файле и готовятся в отдельной конфигурации; на стороне базы работает универсальная обработка обмена |
| Распределённая информационная база (РИБ) | Одна и та же конфигурация в центре и в филиалах | План обмена с признаком распределённой базы; вместе с данными передаются и изменения конфигурации |
| Свой обмен на плане обмена | Нестандартный формат, своя структура сообщений, обмен с внешней системой | Полный контроль над составом и форматом, но регистрацию, выгрузку и загрузку пишет разработчик |
| Обмен с сайтом (CommerceML) | Каталог, остатки и заказы интернет-магазина | Протокол обмена на основе XML и HTTP, поддерживается большинством CMS |
Для разового переноса данных (так называемого «переноса данных 1С» при смене конфигурации) план обмена тоже подходит, но чаще используют готовую выгрузку и загрузку через XML или обработку «Универсальный обмен данными в формате XML», если она есть в вашей конфигурации. План обмена оправдан там, где обмен будет повторяться и нужно отслеживать изменения.
Как создать план обмена
В конфигураторе добавьте объект «План обмена» в ветке «Планы обмена». Что нужно настроить:
- Реквизиты — свойства узла: например, версия формата, адрес каталога обмена, признак выгрузки. Реквизиты узла хранятся для каждого участника отдельно.
- Состав — какие справочники, документы и регистры входят в обмен. Для каждого объекта задаётся «Авторегистрация»: при значении «Разрешить» платформа сама записывает изменение объекта в журнал для всех узлов, кроме отправителя; при «Запретить» регистрацией управляет код.
- Распределённая информационная база — флажок включают только для РИБ. Для своего обмена его оставляют выключенным.
Узел «этот узел» (ЭтотУзел) платформа создаёт сама: он описывает текущую базу. Остальные участники создаются программно или вручную в форме списка плана обмена.
Процедура СоздатьУзелОбмена()
// Идентификатор текущей базы — нужен второй стороне, чтобы адресовать сообщение
ЭтотУзел = ПланыОбмена.ОбменССайтомИФилиалами.ЭтотУзел();
НовыйУзел = ПланыОбмена.ОбменССайтомИФилиалами.СоздатьУзел();
НовыйУзел.Код = "ФИЛ01";
НовыйУзел.Наименование = "Филиал, Казань";
НовыйУзел.Записать();
// Первоначальная выгрузка: регистрируем всё, что входит в состав плана обмена
ПланыОбмена.ЗарегистрироватьИзменения(НовыйУзел.Ссылка);
КонецПроцедуры
Код узла на обеих сторонах должен соответствовать друг другу: код «этого узла» в одной базе — это код узла-корреспондента в другой. Именно по коду отправителя принимающая база находит свой узел при чтении сообщения.
Регистрация изменений в плане обмена
Регистрация изменений — запись в служебную таблицу плана обмена о том, что объект изменился и ещё не доставлен узлу. Есть два способа.
Авторегистрация. Если для объекта в составе плана обмена выбрано «Разрешить», при каждой записи платформа сама регистрирует изменение для всех узлов плана обмена, кроме этого узла и узла, который указан отправителем данных. Это самый простой вариант, когда все данные должны попасть всем получателям.
Регистрация программно. Нужна, если у каждого получателя свой отбор: например, филиал получает только свои документы. Авторегистрацию запрещают, а в подписке на событие «ПередЗаписью» решают, кому отправить объект. Подписка не должна срабатывать при загрузке данных из обмена, иначе изменения «отразятся» обратно.
// Обработчик подписки на событие «ПередЗаписью» для документов
Процедура РегистрацияИзмененийПередЗаписью(Источник, Отказ) Экспорт
Если Источник.ОбменДанными.Загрузка Тогда
Возврат;
КонецЕсли;
ВыборкаУзлов = ПланыОбмена.ОбменССайтомИФилиалами.Выбрать();
Пока ВыборкаУзлов.Следующий() Цикл
Узел = ВыборкаУзлов.Ссылка;
Если Узел = ПланыОбмена.ОбменССайтомИФилиалами.ЭтотУзел() Или Узел.ПометкаУдаления Тогда
Продолжить;
КонецЕсли;
// Филиал получает только документы своей организации
Если Источник.Организация = Узел.Организация Тогда
ПланыОбмена.ЗарегистрироватьИзменения(Узел, Источник);
КонецЕсли;
КонецЦикла;
КонецПроцедуры
Второй параметр ПланыОбмена.ЗарегистрироватьИзменения() принимает объект, ссылку или набор записей. Без него регистрируется весь состав плана обмена — так делают первоначальную выгрузку. Если изменения конкретного объекта не нужны узлу, регистрацию снимают методом ПланыОбмена.УдалитьРегистрациюИзменений(Узел, Данные), передав объект или ссылку.
Выгрузка: выбрать изменения и записать сообщение обмена
Сообщение обмена — это XML-файл (или поток), в который записаны изменённые объекты и служебный заголовок: кто отправитель, кто получатель, какой номер сообщения и какой номер сообщения от получателя уже принят. За заголовок отвечает объект ЗаписьСообщенияОбмена, который создаётся методом ПланыОбмена.СоздатьЗаписьСообщения(). Сами объекты сериализуются в тот же поток глобальным методом ЗаписатьXML() — он использует сериализатор XDTO и умеет писать ссылки, объекты, наборы записей и удаления.
Процедура ВыгрузитьИзменения(УзелОбмена, ИмяФайла)
ЗаписьXML = Новый ЗаписьXML;
ЗаписьXML.ОткрытьФайл(ИмяФайла);
ЗаписьСообщения = ПланыОбмена.СоздатьЗаписьСообщения();
ЗаписьСообщения.НачатьЗапись(ЗаписьXML, УзелОбмена);
Попытка
ВыборкаИзменений = ПланыОбмена.ВыбратьИзменения(УзелОбмена, ЗаписьСообщения.НомерСообщения);
Пока ВыборкаИзменений.Следующий() Цикл
Данные = ВыборкаИзменений.Получить();
ЗаписатьXML(ЗаписьXML, Данные);
КонецЦикла;
ЗаписьСообщения.ЗакончитьЗапись();
Исключение
ЗаписьСообщения.ПрерватьЗапись();
ЗаписьXML.Закрыть();
ВызватьИсключение;
КонецПопытки;
ЗаписьXML.Закрыть();
КонецПроцедуры
Метод ПланыОбмена.ВыбратьИзменения(Узел, НомерСообщения) возвращает выборку незарегистрированных, то есть ещё не подтверждённых изменений. Через Получить() вы получаете объект или, если запись была удалена, специальный объект УдалениеОбъекта со ссылкой удалённого элемента. Платформа запоминает, что изменения отправлены с номером сообщения, но саму регистрацию не снимает: пока получатель не подтвердит приём, изменения будут отправляться повторно. Это защищает обмен от потери файла по дороге.
Если нужно выгрузить не всё, а только часть объектов, третьим параметром ВыбратьИзменения() можно передать фильтр — массив объектов метаданных. Работу с потоком XML подробнее разбирает статья XML в 1С.
Загрузка: чтение сообщения и удаление регистрации
На стороне получателя порядок обратный: открыть файл, прочитать заголовок, снять регистрацию изменений, которые отправитель уже получил, и по очереди записать объекты. Номер принятого сообщения лежит в заголовке: отправитель сообщает, какое наше сообщение он успел принять, и мы удаляем регистрацию до этого номера методом ПланыОбмена.УдалитьРегистрациюИзменений(Узел, НомерСообщения).
Процедура ЗагрузитьИзменения(ИмяФайла)
ЧтениеXML = Новый ЧтениеXML;
ЧтениеXML.ОткрытьФайл(ИмяФайла);
ЧтениеСообщения = ПланыОбмена.СоздатьЧтениеСообщения();
ЧтениеСообщения.НачатьЧтение(ЧтениеXML);
Отправитель = ЧтениеСообщения.Отправитель;
// Отправитель подтвердил приём наших сообщений до этого номера
ПланыОбмена.УдалитьРегистрациюИзменений(Отправитель, ЧтениеСообщения.НомерПринятого);
Пока ВозможностьЧтенияXML(ЧтениеXML) Цикл
Данные = ЧитатьXML(ЧтениеXML);
Если ТипЗнч(Данные) = Тип("УдалениеОбъекта") Тогда
Объект = Данные.Ссылка.ПолучитьОбъект();
Если Объект <> Неопределено Тогда
Объект.ОбменДанными.Отправитель = Отправитель;
Объект.ОбменДанными.Загрузка = Истина;
Объект.Удалить();
КонецЕсли;
Продолжить;
КонецЕсли;
Данные.ОбменДанными.Отправитель = Отправитель;
Данные.ОбменДанными.Загрузка = Истина;
Данные.Записать();
КонецЦикла;
ЧтениеСообщения.ЗакончитьЧтение();
ЧтениеXML.Закрыть();
КонецПроцедуры
Два свойства ОбменДанными принципиальны. Отправитель сообщает платформе, от какого узла пришёл объект, поэтому при авторегистрации изменение не уйдёт ему же обратно. Загрузка = Истина — признак, что объект записывается при обмене. Платформа сама обработчики не пропускает: ПередЗаписью и подписки на события выполнятся, поэтому в них надо проверять ОбменДанными.Загрузка и выходить, не выполняя бизнес-проверок, заполнения и проведения. Проведение документа при загрузке тоже выполняют отдельно, если оно нужно. Прочитанный файл лучше загружать в транзакции или хотя бы пакетами, чтобы при ошибке на середине не получить половину данных.
Обмен с сайтом (CommerceML)
Обмен с интернет-магазином устроен иначе: роль сообщения играет файл в формате CommerceML, а транспортом служит HTTP. Сайт обращается к базе (или база к сайту) по шагам: авторизация, инициализация обмена, передача файла, импорт, получение заказов, подтверждение. Каталог и предложения (import.xml, offers.xml) идут из 1С на сайт, заказы (orders.xml) — обратно. В типовых торговых конфигурациях такой обмен подключается настройкой отдельного узла, учёт изменений там тоже ведётся через план обмена, поэтому знания из этой статьи применимы. Запросы к сайту из своего кода делают через HTTPСоединение, как показано в статье HTTP-запросы к REST API.
Типичные ошибки
- Не проверять
ОбменДанными.Загрузкав обработчиках записи: при загрузке выполняется лишний код, документы перепроводятся или регистрируются повторно, обмен «зацикливается». - Не указывать
Отправительпри записи загруженных данных: объект при авторегистрации уходит обратно отправителю. - Не удалять регистрацию после подтверждения: выгрузка растёт, одни и те же данные уходят снова и снова.
- Писать
ЗаписатьXML()внеЗаписьСообщения: у файла нет заголовка, и принимающая сторона выдаёт ошибку приНачатьЧтение(). - Не обрабатывать
УдалениеОбъекта: загрузка падает на первом удалённом элементе. - Перепутать код узла: сообщение адресовано не той базе, и чтение не начинается.
- Регистрировать изменения в обработчике, который работает и при обмене, — объекты возвращаются отправителю.
Актуальность для новых версий
Планы обмена и методы ПланыОбмена.ВыбратьИзменения(), ЗаписьСообщенияОбмена, ЧтениеСообщенияОбмена работают во всех версиях 8.3 одинаково. В типовых конфигурациях обмен с другими программами сейчас строится на формате EnterpriseData, а настройки синхронизации собраны в разделе администрирования; интерфейс и названия пунктов зависят от версии конфигурации и библиотеки стандартных подсистем. Для собственного кода нужные методы доступны в любом режиме совместимости платформы 8.3.
Частые вопросы
Чем план обмена отличается от обычного справочника узлов?
План обмена хранит не только список узлов, но и журнал регистрации изменений по каждому узлу, номера отправленных и принятых сообщений и состав объектов, участвующих в обмене. Обычный справочник этого не умеет.
Что такое авторегистрация изменений?
Это режим, при котором платформа сама записывает в журнал каждое изменение объекта из состава плана обмена для всех узлов, кроме текущего и узла-отправителя. Если нужны отборы по получателям, авторегистрацию запрещают и вызывают ПланыОбмена.ЗарегистрироватьИзменения() из кода.
Зачем при загрузке ставить ОбменДанными.Загрузка = Истина?
Это признак загрузки данных из обмена. Обработчики записи и подписки на события должны проверять его и пропускать проверки, перепроведение и повторную регистрацию изменений.
Когда удаляется регистрация изменений?
После подтверждения получения: отправитель сообщает в заголовке сообщения номер принятого сообщения, и получатель вызывает ПланыОбмена.УдалитьРегистрациюИзменений(Узел, НомерПринятого). До подтверждения изменения отправляются повторно.