Djust 3.124.0 - Semaine du 6 Juillet 2026

Périmètre

🛠️ API

📘

NEW

Calcul dynamique des frais de livraison au checkout

Contexte

Les frais de livraison au checkout n'étaient pas calculés dynamiquement à partir d'une matrice de prix. Le module Shipping calcule désormais les frais applicables en évaluant la matrice configurée par l'opérateur selon les dimensions famille logistique × zone de livraison × type de livraison (+ supplier en contexte marketplace).

Fonctionnement

  • Split du panier en commandes logistiques : par famille logistique en e-commerce, par combinaison supplier × famille logistique en marketplace. Chaque commande logistique porte ses propres frais.
  • Résolution de la zone de livraison à partir de l'adresse de livraison (priorité au champ department, sinon extraction depuis le code postal).
  • Franco de port appliqué par commande logistique (jamais sur le panier global) : au-delà du seuil, les frais passent à 0 € sur la commande logistique concernée.
  • Recalcul dynamique des frais à chaque consultation du panier, pour refléter en temps réel les changements de matrice ou d'adresse.
  • Sélection du type de livraison et commit de l'adresse : application du prix issu de la matrice sur la commande logistique.
  • Validation de commande : les frais sont figés (snapshot) sur la commande logistique (totalShippingFeesWithTax, totalShippingFeesWithoutTax, totalShippingTaxAmount). Si la matrice a changé entre la sélection et la validation, le prix est recalculé au validate et c'est ce nouveau prix qui est figé.

Cas bloquants au checkout : adresse hors zone ou combinaison sans ligne de matrice (aucun type de livraison retourné, checkout bloqué) ; type de livraison ne correspondant plus à une ligne (404) ; aucune ligne disponible pour la combinaison à la sélection ou à la validation (409). Warnings via blockedLineInformation : référence introuvable ou type de livraison inactif (bloquants), prix modifié suite à un recalcul (informatif).

