Skip to content

Gestion des coupons

Les coupons sont créés depuis l'admin et peuvent être utilisés par les clients pendant le paiement d'un abonnement, l'achat de produits et le checkout du panier. Le backend reste responsable de la validation et du calcul de remise ; le frontend envoie le code coupon et affiche le résultat validé par l'API.

  • Liste admin des coupons : https://admin.acusolo.net/admin/coupons
  • Checkout panier web : https://web.acusolo.net/cart
  • Achat boutique/accessoires : https://web.acusolo.net/accessories
  • Achat de plans : https://web.acusolo.net/plans

Exemple de coupon dans le panier web

Sur la page panier, l'utilisateur peut saisir un code coupon avant Stripe Checkout. Si le coupon est valide, le backend calcule la remise et le montant Stripe est ajusté avant le paiement.

Exemple d'application de coupon dans le panier web

Les coupons peuvent s'appliquer à :

  • Paiements de plans d'abonnement depuis le flux Plans.
  • Achats de produits depuis la boutique/accessoires.
  • Paiements panier depuis la page panier.

Liste admin des coupons

Ouvrez https://admin.acusolo.net/admin/coupons pour gérer les coupons.

Page admin liste des coupons

La liste utilise GET /admin/coupon/all avec pagination et recherche. Le tableau affiche le code, le nom, la remise, la portée, le nombre d'utilisations, les points requis, l'expiration, le statut et les actions.

Actions admin

  • Create Coupon ouvre le modal de création.
  • Edit ouvre le modal d'édition avec les données du coupon sélectionné.
  • Delete supprime le coupon de la base et désactive/supprime les références Stripe.
  • Toggle statut met à jour active et synchronise l'état du promotion code Stripe.
  • Recherche filtre par nom, code ou description.

Le frontend admin utilise RTK Query dans couponApi : création, mise à jour et suppression invalident la liste ; le changement de statut applique une mise à jour optimiste sur les listes en cache et annule si l'API échoue.

Créer un coupon

Cliquez sur Create Coupon pour ouvrir le modal.

Modal de création de coupon

Champs requis

ChampRôle
CodeCode coupon requis. L'UI admin le met en majuscules avant l'envoi. Il doit être unique côté backend et ne pas dépasser 255 caractères.
NameNom requis du coupon. Utilisé comme nom du coupon Stripe.
Discount TypeRequis. PERCENTAGE ou FIXED_AMOUNT.
Discount ValueNombre positif requis. Le frontend bloque un pourcentage supérieur à 100. Le montant fixe est traité en EUR dans l'UI.

Champs optionnels

ChampRôle
DescriptionDescription admin stockée avec le coupon.
Applies ToPortée du coupon : ALL, SUBSCRIPTION, PRODUCT ou SPECIFIC.
Expires AtDate d'expiration optionnelle. Les coupons expirés sont rejetés par le backend.
Select Subscription PlansAffiché pour SUBSCRIPTION et SPECIFIC. Vide signifie tous les abonnements pour SUBSCRIPTION; requis si SPECIFIC dépend de plans ciblés.
Select DevicesAffiché pour PRODUCT et SPECIFIC. Vide signifie tous les appareils pour PRODUCT; les IDs sélectionnés restreignent les lignes appareil.
Select AccessoriesAffiché pour PRODUCT et SPECIFIC. Vide signifie tous les accessoires pour PRODUCT; les IDs sélectionnés restreignent les lignes accessoire.
Coupon DistributionQui peut utiliser le coupon : GENERAL, POINTS_REDEEMABLE ou USER_SPECIFIC.
Allowed User EmailsSeulement pour USER_SPECIFIC. Liste d'emails séparés par virgule ou nouvelle ligne.
Points Required to RedeemSeulement pour POINTS_REDEEMABLE. Requis dans l'UI pour ce type.
Max Total UsesLimite globale d'utilisation. Synchronisée avec les redemptions max Stripe à la création.
Max Uses Per UserLimite d'utilisation par utilisateur après checkout complété. Valeur par défaut : 1.
Min Purchase (EUR)Montant minimum éligible avant application du coupon.

Options de portée

OptionComportement
All (Subscriptions + Products)Peut s'appliquer aux abonnements, appareils et accessoires. Les lignes de livraison ne sont pas remisées.
Subscriptions OnlyS'applique seulement aux lignes abonnement ; les IDs de plans peuvent limiter les plans éligibles.
Products OnlyS'applique seulement aux lignes appareil/accessoire ; les IDs sélectionnés peuvent limiter les produits éligibles.
Specific ItemsRequiert au moins un plan, appareil ou accessoire sélectionné dans la validation backend. Seuls ces éléments sont éligibles.

Options de distribution

OptionComportement
GeneralTout utilisateur éligible peut utiliser le coupon tant que les limites, l'expiration ou le statut ne le bloquent pas.
Points RedeemableL'utilisateur doit déjà avoir une réservation/redemption de coupon avant checkout. Si la session Stripe expire, le backend rembourse les points réservés et supprime la réservation.
User SpecificLe backend compare l'email de l'utilisateur connecté avec allowedUserEmails. Les autres utilisateurs sont rejetés.

