Table des matières :
- Périmètre d’un connecteur PrestaShop ↔ Odoo : flux, contraintes, versions supportées
- Webservice PrestaShop : configuration fine, ACL et limites réelles du cœur
- Exposition côté Odoo : comptes techniques, droits minimaux, mapping métier
- Webhooks signés : HMAC, anti-replay, idempotence, et traitement asynchrone
- Hardening et exploitation : TLS, cloisonnement, logs, rotation des secrets, tests d’attaque
Périmètre d’un connecteur PrestaShop ↔ Odoo : flux, contraintes, versions supportées
Un « connecteur PrestaShop Odoo » n’est pas un module magique : c’est un ensemble de flux (API + traitements asynchrones + règles de mapping) qui synchronise deux modèles de données incompatibles par défaut. Typiquement : catalogue (produits, variantes/attributs, prix, taxes), stock (réservations, emplacements, multi-entrepôts), commandes (statuts, paiements, factures/avoirs), clients (B2C/B2B, adresses, TVA), et parfois expéditions (transporteurs, tracking). Le point critique n’est pas le CRUD, c’est la cohérence transactionnelle (ne pas “doubler” une commande), la latence acceptable (temps réel vs batch), et la traçabilité (rejouer un événement sans corruption).
Avant même de parler technique, fixez le périmètre fonctionnel par flux, sinon vous coderez des “sync” qui semblent marcher… jusqu’à la première exception métier (remise, retour, multi-devise, etc.). Une manière pragmatique de cadrer consiste à lister, pour chaque flux : source de vérité, sens (mono/bidirectionnel), déclencheur (webhook/polling/batch), clé d’idempotence, politique de retry, délai acceptable.
| Flux | Source de vérité (recommandée) | Sens | Déclencheur | Points de friction fréquents |
|---|---|---|---|---|
| Catalogue (templates, variantes) | Odoo (ERP/PIM) | Odoo → PrestaShop | Batch + delta | attributs vs variantes, images, prix multi-listes |
| Stock disponible | Odoo (multi-entrepôts) | Odoo → PrestaShop | Near-real-time ou batch | réservation, backorders, “available for order” |
| Commandes | PrestaShop (checkout) | PrestaShop → Odoo | Webhook/outbox | statuts, paiement vs facture, frais de port/TVA |
| Clients / adresses | PrestaShop (B2C) ou Odoo (B2B) | souvent PS → Odoo | À la commande | doublons email, RGPD (minimisation) |
| Expéditions / tracking | Odoo/WMS/TMS | Odoo → PrestaShop | webhook + retry | codes transporteurs, URLs tracking, retours |
Contexte versions (à figer dès le cadrage, sinon vous allez déboguer dans le vide) : côté PrestaShop, les projets 2026 tournent majoritairement en 8.1/8.2/9.x avec PHP 8.2 ou 8.3 (au moins). Côté Odoo, on rencontre surtout Odoo 16/17/18 (on-prem ou Odoo.sh). Les choix d’API en découlent : PrestaShop expose historiquement le Webservice REST (hérité, XML-centric) et, à partir de PrestaShop 9, une Admin API plus moderne (OAuth2/scopes). Odoo, lui, expose une API XML-RPC et JSON-RPC.
La doc Odoo résume bien le cadre : « Odoo exposes two different APIs: an XML-RPC and a JSON-RPC API » (Odoo Documentation, External API, Odoo Documentation – External API). Ça implique un vrai choix d’architecture : soit vous mettez un middleware (le plus propre pour la sécurité et la résilience), soit vous faites du direct-to-core (PrestaShop ⇄ Odoo) en acceptant d’implémenter vous-même la file d’attente, la gestion des retries et la signature des webhooks.
Quelques contraintes “terrain” à anticiper (et qui ont un vrai impact sur l’architecture) :
- TVA & facturation (FR/UE) : dans beaucoup d’organisations françaises/européennes, Odoo est la référence comptable, donc la facture naît côté Odoo (et pas côté PrestaShop). Le connecteur doit donc éviter de “fabriquer” des documents comptables incohérents côté e-commerce.
- Arrondis & unités : PrestaShop et Odoo n’arrondissent pas toujours au même moment (ligne vs total). Décidez si vous réconciliez au centime via un “ajustement” (ex. ligne d’écart) ou si vous forcez un mode de calcul aligné.
- Multi-sociétés / multi-boutiques : Odoo multi-company et PrestaShop multistore impliquent des clés de routage (companyid, websiteid, store_id) dès le mapping.
- Temps réel vs “quasi temps réel” : viser le temps réel absolu sans file ni outbox, c’est généralement une dette technique immédiate (timeouts, duplication, backpressure).
Pré-requis non négociables avant d’ouvrir quoi que ce soit : HTTPS fonctionnel, accès à la conf Nginx/Apache/LiteSpeed, capacité à déployer un module PrestaShop (sans overrides si possible), et un endroit pour stocker des secrets (Vault/SSM/KMS, ou a minima variables d’environnement). Si vous êtes déjà en train de gérer des 503 ou des fatales PHP, stabilisez d’abord l’infra (cf. Erreur HTTP 503 : diagnostiquer PHP et logs Apache/LiteSpeed et PrestaShop auto-hébergé : prérequis d’installation, maintenance et sécurité).
Webservice PrestaShop : configuration fine, ACL et limites réelles du cœur
Le Webservice PrestaShop reste le socle le plus souvent utilisé, parce qu’il est stable et disponible sur un grand parc. La documentation officielle le positionne comme un accès REST pour des applications tierces (PrestaShop Developer Documentation, devdocs). En pratique, c’est un endpoint /api protégé par une clé, avec des permissions par ressource, et des réponses historiquement en XML (ce qui a un impact sur la taille des payloads et le coût de parsing).
Configuration côté PrestaShop (ex. PrestaShop 8.1–9.2) :
- Activer le Webservice (Back-office > Paramètres avancés > Webservice). Ça positionne
PS_WEBSERVICE=1en configuration. - Générer une clé dédiée à l’intégration (ne réutilisez jamais une clé “admin”, et évitez une clé partagée entre environnements).
- Régler les ACL au strict nécessaire :
orders,order_details,customers,addresses,products,combinations,stock_availables… et rien de plus. Le “read-only” est souvent suffisant pour un premier flux.
Pour rendre ça plus concret, voici une grille de permissions “minimum viable” (à adapter à vos flux réels) :
| Objectif | Ressources Webservice souvent nécessaires | Niveau conseillé |
|---|---|---|
| Import commandes vers Odoo | orders, order_details, customers, addresses, order_payments (selon besoin) |
lecture seule au départ |
| Export stock depuis Odoo (et lecture côté PS) | stock_availables, éventuellement products, combinations |
lecture/écriture ciblée |
| Export catalogue depuis Odoo | products, combinations, images (si vous gérez médias) |
écriture uniquement si maîtrisé |
| Support SAV (avoirs/retours) | order_slip, order_histories |
lecture, puis écriture si workflow établi |
Tester proprement sans exfiltrer la clé dans des logs : utilisez l’Authorization header (HTTP Basic), pas un paramètre d’URL. Exemple minimal :
# clé Webservice = WS_KEY
curl -sS -u "WS_KEY:" "https://shop.example.com/api/orders?display=[id,reference,date_add]"
Pour éviter les “full exports” involontaires, testez aussi dès le départ les patterns pagination et filtrage (les capacités varient selon ressource, mais le filtrage filter[...] est un outil clé pour le delta). Exemple de lecture incrémentale (principe) :
# Exemple de delta sur date de mise à jour (selon ressources / version)
curl -sS -u "WS_KEY:" \
"https://shop.example.com/api/orders?display=[id,reference,date_upd]&filter[date_upd]=>[2026-09-01 00:00:00]&limit=0,100"
Point important : le cœur PrestaShop n’est pas généreux sur les garanties côté API. Les filtres existent mais restent limités (selon ressources) et les payloads “full” sont lourds. Sur des boutiques volumineuses, vous devez impérativement limiter display et paginer, sinon vous créez une charge CPU + DB inutile (et vous allez ensuite “optimiser” à coups de cache au lieu de réduire le volume). Pour aller plus loin sur les patterns CRUD/ressources et les pièges, appuyez-vous sur : API Webservice PrestaShop : guide CRUD et ressources développeur.
Limites “réelles” qu’on découvre vite en intégration PrestaShop ↔ ERP :
- Stock :
stock_availablesreprésente une disponibilité “boutique”, pas un WMS. Si vous avez plusieurs entrepôts côté Odoo, vous devrez définir une règle d’agrégation (ex. entrepôt principal = stock e-commerce, ou somme des entrepôts vendables). - Prix : promotions, prix spécifiques, taxes et écotaxes peuvent exiger plus que
products. Selon votre stratégie, vous exportez un prix TTC final ou un prix HT + tax rules (mais attention à la cohérence). - Statuts de commande : PrestaShop a des “order states” configurables et des transitions souvent pilotées par les modules de paiement/transport. Le connecteur doit mapper vers les étapes Odoo (ex. confirmation, livraison, facturation) sans créer de boucles.
Sécurité spécifique au Webservice : (1) la clé est un identifiant d’accès, donc rotation et segmentation (une clé par usage), (2) le Webservice doit être HTTPS only (sinon Basic Auth = fuite), (3) si possible, restriction IP sur /api (Odoo.sh ou votre serveur Odoo), et (4) durcissement du serveur pour éviter d’exposer des endpoints inutiles. Exemple Nginx (à adapter) :
location ^~ /api/ {
allow 203.0.113.10; # IP Odoo / middleware
deny all;
limit_req zone=api burst=20 nodelay;
proxy_set_header Authorization $http_authorization;
}
Vous noterez le trou béant : PrestaShop n’a aucun webhook natif pour pousser des changements à Odoo. Donc si vous voulez du near-real-time sans polling, vous allez implémenter une sortie événementielle (hooks PrestaShop + file/outbox) et des webhooks signés.
Exposition côté Odoo : comptes techniques, droits minimaux, mapping métier
Côté Odoo, la base saine consiste à créer un compte technique avec le minimum de groupes et une API key (plutôt qu’un mot de passe utilisateur). L’erreur classique est de connecter PrestaShop à un compte “Administrateur” parce que “ça marche”. Ça marche… jusqu’au jour où une fuite de secret donne accès à votre compta. Le principe de moindre privilège est un classique de la sécurité applicative ; OWASP rappelle l’impact systémique des erreurs de droits dans son Top 10 (“Broken Access Control” est une catégorie récurrente), cf. OWASP Top 10.
Checklist rapide côté Odoo (utile en atelier de cadrage) :
- Créer un utilisateur “integration_prestashop” (pas un compte partagé humain).
- Limiter les droits par modèle (ACL) aux objets réellement nécessaires :
res.partner,sale.order,sale.order.line, éventuellementproduct.*,stock.*,account.moveselon le périmètre. - Vérifier les record rules (multi-sociétés) : l’utilisateur ne doit voir/écrire que la société/boutique concernée.
- Mettre une API key et planifier une rotation (et une révocation testée).
Le mapping doit être cadré avant de coder :
- Produits :
product.templatevsproduct.product(variantes). PrestaShop “produit + déclinaisons” se mappe généralement surproduct.template+product.product. Décidez explicitement où vous stockez les identifiants externes (ex. champ “xprestashopid” ou table de correspondance). - Clients : PrestaShop a
customer+addresses, Odoo centralise surres.partner(avec types d’adresses). Attention aux doublons email et aux contacts enfants. En B2B (fréquent en France), une même entreprise peut avoir plusieurs contacts et adresses de livraison : prévoyez une règle de déduplication (par email, SIREN/SIRET si vous les collectez, ou identifiant externe). - Commandes :
sale.order(devis/commande) +account.move(facture). Ne mélangez pas “commande e-commerce” et “facture” : elles n’ont pas le même cycle de vie.
Mini-scenario (très courant) : vous importez une commande PrestaShop payée, vous créez un sale.order confirmé dans Odoo, puis la logistique expédie depuis un entrepôt. Si votre connecteur pousse trop tôt un statut “expédié” vers PrestaShop (sur simple confirmation de commande), vous déclenchez des emails clients faux et des tickets SAV. La règle à définir : quel événement Odoo (picking validé ? tracking renseigné ?) correspond à quel statut PrestaShop.
Exemple d’appel JSON-RPC (lecture d’un partenaire) :
POST /jsonrpc
{
"jsonrpc": "2.0",
"method": "call",
"params": {
"service": "object",
"method": "execute_kw",
"args": [
"ODOO_DB",
2,
"API_KEY_OR_PASSWORD",
"res.partner",
"search_read",
[["email", "=", "[email protected]"]],
{"fields": ["id", "name", "email"]}
]
},
"id": 1
}
Si vous prévoyez des webhooks Odoo → PrestaShop, vous allez en pratique : (a) développer un petit module Odoo exposant une route HTTP (contrôleur) ou (b) passer par un middleware (FastAPI/Symfony/Node) qui parle Odoo d’un côté et PrestaShop de l’autre. Le middleware gagne sur la sécurité (secret centralisé, rate limiting, schémas JSON, buffering), et sur l’exploitation (logs unifiés, retries). Sur de la volumétrie sérieuse (catalogues > 50k SKU, commandes > 1k/j), la stratégie “direct sync” sans file finit en timeouts et en traitements partiels.
Un point souvent sous-estimé : la gestion des erreurs fonctionnelles. Exemple : Odoo refuse une commande faute de produit mappé, de taxe manquante ou de “journal” non configuré. Si votre connecteur ne fait que “retry”, vous créez un bruit infini. Prévoyez une dead-letter queue (DLQ) ou un état “à traiter” côté back-office intégration, avec message d’erreur lisible et action corrective.
Pour les patterns architecture (webhooks + files RabbitMQ), voir : Intégration ERP e‑commerce : architecture API, webhooks et files RabbitMQ et Intégration API : synchronisation bidirectionnelle et automatisation pour forte volumétrie.
Webhooks signés : HMAC, anti-replay, idempotence, et traitement asynchrone
Un webhook sans signature est un endpoint public qui exécute vos règles métier sur simple POST : c’est inacceptable en prod. Le mécanisme standard (et robuste) est la signature HMAC d’un payload avec un secret partagé. La définition canonique est dans RFC 2104 : « HMAC is a mechanism for message authentication using cryptographic hash functions » (RFC 2104, RFC 2104). Ce que vous cherchez concrètement : intégrité (payload non modifié) + authenticité (émetteur possédant le secret).
Points d’attention concrets (souvent la source de bugs en prod) :
- signez le raw body (octets exacts), pas un JSON re-encodé : sinon vous cassez la signature avec un simple changement d’espaces/ordre de clés ;
- incluez un timestamp pour l’anti-replay ;
- versionnez le schéma (
v1=) pour pouvoir migrer (SHA-256 → autre, changement de format) sans downtime ; - comparez avec
hash_equals()pour éviter les attaques timing.
Design recommandé (inspiré des bonnes pratiques Stripe/PayPal, sans en dépendre) :
- Header
X-Webhook-Timestamp: 1690000000 - Header
X-Webhook-Id: evt_01H...(idempotence) - Header
X-Webhook-Signature: v1=<hex(hmac_sha256(secret, timestamp + '.' + raw_body))>
Côté PrestaShop (module custom) : contrôleur front dédié, lecture de php://input, calcul HMAC et comparaison avec hash_equals() (anti timing attacks). Exemple minimal (PHP 8.2) :
$raw = file_get_contents('php://input');
$ts = $_SERVER['HTTP_X_WEBHOOK_TIMESTAMP'] ?? '';
$sig = $_SERVER['HTTP_X_WEBHOOK_SIGNATURE'] ?? '';
$expected = hash_hmac('sha256', $ts . '.' . $raw, $secret);
if (!hash_equals('v1='.$expected, $sig)) {
http_response_code(401);
exit;
}
Ajoutez ensuite anti-replay et idempotence, sinon un attaquant peut rejouer un POST signé capturé (ou vous allez vous auto-DDoS via des retries). Anti-replay : refuser si abs(now - ts) > 300s, et stocker X-Webhook-Id dans Redis/MySQL avec TTL (ne retraiter qu’une fois). Idempotence : vos handlers doivent être conçus pour que deux exécutions consécutives ne cassent rien (ex. “upsert” par référence externe, pas “insert” aveugle).
Un exemple simple d’idempotence côté commande : utilisez la reference PrestaShop (ou un identifiant technique stable) comme clé externe dans Odoo. Si l’événement est rejoué, vous faites un search puis un write, plutôt qu’un create systématique.
Sur ce sujet, le pattern est identique à la vérification d’authenticité PayPal : Webhooks PayPal : vérifier l’authenticité des notifications serveur.
Dernier point : ne traitez pas le webhook en synchrone si vous faites plus qu’un update trivial. Répondez 200/202 rapidement, poussez le message dans une file (RabbitMQ/Redis stream/DB outbox), et faites le travail en worker. Sinon, vous allez coupler la latence du réseau + DB + Odoo à la disponibilité de PrestaShop, et transformer une pointe de commandes en avalanche de timeouts.
Le cœur PrestaShop n’aide pas : il n’a pas de job runner natif standardisé. Donc soit vous passez par un middleware, soit vous implémentez un worker (cron + queue) et un outbox pattern : à la validation de commande (actionValidateOrder), vous écrivez un événement dans une table ps_odoo_outbox dans la même transaction, puis un job l’expédie avec retries exponentiels.
Un schéma de table outbox minimal (pour garder la maîtrise des rejouements) :
id(PK)event_id(unique, =X-Webhook-Id)event_type(ex.order.validated)payload(JSON)status(pending,processing,done,failed)attempts(int)next_retry_at(datetime)last_error(text)created_at,updated_at
Ce design rend l’intégration observable : vous savez ce qui est parti, ce qui est en échec, et vous pouvez rejouer proprement.
Hardening et exploitation : TLS, cloisonnement, logs, rotation des secrets, tests d’attaque
Sur un connecteur PrestaShop Odoo, la sécurité ne se limite pas à “mettre un HMAC”. Il faut réduire la surface. Côté PrestaShop : restreindre IP sur /api et sur l’endpoint webhook, activer un rate limit, et refuser toute méthode HTTP non attendue. Si vous êtes derrière Cloudflare/Reverse proxy, faites attention au “real client IP” (sinon votre allowlist est fictive).
Pour le durcissement TLS, ajoutez HSTS et visez un profil moderne (TLS 1.2 minimum, idéalement 1.3). Pour une base de configuration serveur maintenue et testable, la référence pratique est le générateur Mozilla SSL Configuration : Mozilla SSL Configuration Generator
Exemple (idée générale) : refuser TRACE, limiter aux verbes nécessaires :
if ($request_method !~ ^(GET|POST|PUT|PATCH|DELETE)$ ) { return 405; }
Hygiène patch : suivez les correctifs de sécurité (cœur, modules, serveur). Pour les annonces officielles PrestaShop, un point d’entrée fiable est la page GitHub Security Advisories : PrestaShop Security Advisories
Côté secrets : rotation planifiée, pas de secret en dur dans le repo, pas de secret en config BO visible. Dans un module PrestaShop, stocker un secret dans Configuration sans chiffrement est un compromis (lisible en DB). Si vous n’avez pas de KMS, au minimum : (1) restreindre l’accès DB, (2) séparer les secrets par environnement, (3) chiffrer côté applicatif avec libsodium si vous pouvez. Et surtout : ne loggez jamais l’Authorization Webservice ni les headers de signature (ou redaction). Les logs d’accès web + traces applicatives sont l’endroit #1 où les clés finissent par fuiter.
Sur la conformité (FR/UE), gardez en tête un principe simple : minimisation. Un connecteur n’a pas besoin de répliquer “tout le client” partout. Par exemple, si Odoo n’a besoin que du nom, email, adresse de livraison et historique de commande, évitez de dupliquer des champs inutiles (date de naissance, marketing opt-in, etc.). Ça réduit l’exposition en cas d’incident.
Observabilité : vous avez besoin de métriques et de preuves, pas de “ça a l’air bon”. Indicateurs utiles :
- taux de succès des webhooks (par
event_type) ; - temps de traitement moyen (p50/p95) ;
- backlog de queue ;
- nombre de retries et taux d’échec final (DLQ) ;
- âge du plus vieux message (lag) ;
- ratio “idempotence hits” (événements reçus en double mais correctement ignorés).
Ajoutez un X-Correlation-Id propagé PrestaShop ⇄ middleware ⇄ Odoo pour corréler. En diagnostic perf, l’approche reproductible est la seule qui tient (cf. Audit performance PrestaShop : méthode reproductible et preuves terrain).
Et côté tests, ne vous contentez pas du “happy path”. Une check-list réaliste (qui attrape les bugs coûteux) :
- payload JSON invalide / champs manquants ;
Content-Typeerroné, encodage inattendu ;- timestamp hors fenêtre (anti-replay) ;
- signature corrompue (doit retourner 401) ;
- doubles envois (idempotence) ;
- coupures réseau vers Odoo (doit queue + retry) ;
- surcharge (100 événements en rafale) : vérifiez la backpressure, pas seulement la “réussite”.
Enfin, si vous êtes en PrestaShop 9.x, posez explicitement la question : certaines opérations critiques (création/édition) ont plus de sens via l’Admin API (scopes, clients séparés) que via le Webservice legacy. Sans basculer tout le connecteur, vous pouvez hybrider : Webservice pour lecture catalogue/stock, Admin API pour opérations sensibles.
Pour cadrer la sécurité des clients/scopes, voir : PrestaShop Admin API : sécuriser secret et scopes par client et, côté webhooks “à la vraie vie” (échecs, polling fallback, retries), l’exemple d’intégration multi-cas : Intégration TikTok Shop PrestaShop : webhooks, polling et gestion des échecs.




