1C-CodeОсновы 1С → Обмен данными и интеграции

Обмен данными и интеграции

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

Глава 33 из 36 · чтение примерно 24 минут

База редко живёт одна. Торговля отдаёт документы в бухгалтерию, сайт присылает заказы, банк — выписку, маркетплейс — остатки.

Механизмов для этого несколько, и выбор между ними определяется одним вопросом: обе стороны — 1С или нет.

Чем обмениваются

МеханизмКогда берут
План обменаобе стороны 1С: регистрация изменений и порционная выгрузка
EnterpriseDataобе стороны 1С, но конфигурации разные
HTTP-сервисчужая система зовёт нас
Внешний HTTP-запросмы зовём чужую систему
Web-сервис (SOAP)старые интеграции, обмен с корпоративными системами
Файл: CSV, JSON, XMLпростой односторонний обмен, выгрузка по расписанию

План обмена: главная идея

Наивный обмен выглядит так: выгрузить всё и загрузить всё. Работает на сотне документов и умирает на сотне тысяч.

План обмена решает это регистрацией изменений. В нём перечислены узлы — другие базы — и состав: какие объекты обмениваются. Когда объект меняется, платформа сама помечает: «для узла Б этот документ изменился».

Выгрузка берёт только помеченное. Получив подтверждение, что порция принята, снимает пометки.

Почему подтверждение обязательно

Если снимать регистрацию сразу после выгрузки, любой сбой на той стороне означает потерю: изменения уже «отправлены», а на деле не дошли. И узнать об этом нельзя — пометок больше нет.

Поэтому в обмене есть номера сообщений: сторона Б сообщает, какое сообщение она приняла, и только тогда сторона А снимает регистрацию по этот номер.

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

Узлы: кто с кем разговаривает

Узел плана обмена — это другая база в терминах вашей. Один из узлов особенный: он обозначает вас самих, и берут его через ПланыОбмена.Имя.ЭтотУзел().

У каждого узла есть код и наименование, и код здесь не украшение: по нему стороны друг друга и находят. Завели в двух базах узлы с несовпадающими кодами — обмен пойдёт в пустоту и ошибки не покажет.

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

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

Выгрузка порции: как это выглядит в коде

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

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

// Только то, что для этого узла изменилось
Выборка = ПланыОбмена.ВыбратьИзменения(Узел, ЗаписьСообщения.НомерСообщения);
Пока Выборка.Следующий() Цикл
	СериализаторXDTO.ЗаписатьXML(Запись, Выборка.Получить());
КонецЦикла;

ЗаписьСообщения.ЗакончитьЗапись();
Запись.Закрыть();
ЧастьЧто означает
ЭтотУзел и Узелпервый — вы, второй — та база, которой пишете
НомерСообщениярастёт с каждой порцией; по нему получатель понимает, не пришло ли старое
ВыбратьИзмененияберёт ТОЛЬКО помеченное для этого узла — в этом весь смысл плана обмена
Выборка.Получить()отдаёт сам объект; удалённые приезжают как УдалениеОбъекта

ОбменДанными.Загрузка — самый важный флаг обмена

При загрузке объект записывают с флагом Объект.ОбменДанными.Загрузка = Истина. Он отключает проверку заполнения, проведение и ваш код в модуле объекта.

Это не «чтобы быстрее». Это единственный способ получить в приёмнике то же самое, что в источнике. Иначе ваш ПередЗаписью пересчитает сумму по своим правилам, и базы разойдутся — а разойдутся они тихо, цифрами.

Обратная сторона: если в модуле объекта есть код, который обязан отработать и при загрузке, его придётся звать явно. И наоборот — весь код модуля объекта надо писать так, чтобы он умел ничего не делать при загрузке: Если ОбменДанными.Загрузка Тогда Возврат; КонецЕсли; первой строкой — стандартная заготовка типовых.

Как связать объекты двух баз

Ссылка в 1С — это внутренний идентификатор. У одного и того же контрагента в двух базах идентификаторы разные.