Cohabitation avec le legacy : si le module Shipping est désactivé (shippingEnabled: false), le comportement historique est inchangé (custom fields d'offre shippingTaxe / shippingCode) ; s'il est activé (shippingEnabled: true), la matrice est utilisée exclusivement (custom fields d'offre ignorés).

Marketplace : les frais de livraison sont reversés au supplier dans le split de paiement ; la marketplace ne prélève pas de commission sur le shipping.

Impact API

  • GET /v2/shop/carts/{cartId} et /lines — recalcul dynamique des frais à la consultation du panier.
  • PUT /v2/shop/commercial-orders/{id}/shipping-information — sélection du type de livraison et commit de l'adresse.
  • POST /v2/shop/commercial-orders/{id}/validate — frais figés sur la commande logistique.

Aucun changement de contrat API : mêmes champs, mêmes types, même structure sur les DTOs cart v2 et order. Codes d'erreur : 404 (type de livraison sans ligne de matrice), 409 (aucune ligne disponible pour la combinaison).

👉 Côté métier : les frais de livraison sont calculés automatiquement au checkout selon la matrice de l'opérateur (famille logistique, zone, type de livraison, supplier), avec franco de port par commande logistique.

👉 Côté technique : calcul dynamique sur les routes cart v2 et commandes commerciales, sans changement de contrat ; frais figés à la validation ; comportement legacy préservé quand shippingEnabled: false.


Historique des modifications sur les rôles & groupes (API admin)

Contexte

Aucun audit log ne permettait de retracer les modifications de droits sur le module groupes & rôles — prérequis pour ouvrir le module aux clients en confiance.

Fonctionnement

Un nouvel endpoint admin paginé expose l'historique chronologique des modifications de droits. Sept types d'événements sont journalisés : ADD_ROLE / REMOVE_ROLE (ajout / retrait d'une permission sur un groupe), ADD_USER / REMOVE_USER (ajout / retrait d'un utilisateur), RENAME_GROUP (ancien → nouveau nom), CREATE_GROUP / DELETE_GROUP.

Les snapshots sont figés : noms, emails et noms de groupes sont conservés au moment de l'événement (un utilisateur supprimé ou un groupe renommé/supprimé reste consultable avec ses valeurs d'origine). Les événements sont append-only : aucun endpoint d'édition ou de suppression n'est exposé.

Impact API

  • GET /v1/group-roles/history — endpoint tenant-level (headers dj-store / dj-store-view ignorés).
  • Authentification : header dj-client: OPERATOR, rôle ALL_USER_GROUPS_READ.
  • Champs de l'événement : id, createdAt (UTC), eventType, clientType (OPERATOR / ACCOUNT / SUPPLIER), user, role, group, targetUser, previousValue.
  • Filtres (AND entre filtres, OR entre valeurs d'un même filtre) : clientType (obligatoire — absent → 400 Bad Request), groupId, userId, eventType (multi), from / to. Tri createdAt:desc par défaut. Pagination page (0-based, défaut 0), size (défaut 20, max 100).

👉 Côté métier : chaque modification de droits (rôles, membres, groupes) est traçable — qui a fait quoi et quand — pour l'investigation, la sécurité et la conformité.

👉 Côté technique : nouvel endpoint admin paginé GET /v1/group-roles/history, append-only, snapshots figés, 7 types d'événements, filtre clientType obligatoire.

⚠️

IMPORTANT UPDATE

Recherche unifiée sur les listes paginées Shipping

Contexte

Les endpoints de liste paginée du module Shipping filtraient uniquement sur le nom, via un query param name.

Fonctionnement

Les trois endpoints de liste paginée du module Shipping filtrent désormais à la fois sur le nom et sur l'externalId (recherche OR, insensible à la casse et aux accents). Le query param name est remplacé par un query param unifié search, aligné sur le comportement déjà en place sur l'endpoint classification-categories.

Impact API

Sur GET /v1/shipping-types, GET /v1/shipping-zones et GET /v1/logistic-families, le query param name est remplacé par search (filtre sur nom + externalId). Les intégrations utilisant name doivent migrer vers search.

👉 Côté métier : la recherche sur les listes Shipping porte désormais sur le nom et l'externalId, comme sur les classifications.

👉 Côté technique : query param name remplacé par search sur shipping-types, shipping-zones et logistic-families — migration requise pour les intégrations utilisant name.


Garde-fou « no-orphan user » — un utilisateur toujours rattaché à au moins un groupe

Contexte

Un utilisateur pouvait se retrouver « sans groupe » (perte totale d'accès). Cet état n'est plus valide.

Fonctionnement

Un utilisateur doit désormais appartenir à au moins un groupe à tout instant ; seul l'état 0 groupe devient interdit (le multi-groupe reste autorisé). Le garde-fou est appliqué côté back, afin qu'un appel API direct (curl, Postman, intégration tierce) ne puisse pas le contourner. Ajouter et retirer un utilisateur d'un groupe restent deux opérations indépendantes (pas de « move » forcé). Les utilisateurs déjà en multi-groupe ne sont pas impactés (pas de migration).

Impact API

Opérations encadrées (refus avec le message « L'utilisateur doit être rattaché à au moins un groupe. ») :

  • Création d'un utilisateur : au moins un groupe obligatoire (refus si groups[] absent ou vide).
  • DELETE /v2/user-groups/{groupId}/users/USERID : refus si c'est le seul groupe de l'utilisateur.
  • PATCH /v1/customer-users/USERID/groups : refus si le payload contient un array vide.
  • PUT /v1/operator-users/{id} et PUT /v1/supplier-users/{id} : refus si le champ groups[] est vide.

👉 Côté métier : plus aucun utilisateur ne peut se retrouver sans groupe (donc sans accès) ; le multi-groupe reste possible.

👉 Côté technique : garde-fou back-side refusant tout état 0 groupe à la création et sur les endpoints de retrait / mise à jour de groupes (DELETE user-groups, PATCH customer-users/groups, PUT operator-users / supplier-users).