1C-Code → Основы 1С → Обмен данными и интеграции
Как базы разговаривают между собой и с чужими системами. Планы обмена, форматы и правило, которое дороже всех остальных: обмен обязан переживать сбой.
Глава 33 из 36 · чтение примерно 24 минут
База редко живёт одна. Торговля отдаёт документы в бухгалтерию, сайт присылает заказы, банк — выписку, маркетплейс — остатки.
Механизмов для этого несколько, и выбор между ними определяется одним вопросом: обе стороны — 1С или нет.
| Механизм | Когда берут |
|---|---|
| План обмена | обе стороны 1С: регистрация изменений и порционная выгрузка |
| EnterpriseData | обе стороны 1С, но конфигурации разные |
| HTTP-сервис | чужая система зовёт нас |
| Внешний HTTP-запрос | мы зовём чужую систему |
| Web-сервис (SOAP) | старые интеграции, обмен с корпоративными системами |
| Файл: CSV, JSON, XML | простой односторонний обмен, выгрузка по расписанию |
Наивный обмен выглядит так: выгрузить всё и загрузить всё. Работает на сотне документов и умирает на сотне тысяч.
План обмена решает это регистрацией изменений. В нём перечислены узлы — другие базы — и состав: какие объекты обмениваются. Когда объект меняется, платформа сама помечает: «для узла Б этот документ изменился».
Выгрузка берёт только помеченное. Получив подтверждение, что порция принята, снимает пометки.
Почему подтверждение обязательно
Если снимать регистрацию сразу после выгрузки, любой сбой на той стороне означает потерю: изменения уже «отправлены», а на деле не дошли. И узнать об этом нельзя — пометок больше нет.
Поэтому в обмене есть номера сообщений: сторона Б сообщает, какое сообщение она приняла, и только тогда сторона А снимает регистрацию по этот номер.
Это тот случай, когда механизм кажется переусложнённым ровно до первого сбоя.
Узел плана обмена — это другая база в терминах вашей. Один из узлов особенный: он обозначает вас самих, и берут его через ПланыОбмена.Имя.ЭтотУзел().
У каждого узла есть код и наименование, и код здесь не украшение: по нему стороны друг друга и находят. Завели в двух базах узлы с несовпадающими кодами — обмен пойдёт в пустоту и ошибки не покажет.
В состав плана обмена входят те объекты, которые обмениваются. И у каждого есть настройка авторегистрации: включена — платформа помечает изменения сама; выключена — помечать обязан ваш код. Второе выбирают, когда уезжать должны не все объекты, а только подходящие под условие.
Забытая авторегистрация даёт самую тихую поломку обмена: всё настроено, обмен идёт, ошибок нет — и ничего не уезжает, потому что регистрировать изменения некому.
Запись = Новый ЗаписьXML;
Запись.ОткрытьФайл(ИмяФайла);
// Заголовок сообщения: кто, кому и какой номер
ЗаписьСообщения = ПланыОбмена.СоздатьЗаписьСообщения();
ЗаписьСообщения.НачатьЗапись(Запись, Узел);
// Только то, что для этого узла изменилось
Выборка = ПланыОбмена.ВыбратьИзменения(Узел, ЗаписьСообщения.НомерСообщения);
Пока Выборка.Следующий() Цикл
СериализаторXDTO.ЗаписатьXML(Запись, Выборка.Получить());
КонецЦикла;
ЗаписьСообщения.ЗакончитьЗапись();
Запись.Закрыть();
| Часть | Что означает |
|---|---|
ЭтотУзел и Узел | первый — вы, второй — та база, которой пишете |
НомерСообщения | растёт с каждой порцией; по нему получатель понимает, не пришло ли старое |
ВыбратьИзменения | берёт ТОЛЬКО помеченное для этого узла — в этом весь смысл плана обмена |
Выборка.Получить() | отдаёт сам объект; удалённые приезжают как УдалениеОбъекта |
ОбменДанными.Загрузка — самый важный флаг обмена
При загрузке объект записывают с флагом Объект.ОбменДанными.Загрузка = Истина. Он отключает проверку заполнения, проведение и ваш код в модуле объекта.
Это не «чтобы быстрее». Это единственный способ получить в приёмнике то же самое, что в источнике. Иначе ваш ПередЗаписью пересчитает сумму по своим правилам, и базы разойдутся — а разойдутся они тихо, цифрами.
Обратная сторона: если в модуле объекта есть код, который обязан отработать и при загрузке, его придётся звать явно. И наоборот — весь код модуля объекта надо писать так, чтобы он умел ничего не делать при загрузке: Если ОбменДанными.Загрузка Тогда Возврат; КонецЕсли; первой строкой — стандартная заготовка типовых.
Ссылка в 1С — это внутренний идентификатор. У одного и того же контрагента в двух базах идентификаторы разные.
Поэтому при обмене объекты сопоставляют: по уникальному идентификатору (если базы родственные и он общий), либо по естественному ключу — ИНН, коду, артикулу, номеру и дате.
Ошибка сопоставления даёт самый неприятный вид поломки: дубли. Один контрагент превращается в двух, документы расходятся между ними, и разбирать это придётся руками.
План обмена — это про две базы 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 — родной для 1С: ЗаписьXML, ЧтениеXML, сериализация объектов через СериализаторXDTO. Так устроен обмен по планам обмена.
JSON — то, на чём говорит остальной мир. ЗаписатьJSON, ПрочитатьJSON, а результат ложится в соответствия и массивы — знакомые коллекции.
EnterpriseData — общий формат 1С для обмена между РАЗНЫМИ конфигурациями. Его смысл в том, что отправитель и получатель не знают структуру друг друга: оба знают формат.
Это правило дороже всех остальных в главе, и нарушают его чаще всего.
Связь оборвётся посреди порции. Сервер на той стороне перезагрузится. Задание упадёт по таймауту. Это не редкость, а нормальная жизнь обмена, и код должен быть написан в расчёте на неё.
Что из этого следует на практике.
Повторный запуск не должен ломать данные. Запустили загрузку второй раз на том же файле — должно получиться то же самое, а не дубли. Это и есть поиск объекта по идентификатору вместо создания нового.
Пометки снимают только после подтверждения. Сняли раньше — при сбое порция потеряется навсегда, и никто не заметит: ошибки-то не было.
Порции должны быть небольшими. Выгрузка на сто тысяч объектов одним куском падает по памяти и начинается заново. Десять порций по десять тысяч переживают сбой девятой.
Всё пишется в журнал. Что ушло, что пришло, что не сошлось. Обмен — единственное место, где «работает молча» хуже, чем «ругается».
Пустой файл — тоже результат
Частая ошибка: загрузка получает пустой или обрезанный файл и молча заканчивается успехом. Порция ведь обработана.
Проверять надо не только «файл прочитался», но и «в нём было то, чего мы ждали»: есть заголовок сообщения, номер больше предыдущего, узел-отправитель тот самый.
Файл, не прошедший проверку, не загружают и не удаляют — откладывают и сообщают. Удалённый непонятный файл разбирать уже нечем.
Чего в обмене не хватает чаще всего
Журнала. Обмен, который не записывает, что и когда отправил, невозможно разобрать: «у нас нет заказа» — и проверить нечем.
Признака «обработано». Без него после сбоя непонятно, с какого места продолжать.
Обработки отказа. Чужая система ответила ошибкой — это нормальная ситуация, а не исключение: её надо показать человеку и дать повторить.
На чём спотыкаются
Ходят в чужую систему из проведения документа. HTTP-запрос внутри транзакции держит блокировки всё время ожидания ответа. Чужая система задумалась на тридцать секунд — ваша база стоит. Интеграции место в фоновом задании.
Не обрабатывают повтор. Сеть оборвалась после отправки, но до ответа — отправят снова. Приёмник обязан узнать повторное сообщение и не создать второй документ.
Доверяют присланным данным. Всё, что пришло снаружи, проверяют: тип, обязательность, осмысленность. Чужая система однажды пришлёт минус в количестве.
Не ведут журнал обмена. «Документ не дошёл» без журнала выясняется днями.
Упражнение 1. Повтор не создаёт второй документ
Функция НужноСоздавать(ВнешнийКлюч, УжеЕсть) отвечает, создавать ли документ по пришедшему сообщению. УжеЕсть — признак того, что документ с таким внешним ключом уже создан. Пустой ключ — тоже не создавать: без ключа повтор потом не опознать.
Решается в тренажёре: код запускается и проверяется сразу.
Обе стороны 1С — план обмена: регистрация изменений, порции, подтверждение по номеру сообщения. Чужая система — HTTP-сервис или запрос наружу. Объекты сопоставляют по идентификатору или естественному ключу: ошибка здесь даёт дубли. Интеграции не место в транзакции проведения — только фоновое задание. Повтор обязан быть узнан, присланное — проверено, обмен — записан в журнал.
Читать про код и писать код — разные умения. В тренажёре к этой главе идут упражнения: вы пишете решение, оно запускается на настоящем интерпретаторе 1С и проверяется сразу, без установки платформы.
← Обработки и отчёты: внешние и встроенные
→ Таблица значений