Module v1.72.0
Configurer Boutique
Vendez en ligne : produits, panier, comptes clients, livraison par zones et paiement sécurisé, sans jamais toucher une carte bancaire.
Ce qu'il fait
Boutique en ligne complète : produits physiques avec stock et TVA, catégories multiples hiérarchiques, étiquettes, attributs enregistrés, statut brouillon/publié, image de mise en avant, prix promo barré, référencement unifié via le hub SEO (module seo, filtre seo.items), comptes clients, panier, checkout, livraison par zones (types de livraison, blocs de prix, classes d'expédition) et paiement par prestataires branchables (Stripe, PayPal, Mollie, PayPlug, Lyra/Systempay fournis nativement, personnalisables via le filter shop.payment.providers) — sans jamais coder le paiement lui-même. Bâtie sur un tronc aveugle au type de produit (résolveur de prix unique, accomplissement par type de ligne, paiement partiel), extensible par satellites cumulables (variantes, digital, promo, factures, B2B…). Aucune connexion avec le module Catalogue : tables et admin propres de bout en bout.
- Produits avec stock, TVA, catégories multiples hiérarchiques et attributs enregistrés
- Éditeur façon boutique pro : brouillon/publié, image de mise en avant, prix promo barré, score SEO
- Comptes clients + commande invité (au choix)
- Livraison par zones : types de livraison (domicile, retrait, point relais…), forfait, grille au poids, gratuité dès un montant, classes d'expédition
- Checkout en 2 étapes + commandes avec échéancier de paiement
- Paiement par prestataires branchables : Stripe, PayPal, Mollie, PayPlug et Lyra fournis
- Statuts de commande à vous : étapes sur mesure, e-mail au client à chaque étape, compteur « à préparer » et chiffre encaissé qui suivent vos étapes
- Tableau de bord des ventes : encaissé du mois, panier moyen, commandes à préparer
- Statistiques par période (chiffre d'affaires, panier moyen, meilleures ventes) et alerte e-mail quand un stock passe sous le seuil
- Au premier clic sur « Boutique », un formulaire de mise en route pose les réglages (TVA, paiement, livraison) et active les satellites utiles
Où le trouver
Les écrans que ce module ajoute à l'administration, une fois activé.
-
Boutique
/admin/shop
Ses réglages
Ils se modifient depuis l'administration. La clé est donnée pour qui pilote le site en ligne de commande ou par l'API.
| Réglage | Clé | Type | Par défaut |
|---|---|---|---|
| Autoriser la commande sans compte (invité) — historique, piloté par shop.checkout.compte | shop.guest_checkout |
bool | oui |
| Le compte client à la commande (invite | creation | obligatoire) | shop.checkout.compte |
string | (vide) |
| Régime fiscal du site (ue_assujetti, ue_franchise, hors_ue) | shop.vat.regime |
text | ue_assujetti |
| Miroir du régime : TVA européenne calculée (seul ue_assujetti l'allume) | shop.vat.enabled |
bool | oui |
| Taux de TVA du site (%) — étage 1 de la cascade site → catégorie → produit | shop.vat.default_rate |
float | 20 |
| Les prix des fiches produit sont saisis TTC (décoché = HT, la TVA s'ajoute) | shop.vat.prices_include_tax |
bool | oui |
| Afficher les prix en TTC sur le site (décoché = HT, mention « HT » ajoutée) | shop.vat.display_include_tax |
bool | oui |
| Préfixe des numéros de commande (vide : pas de préfixe) | shop.order.number_prefix |
string | CMD |
| L'année dans les numéros de commande | shop.order.number_annee |
bool | oui |
| Nombre de chiffres des numéros de commande (complétés par des zéros) | shop.order.number_chiffres |
int | 6 |
| Page des CGV (lien de la case à cocher) | shop.cgv_url |
string | /cgv |
| Panier multi-classes : tarif retenu (max|sum) | shop.shipping.multi_class_rule |
string | max |
| Masquer les méthodes payantes quand une livraison offerte (seuil « dès X € ») est atteinte | shop.shipping.hide_others_when_free |
bool | oui |
| Message affiché au checkout pour un produit non livrable vers la destination (jetons {produit} et {pays}) | shop.shipping.uncovered_message |
string | Le produit {produit} ne peut pas être livré vers {pays}. |
| Purge des paniers abandonnés après (jours) | shop.cart.gc_days |
int | 60 |
| Seuil « stock bas » (unités) | shop.stock.low_threshold |
int | 5 |
| Masquer du catalogue les produits en rupture | shop.stock.hide_out_of_stock |
bool | non |
| Affichage du stock côté client (always|low_only|never) | shop.stock.display_mode |
string | low_only |
| Prévenir par e-mail quand un produit passe sous le seuil | shop.stock.notify |
bool | non |
| Destinataire des alertes de stock (vide = e-mail de contact du site) | shop.stock.notify_email |
string | (vide) |
| Tentatives de commande autorisées par quart d'heure et par visiteur (0 = pas de limite) | shop.checkout.rate_limit |
int | 12 |
| Page de politique de confidentialité liée au checkout (vide = pas de lien) | shop.privacy_url |
string | (vide) |
| Après un ajout au panier : rester sur la page (stay) ou aller au panier (cart) | shop.cart.after_add |
string | stay |
| Adresse de la page Panier (requise pour « aller au panier » après un ajout) | shop.cart.url |
string | (vide) |
| Image de remplacement des produits sans photo (nom de fichier dans /assets/img/shop/) | shop.product.placeholder_image |
string | (vide) |
| Motif d'URL publique d'un produit (ex : /boutique/{slug}) | shop.product_url |
string | (vide) |
Ses droits
Ce que chaque rôle peut faire par défaut. Modifiable rôle par rôle depuis l'administration.
| Droit | Clé | Administrateur | Éditeur |
|---|---|---|---|
| Voir la boutique (commandes, produits) | shop.read |
✓ | ✓ |
| Créer / modifier les produits | shop.products.manage |
✓ | ✓ |
| Gérer les commandes (statuts, création manuelle) | shop.orders.manage |
✓ | — |
| Voir les comptes clients (données personnelles) | shop.customers.read |
✓ | — |
| Régler livraison, paiement et réglages boutique | shop.config.manage |
✓ | — |
Ses satellites
Des modules qui se greffent sur celui-ci et s'activent séparément. Chacun a sa page.
- Abonnements Vendez des abonnements : un 4e type de produit (jamais une variation) qui porte des PLANS (mensuel, annuel, hebdo, période fixe…
- Achats en direct La petite bulle « Camille vient de commander… », en bas de page. Elle lit vos VRAIES commandes payées
- Avis produits Avis produits avec notes, photos et modération : note globale (ou moyenne de sous-notes que vous nommez), badge « achat vérifié »…
- Cartes cadeaux Vendez des cartes cadeaux, ou offrez un avoir à un client. Chaque carte a son code, son solde et son journal
- Catégories de clients Catégories de clients pro (« Revendeur 1 », « Gros compte »…) avec picto+couleur, prix, conditionnement, conditions de paiement…
- Connexion comptabilité Branche la boutique sur votre vrai logiciel de comptabilité. La descente : votre compta vient chercher les ventes d'une période…
- Connexion sécurisée Ajoute une vérification par email à la connexion des comptes clients : après le mot de passe, un code à 6 chiffres (valable 10…
- Contenus réutilisables Bibliothèque de contenus courts (guide des tailles, entretien) écrits une fois puis rattachés aux produits.
- Devis & conditions de paiement Devis (+ conversion en commande en un clic, wording dédié sur ses 2 emails de création), échéancier de paiement MANUEL (N…
- Documents & factures Génère un document imprimable (facture / devis / bon de livraison / avoir) pour n'importe quelle commande de la Boutique — HTML…
- Douane & expédition internationale Prépare les déclarations douanières de vos envois hors Union européenne. Renseignez le code SH (la nomenclature douanière) et le…
- Expédition & étiquettes Le socle d'expédition de votre boutique : préparez une expédition depuis la commande sur un écran de vérification pré-rempli…
- Flux catalogue Envoie vos produits à Google Shopping, Facebook, Instagram, TikTok et Pinterest. Vous collez une adresse une fois dans chaque…
- Passerelles (webhooks) Envoie vos événements de commande vers une URL externe : votre logiciel de comptabilité crée sa facture tout seul quand une…
- Promotions Créez des codes promo (« ETE2026 ») que vos clients saisissent au panier ou au checkout
- Questions de la commande Ajoutez vos propres questions au tunnel de commande : une date souhaitée (« pour quand ? »), une référence, une précision, un…
- Tarifs dégressifs Des paliers de quantité PUBLICS sur un produit simple (a partir de 150 : 8 euros l'unite, a partir de 300
- TVA du pays du client (guichet OSS) Gère la TVA de vos ventes aux particuliers de l'Union européenne. Le module compte votre chiffre d'affaires transfrontalier de…
- TVA à l'international Applique les deux régimes de vente à l'étranger. Vos clients PROFESSIONNELS de l'Union européenne
- Téléchargements Vendez des fichiers téléchargeables (PDF, ZIP, ebooks, audio/vidéo…) : choisissez le type « Produit téléchargeable » sur…
- Variations Déclinez un produit en plusieurs variations (tailles, couleurs…) : cochez, sur chaque attribut — enregistré OU LIBRE, converti…
- Vente internationale Ouvre la vente à l'étranger : le client choisit son pays, et le formulaire d'adresse s'adapte — l'ordre des champs, leurs noms…
- Import Reprenez un catalogue existant : déposez le fichier exporté de votre ancienne boutique (WooCommerce ou n'importe quel tableau…
Ce qu'il suppose
Ce module a besoin de :
- comptes *
- categories *
Le désactiver arrêterait aussi :
- Boutique — Abonnements
- Boutique — Achats en direct
- Boutique — Avis produits
- Boutique — Boxtal (quatorze transporteurs)
- Boutique — Cartes cadeaux
- Boutique — Catégories de clients
- Boutique — Clés de licence
- Boutique — Colissimo (La Poste)
- Boutique — Connexion comptabilité
- Boutique — Connexion sécurisée
- Boutique — Contenus réutilisables
- Boutique — Devis & conditions de paiement
- Boutique — Documents & factures
- Boutique — Douane & expédition internationale
- Boutique — Expédition & étiquettes
- Boutique — Flux catalogue
- Boutique — Passerelles (webhooks)
- Boutique — Promotions
- Boutique — Questions de la commande
- Boutique — Tarifs dégressifs
- Boutique — TVA du pays du client (guichet OSS)
- Boutique — TVA à l'international
- Boutique — Téléchargements
- Boutique — Variations
- Boutique — Vente internationale
- Import
Piloter par une IA
Ce que ce module sait faire quand on le lui demande en langage naturel, et ce que chaque action engage.
-
produitslecture seuleListe les produits de la boutique (lecture seule) : nom, slug, description, prix (centimes + price_display formaté), catégorie, stock, images, url publique absolue. La réponse porte la devise du site (currency ISO 4217, symbol) et site_url. Params : category_slug (optionnel), limit (max 50).
« quels produits j'ai en boutique ? »
-
produit_champslecture seuleDétaille un produit : ses textes modifiables, et ses données commerciales en LECTURE SEULE (prix, stock, statut). À lire avant de modifier.
« qu'est-ce qu'il y a sur la fiche du produit 12 ? »
-
produit_modifierécrit, annulableModifie le NOM, l'ACCROCHE ou la DESCRIPTION d'un produit. Écriture journalisée : annulable. Ne touche JAMAIS au prix, au stock, au statut ni aux variations — ce sont des décisions commerciales, prises depuis la fiche produit.
« réécris la description du produit 12 en plus court » « change l'accroche de la bougie parfumée »
-
commandeslecture seule réservée à votre accès MCP (clé maître)Liste les commandes récentes de la boutique (lecture seule) : numéro, email, statut, total, date. Params : status (optionnel), limit (max 50).
-
commandelecture seule réservée à votre accès MCP (clé maître)Une commande en entier : client, lignes (variante, options, texte personnalisé), ce que le client a précisé, livraison et suivis, totaux, règlements, note interne, message au client, et les statuts qu'on peut poser. Par « id » ou « numero ».
« qu'a commandé la cliente de la commande CMD-2026-0042 ? »
-
commande_noterécrit, annulableÉcrit dans la NOTE INTERNE d'une commande (jamais vue du client) : à la suite par défaut, ou en remplaçant. Journalisée : annulable. Ne touche ni au statut, ni aux montants, ni aux lignes.
« note sur la commande 42 que la cliente a choisi le calendrier version chats »
-
commande_message_clientconfirmation demandéePose le MESSAGE AU CLIENT d'une commande : il s'affiche sur sa page commande et part par e-mail, comme depuis la fiche. Remplace le précédent. Un e-mail part : confirmation demandée.
-
commande_suiviconfirmation demandéeAjoute un NUMÉRO DE SUIVI à une commande (une commande peut en avoir plusieurs). Le transporteur de la commande sert par défaut. Selon les réglages, le statut avance et le client est prévenu : confirmation demandée.
-
commande_statutconfirmation demandéeChange le STATUT d'une commande, comme le sélecteur de la fiche (les e-mails réglés sur le statut partent). Refusés : Payée et Partiellement payée (passer par commande_encaisser), Remboursée, Corbeille, Devis. Confirmation demandée.
-
commande_encaisserconfirmation demandéeNote un RÈGLEMENT REÇU hors ligne (virement, chèque, espèces) sur une commande en attente de paiement, comme « Paiement manuel » de la fiche ; jamais plus que ce qui reste à régler. La commande avance d'elle-même. Confirmation demandée.
-
commande_creerconfirmation demandéeCrée une COMMANDE (ou un DEVIS si le pack commercial est actif), comme « Nouvelle commande » de l'admin. Les prix viennent du catalogue, jamais de l'appel ; les e-mails suivent les règles de l'admin (le client choisit son moyen de paiement en réglant). Une pièce qui engage la boutique : confirmation demandée.
« fais une commande de 2 tasses Tsukoozu pour Camille Martin, livraison Colissimo »
Ses points de branchement
Pour greffer du code sans toucher au module : ce qu'il annonce, et ce qu'il écoute.
Ce qu'il annonce 77
shop.remboursement.avoir_possible- Filtre (bool) — un satellite sait rembourser EN AVOIR (bon d'achat) : la fenêtre « Rembourser » le propose. Args: [bool $possible]
shop.remboursement.avoir- Filtre — émet le bon d'achat d'un remboursement en avoir ; rend {ok, id, code, errors}, null sans écouteur. Args: [null, array $order, int $montantCents, string $motif, ?int $actorId]
shop.commandes.gestes_groupes- Event — la barre des commandes cochées (liste des commandes) s'affiche. Un satellite y ÉCRIT un bouton submit avec `formaction` vers son écran : les cases ids[] et le jeton CSRF partent avec. Args: aucun.
shop.compte.donnees- Filter — CE QUE LES SATELLITES DÉPOSENT POUR L'ESPACE CLIENT. Args: [array $extras, array $client]. Clés connues : `abonnements` (shop-abonnements, chacun DÉJÀ enrichi de `statut_libelle` et `fichiers`), `licences_abonnement` et `licences_seules` (shop-licences). ⚠️ L'ORDRE COMPTE : les licences se calculent à partir des abonnements, d'où les priorités 10 puis 20. Même raison d'être que `shop.produit.donnees` : la Boutique appelait ces satellites par leur nom de classe jusqu'au 2026-09-28.
shop.connexion.etat- Filter — L'ÉTAT DE LA CONNEXION, dit par le satellite qui le connaît. Args: [array $etat]. Clés : `code_en_attente` (bool) et `minutes` (durée de validité). Sert à la page de connexion de la boutique, qui affiche le formulaire de code à six chiffres à la place des autres quand un code est en attente.
shop.produit.donnees- Filter — CE QUE LES SATELLITES DÉPOSENT POUR LA FICHE PRODUIT. Args: [array $extras, array $raw, ?array $front] — $raw est le produit BRUT (avec son `type`), $front celui que la vue affiche. Chaque satellite ajoute SA clé et rend le tableau : `variants` (shop-variants), `abonnement` (shop-abonnements), `avis_resume` (shop-avis). Une clé absente vaut « pas concerné » et la vue n'affiche alors aucun bloc. 🔴 EXISTE POUR RÉTABLIR LE SENS DE LA DÉPENDANCE : jusqu'au 2026-09-28 la vue appelait ces trois satellites par leur nom de classe, donc retirer un satellite obligeait à modifier la Boutique. Le BALISAGE, lui, reste dans la vue : les classes `s-shop-*` sont le contrat des thèmes.
shop.product.url_publique- Filter — l'adresse publique d'un produit, pour les liens de l'admin vers le site. Args: [string $url, array $product]. Défaut du socle : /boutique/<slug>. Rendre '' pour retirer le lien.
shop.price.line- Filter — LE résolveur de prix. Args: [array $line, array $product, int $qty, array $ctx]
shop.shipping.item- Filter — UNE LIGNE À EXPÉDIER : ce qu'elle pèse et dans quelle classe elle part. Args: [array $ligne, array $source] — $ligne = ['product' => array, 'qty' => int], $source = la ligne de panier ou de commande (avec ses `options`). Un satellite corrige `product` (`weight_g`, `shipping_class_id`) et rend la ligne : shop-variants y pose le poids et la classe de la DÉCLINAISON choisie. Lue par le calcul du port (`Shipping::shippableItems`) ET par le poids de l'étiquette (shop-expedition). Zéro écouteur = le produit seul, comme avant (2026-09-30).
shop.catalogue.precharger- Action — LA PAGE DE CATALOGUE VA ÊTRE TARIFÉE : voici ses produits. Args: [array<int> $productIds, array<int, array> $categoriesParProduit]. Un satellite qui lit la base dans `shop.price.line` charge ici, en une fois, ce que sa part du prix demandera pour chaque produit ; son écouteur de prix lit alors sa mémoire au lieu de la base. Appelée par `Products::frontList()` (2026-09-30 : shop-pro coûtait 46 requêtes sur 51 pour 17 produits). Un satellite qui ne l'écoute pas reste juste, simplement plus lent.
shop.price.mention- Filter — la phrase affichée au client quand le prix n'est pas celui qu'il attendait (taxe d'un autre pays, taxe retirée). Le socle voit un taux tombé à zéro mais PAS pourquoi : deux régimes s'y cachent (autoliquidation intra-UE, export hors UE) et ils ne se disent pas pareil. Celui qui a exonéré fournit sa mention, comme il fournit celle de la facture via shop.documents.snapshot. Rendre $mention inchangé pour se taire. Args: [?string $mention, array $line, array $ctx, string $pays]
shop.vat.export_detaxe- Filter — LA GARDE DE COHÉRENCE de l'affichage (#103) : le socle demande si la détaxe export aura RÉELLEMENT lieu pour cette destination avant d'afficher un prix hors taxes — sinon il montrerait moins que ce qu'il encaisse. shop-tva-intra répond selon son interrupteur export et sa carte du territoire fiscal. Zéro écouteur = zéro détaxe = affichage TTC. Args: [bool $deja, string $pays]
shop.shipping.rate- Filter — tarif de livraison résolu. Args: [?array $rate, array $method, ?array $zone, array $classes, array $cart]
shop.shipping.product_excluded- Filter bool — un produit doit-il être EXCLU du calcul de classe/zone de livraison ? Args: [bool, array $product]. Défaut false.
shop.cart.validate- Filter — erreurs bloquantes du panier au checkout. Args: [array $errors, array $cart, array $ctx]
shop.cart.add.validate- Filter — validation + enrichissement à L'AJOUT au panier (Cart::add(), juste avant l'écriture de la ligne). Args: [array $result{errors: string[], options: array}, array $product, int $qty] — $qty = quantité RÉSULTANTE de la ligne (existante + cet ajout). Le satellite pousse ses erreurs dans $result['errors'] (fail closed, la moindre erreur bloque l'ajout) et peut remplacer $result['options'] par une version enrichie (ex. libellé lisible) — utilisée UNIQUEMENT pour le JSON stocké sur une ligne NOUVELLE, jamais pour le hash d'identité (toujours calculé sur les options brutes de l'appelant).
shop.cart.added- Event — un ajout au panier a RÉUSSI (Cart::add(), après l'écriture). Args: [array $product, int $qty, array $options] — $qty = ce que CE geste a ajouté, $options = les options brutes de l'appelant (variant_id d'une déclinaison). Les pixels publicitaires y notent l'« ajout au panier ».
shop.checkout.consentements- Event — rendu HTML direct sous la case des CGV du passage en caisse (écho). Args: [array $cart]. La newsletter y pose la case « Je ne souhaite pas recevoir vos nouveautés » quand elle inscrit les clients à leur commande ; elle lit la case dans `shop.cart.validate`.
shop.checkout.usage_donnees- Filter string — la phrase « Vos données servent à traiter votre commande… » au-dessus du lien de confidentialité. Args: [string $phrase, array $cart]. Un module qui se sert des coordonnées pour autre chose la réécrit (la newsletter : « … et, sauf refus de votre part, à vous envoyer nos nouveautés »).
shop.cart.needs_shipping- Filter bool — le panier requiert-il une livraison ? Args: [bool, array $cart]
shop.order.created- Event — commande créée (pending_payment), web (Checkout::place()) ou manuelle (Orders::createManual()). Args: [array $order]
commande.creee- Event neutre — commande créée (Checkout::place() + Orders::createManual()). Args: [array $order]
paiement.recu- Event neutre — commande intégralement réglée (Orders::markPaid(), après shop.order.paid). Args: [array $order]
commande.a_livrer- Event neutre — commande DUE, à livrer : émis par markPaid() (après paiement.recu) ET par Orders::livrer() (commande due sans paiement propre, ex. box d'abonnement). Les satellites de LIVRAISON écoutent celui-ci, jamais paiement.recu. Args: [array $order]
numero_suivi.ajoute- Event neutre — n° de suivi nouvellement renseigné (Orders::updateAdmin()). Args: [array $order]
devis.accepte- Event neutre — devis converti en commande (Orders::convertToOrder(), bouton fiche §4). Args: [array $order]
shop.order.status_changed- Event — statut modifié (Orders::setStatus() ou Payments::register()/registerManual()). Args: [array $order, string $from, string $to]
shop.order.ready_to_fulfill- Filter bool — la commande peut-elle être accomplie ? Émis par Orders::markPaid() (admin ou Payments, dès qu'intégralement réglée). Args: [bool, array $order]
shop.order.paid- Event — commande intégralement payée (après ready_to_fulfill). Args: [array $order]
shop.fulfill.<type>- Event dynamique — accomplissement d'une ligne payée, une fois par type de ligne présent. Args: [array $order, array $line]
shop.order.shipping.actions- Event — actions transporteur COURTES, dans le RAIL sous le bloc Livraison ; rendu HTML direct (écho, pattern do_action §5bis). Un écran de travail va sur shop.order.main.panels. Args: [array $order]
shop.order.public.livraison- Event — rendu HTML direct sous la ligne de livraison de la page « Ma commande » du CLIENT (écho, patron do_action). Args: [array $order]. Là où se lit le LIEU quand le mode ne suffit pas : shop-expedition y affiche le point relais que le client a choisi.
shop.order.adresses.apres- Event — rendu HTML direct sous les deux adresses de la fiche commande (écho, patron do_action). Args: [array $order]. Là où se lit la DESTINATION RÉELLE quand elle n'est pas l'adresse de livraison : shop-expedition y affiche le point relais choisi par le client.
shop.order.main.panels- Event — un écran de travail en BAS DE LA COLONNE PRINCIPALE de la fiche commande (préparation d'expédition, par exemple) ; rendu HTML direct (écho). Le rail porte les leviers courts, la colonne porte ce qui se travaille. Args: [array $order]
shop.order.editor.fields- Event — rendu HTML direct dans le formulaire commande-creer.php (écho, pattern do_action). Args: [array $post, string $section] — $section = 'document_type'|'payment_modality' (deux points d'ancrage distincts dans le même formulaire).
shop.order.editor.save- Event — après un Orders::createManual() réussi. Args: [int $orderId, array $post] — le satellite y persiste document_type + échéancier (sa propre logique, table shop_order_installments).
shop.order.fiche.banner- Event — RÉORG FICHE COMMANDE (2026-07-23) : rendu HTML direct tout en haut de la fiche commande, AVANT la rangée de statuts (écho, pattern do_action). Args: [array $order] — bandeau devis + bouton Convertir SEUL (remplace shop.order.fiche.panels pour cette partie ; le seul cas légitime d'info avant le contenu réel de la commande).
shop.order.payment.panels- Event — RÉORG FICHE COMMANDE (2026-07-23) : rendu HTML direct À L'INTÉRIEUR de la carte Règlement du socle, entre « Moyen de paiement » et « Règlements reçus » (écho, pattern do_action). Args: [array $order] — panneau échéancier (remplace shop.order.fiche.panels pour cette partie).
shop.order.documents.actions- Event — RÉORG FICHE COMMANDE (2026-07-23) : rendu HTML direct dans la colonne de DROITE de la fiche commande (rail Statut/Informations), sous forme de boutons (écho, pattern do_action). Args: [array $order] — boutons Télécharger/Générer facture/devis/BL (remplace le panneau-section shop-documents posé sur shop.order.fiche.panels).
shop.order.creation_email- Filter — email de création avant envoi (Orders::sendConfirmationEmail()/sendMerchantNotification(), appelées par Orders::sendCreationEmails()). Args: [array $email{to,subject,body,footer_note}, array $order, string $kind] — $kind = 'customer'|'merchant'.
shop.order.fiche.status_row- Filter bool — affiche la rangée de pictos de statut sur la fiche commande ? Args: [bool, array $order] — un satellite (shop-commercial) renvoie false pour un devis (sa seule sortie = le bouton Convertir du bandeau).
shop.order.fiche.action- Filter — dispatch générique d'une action satellite postée depuis la fiche commande (commande.php, action=satellite_action, sub_action=<identifiant propre au satellite>). Args: [array $result{ok,errors,message}, string $subAction, int $orderId, array $post, int $actorId]. Zéro écouteur = flash d'erreur générique ("Action inconnue.").
shop.hub.tiles- Filter — vignettes du hub Boutique (modules/shop/admin/index.php), appliqué juste avant la bucketisation par groupe (HubDashboard::bucketize()). Args: [array $tiles]. Un satellite avec son propre écran admin (ex. shop-documents) y ajoute la sienne, avec sa clé 'group' (quotidien|gerer|reglages — défaut 'gerer' si absente/invalide). Zéro écouteur = hub inchangé.
shop.order.public.actions- Event — rendu HTML direct sur la page commande CLIENT (modules/shop/views/commande.php, prise front DATA-ONLY — aucun <style>). Args: [array $order] (Orders::findByToken()). Un satellite y échoit ses liens publics par access_token (ex. « Télécharger ma facture »).
shop.stock.decrement- Filter bool $handled — décrément de stock d'une ligne payée. Args: [bool, array $order, array $line]
shop.payment.providers- Filter — adaptateurs PaymentProvider disponibles [slug => classe]. Args: [array $providers]
shop.checkout.champs- Event — rendu HTML direct à la dernière étape du tunnel, APRÈS la livraison et AVANT le paiement, panier dématérialisé compris (écho, patron do_action). Args: [array $cart]. Le satellite y pose ses champs, les valide sur `shop.cart.validate` et les range sur `shop.order.created`.
shop.regles_vente.champs- Event — rendu HTML direct dans le formulaire de Boutique → Règles de vente, sous la section Commande (écho). Args: aucun. Les champs postés reviennent par `shop.regles_vente.save`.
shop.regles_vente.save- Filter — Boutique → Règles de vente enregistrée. Args: [array $erreurs, array $post, int $actorId]. Le satellite enregistre SES champs et ajoute ses erreurs (phrases) à la liste : non vide, l'écran les affiche.
shop.commandes.colonnes- Filter — les colonnes en plus de la liste des commandes, EN LOT pour la page. Args: [array $colonnes, array<int> $orderIds]. Rendre clé => ['label' => string, 'valeurs' => [id => texte], 'triable' => bool, 'compact' => bool (valeur courte, sur une ligne)]. Du texte, jamais du HTML.
shop.commandes.ordre- Filter — le tri de la liste par une colonne d'un satellite (?tri=<clé>). Args: [?array $ids, string $cle]. Rendre les ids dans l'ordre voulu (les autres commandes suivent), ou null pour une clé qui n'est pas la sienne.
shop.order.livraison.infos- Filter — des lignes [label, valeur] dans la carte Livraison de la fiche commande, sous la méthode. Args: [array $lignes, array $order]. Du texte, jamais du HTML.
shop.order.recap.lignes- Filter — des lignes [label, valeur] dans le récapitulatif des e-mails de commande (Orders::renderSummaryHtml). Args: [array $lignes, array $order]. Un thème qui compose son propre récapitulatif les relit par Orders::lignesRecap($order).
shop.order.anonymized- Event — une commande vient d'être anonymisée (RGPD, Orders::anonymizeForCustomer). Args: [int $orderId]. Un satellite y efface ce qu'il a rangé de personnel sur la commande.
shop.checkout.livraison.apres- Event — rendu HTML direct APRÈS le choix du mode de livraison et AVANT le paiement (écho, patron do_action). Args: [array $options, array $cart]. Là où un satellite demande une précision qui DÉPEND du mode retenu : shop-expedition y pose le choix du point relais.
shop.checkout.payment_terms- Filter — conditions de paiement AFFICHÉES au client au checkout (pas des choix : il lit « paiement à 30 jours » et choisit son moyen normalement). shop-pro y met celles de sa catégorie. Args: [array $terms, array $cart]
shop.vat.display_include_tax- Filter — le prix affiché est-il TTC (true) ou HT (false) ? Défaut = réglage du site ; shop-pro l'inverse pour une catégorie de clients. Args: [bool $includeTax, array $product, array $ctx]
shop.product.types- Filter — types de produit du sélecteur. Args: [array $types]
shop.editor.fields- Event — champs satellites dans l'éditeur produit. Args: [array $product]
shop.editor.save- Event — après save produit réussi. Args: [int $id, array $post]
shop.product.front- Filter — enrichit le DTO de la fiche FRONT (Products::front). Args: [array $dto, array $rawProduct] (shop 1.60)
shop.products.front.rows- Filter — les LIGNES brutes d'une liste front (Products::frontList), avant que les cartes soient construites. Args: [array $rows]. Un satellite y corrige des colonnes de shop_products EN UNE SEULE REQUÊTE groupée, et peut poser trois clés que la carte transmet : `promo_sur_option` (bool), `remise_max_pct` (int) et `prix_varie` (bool, les déclinaisons n'ont pas toutes le même prix effectif : le thème écrit « dès »). ⚠️ Il ne force PAS `sale_price_cents` du parent : une option en promo ne fait pas un produit soldé, et `on_sale` doit rester la vérité du produit. shop-variants y remonte le prix « à partir de » réel d'un produit variable. Doit renvoyer les mêmes lignes, dans le même ordre, sans en ajouter ni en retirer (shop 1.61)
shop.category.editor.fields- Event — champs satellites dans l'éditeur de catégorie. Args: [array $category]
shop.category.editor.save- Event — après save catégorie réussi. Args: [int $id, array $post]
shop.product.deleted- Event — produit supprimé (filet satellites). Args: [int $id]
shop.list.filters- Event — onglets de filtre liste produits. Args: []
shop.list.ids- Filter — restriction d'ids liste produits. Args: [?array $ids, array $get]
shop.list.row.badges- Filter — badges HTML d'une ligne produit (liste admin). Args: [string $html, array $product]
shop.customer.editor.fields- Event — rendu HTML direct sur la fiche client (client.php), form-section satellite autonome (écho, pattern do_action). Args: [array $client] (Customers::find()).
shop.customer.editor.fields.save- Event — après un POST client.php avec action='save_satellite_fields' (dispatch générique, MÊME patron que shop.editor.save : chaque satellite reçoit $_POST en entier et se garde via son propre champ marqueur — plusieurs satellites peuvent cohabiter sur ce même point d'accroche). Args: [int $customerId, array $post, ?int $actorId].
shop.editor.base_price_hidden_for_types- Filter array<string> — types de produit pour lesquels le champ Prix du socle doit être CACHÉ dans l'éditeur produit (patron data-type-only). Args: [array $hiddenTypes, array $product]. Défaut [].
shop.editor.type_change_warnings- Filter — avertissements précis (fragments de phrase, ex. "ses 4 variations"/"son fichier") de ce que CE produit perd en quittant son type ACTUEL, affichés dans la pop-up de confirmation de produit-editer.php AVANT tout changement réel. Args: [array $warnings, array $product{id,type}]. Défaut [] (zéro écouteur = aucune donnée type-spécifique à perdre = pas de pop-up, changement direct).
shop.editor.type_changed- Event — après un Products::save() réussi dont le type a RÉELLEMENT changé (comparé au type enregistré AVANT le POST) : chaque satellite efface UNIQUEMENT sa donnée type-spécifique devenue incompatible avec le NOUVEAU type (jamais l'universel ni les attributs, gérés indépendamment par Products::save()). Inconditionnel — fiable même en dégradation sans JS (la pop-up n'est qu'un avertissement avant coup). Args: [int $productId, string $oldType, string $newType, int $actorId].
shop.customer.category_options- Filter — options catégorie DATA-ONLY pour le filtre Catégorie + le sélecteur « changer de catégorie » (masse/création). Chaque option : [id, name, is_default, icon_svg, bg, fg]. Args: [array $options]. Défaut [].
shop.customer.list.categories- Filter — catégories de PLUSIEURS clients EN BLOC (évite le N+1 par ligne), uniquement les assignations EXPLICITES (absent = Standard implicite). Args: [array $map, array $customerIds]. Défaut []. Map : customer_id => option (même forme que ci-dessus).
shop.customer.list.ids- Filter — restriction d'ids liste clients (même patron que shop.list.ids), ex. filtre Catégorie (`?ccat=`). Args: [?array $ids, array $get]. Défaut null (pas de restriction).
shop.customer.category.bulk_assign- Event — changement de catégorie EN MASSE depuis la liste clients (sélection + bouton « Changer la catégorie »). Args: [array $customerIds, ?int $categoryId, ?int $actorId].
Ce qu'il écoute 10
emails.catalogue- priorité 10
emails.apercu- priorité 10
dashboard.blocs- priorité 10
media.usages.counts- priorité 10
media.usages- priorité 10
seo.coverage- priorité 10
seo.image_du_contenu- priorité 40
guide.boutique.prete- priorité 10
seo.items- priorité 40
admin.alerts- priorité 40
Ses prises front
Les morceaux de page que ce module fournit, et les classes qu'ils posent. Un thème les habille par ces classes : il ne recopie pas le balisage, sinon il rate les corrections des versions suivantes.
views/checkout.php
48 classes
s-shop-checkouts-shop-checkout-actionss-shop-checkout-adresses-enregistreess-shop-checkout-cgvs-shop-checkout-champs-shop-checkout-compte-notes-shop-checkout-conditions-shop-checkout-condition-descs-shop-checkout-condition-labels-shop-checkout-conditionss-shop-checkout-confidentialites-shop-checkout-confirmers-shop-checkout-connexion-requises-shop-checkout-continuers-shop-checkout-dematerialises-shop-checkout-emails-shop-checkout-errors-shop-checkout-etape1s-shop-checkout-etape2s-shop-checkout-facturation-adresses-shop-checkout-facturation-toggles-shop-checkout-hps-shop-checkout-inputs-shop-checkout-livraison-adresses-shop-checkout-livraison-descs-shop-checkout-livraison-indisponibles-shop-checkout-livraison-methodess-shop-checkout-livraison-options-shop-checkout-modifiers-shop-checkout-notes-shop-checkout-optionnels-shop-checkout-paiements-shop-checkout-paiement-echeances-shop-checkout-paiement-instructionss-shop-checkout-paiement-labels-shop-checkout-paiement-options-shop-checkout-paiement-pictos-shop-checkout-produits-non-livrabless-shop-checkout-recap-lignes-shop-checkout-recap-ligness-shop-checkout-recap-noms-shop-checkout-recap-prixs-shop-checkout-recap-qtys-shop-checkout-recap-sous-totals-shop-checkout-recap-taxess-shop-checkout-recap-total-dus-shop-checkout-textareas-shop-checkout-vide
views/commande.php
43 classes
s-shop-commandes-shop-commande-adresse-livraisons-shop-commande-adresse-titres-shop-commande-attente-paiements-shop-commande-carte-cadeau-notices-shop-commande-details-shop-commande-echeances-shop-commande-echeance-labels-shop-commande-echeance-montants-shop-commande-echeance-statuts-shop-commande-echeanciers-shop-commande-introuvables-shop-commande-lignes-shop-commande-ligne-labelss-shop-commande-ligne-noms-shop-commande-ligne-prixs-shop-commande-ligne-qtys-shop-commande-ligness-shop-commande-livraisons-shop-commande-message-vendeurs-shop-commande-message-vendeur-textes-shop-commande-message-vendeur-titres-shop-commande-numeros-shop-commande-paiement-consigness-shop-commande-paiement-flashs-shop-commande-paiement-instructionss-shop-commande-paiement-moyens-shop-commande-payers-shop-commande-payer-submits-shop-commande-promo-notices-shop-commande-remises-shop-commande-statuts-shop-commande-suivis-shop-commande-suivi-contenus-shop-commande-suivi-liens-shop-commande-suivi-nums-shop-commande-suivi-transporteurs-shop-commande-suiviss-shop-commande-suivis-listes-shop-commande-suivis-titres-shop-commande-totals-shop-commande-tvas-shop-ligne-variante
views/compte.php
102 classes
s-shop-abonnement-echeances-shop-abonnement-fichiers-shop-abonnement-fichier-liens-shop-abonnement-fichier-noms-shop-abonnement-fichierss-shop-abonnement-noms-shop-abonnement-prixs-shop-abonnement-resiliers-shop-abonnement-resilier-submits-shop-abonnement-statuts-shop-adresse-cartes-shop-adresse-champs-shop-adresse-contacts-shop-adresse-contact-herites-shop-adresse-defauts-shop-adresse-defaut-livraisons-shop-adresse-emails-shop-adresse-etats-shop-adresse-facturations-shop-adresse-facturation-definirs-shop-adresse-facturation-retirers-shop-adresse-forms-shop-adresse-inputs-shop-adresse-labels-shop-adresse-localites-shop-adresse-modifiers-shop-adresse-noms-shop-adresse-nouvelles-shop-adresse-rues-shop-adresse-societes-shop-adresse-submits-shop-adresse-supprimers-shop-adresse-supprimer-submits-shop-adresse-titres-shop-adresse-types-shop-comptes-shop-compte-abonnements-shop-compte-abonnementss-shop-compte-abonnements-listes-shop-compte-abonnements-titres-shop-compte-adresses-shop-compte-adressess-shop-compte-adresses-notes-shop-compte-commandes-shop-compte-commande-dates-shop-compte-commande-liens-shop-compte-commande-numeros-shop-compte-commande-statuts-shop-compte-commande-totals-shop-compte-commandess-shop-compte-commandes-listes-shop-compte-commandes-titres-shop-compte-commandes-vides-shop-compte-deconnexions-shop-compte-deconnexion-submits-shop-compte-errors-shop-compte-infoss-shop-compte-infos-aides-shop-compte-infos-champs-shop-compte-infos-email-forms-shop-compte-infos-forms-shop-compte-infos-inputs-shop-compte-infos-submits-shop-compte-infos-titres-shop-compte-licencess-shop-compte-licences-titres-shop-compte-mdps-shop-compte-mdp-champs-shop-compte-mdp-forms-shop-compte-mdp-inputs-shop-compte-mdp-optionnels-shop-compte-mdp-submits-shop-compte-mdp-titres-shop-compte-requiert-connexions-shop-compte-successs-shop-connexion-optionnels-shop-licences-shop-licence-codes-shop-licence-copiers-shop-licence-echeances-shop-licence-etats-shop-licence-generers-shop-licence-generer-submits-shop-licence-labels-shop-licence-label-inputs-shop-licence-regenerers-shop-licence-regenerer-submits-shop-licence-resets-shop-licence-reset-submits-shop-licence-sites-shop-licences-echeances-shop-licences-libress-shop-licences-listes-shop-licences-offres-shop-licences-plans-shop-licences-quotas-shop-licences-totals-shop-licences-utiliseess-shop-password-eyes-shop-password-generers-shop-password-regless-shop-password-wrap
views/connexion.php
28 classes
s-shop-connexions-shop-connexion-champs-shop-connexion-codes-shop-connexion-code-champs-shop-connexion-code-forms-shop-connexion-code-intros-shop-connexion-code-renvoyers-shop-connexion-code-renvoyer-btns-shop-connexion-dejas-shop-connexion-emails-shop-connexion-errors-shop-connexion-hps-shop-connexion-inputs-shop-connexion-inscriptions-shop-connexion-logins-shop-connexion-noms-shop-connexion-optionnels-shop-connexion-oublis-shop-connexion-passwords-shop-connexion-password-confirms-shop-connexion-prenoms-shop-connexion-submits-shop-connexion-successs-shop-connexion-telephones-shop-password-eyes-shop-password-generers-shop-password-regless-shop-password-wrap
views/panier.php
24 classes
s-shop-ligne-variantes-shop-paniers-shop-panier-actionss-shop-panier-checkouts-shop-panier-errors-shop-panier-images-shop-panier-labels-shop-panier-labelss-shop-panier-lignes-shop-panier-ligness-shop-panier-noms-shop-panier-options-shop-panier-optionss-shop-panier-qtys-shop-panier-qty-inputs-shop-panier-qty-submits-shop-panier-retirers-shop-panier-retirer-submits-shop-panier-successs-shop-panier-totals-shop-panier-total-lignes-shop-panier-vides-shop-panier-viders-shop-panier-vider-submit
views/pays.php
8 classes
s-payss-pays-choixs-pays-noms-pays-options-pays-option<?=s-pays-radios-pays-titres-pays-valider
views/produit.php
61 classes
s-shop-abos-shop-abo-champs-shop-abo-champ-cases-shop-abo-champ-choixs-shop-abo-champ-options-shop-abo-champ-textes-shop-abo-plans-shop-abo-plan-essais-shop-abo-plan-noms-shop-abo-plan-prixs-shop-abo-plan-radios-shop-abo-planss-shop-abo-plans-titres-shop-attributs-shop-attribut-noms-shop-attribut-valeurss-shop-badges-shop-badge-favoris-shop-badge-promos-shop-badge-ruptures-shop-badge-stocks-shop-categorie-items-shop-etiquettes-shop-produit-achats-shop-produit-ajouters-shop-produit-ajouter-qtys-shop-produit-ajouter-qty-labels-shop-produit-ajouter-submits-shop-produit-attributss-shop-produit-badgess-shop-produit-categories-shop-produit-categoriess-shop-produit-champ-libres-shop-produit-descs-shop-produit-details-shop-produit-etiquettess-shop-produit-excerpts-shop-produit-fiches-shop-produit-galeries-shop-produit-images-shop-produit-image-avants-shop-produit-imagess-shop-produit-inputs-shop-produit-noms-shop-produit-non-commandables-shop-produit-prixs-shop-produit-prix-barres-shop-produit-prix-mentions-shop-produit-supplements-shop-produit-variantess-shop-variante-axes-shop-variante-axe-noms-shop-variante-descriptions-shop-variante-epuises-shop-variante-items-shop-variante-parts-shop-variante-radios-shop-variante-statuts-shop-variante-valeurs-shop-variante-valeur-libelles-shop-variantes-catalogue
views/produits.php
23 classes
s-shop-badges-shop-badge-favoris-shop-badge-promos-shop-badge-ruptures-shop-cat-images-shop-categories-shop-categorie-'s-shop-categorie-<slug>s-shop-categorie-descs-shop-categorie-titres-shop-categorie<?=s-shop-produits-shop-produit-ajouters-shop-produit-ajouter-submits-shop-produit-badgess-shop-produit-excerpts-shop-produit-images-shop-produit-noms-shop-produit-prixs-shop-produit-prix-barres-shop-produit-prix-mentions-shop-produitss-shop-produits-liste
Ses données
Les tables que ce module crée. Désactiver un module ne les efface pas : ses données restent en base et reviennent s'il est réactivé.
Les tables 39
shop_addressesshop_attribute_valuesshop_attributesshop_carriersshop_cart_itemsshop_cartsshop_category_imagesshop_category_shippingshop_category_vatshop_customer_tokensshop_customersshop_order_installmentsshop_order_itemsshop_order_statusesshop_order_trackingshop_ordersshop_orders_countersshop_payment_methodsshop_payment_providersshop_paymentsshop_product_attributesshop_product_categoriesshop_product_imagesshop_product_tagsshop_productsshop_shipping_bloc_categoriesshop_shipping_bloc_classesshop_shipping_bloc_productsshop_shipping_bloc_ratesshop_shipping_blocsshop_shipping_classesshop_shipping_methodsshop_shipping_ratesshop_shipping_typesshop_shipping_zone_rulesshop_shipping_zonesshop_status_iconsshop_tagsshop_tax_rates