7496aafe64
- Bloquants: mermaid 03-picking/_index reconstitue (archive 11-05), 13 liens vers pages squelette retires, 2 liens recibles (anoxie, application-dictionary) - Conventions: 910 em dashes -> tirets simples, 145 checklists -> puces question, 13 questions resolues barrees - Liens: 9 ancres reparees (slugs GitHub) - Delta: 12 standard_ref remappes, blocs Standard EasyWMS + sections References ajoutes, front matter complete - Glossaire: 15 termes standard deplaces en section rappel avec renvoi - Rapport: limagrain/_lint_report.md (Phase 1 + Phase 2 + re-scan final) - Inclut les pages des sessions precedentes non commitees + CLAUDE.md et consume.log en l'etat
297 lines
13 KiB
Markdown
297 lines
13 KiB
Markdown
---
|
|
title: "Intégration GNA → SAP-CPI"
|
|
tags: [ERP, GNA, SAP-CPI, OAuth, middleware, API, BOO]
|
|
status: review
|
|
standard_ref: concepts/erp-interface.md
|
|
jira_refs: [LIM-89]
|
|
confluence_refs: []
|
|
sources:
|
|
|
|
- "LIM-89 GNA Mise en place de la communication API EasyWMS SAP CPI.md"
|
|
- "recap_session_LIM-72_13-05-2026.md"
|
|
- "Jira LIM-89 (lecture directe, revue de code validée 2026-05-21)"
|
|
last_updated: 2026-07-17
|
|
author: Arthur
|
|
---
|
|
|
|
# Intégration GNA → SAP-CPI
|
|
|
|
> **Résumé** : mise en place de la communication entre le GNA (middleware
|
|
> EasyWMS) et SAP-CPI (middleware cloud SAP) pour l'envoi de tous les
|
|
> messages WMS sortants. Authentification OAuth 2.0 client_credentials,
|
|
> endpoint unique, routage par MessageType.
|
|
|
|
> **Standard EasyWMS** : → voir [ERP Integration](../../concepts/erp-interface.md)
|
|
> L'intégration standard cible généralement un ERP via API REST classique
|
|
> (OAuth password grant). Chez Limagrain, la cible est **SAP-CPI** avec
|
|
> un mécanisme spécifique.
|
|
|
|
> Voir aussi : [LOC - Message périodique](loc-message-periodique.md),
|
|
> [Référence messages](messages-reference.md),
|
|
> [Mapping ERP-WMS](mapping-erp-wms.md)
|
|
|
|
## Contexte projet
|
|
|
|
Dans le cadre du projet Limagrain, le middleware GNA doit envoyer les
|
|
messages WMS vers SAP via la plateforme **SAP-CPI** (Cloud Platform
|
|
Integration). Une implémentation de référence existe chez un autre client
|
|
(AD) mais communique avec un ERP SAP-AIG via une API REST classique
|
|
(OAuth password grant).
|
|
|
|
L'intégration Limagrain est différente : elle cible **SAP-CPI** avec un
|
|
**endpoint unique** et une authentification **OAuth 2.0 client_credentials**.
|
|
|
|
## Architecture technique
|
|
|
|
### Script principal
|
|
|
|
Le script `CommonExportWebApi.boo` est le point d'entrée pour tous les
|
|
exports WMS → SAP-CPI. Il gère l'authentification, le formatage et
|
|
l'envoi des messages.
|
|
|
|
Structure (revue de code LIM-89) :
|
|
|
|
| Élément | Rôle |
|
|
|---|---|
|
|
| `CheckConnection()` | Authentification OAuth 2.0 client_credentials. Retry backoff exponentiel **4 tentatives (2s/4s/8s)**. Token persisté en JSON sur disque, gestion d'expiration (marge 60s). Arrêt immédiat sur 401 |
|
|
| `SendWebApiMessage` | Envoi POST vers l'endpoint unique. Détermination du `MessageSAP` puis construction du body. Retry backoff **5 tentatives (2s/4s/8s/16s)**. Token relu depuis le cache à chaque envoi |
|
|
| `CpiTokenResponse` | Désérialisation de la réponse OAuth (`access_token`, `token_type`, `expires_in`) |
|
|
| `CpiTokenCache` | Cache token JSON sur disque (`AccessToken`, `ExpiresAtUtc`) |
|
|
| `ReadWebApiFile`, `GenerateWebApiError`, `RegisterObservers` | Inchangés (template Mecalux standard) |
|
|
|
|
### Flux de communication
|
|
|
|
```mermaid
|
|
sequenceDiagram
|
|
participant WMS as EasyWMS
|
|
participant GNA as GNA (BOO)
|
|
participant OAuth as SAP OAuth Server
|
|
participant CPI as SAP-CPI
|
|
|
|
WMS->>GNA: Transaction WMS (LOC.SEND, REF01, etc.)
|
|
GNA->>GNA: Vérifier cache token
|
|
alt Token expiré ou absent
|
|
GNA->>OAuth: POST /oauth/token (client_credentials)
|
|
OAuth-->>GNA: Bearer token + expiration
|
|
GNA->>GNA: Sauvegarder token sur disque
|
|
end
|
|
GNA->>CPI: POST /http/ATHInboundMessage
|
|
Note right of CPI: Body: {MessageType, MessageSAP, data}
|
|
CPI-->>GNA: HTTP 200 / erreur
|
|
alt Erreur HTTP (hors 401)
|
|
GNA->>CPI: Retry backoff (2s, 4s, 8s, 16s)
|
|
end
|
|
alt HTTP 401
|
|
GNA->>GNA: Échec immédiat (token invalide)
|
|
end
|
|
```
|
|
|
|
## Authentification OAuth 2.0
|
|
|
|
### Mécanisme
|
|
|
|
1. Le GNA obtient un **token bearer** auprès du serveur SAP via un POST
|
|
sur `/oauth/token` avec `client_id` et `client_secret`
|
|
2. Le grant type est `client_credentials` (pas de password grant)
|
|
3. Le token est **mis en cache sur disque** (fichier JSON) avec gestion
|
|
de l'expiration (marge de sécurité de 60 secondes)
|
|
4. À chaque envoi, le GNA vérifie le cache : si le token est encore valide,
|
|
il le réutilise ; sinon il en demande un nouveau
|
|
|
|
## Envoi des messages - Format du body
|
|
|
|
Pour chaque message WMS exporté, le GNA envoie un POST vers l'endpoint
|
|
unique SAP-CPI `/http/ATHInboundMessage` avec le body JSON suivant :
|
|
|
|
```json
|
|
{
|
|
"MessageType": "<type_message_WMS>",
|
|
"MessageSAP": "<code_CPI>",
|
|
"data": "<contenu_message>"
|
|
}
|
|
```
|
|
|
|
Le champ `MessageType` permet au iFlow CPI de **router le message** vers
|
|
le bon traitement SAP.
|
|
|
|
## Table de correspondance MessageType → MessageSAP
|
|
|
|
Le champ `MessageSAP` est déterminé par une table de correspondance entre
|
|
le préfixe du MessageType WMS (3 premiers caractères) et le code SAP-CPI :
|
|
|
|
| Code CPI | Équivalent WMS | Description |
|
|
|----------|----------------|-------------|
|
|
| ATH214 | Check flux retour (BAPI) | Vérification lot retour client |
|
|
| ATH215 | REF (type = Retour) | Finalisation réception retour |
|
|
| ATH217 | REF (type = Supplier) **ou ROF** | Finalisation réception fournisseur / clôture OE |
|
|
| ATH201 | LOC | Message périodique delta mouvements |
|
|
| ATH202 | LOF | Finalisation chargement |
|
|
|
|
> ⚠️ **Correction (revue de code LIM-89, 2026-05-21)** : le sens
|
|
> `REF Retour → ATH215` / `REF Supplier → ATH217` retenu ici est celui
|
|
> de la table de l'intégrateur ERP et de l'implémentation. Une version
|
|
> antérieure de cette page inversait les deux codes. `ROF` est mappé sur
|
|
> `ATH217` (et non `ATH215` comme le suggérait la description initiale).
|
|
|
|
> ⚠️ Si un type de message n'a pas de correspondance dans la table, un
|
|
> **warning** est logué et le champ MessageSAP n'est pas inclus dans le
|
|
> body.
|
|
|
|
### Détermination conditionnelle du MessageSAP pour REF
|
|
|
|
Le message REF est routé vers **ATH215** (type Retour) ou **ATH217**
|
|
(type Supplier) selon le type de préavis de réception lié.
|
|
|
|
**Implémentation définitive (revue de code)** : la détermination se fait
|
|
**dans `CommonExportWebApi.boo`** (bloc `SendWebApiMessage`), via une
|
|
requête LINQ sur `Context.Receptions` en utilisant le `ReceiptCode`
|
|
extrait du payload JSON. Le préfixe 3 caractères du `MessageType`
|
|
(`REF01` → `REF`) sert au lookup dans le dictionnaire `messageSapMap` ;
|
|
pour REF, la logique conditionnelle sur le type de préavis choisit
|
|
ATH215 (Retour) ou ATH217 (Supplier).
|
|
|
|
- Type Retour → `ATH215`
|
|
- Type Supplier → `ATH217`
|
|
|
|
> **Note (reversal)** : la conception initiale prévoyait de porter le
|
|
> type via `RecCustomAttributes.CstAtt20` écrit par le `REF01Observer.boo`
|
|
> (requête sur `Context.RecLineInboundOrderLines` → `Context.InboundOrders`).
|
|
> Cette approche a été **abandonnée** : le type est désormais résolu
|
|
> directement dans `CommonExportWebApi.boo` via le `ReceiptCode`
|
|
> (`Context.Receptions`). `REF01Observer.boo` n'est donc pas modifié.
|
|
|
|
## Cartographie complète des interfaces Athenzat
|
|
|
|
Tous les flux entre SAP et EasyWMS sont identifiés par un code ATH.
|
|
Source : doc CPI Maxime Tourrette (24/04/2026) + mail S15 Justine.
|
|
|
|
### Flux SAP → EasyWMS (entrants)
|
|
|
|
| Code ATH | Type SAP | Type Easy | Description |
|
|
|----------|----------|-----------|-------------|
|
|
| ATH002 | BATMAS | ITM01 | Fiche article (Item) |
|
|
| ATH103A | DELIVRY07 | ROR01 | Ordre de réception (Inbound delivery) |
|
|
| ATH108 | ORDRSP | ROR01 | Ordre de réception retour (Return delivery) |
|
|
| ATH103B | SHPUNT7 | RUT | Ordre de sortie (Outbound delivery) |
|
|
| ATH102BOM | LOIPRO | SOR | Ordre d'expédition (Shipping order) |
|
|
| ATH111 | ZSTKATH11 | ASN / STR | HU à recevoir / HU change |
|
|
| ATH302 | ZQMINSPLOT | COR | Tâche inventaire / échantillon |
|
|
|
|
### Flux EasyWMS → SAP (sortants via CPI)
|
|
|
|
| Code ATH | Type Easy | Type SAP | Description |
|
|
|----------|-----------|----------|-------------|
|
|
| ATH214 | Z_IATH214 | Z_IAT214 | Check Batch (vérification lot retour) |
|
|
| ATH215 | REF (Retour) | Z_IAT215 | Bon de réception retour |
|
|
| ATH217 | REF (Supplier) / ROF | Z_IAT217 | Bon de réception fournisseur / clôture OE |
|
|
| ATH201 | LOC / STV | Z_IAT201 | Mouvement stock (rangement ASRS, mvt HU, prep mix, customer flag, stock adjust) |
|
|
| ATH202 | LOF | Z_IAT202 | Chargement (Loading / Goods Issue) |
|
|
|
|
> **Note** : les flux ATH103A/B, ATH108, ATH111, ATH302 utilisent
|
|
> l'infrastructure GNA standard (pas de custom CPI côté EasyWMS).
|
|
> Seuls les flux sortants (ATH2xx) passent par `CommonExportWebApi.boo`.
|
|
|
|
> **Note** : le flux ATH214 est le seul appelé **directement depuis un
|
|
> workflow** (pas via GNA/BOO). Voir [Réception retour](../01-inbound/reception-retour.md).
|
|
|
|
## Gestion des erreurs - Retry avec backoff
|
|
|
|
| Situation | Comportement |
|
|
|-----------|-------------|
|
|
| HTTP 200 | Succès - message envoyé |
|
|
| HTTP 401 | **Échec immédiat** - token invalide, pas de retry |
|
|
| Autre erreur HTTP (auth) | **Retry backoff** : 4 tentatives (2s → 4s → 8s) |
|
|
| Autre erreur HTTP (envoi message) | **Retry backoff** : 5 tentatives (2s → 4s → 8s → 16s) |
|
|
|
|
## Configuration requise
|
|
|
|
Six clés `CPI_*` à ajouter dans `CommonAppSettings.config`
|
|
(section `appSettings`) :
|
|
|
|
| Clé | Description |
|
|
|-----|-------------|
|
|
| CPI_AUTH_URL | URL du serveur d'authentification SAP OAuth |
|
|
| CPI_CLIENT_ID | Identifiant OAuth |
|
|
| CPI_CLIENT_SECRET | Secret OAuth (**chiffré via `PasswordEncrypt.exe`**) |
|
|
| CPI_ENDPOINT_URL | Endpoint unique SAP-CPI (`/http/ATHInboundMessage`) |
|
|
| CPI_TOKEN_PATH | Chemin du fichier cache token sur disque |
|
|
| CPI_TIMEOUT | Timeout HTTP en secondes (auth + messages) |
|
|
|
|
**Valeurs environnement TEST** :
|
|
|
|
- `CPI_AUTH_URL` :
|
|
`https://vilm-cpi-test-73ltxp48.authentication.eu30.hana.ondemand.com/oauth/token`
|
|
- `CPI_ENDPOINT_URL` :
|
|
`https://vilm-cpi-test-73ltxp48.it-cpi020-rt.cfapps.eu30.hana.ondemand.com/http/ATHInboundMessage`
|
|
- Environnement PROD : URLs à définir
|
|
|
|
## Fichiers impactés
|
|
|
|
| Fichier | Modification |
|
|
|---------|-------------|
|
|
| `Scripts2015/CommonExportWebApi.boo` | Script principal d'export WMS → SAP-CPI (auth, MessageSAP, envoi) |
|
|
| `Configuration/LIMAGRAI2512/CommonAppSettings.config` | Ajout des 6 clés CPI_* (secret chiffré) |
|
|
| ~~`Scripts2015/EasyWMS/XML/REF01/REF01Observer.boo`~~ | Prévu initialement (CstAtt20) - **non retenu** : type REF résolu via `ReceiptCode` dans `CommonExportWebApi.boo` |
|
|
|
|
## Logging
|
|
|
|
Chaque étape (connexion, récupération token, envoi message) doit être
|
|
loguée avec les détails de la requête et de la réponse. Le body JSON
|
|
est logué en **format indenté** pour faciliter le debug.
|
|
|
|
> ⚠️ Le **token ne doit jamais être logué** (sécurité).
|
|
|
|
## Cas de tests
|
|
|
|
- ❓ Le GNA compile sans erreur
|
|
- ❓ L'authentification OAuth client_credentials fonctionne (HTTP 200)
|
|
- ❓ Le token est mis en cache sur disque et réutilisé tant qu'il est
|
|
valide
|
|
- ❓ Les messages WMS sont envoyés en POST avec le bon format JSON
|
|
- ❓ Le champ MessageSAP est présent avec la bonne valeur selon le type
|
|
- ❓ REF type Retour → MessageSAP = ATH215
|
|
- ❓ REF type Supplier → MessageSAP = ATH217
|
|
- ❓ REF type résolu via `ReceiptCode` (query `Context.Receptions`)
|
|
- ❓ Warning logué si MessageType sans correspondance
|
|
- ❓ Retry backoff fonctionne (hors 401)
|
|
- ❓ Logs détaillés et lisibles (JSON indenté, token masqué)
|
|
- ❓ HTTP 401 → échec immédiat sans retry
|
|
|
|
## Points d'attention
|
|
|
|
✅ Le **secret OAuth est chiffré** via `PasswordEncrypt.exe` dans le
|
|
fichier de configuration (résout la question initiale du secret en clair).
|
|
|
|
⚠️ La marge de 60 secondes sur l'expiration du token évite les races
|
|
conditions mais peut générer des re-authentifications prématurées sous
|
|
forte charge.
|
|
|
|
⚠️ Le backoff exponentiel plafonne à 16 secondes - si SAP-CPI est
|
|
durablement indisponible, les messages seront perdus (pas de file
|
|
d'attente persistante).
|
|
|
|
## Questions ouvertes
|
|
|
|
- ❓ Faut-il implémenter une file d'attente persistante pour les
|
|
messages en échec après 5 retries ? (@Nicolas)
|
|
- [x] ~~Le secret OAuth doit-il être chiffré dans le config ?~~
|
|
→ **Résolu** (revue de code) : oui, chiffré via `PasswordEncrypt.exe`
|
|
|
|
## Historique des modifications
|
|
|
|
| Date | Auteur | Modification |
|
|
|------|--------|--------------|
|
|
| 2026-05-12 | Arthur | Création depuis LIM-89 |
|
|
| 2026-05-13 | Arthur | Ajout cartographie ATH complète, URLs TEST, note ATH214 hors GNA |
|
|
| 2026-07-17 | Arthur | Delta revue de code : structure du script (CheckConnection/SendWebApiMessage/CpiTokenCache), retry auth 4 vs envoi 5, secret chiffré PasswordEncrypt.exe (question résolue) ; **correction du sens REF Retour→ATH215 / Supplier→ATH217 + ROF→ATH217** ; type REF résolu via ReceiptCode (REF01Observer/CstAtt20 abandonné) ; statut préprod |
|
|
|
|
## Références
|
|
|
|
| Source | Type | Date |
|
|
|--------|------|------|
|
|
| [LIM-89](https://easywmsfrance.atlassian.net/browse/LIM-89) | Ticket Jira (statut préprod / test client) | 2026 |
|
|
| Revue de code LIM-89 (Arthur, N. Chabanis) | Revue de code validée | 2026-05-21 |
|
|
| Table de correspondance intégrateur ERP | Commentaire LIM-89 | 2026-05-11 |
|
|
| Athenzat SAP-CPI Webservices Documentation v1.0 | PDF (Maxime Tourrette) | 2026-04-24 |
|
|
| Mail Justine S15 | Cartographie interfaces | 2026-04 |
|