Описание ecos-edi-ftps-lib =========================== .. contents:: :depth: 4 1. Цель либы ------------- Либа создана для обмена EDI-сообщениями с контрагентами через какой-то FTP-сервер. Общий принцип работы: Контрагент кладет в определенную папку сообщение, либа при активированной синхронизации раз в какое-то время производит рекурсивный обход по папкам на сервере и находит новые документы (подробнее в п.4). Отправка сообщений контрагенту происходит наоборот: В специальную папку либа кладет EDI-сообщение и когда то в будущем контрагент его заберет (подробнее в п.3). 2. Настройка интеграции -------------------------- Для настройки, как и для любой интеграции ЭДО - необходимо создать **ecos-credentials**, **ecos-data-sources**, **edi-box** и **ecos-sync** сущности. 2.1. Создание ecos-credentials сущности ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Тут все стандартно, создаем через журнал **ecos-credentials** запись, в которой указываем логин и пароль для подключения к FTP-серверу. 2.2. Создание ecos-data-sources сущности ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Создавать необходимо сущность **"FTP Data source"**. Поля **id** и **name** не важны. .. image:: _static/ecos-edi-ftps-lib/ecos-edi-ftps-lib_1.png :width: 400 :align: center Важны **host**, **port** и **protocol**, где: - ``host`` - путь к серверу. В моем случае - локальный хост. - ``port`` - порт по которому ходим к серверу. Стандарт обычно 21. - ``protocol`` - на данный момент поддерживается FTP или FTPS. 2.3. Создание edi-box сущности ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Создаем сущность **"FTP box"**. .. image:: _static/ecos-edi-ftps-lib/ecos-edi-ftps-lib_2.png :width: 600 :align: center Самая основная часть конфигурации именно тут. Тут существует 3 раздела. В верхнем разделе: - ``id`` - указываем любой (или оставляем пустым и оно само сгенерится при создании). - ``name`` - любое человеко-читаемое название для этого ящика. - ``URL``- указываем созданный в 2.2 датасорс. - ``Credentials`` - указываем созданные в 2.1 креды. В разделе **Box configuration** - заполняем идентификатор номером GLN организации, от имени которой происходит разбор EDI-сообщений. Раздел **Other**: - ``Outbound documents folder path template`` - шаблон пути, по которому будут отправляться исходящие сообщения. Подробнее в п.3. - ``Inbound documents folder path template`` - шаблон пути, по которому будут получаться входящие сообщения. Подробнее в п.4. - ``Search documents in subdirectories`` - чекбокс с говорящим названием, который означает, что мы должны искать документы не только в папке полностью соответствующей конфигу выше, но и в поддиректориях. - ``Inbound processing policy`` - выбор из вариантов обработки входящих сообщений. Существует 2 варианта - ``MOVE_AFTER_PROCESSING`` и ``DELETE_ON_SUCCESS``. Подробнее в п.4. - ``Inbound documents success folder path template`` - (используется только при ``MOVE_AFTER_PROCESSING``) - папка куда складываются документы, которые были успешно обработаны. - ``Inbound documents error folder path template`` - (используется только при ``MOVE_AFTER_PROCESSING``) - папка, куда складываются документы, в результате обработки которых получили ошибку. 2.4. Создание ecos-sync сущности ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Ничем не отличается от остальных интеграций, можно посмотреть в общей статье: :ref:`Настройка получения событий с ящиком Контур_Диадок` Указывать, конечно, сущность **edi-box** из п.2.3. 3. Принципы работы при отправке сообщений ----------------------------------------- Вся либа построена на том, что мы указываем относительные пути в конфигурации. Переменные для подстановки приходят из структуры **EdiXmlRequest** из либы ``ecos-edi-commons`` `Описание работы интеграции :ref:` Эта структура состоит из следующих полей: .. code-block:: private OurId ourId; private CounterpartyId counterpartyId; private EdiXml ediXml; private ObjectData data; где: - ``ourId`` маппится для подстановки в виде ``ourId.key_from_attributes`` (``OurId`` состоит из **ObjectData**. Это означает, что если в **ObjectData** находится 2 значения с ключами ``key1`` и ``key2``, то в шаблоне можем использовать значения по следующим ключам: ``ourId.key1`` и vourId.key2``). - ``counterpartyId`` маппится для подстановки в виде ``counterpartyId.key_from_attributes`` (аналогично ourId). - ``ediXml`` маппится всего в 2 значения: ``document.type``, где могут быть значения ORDERS, ORDRSP, DESADV, RECADV, etc и в document.lowerType, где могут быть значения orders, ordrsp, desadv, recadv, etc. - ``data`` - полностью маппится в виде addInfo.key. Для заполнения ``data`` - можно на проектах расширить интерфейс ``FtpCustomAddInfoProvider`` и зарегистрировать его в бине ``FtpCustomAddInfoProviderRegistry``. Таким образом, можно на любом проекте кастомную логику по определению путей сделать. Пример шаблонов: .. code-block:: /${addInfo.counterparty.esk}_S4TEST/OUTBOUND/${document.type} Это означает, что если в структуре data содержится значение 123456 по ключу ``counterparty.esk`` и ``ediXml.ediDocumentType`` содержит значение ORDERS, то данное сообщение отправится в следующую папку: .. code-block:: /123456_S4TEST/OUTBOUND/ORDERS/ Можно вовсе не использовать шаблоны, тогда все документы будут попадать в любую папку. Например, шаблон: .. code-block:: /${addInfo.path} Разработать реализацию ``FtpCustomAddInfoProvider``, которая бы возвращала переменную ``path``. Например, если она будет равна ``some/path/type/kind/outbound``, то путь будет следующим: .. code-block:: /some/path/type/kind/outbound Для шаблонизации пути используется компонент ``StringSubstitutor`` из библиотеки commons-text от Apache с небольшой модернизацией. Подробнее можно ознакомиться в тестах к либе. Отправить сообщение можно с помощью интерфейса **EdiService**, передав ему ``EdiProviderType.FTP``. Доступные методы: - ``generateEdiXml`` - доступен, но пока что реализованных генераторов не имеет ввиду ненадобности. Можно расширять список генераторов в рамках бандла ``ecos-edi-ftps-lib`` или других, если появится такая необходимость. - ``sendEdiXml`` - отправка сообщения, данные которого сериализованы в ``EdiXmlRequest`` на FTP-сервер. Сервис **EdiService** доступен из микросервиса **integrations-app**. 4. Принципы работы при получении сообщений ------------------------------------------- Для получения сообщений мы проходим через 3 фазы: 1. Ищем сообщения. 2. Обрабатываем сообщения. 3. Фиксируем, что сообщение обработано. 4.1. Обход в поиске сообщений ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Для поиска документов - используется рекурсивный обход по папкам. Алгоритм не забирает все документы разом и отправляет их на обработку, а запоминает место последнего найденного документа, отправляет на обработку и позже возобновляет обход с той же точки. Реализовано это в виде итератора ``FtpWalkIterator``. Итератору скармливаются параметры ``Inbound documents folder path template`` (далее - шаблон поиска входящих) и Search documents in subdirectories (флаг поиска в поддиректориях), которые описаны в п.2.3. Шаблон поиска входящих разбивается на уровни по папкам. То есть, например, шаблон ``/${addInfo.counterparty.esk}_S4TEST/INBOUND/${document.type}`` разобьется на 4 части: .. code-block:: / /${addInfo.counterparty.esk}_S4TEST /${addInfo.counterparty.esk}_S4TEST/INBOUND /${addInfo.counterparty.esk}_S4TEST/INBOUND/${document.type} После этого, части будут преобразованы в корректные регулярные выражения. То есть, эти части будут иметь теперь следующие значения: .. code-block:: / /(?[\\w\\s-]+)_S4TEST /(?[\\w\\s-]+)_S4TEST/INBOUND /(?[\\w\\s-]+)_S4TEST/INBOUND/(?ORDERS|ORDRSP|DESADV|RECADV) Обратите внимание, замена происходит не просто на регулярки, а создаются группы для того чтоб потом вынуть эти значения для создания события Event (внутри на самом деле еще заменяются точки на A1B2C3 строки, но это опустим, чтобы не ухудшать читаемость). Так же, обратите внимание, document.type и document.lowerType преобразуются в конкретные значения enum, а остальные переменные - в регулярки из букв, цифр, пустых символов или символа “-”. Если включен флаг поиска в поддиректориях - к последнему регулярному выражению добавляется “.*“. Таким образом становится возможным поиск по подпапкам. Так же, есть возможность указывать не стандартную регулярку, а свою. Пример - .. code-block:: /${addInfo.counterparty.esk(\d+)}_S4TEST/INBOUND/${document.type} Алгоритм обхода: Итератор внутри себя содержит очередь. В эту очередь вносятся файлы или папки, которые нужно будет в будущем посмотреть и проверить на предмет файлов, соответствующих регуляркам. 0. Инициализируем итератор, загрузив в очередь файлы из папки “/” (из рута). Этот шаг выполняется только 1 раз. 1. Берем из очереди следующий элемент. 2. Определяем его уровень (по количеству символов “/“). Берем соответствующий этому уровню regexp (или последний, если уровень больше чем есть regexp'ов). 3. Проверяем совпадение по regexp. 3.1. Если совпадает - смотрим, папка это или файл. Если папка - выбираем из нее список файлов и ложим в начало очереди для дальнейшего разбора, переходим на пункт 1. Если файл (для файлов проверяем только на соответствие последнему регулярному выражению) - отправляем его на обработку. 3.2. Не совпадает - выбрасываем элемент из очереди. Переходим на пункт 1. 4.2. Обработка сообщения ~~~~~~~~~~~~~~~~~~~~~~~~~ Этот шаг состоит из 2х пунктов: - Наполнения **Event** (Что такое Event в интеграции - можно почитать тут :ref:`Описание работы интеграции`. Как уже написано выше, необходимо запомнить группы из regexp. Сделано это для того, чтобы передать по тем же ключам значения в структуру **Event**. То есть, для шаблона поиска входящих ``/${addInfo.counterparty.esk}_S4TEST/OUTBOUND/${document.type}`` - в структуру **Event** пробросятся значения из пути сообщения на FTP-сервере. - Дальше, созданный **Event** отправляется в **EdiStateService** (:ref:`Описание работы интеграции`) для обработки дальше системой силами роутов Camel. 4.3. Фиксация обработанного сообщения ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ После успешной (или не успешной) обработки сообщения - необходимо зафиксировать, что сообщение было обработано. Происходит это за счет выбранной политики, переданной через конфигурацию Inbound processing policy (см. п.2.3). 4.3.1. Политика MOVE_AFTER_PROCESSING """""""""""""""""""""""""""""""""""""" В случае успеха - перемещаем файл в папку, которая указана в конфигурации ``Inbound documents success folder path template`` (см. п.2.3). В случае провала - перемещаем файл в папку, которая указана в конфигурации ``Inbound documents error folder path template`` (см. п.2.3). Обратите внимание, оба этих параметра являются шаблонами. В шаблонах можно использовать переменные, которые участвуют в шаблоне поиска входящих (пример можно посмотреть на скриншоте в п.2.3). 4.3.2. Политика DELETE_ON_SUCCESS """""""""""""""""""""""""""""""""""" В случае успешно обработанного события - файл удаляется с FTP-сервера. В случае провала - ничего не происходит.