# Module — Connecteur WooCommerce (WordPress)

> ⚠️ **Révision ADR-008 (2026-07-26)** : le modèle est désormais **plugin *pull*** (le plugin WordPress
> tire le catalogue depuis yima avec sa **clé de licence** et pousse les commandes vers yima), et non
> plus « yima pousse via l'API REST WooCommerce ». yima ne stocke pas les clés API WooCommerce ; l'accès
> est **gaté par une licence** ([licences & comptes](licences-comptes.md), E1‑A) + signature HMAC (E1‑B).
> Les sections ci-dessous décrivant `WooCommerceConnection` (clés API stockées, webhooks entrants) sont
> conservées comme historique mais **remplacées** par ce modèle. Philosophie inchangée (central
> autoritaire, upsert par SKU, commandes → `Sale channel=online`).

> Certains clients possèdent **déjà** un site **WordPress + WooCommerce**. Ce module les connecte au portail : ils gèrent **les produits de leur site depuis le portail/POS**, dans le **même système**. C'est un **canal e-commerce alternatif** à la [projection e-commerce](ecommerce-projection.md) (base Symfony projetée) : la projection s'adresse aux clients **sans** site ; le connecteur WooCommerce aux clients **avec** un site existant. Une boutique choisit son canal (voir [ADR-007](../notes/decisions.md)).

## 1. Objectif

Permettre à un commerçant disposant d'un WooCommerce existant de :
- gérer **un seul catalogue** (au centre) et le **synchroniser** vers son site (produits, prix, stock) ;
- **remonter les commandes** du site dans le POS central (source de vérité), pour une vision unifiée ventes boutique + en ligne.

Personas : **Manager** (configure la connexion, choisit ce qui est synchronisé), **Admin plateforme** (supervise). L'employé/caissier n'interagit pas directement.

## 2. Périmètre

**In (v1)** : configuration de la connexion (URL + clés API WooCommerce), **push** produits/prix/stock central → WooCommerce (par SKU), **pull** des commandes WooCommerce → central (webhook + repli planifié), mapping produit ↔ produit WooCommerce, statut/journal de synchro, test de connexion.

**Out (initial)** : gestion du thème/pages WordPress, plugins, clients du site (comptes WooCommerce restent gérés par le site), paiements en ligne (gérés par WooCommerce), synchro temps réel bidirectionnelle des stocks au niveau transaction (on push le stock central, source de vérité).

## 3. Entités

Rattachées à une **boutique** (`Company`). Secrets **chiffrés** via `EncryptionService` (comme `CompanyDatabase`).

| Entité | Rôle |
|---|---|
| `WooCommerceConnection` | 1:1 avec `Company` : `storeUrl`, `consumerKey`, `consumerSecretEncrypted`, `webhookSecretEncrypted`, options (`syncProducts`, `syncPrices`, `syncStock`, `pullOrders`), `connectionStatus` (`unknown`/`ok`/`failed`), `lastSyncAt`, `lastTestMessage`, `isActive` |
| `WooCommerceProductMap` | Correspondance `Product`/`ProductVariant` central ↔ WooCommerce (`wooProductId`, `wooVariationId`, `sku`, `lastPushedAt`, `syncHash`) |
| `WooCommerceSyncLog` | Journal append-only des opérations (type, direction push/pull, entité, statut, message, horodatage) |

Relations : `WooCommerceConnection (1) ── (N) WooCommerceProductMap` ; un `Product` (catalogue) peut avoir 0..1 mapping par connexion. Une commande WooCommerce importée crée une `Sale` (canal = `online`) rattachée à la boutique (client optionnel — cf. vente anonyme).

## 4. Permissions

| Code | Rôle | Usage |
|---|---|---|
| `integration.woocommerce.view` | Manager | Voir le statut/journal de synchro |
| `integration.woocommerce.manage` | Manager | Configurer la connexion, lancer une synchro, mapper les produits |

À seeder via `RbacSeedCommand` (voir [conventions](../notes/conventions.md)). Gater : `denyAccessUnlessGranted('integration.woocommerce.manage', $company)`.

## 5. API

| Méthode | Route (`/api/v1`) | Corps | Permission |
|---|---|---|---|
| GET | `/integrations/woocommerce` | — | `integration.woocommerce.view` |
| PUT | `/integrations/woocommerce` | `{storeUrl, consumerKey, consumerSecret?, options}` | `integration.woocommerce.manage` |
| POST | `/integrations/woocommerce/test` | — | `integration.woocommerce.manage` |
| POST | `/integrations/woocommerce/sync` | `{scope: products|stock|prices|all}` | `integration.woocommerce.manage` |
| GET | `/integrations/woocommerce/logs` | — | `integration.woocommerce.view` |
| POST | `/integrations/woocommerce/webhook` | payload WooCommerce (HMAC vérifié) | **public signé** (pas de JWT) |