Après la création

Le backend POST /admin/coupon vérifie l'unicité du code, crée un coupon Stripe, crée ou réactive un promotion code Stripe, puis stocke le coupon avec les IDs Stripe. Les coupons en pourcentage utilisent percent_off; les montants fixes utilisent amount_off en centimes.

Modifier un coupon

Cliquez sur le bouton d'édition dans la liste pour ouvrir le modal.

Modal d'édition de coupon

Le modal est prérempli depuis les données de la ligne sélectionnée. Code, Type et Discount Value sont affichés mais désactivés dans l'UI actuelle. Les champs modifiables incluent le nom, la description, la portée, l'expiration, les plans/appareils/accessoires sélectionnés, les limites d'utilisation, le minimum d'achat, le type de distribution, les emails autorisés et les points requis.

Le statut est modifié depuis le toggle de la liste, pas depuis le modal d'édition. Désactiver un coupon le rend inutilisable au checkout et désactive le promotion code Stripe.

Les règles mises à jour s'appliquent aux futures validations et futures sessions de paiement. Les paiements déjà complétés ne sont pas recalculés.

Validation backend

Les contrôles coupon se font côté serveur avant que le frontend considère le coupon comme appliqué.

Endpoint d'application coupon

GET /payment/apply-coupon/:codeOrId vérifie :

  • Le code ou ID existe et est actif.
  • Le coupon n'est pas expiré.
  • La limite globale maxUses n'est pas atteinte.
  • L'utilisateur existe.
  • USER_SPECIFIC contient l'email de l'utilisateur.
  • POINTS_REDEEMABLE possède une redemption/réservation existante.
  • maxUsesPerUser n'est pas atteint pour les checkouts complétés.
  • Les références Stripe coupon et promotion code sont valides et actives lorsqu'elles existent.

La réponse retourne l'ID du coupon, le code, la valeur de remise, la devise et le symbole. Le frontend doit afficher ce résultat validé sans inventer son propre statut.

Validation checkout panier

POST /payment/cart-checkout valide à nouveau le panier soumis, la livraison et le coupon avant de créer Stripe Checkout. Il rejette les totaux invalides, les coupons inactifs/expirés et les minimums d'achat non atteints.

Pour le panier, le backend calcule la remise depuis le sous-total :

  • PERCENTAGE : sous-total multiplié par le pourcentage.
  • FIXED_AMOUNT : montant fixe limité au sous-total.
  • La remise ne descend jamais sous 0 et ne dépasse jamais le sous-total.
  • La livraison est ajoutée après le sous-total remisé.
  • Stripe reçoit des montants de lignes ajustés, donc l'utilisateur paie le total remisé.

La commande stocke couponId, les données du coupon dans les métadonnées et discountAmount.

Validation abonnement/produit

Le flux wallet payment-link accepte un couponCode optionnel. Il valide le coupon, puis l'applique aux lignes éligibles pour les checkouts d'abonnement. L'éligibilité suit appliesTo et les IDs ciblés dans metadata. La livraison est exclue des remises.

Pour les payment links produit non-abonnement, le backend actuel attend que le frontend envoie déjà un montant remisé et ne réapplique pas le coupon une seconde fois.

Stripe et suivi d'utilisation

Les opérations admin de création, mise à jour, statut et suppression synchronisent les coupons ou promotion codes Stripe. Les sessions checkout transportent couponCode dans les métadonnées quand applicable.

Sur checkout.session.completed, le webhook Stripe enregistre l'utilisation dans coupon_redemptions et incrémente Coupon.usedCount. Ce suivi s'applique aux checkouts abonnement et paiement. Pour les coupons avec points, le webhook transforme la réservation en redemption complétée en ajoutant l'ID de session Stripe.

Cas d'erreur

L'utilisateur doit recevoir un rejet lorsque :

  • Le code coupon est vide ou introuvable.
  • Le coupon est inactif ou expiré.
  • La synchronisation Stripe coupon/promotion-code est invalide.
  • La limite globale ou la limite par utilisateur est atteinte.
  • Le minimum d'achat n'est pas atteint.
  • Un coupon spécifique utilisateur est utilisé par un email non autorisé.
  • Un coupon avec points n'a pas été réservé/racheté d'abord.
  • Un coupon SPECIFIC n'a aucune ligne éligible dans le checkout.

Flux d'utilisation

  1. L'admin crée un coupon depuis https://admin.acusolo.net/admin/coupons.
  2. Le backend le stocke et le synchronise avec Stripe.
  3. L'utilisateur saisit le coupon dans le panier, l'achat produit ou le checkout abonnement.
  4. Le backend valide le coupon et les règles de ciblage.
  5. Le backend calcule la remise sur les éléments éligibles.
  6. Stripe Checkout est créé avec le montant remisé.
  7. Après paiement réussi, le webhook Stripe enregistre l'utilisation.