Aller au contenu principal

Module Web-Orders

:::info Module UI — logique sur SRV-APPS Le module Laravel WebOrders de l'intranet est une interface utilisateur : les webhooks WooCommerce et le transfert SCP sont gérés par la Laravel API de SRV-APPS (192.168.1.17:8002), pas par l'intranet.

→ Architecture de SRV-APPS : Vue d'ensemble SRV-APPS
→ Référence API : API SRV-APPS :::

Rôle

Recevoir les commandes passées en ligne via les boutiques WooCommerce, les parser, les stocker en base, et les transférer vers le NAS ERP pour traitement par le système 4D.

Ce module est distinct de l'EDI Engine : il traite les commandes B2C et B2B en ligne (format XML WooCommerce), là où l'EDI Engine traite les commandes B2B fournisseurs (PDF, XLS, EDI).

Architecture

WooCommerce (boutique)

│ POST XML — User-Agent: WooCommerce/WordPress

Laravel API (/opt/medithau/api/)
POST /api/web-orders/webhook/{source}

├─ Validation User-Agent
├─ Validation XML bien formé
├─ Vérification token (dans le corps XML)
├─ WebOrder::create (status: received)
└─ dispatch TransferWebOrderJob


Queue "web-orders" (Laravel Horizon)


TransferWebOrderJob::handle()
├─ WebOrderParser::parse(xml) → parsed_data
├─ update (status: transferring)
├─ Écriture XML → /opt/medithau/web-orders/incoming/{source}/order_*.xml
├─ exec python transfer_web_order.py --source {source} --file {file}
│ └─ SCP → NAS ERP /volume1/DATAS/4DDocuments/WebOrders/{FTP|OFTP}/
└─ update (status: transferred | failed)

Deux sources de boutiques

SourceBoutiqueDossier NAS destination
mainBoutique principale/volume1/DATAS/4DDocuments/WebOrders/FTP/
ostrealiaBoutique Ostrealia/volume1/DATAS/4DDocuments/WebOrders/OFTP/

Modèle — table web_orders

ColonneTypeDescription
idUUID (PK)Identifiant unique
sourceenum(main, ostrealia)Boutique d'origine
filenamestring(100)Nom du fichier XML (order_{Ymd_His}_{hash8}.xml)
xml_contentlongTextCorps XML brut reçu du webhook
parsed_dataJSONDonnées parsées par WebOrderParser (voir ci-dessous)
statusenumCycle de vie (voir ci-dessous)
errorstring nullableMessage d'erreur (max 500 chars)
received_attimestampDate/heure de réception
transferred_attimestamp nullableDate/heure de transfert réussi

Pas de created_at / updated_at Laravel — $timestamps = false.

Cycle de statut

[*] → received
↓ (job démarré)
transferring
↓ SCP OK ↓ SCP échoué (3 tentatives)
transferred failed
↓ (POST /retry)
received (rejeu)

Services

WebOrderParser

App\Services\WebOrders\WebOrderParser::parse(string $xml): ?array

Parse le XML WooCommerce et retourne un tableau structuré ou null si le XML est invalide.

Structure de parsed_data :

parsed_data
├── order_number (NumCommandeweb)
├── order_date (datecommande)
├── delivery_date (Datedelivraison)
├── delivery_type (TypedeLivraison)
├── shipping_method (Shipping_Method_Title)
├── payment_method (ModeReglement)
├── client_role (RoleClient)
├── note (Commandenote)
├── billing {}
│ ├── last_name / first_name / company
│ ├── email / phone
│ └── address / zip / city / country
├── shipping {}
│ ├── last_name / first_name / company
│ ├── phone
│ └── address / zip / city / country
├── lines[]
│ ├── reference (ref ERP — Reference)
│ ├── name (NomProduit)
│ ├── qty (Nbre)
│ ├── unit_price (PrixUnitaire)
│ └── line_total (qty × unit_price, recalculé)
├── totals {}
│ ├── shipping (Order_Shipping)
│ ├── refund (Order_Refund)
│ └── total (Order_Total)
└── coupons[] (codes promo)

TransferWebOrderJob

App\Jobs\WebOrders\TransferWebOrderJob

  • Queue : web-orders
  • Tentatives : 3 ($tries = 3)
  • Timeout : 60 secondes
  • En cas d'échec sur les 3 tentatives : failed() remet le statut à failed

