màj wiki avec retour MES lot-5 AD
This commit is contained in:
@@ -0,0 +1,219 @@
|
||||
---
|
||||
title: "Intégration GNA → SAP-CPI"
|
||||
tags: [ERP, GNA, SAP-CPI, OAuth, middleware, API, BOO]
|
||||
status: draft
|
||||
standard_ref: architecture/erp-integration.md
|
||||
jira_refs: [LIM-89]
|
||||
confluence_refs: []
|
||||
sources:
|
||||
- "LIM-89 GNA Mise en place de la communication API EasyWMS SAP CPI.md"
|
||||
last_updated: 2026-05-12
|
||||
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](../../architecture/erp-integration.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.
|
||||
|
||||
### 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 (batch) | Vérification lot retour client |
|
||||
| ATH215 | REF (type = Supplier) | Finalisation réception fournisseur |
|
||||
| ATH217 | REF (type = Return) | Finalisation réception retour |
|
||||
| ATH201 | LOC | Message périodique delta mouvements |
|
||||
| ATH202 | LOF | Finalisation chargement |
|
||||
|
||||
> ⚠️ 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 peut être routé vers **ATH215** (Supplier) ou **ATH217**
|
||||
(Return) selon le type de préavis de réception (InboundOrder) lié :
|
||||
|
||||
1. Le **REF01Observer.boo** récupère le type de préavis via une requête
|
||||
LINQ sur `Context.RecLineInboundOrderLines` → `Context.InboundOrders`
|
||||
2. Le type est transmis dans le champ `RecCustomAttributes.CstAtt20` du
|
||||
message REF01
|
||||
3. Le script `CommonExportWebApi.boo` lit `CstAtt20` dans le payload JSON
|
||||
pour déterminer le `MessageSAP` :
|
||||
- Type Supplier → `ATH215`
|
||||
- Type Return → `ATH217`
|
||||
|
||||
## 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 | **Retry backoff exponentiel** : 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 (en clair dans le config) |
|
||||
| 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) |
|
||||
|
||||
## Fichiers impactés
|
||||
|
||||
| Fichier | Modification |
|
||||
|---------|-------------|
|
||||
| `Scripts2015/CommonExportWebApi.boo` | Script principal d'export WMS → SAP-CPI |
|
||||
| `Scripts2015/EasyWMS/XML/REF01/REF01Observer.boo` | Ajout requête InboundOrderType + écriture CstAtt20 |
|
||||
| `Configuration/LIMAGRAI2512/CommonAppSettings.config` | Ajout des 6 clés CPI_* |
|
||||
|
||||
## 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 Supplier → MessageSAP = ATH215
|
||||
- [ ] REF type Return → MessageSAP = ATH217
|
||||
- [ ] CstAtt20 renseigné dans le message REF01 par le REF01Observer
|
||||
- [ ] 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 en clair** dans le fichier de configuration —
|
||||
accès au fichier à restreindre.
|
||||
|
||||
⚠️ 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 4 retries ? (@Nicolas)
|
||||
- [ ] Le secret OAuth doit-il être chiffré dans le config ?
|
||||
(@Fabien)
|
||||
|
||||
## Historique des modifications
|
||||
|
||||
| Date | Auteur | Modification |
|
||||
|------|--------|--------------|
|
||||
| 2026-05-12 | Arthur | Création depuis LIM-89 |
|
||||
|
||||
## Références
|
||||
|
||||
| Source | Type | Date |
|
||||
|--------|------|------|
|
||||
| [LIM-89](https://easywmsfrance.atlassian.net/browse/LIM-89) | Ticket Jira | 2026 |
|
||||
Reference in New Issue
Block a user