Поэтому при обмене объекты сопоставляют: по уникальному идентификатору (если базы родственные и он общий), либо по естественному ключу — ИНН, коду, артикулу, номеру и дате.

Ошибка сопоставления даёт самый неприятный вид поломки: дубли. Один контрагент превращается в двух, документы расходятся между ними, и разбирать это придётся руками.

Обмен с чужой системой: HTTP

План обмена — это про две базы 1С. С чужой системой — сайтом, складской программой, банком — разговаривают по HTTP, и здесь 1С бывает по обе стороны.

1С спрашивает: HTTPСоединение и HTTPЗапрос — мы обращаемся к чужому адресу, получаем ответ, разбираем.

1С отвечает: HTTP-сервис в конфигурации — чужая система обращается к нам, а мы отдаём данные. Старший брат — веб-сервис (SOAP), он строже и многословнее; новое пишут на HTTP-сервисах.

Запрос к чужому сервису

Соединение = Новый HTTPСоединение("api.example.ru", , , , , 30,
	Новый ЗащищённоеСоединениеOpenSSL);

Запрос = Новый HTTPЗапрос("/v1/orders");
Запрос.Заголовки.Вставить("Content-Type", "application/json");
Запрос.УстановитьТелоИзСтроки(Тело, КодировкаТекста.UTF8);

Ответ = Соединение.ОтправитьДляОбработки(Запрос);
Если Ответ.КодСостояния <> 200 Тогда
	// разбираем ошибку, а не делаем вид, что её нет
КонецЕсли;
ЧастьЧто означает
30таймаут в секундах: без него чужой сервер может держать нас сколько угодно
ЗащищённоеСоединениеOpenSSLдля https обязательно — без этого соединение просто не встанет
КодировкаТекста.UTF8указывается явно; «кракозябры» на той стороне почти всегда отсюда
КодСостоянияответ 500 — это тоже ответ: исключения не будет, проверять надо самому

Коллизии: обе базы поправили одно и то же

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

Универсального ответа нет, есть три рабочих подхода.

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

Разделение по владению. Каждый объект принадлежит одной базе: своя нумерация, свой префикс, чужое только читают. Коллизия тогда невозможна по построению — это лучший вариант, если его удаётся заложить сразу.

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

Чего делать нельзя — молча применять последнее пришедшее. Это работает ровно до первого спорного документа, и обнаружится расхождение при сверке через полгода.

Префикс базы решает половину проблем

Приём, который стоит одну настройку и снимает целый класс бед: у каждой базы свой префикс номеров. Документы торговли — ТД-000012, документы бухгалтерии — БУ-000012.

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

Повторы и двойные заказы

Сеть ненадёжна, и главное следствие этого: ответ может не дойти, хотя операция прошла. Отправили заказ, ответа не дождались, отправили ещё раз — и заказов стало два.

Лечится это не «повторять аккуратнее», а тем, что каждая операция получает свой ключ: номер документа, уникальный идентификатор. Принимающая сторона по этому ключу узнаёт повтор и не создаёт второй объект.

Тот же приём работает и внутри 1С при обмене между базами: узел ищет объект по идентификатору, а не создаёт новый.

Отдать данные наружу

До сих пор 1С была той стороной, которая спрашивает. Бывает и наоборот: сайт или мобильное приложение хочет спросить у 1С. Способов три, и выбирают между ними по объёму работы.

HTTP-сервис — вы описываете адреса и сами пишете, что на них отвечать. Полный контроль над тем, что уходит наружу, и никакой лишней информации. Так делают, когда нужно отдать своё и в своём формате.

OData — платформа отдаёт справочники и документы сама, без единой строки кода: включили в настройках, разрешили состав. Быстро, но наружу уезжает структура базы как она есть, и менять её потом больно — на той стороне на неё уже опираются.

Web-сервис (SOAP) — старый способ, встречается в обмене с государственными системами и крупными заказчиками, потому что там он уже был.

Что общего у всех трёх: их надо закрывать. Это вход в базу снаружи, и права у пользователя, под которым работает сервис, должны быть ровно те, что нужны, — отдельная учётная запись с узкой ролью, а не «Полные права, чтобы точно заработало».