- Idiome « laisser vide pour conserver » sur `consumerSecret` (comme SMTP/`CompanyDatabase`).
- Le **webhook** entrant est authentifié par **signature HMAC** (secret partagé stocké chiffré), pas par JWT — c'est WooCommerce qui appelle.

## 6. Écrans

- **Portail (web, Manager)** : section « Boutique en ligne » → sous-onglet « WooCommerce » : formulaire connexion (URL, clés API, options), bouton **Tester la connexion** (mirror du test `CompanyDatabase`), tableau de mapping produits, journal de synchro, bouton « Synchroniser maintenant ».
- **PWA** : lecture seule (statut de connexion, dernière synchro) ; la configuration reste au portail.

## 7. Règles métier

- **Central autoritaire** pour produits/prix/stock : le portail **pousse** vers WooCommerce (le site est un miroir de vente en ligne). En cas de divergence, le central gagne.
- **Commandes** : elles naissent sur le site → **pull** vers le central (webhook `order.created`/`order.updated`, repli planifié) → création d'une `Sale` (canal `online`) + décrément du **stock central** → re-push du stock vers WooCommerce (boucle cohérente).
- **Mapping par SKU** : appariement produit central ↔ WooCommerce par SKU ; création si absent (option). `syncHash` évite les push inutiles (idempotence).
- **Résilience** : appels à l'API WooCommerce via Messenger (retry, backoff) ; jamais bloquer une opération POS sur une erreur de synchro ; journaliser dans `WooCommerceSyncLog` et alerter (dédup) en cas d'échec répété.
- **Sécurité** : HTTPS obligatoire, clés stockées chiffrées, vérification HMAC des webhooks, jamais de secret dans les logs. Rate-limit des appels sortants.

## 8. Projection e-commerce

Ce module **remplace** la [projection vers base Symfony](ecommerce-projection.md) pour les boutiques ayant choisi WooCommerce : la « projection » se fait directement dans **leur** WooCommerce via l'API REST, pas dans une `CompanyDatabase`. Les deux mécanismes partagent la même philosophie (central autoritaire, upsert idempotent, événements Messenger) mais des **cibles** différentes (base client projetée vs API WooCommerce). Une boutique peut, à terme, n'utiliser aucun, l'un, ou (rare) les deux.

## 9. Tests

- **Unitaires** : construction des payloads WooCommerce (produit/variation/stock), calcul du `syncHash`, mapping SKU, vérification de signature HMAC du webhook.
- **Fonctionnels** : configurer une connexion (secret chiffré en base, jamais en clair), endpoint `test` (mock HTTP), réception d'un webhook signé → création d'une `Sale` online + mouvement de stock ; rejeu du même webhook (Idempotency/clé WooCommerce) → une seule vente.
- **Accès** : `integration.woocommerce.manage` requis (autorisé/refusé → 403) ; webhook avec signature invalide → 401.
- **Intégration réelle** : contre un WooCommerce de test (sandbox) — hors CI, manuel.

## 10. Dépendances

- **Fondations** : `EncryptionService` (secrets), RBAC, `FileLogger`, `AlertDeduplicationService`, Messenger.
- **Modules** : [Catalogue](catalogue-produits.md) (produits/SKU), [Stock](stock-inventaire.md) (mouvements), [POS/Ventes](pos-ventes.md) (Sale canal `online`), [Clients/CRM](clients-crm.md) (client optionnel).
- **Externe** : client HTTP (Symfony HttpClient) vers l'API REST WooCommerce v3 (`/wp-json/wc/v3/...`).

## 11. Notes / ADR liés

- [ADR-001](../notes/decisions.md) (central autoritaire + projection), [ADR-003](../notes/decisions.md) (chiffrement des secrets), [ADR-005/006](../notes/decisions.md) (vente anonyme, append-only), **[ADR-007](../notes/decisions.md)** (canaux e-commerce : base projetée **ou** WooCommerce connecté).
- Voir aussi l'architecture générale [01](../01-architecture.md) et [`portail-manager/docs/ARCHITECTURE_MULTITENANT.md`](../../portail-manager/docs/ARCHITECTURE_MULTITENANT.md).
- Extension future : autres connecteurs (Shopify, PrestaShop) sur le même patron (connexion chiffrée + mapping + push/pull Messenger).