Le job appelle un script Python externe pour le transfert SCP :

{EDI_ENGINE_VENV_PYTHON} /opt/medithau/agents/edi-engine/tools/transfer_web_order.py \
--source {source} --file {xmlPath}

Routes

Déclarées dans /opt/medithau/api/routes/api.php.

MéthodeRouteAuthDescription
POST/api/web-orders/webhook/mainSignature webhookRéception commande boutique principale
POST/api/web-orders/webhook/ostrealiaSignature webhookRéception commande Ostrealia
POST/api/web-orders/debugaucuneLog les headers/body (temporaire, diagnostic)
GET/api/web-ordersBearer tokenListe des commandes (100 dernières, filtrables)
GET/api/web-orders/{id}Bearer tokenDétail complet (sans xml_content)
POST/api/web-orders/{id}/retryBearer tokenRelancer une commande failed

Filtres disponibles sur GET /api/web-orders

  • ?source=main|ostrealia
  • ?status=received|transferring|transferred|failed

La réponse liste retourne directement order_number, client, company, total, delivery_date, lines_count depuis parsed_data — sans re-parser le XML.

Commandes Artisan

web-orders:parse-existing

php artisan web-orders:parse-existing
php artisan web-orders:parse-existing --force # re-parser même les commandes déjà parsées

Backfill de parsed_data pour les commandes existantes qui ont xml_content mais pas encore parsed_data. Traitement par chunks de 50. Utile après une migration ou une modification du parser.

Configuration

Fichier : /opt/medithau/api/config/web_orders.php

CléVariable .envValeur par défaut
sources.main.remote_path/volume1/DATAS/4DDocuments/WebOrders/FTP/
sources.ostrealia.remote_path/volume1/DATAS/4DDocuments/WebOrders/OFTP/
ssh.hostWEB_ORDERS_SSH_HOST192.168.1.13
ssh.portWEB_ORDERS_SSH_PORT34322
ssh.userWEB_ORDERS_SSH_USERedi
ssh.keyWEB_ORDERS_SSH_KEY/opt/medithau/config/ssh/id_rsa_weborders
incoming_dirWEB_ORDERS_INCOMING_DIR/opt/medithau/web-orders/incoming
archive_dirWEB_ORDERS_ARCHIVE_DIR/opt/medithau/web-orders/archive
webhook_tokenWEB_ORDERS_WEBHOOK_TOKEN(vide — désactive la vérification)
pythonEDI_ENGINE_VENV_PYTHON/opt/medithau/agents/edi-engine/.venv/bin/python

Structure des fichiers

/opt/medithau/web-orders/
├── incoming/
│ ├── main/ ← XML en transit (avant SCP)
│ └── ostrealia/
└── archive/
├── main/ ← XML archivés après transfert réussi
└── ostrealia/

Sécurité

  • User-Agent : le webhook vérifie que l'UA contient woocommerce ou wordpress (insensible à la casse). Toute autre source reçoit un HTTP 403.
  • Token webhook : si WEB_ORDERS_WEBHOOK_TOKEN est défini, il est comparé à $parsed->Order->token via hash_equals() (résistant aux timing attacks). Si la variable n'est pas définie, la vérification est désactivée.
  • Validation XML : simplexml_load_string() avec libxml_use_internal_errors(true). Un XML mal formé retourne HTTP 400.
  • Auth API : les routes de lecture/retry nécessitent le Bearer token EDI_ENGINE_API_TOKEN (middleware EdiEngineToken).
  • Clé SSH dédiée : le transfert SCP web-orders utilise id_rsa_weborders, distincte de la clé EDI Engine, pour limiter les permissions en cas de compromission.

Cas particuliers

  • Retry : seules les commandes en statut failed peuvent être relancées. Tenter un retry sur une commande transferred ou transferring retourne HTTP 409.
  • Payload vide : retourne HTTP 400 avant tout traitement.
  • Webhook debug : POST /api/web-orders/debug log les headers, query params et les 500 premiers caractères du body dans /opt/medithau/logs/web_orders_debug.log. Route temporaire à supprimer après identification du format plugin WooCommerce.
  • Connexion NAS ERP : utilise les mêmes variables SSH que l'EDI Engine (ERP_SSH_IP, ERP_SSH_PORT) en fallback si WEB_ORDERS_SSH_HOST/PORT ne sont pas définis.