Чем отдавать данные наружу

СпособСколько работыКогда подходит
HTTP-сервиспишете обработчики самисвой формат, узкий набор данных, контроль над ответом
ODataвключается настройкойбыстро отдать типовые данные внутренней системе
Web-сервис (SOAP)описываете операции и типына той стороне уже ждут именно SOAP
Файл по расписаниюрегламентное заданиенет постоянной связи или объём большой

Форматы: XML, JSON и EnterpriseData

XML — родной для 1С: ЗаписьXML, ЧтениеXML, сериализация объектов через СериализаторXDTO. Так устроен обмен по планам обмена.

JSON — то, на чём говорит остальной мир. ЗаписатьJSON, ПрочитатьJSON, а результат ложится в соответствия и массивы — знакомые коллекции.

EnterpriseData — общий формат 1С для обмена между РАЗНЫМИ конфигурациями. Его смысл в том, что отправитель и получатель не знают структуру друг друга: оба знают формат.

Обмен обязан переживать сбой

Это правило дороже всех остальных в главе, и нарушают его чаще всего.

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

Что из этого следует на практике.

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

Пометки снимают только после подтверждения. Сняли раньше — при сбое порция потеряется навсегда, и никто не заметит: ошибки-то не было.

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

Всё пишется в журнал. Что ушло, что пришло, что не сошлось. Обмен — единственное место, где «работает молча» хуже, чем «ругается».

Пустой файл — тоже результат

Частая ошибка: загрузка получает пустой или обрезанный файл и молча заканчивается успехом. Порция ведь обработана.

Проверять надо не только «файл прочитался», но и «в нём было то, чего мы ждали»: есть заголовок сообщения, номер больше предыдущего, узел-отправитель тот самый.

Файл, не прошедший проверку, не загружают и не удаляют — откладывают и сообщают. Удалённый непонятный файл разбирать уже нечем.

Чего в обмене не хватает чаще всего

Журнала. Обмен, который не записывает, что и когда отправил, невозможно разобрать: «у нас нет заказа» — и проверить нечем.

Признака «обработано». Без него после сбоя непонятно, с какого места продолжать.

Обработки отказа. Чужая система ответила ошибкой — это нормальная ситуация, а не исключение: её надо показать человеку и дать повторить.

На чём спотыкаются

Ходят в чужую систему из проведения документа. HTTP-запрос внутри транзакции держит блокировки всё время ожидания ответа. Чужая система задумалась на тридцать секунд — ваша база стоит. Интеграции место в фоновом задании.

Не обрабатывают повтор. Сеть оборвалась после отправки, но до ответа — отправят снова. Приёмник обязан узнать повторное сообщение и не создать второй документ.

Доверяют присланным данным. Всё, что пришло снаружи, проверяют: тип, обязательность, осмысленность. Чужая система однажды пришлёт минус в количестве.

Не ведут журнал обмена. «Документ не дошёл» без журнала выясняется днями.

Упражнение 1. Повтор не создаёт второй документ

Функция НужноСоздавать(ВнешнийКлюч, УжеЕсть) отвечает, создавать ли документ по пришедшему сообщению. УжеЕсть — признак того, что документ с таким внешним ключом уже создан. Пустой ключ — тоже не создавать: без ключа повтор потом не опознать.

Решается в тренажёре: код запускается и проверяется сразу.

Короткий свод

Обе стороны 1С — план обмена: регистрация изменений, порции, подтверждение по номеру сообщения. Чужая система — HTTP-сервис или запрос наружу. Объекты сопоставляют по идентификатору или естественному ключу: ошибка здесь даёт дубли. Интеграции не место в транзакции проведения — только фоновое задание. Повтор обязан быть узнан, присланное — проверено, обмен — записан в журнал.

Как закрепить

Читать про код и писать код — разные умения. В тренажёре к этой главе идут упражнения: вы пишете решение, оно запускается на настоящем интерпретаторе 1С и проверяется сразу, без установки платформы.

Открыть эту главу в тренажёре

Обработки и отчёты: внешние и встроенные
Таблица значений