Ibexa Commerce 4.6 : une promotion réservée aux clients VIP — REX VIP20

Ibexa Commerce 4.6 : une promotion réservée aux clients VIP — REX VIP20

Après la remise catalogue et le code promotionnel classique, notre formation Ibexa Commerce aborde un cas plus proche d’un vrai projet B2C ou B2B : réserver une offre à une catégorie de clients.

Notre règle est volontairement lisible : un client du groupe vip reçoit 20 % de remise avec le code VIP20, à partir de 100 € HT et uniquement en EUR.

Ce que nous allons relier

Cette démonstration utilise quatre objets différents :

  • un Customer Group Commerce nommé vip ;
  • un contenu utilisateur de type customer, nommé vip.demo ;
  • un code promotionnel VIP20 ;
  • une remise panier qui réunit toutes les conditions.

Un groupe client Commerce n’est pas un groupe d’utilisateurs Ibexa. Le premier sert au contexte commercial : prix personnalisés et promotions. Le second sert principalement à l’organisation des utilisateurs et à l’attribution des rôles et permissions.

1. Créer le groupe client et la promotion

La migration src/Migrations/Demo/16_vip_customer_promotion.yaml crée le groupe, le code et la remise :

- type: customer_group
  mode: create
  identifier: vip
  names:
    eng-GB: 'VIP customers'
  global_price_rate: '0'

- type: discount_code
  mode: create
  code: VIP20
  global_usage_limit: 100
  user_usage_limit: 1

- type: discount
  mode: create
  identifier: demo_vip20
  discount_type: cart
  priority: 8
  enabled: true
  rule:
    type: percentage
    expressionValues:
      discount_percentage: 20
  conditions:
    - identifier: is_in_currency
      expressionValues:
        currency_code: EUR
    - identifier: minimum_purchase_amount
      expressionValues:
        minimum_purchase_amount: 100
    - identifier: is_valid_discount_code
      expressionValues:
        discount_code: VIP20
        usage_count: 1
        global_usage_count: 100
    - identifier: is_user_in_customer_group
      expressionValues:
        customer_groups: [vip]

Le code et la remise sont deux objets distincts. Le code représente ce que le client saisit et porte les limites d’usage. La remise contient le calcul et les conditions d’éligibilité.

2. Créer un client réellement rattaché au groupe

La migration 17_vip_customer.yaml crée vip.demo avec le Content Type customer. Son champ customer_group, de type ibexa_customer_group, pointe vers le groupe Commerce VIP.

- type: user
  mode: create
  metadata:
    login: vip.demo
    contentType: customer
  groups:
    - ibexa_customer_group
  fields:
    - fieldDefIdentifier: customer_group
      fieldTypeIdentifier: ibexa_customer_group
      languageCode: eng-GB
      value:
        customer_group_id: 2

Dans cette instance de formation, le groupe vip possède l’ID 2. Dans un projet déployé sur plusieurs environnements, il faut résoudre l’ID à partir de l’identifiant vip au lieu de figer une valeur locale.

3. Ne pas oublier les permissions Storefront

Notre premier test connecté a échoué avec :

The User does not have the 'view' 'customer_group' permission

Le moteur doit lire le groupe commercial du client pour résoudre son contexte de prix et ses promotions. Nous avons donc ajouté cette permission au rôle Storefront User dans 18_storefront_customer_group_permission.yaml :

- type: role
  mode: update
  match:
    field: identifier
    value: 'Storefront User'
  policies:
    mode: append
    list:
      - module: customer_group
        function: view

Ce détail est important : une configuration correcte en Back Office ne suffit pas si l’utilisateur connecté n’a pas le droit de lire son contexte commercial.

4. Exécuter les migrations

php bin/console ibexa:migrations:migrate \
  --file=16_vip_customer_promotion.yaml --dry-run

php bin/console ibexa:migrations:migrate \
  --file=16_vip_customer_promotion.yaml

php bin/console ibexa:migrations:migrate \
  --file=17_vip_customer.yaml

php bin/console ibexa:migrations:migrate \
  --file=18_storefront_customer_group_permission.yaml

php bin/console ibexa:discounts:reindex
php bin/console cache:clear

5. Vérifier d’abord la logique en ligne de commande

La commande de démonstration crée un panier appartenant à vip.demo, ajoute quatre T-shirts puis fournit le code VIP20 :

php bin/console app:demo:vip-cart

Résultat obtenu :

owner=vip.demo
quantity=4
unit_amount=2392
code=VIP20

Les montants de l’API Commerce sont exprimés dans l’unité mineure : 2392 correspond à 23,92 €.

6. Tester dans le Storefront

Nous nous connectons avec le compte VIP, plaçons quatre T-shirts à 29,90 € HT dans le panier, puis saisissons VIP20.

Panier VIP20 et commande Ibexa Commerce créée avec la remise réservée au groupe VIP

La preuve visuelle confirme le calcul :

Prix avant remise :       4 × 29,90 € = 119,60 € HT
Remise VIP de 20 % :                    -23,92 €
Sous-total remisé :                       95,68 € HT
TVA à 20 % :                              19,12 €
Total :                                  114,80 € TTC

Le seuil de 100 € est évalué avant la remise. Le total HT peut donc passer sous 100 € après application de VIP20.

Après validation du Checkout, Ibexa crée la commande en conservant la réduction. L'ajout des 7,08 € de livraison porte le total final à 121,88 € TTC. La commande, le paiement et l'expédition commencent avec le statut Pending : ils poursuivront ensuite leurs workflows respectifs.

Ce qui se passe avec les autres promotions

Le produit possède déjà une remise catalogue de 10 %. Avant de saisir un code, le panier affiche donc 26,91 € HT par unité. Le code général IBEXA15 peut également appliquer 15 %.

Pour notre client VIP, VIP20 produit finalement 23,92 € HT par unité. Les remises actives coexistent dans la configuration, mais elles ne sont pas automatiquement additionnées : dans ce scénario, Ibexa retient la promotion panier applicable à la place de la remise catalogue.

Sans code :  remise catalogue 10 % → 26,91 €
IBEXA15 :    remise panier 15 %     → 25,42 €
VIP20 :      remise panier VIP 20 % → 23,92 €

Il faut donc tester les règles, leurs conditions et leurs priorités. « Plusieurs promotions actives » ne signifie pas « plusieurs promotions cumulées ».

Pourquoi ce mécanisme est intéressant

Ibexa Commerce permet de construire des offres adaptées au contexte client sans dupliquer les produits : tarifs fidélité, avantages partenaires, conditions revendeurs ou campagnes B2B. La même fiche produit peut ainsi produire un résultat commercial différent selon l’utilisateur connecté, sa devise, son groupe et son panier.

La séparation des responsabilités reste claire :

  • le Content Type customer décrit le client ;
  • le Customer Group porte son segment commercial ;
  • le code contrôle l’activation et les usages ;
  • la remise contient les règles de calcul ;
  • les permissions autorisent le Storefront à résoudre ce contexte.

Conclusion

Ce REX valide toute la chaîne : groupe VIP, client rattaché, permission Storefront, code limité, seuil de panier et calcul réel de 20 %. Le résultat n’est pas seulement visible dans le Back Office : il est vérifié en commande puis dans le panier du client connecté.

La prochaine étape naturelle sera la migration de cette formation d’Ibexa 4.6 vers Ibexa 5, en conservant ces scénarios comme tests de non-régression Commerce.