Catalogue

Référence technique du domaine Catalogue — produits, catégories hiérarchiques, variantes, attributs et modalités de vente.

Catalogue

Périmètre : produits (équipements et services), catégories hiérarchiques, attributs, variantes et modalités de vente (achat, abonnement, location, service). Le catalogue est la source de vérité pour la tarification et la configuration des devis/commandes/contrats. À distinguer des Asset (instances physiques d'un produit).

Les écrans vivent sous /workspace/{products,product-categories,product-variants,product-modalities} et les routes API à plat sous /api/workspace/{products,product-categories,product-variants,product-modalities} (le préfixe /catalog/ n'existe pas). Source de cette page : docs/12-domain-catalog.md.

Vocabulaire & entités

TermeEntitéDéfinition
ProduitProductRéférence catalogue (modèle, forfait…). Distinct de l'instance physique Asset.
CatégorieProductCategoryClassification hiérarchique drag-drop pour la navigation.
VarianteProductVariantDéclinaison d'un produit (taille, couleur, capacité). Hérite du prix parent si non surchargé.
Attribut de varianteProductVariant.attributesJsonAttributs de déclinaison stockés en JSON ({ color: "white", size: "500L" }). Pas d'entité ProductAttribute dédiée.
ModalitéProductSellModalityFaçon de vendre/louer : ONE_SHOT, SUBSCRIPTION, LEASE, SERVICE. Un produit peut en avoir plusieurs.
Référence (SKU)Product.referenceRéférence interne unique par organisation. ProductVariant porte sa propre sku.

Le schéma complet est dans docs/04-data-model.md §5. Le stock est porté par Product.stockQuantity/stockThreshold; les variantes ont leur propre stock.

Écrans

ÉcranRouteContenu
Liste produits/workspace/productsDataTable : référence, nom, catégorie, prix HT, stock, modalités, statut. Filtres + recherche.
Création / édition/workspace/products/[id|new]Identité, tarification, stock, catégorie, statut (ACTIVE / ARCHIVED).
Catégories/workspace/product-categoriesListe + création/édition (/new, /[id]). Hiérarchie via position / parentId.
Variantes/workspace/product-variantsDéclinaisons d'un produit (/new, /[id]).
Modalités/workspace/product-modalitiesModalités de vente d'un produit (/new, /[id]).
Catalogue client/client/catalog(futur) Vue portail client — navigation catégorie, filtres, demande de devis.

Modèle de données (points clés)

  • Product.reference est unique par organisation ; contrainte DB @@unique([organizationId, reference]).
  • ProductVariant.unitPriceHt : si renseigné, prime sur Product.defaultUnitPriceHt ; sinon héritage automatique.
  • Soft delete via Product.deletedAt — hard delete interdit si le produit est référencé dans un devis, une commande ou une facture.
  • Stock négatif autorisé (back-order) mais alerte visuelle déclenchée.
  • ProductSellModality porte les paramètres propres à chaque type de vente (cf. tableau des modalités ci-dessous).

Types de modalités

TypeParamètres principaux
ONE_SHOT (achat)Prix HT, TVA, conditions
SUBSCRIPTIONPrix HT/période, période (mensuel/trimestriel/annuel), durée min d'engagement
LEASE (location)Durée min/max (mois), caution éventuelle, conditions LLD/LCD
SERVICEUnité (intervention, heure, km), tarif HT/unité

API

Toutes les routes exigent une permission catalog.product:* (vérifiée côté API et UI). Les routes sont à plat : aucun préfixe /catalog/. Il n'existe que trois permissions catalogue : catalog.product:read, catalog.product:create, catalog.product:update (catégories, variantes et modalités sont gouvernées par ces mêmes permissions).

Produits (products)

MéthodeRoutePermission
GET/api/workspace/productscatalog.product:read
POST/api/workspace/productscatalog.product:create
GET/api/workspace/products/[id]catalog.product:read
PATCH/api/workspace/products/[id]catalog.product:update

L'archivage se fait via PATCH /api/workspace/products/[id] avec { "status": "ARCHIVED" } (il n'existe pas de route /archive dédiée).

Catégories (product-categories)

MéthodeRoutePermission
GET/api/workspace/product-categoriescatalog.product:read
POST/api/workspace/product-categoriescatalog.product:update
GET/api/workspace/product-categories/[id]catalog.product:read
PATCH/api/workspace/product-categories/[id]catalog.product:update

Variantes (product-variants)

MéthodeRoutePermission
GET/api/workspace/product-variantscatalog.product:read
POST/api/workspace/product-variantscatalog.product:update
GET/api/workspace/product-variants/[id]catalog.product:read
PATCH/api/workspace/product-variants/[id]catalog.product:update

Modalités (product-modalities)

MéthodeRoutePermission
GET/api/workspace/product-modalitiescatalog.product:read
POST/api/workspace/product-modalitiescatalog.product:update
GET/api/workspace/product-modalities/[id]catalog.product:read
PATCH/api/workspace/product-modalities/[id]catalog.product:update
Cible (non implémentée) : import en masse de produits (CSV / XLSX). Contrairement à l'annuaire (POST /api/workspace/companies/import), il n'existe aucune route d'import produits. De même, il n'y a ni route de suppression (DELETE) ni de réorganisation (reorder) des catégories.

Exemple de référence d'endpoint :

PATCH/api/workspace/products/[id]Auth

Met à jour un produit. Sert aussi à l'archivage en passant status: "ARCHIVED". Permission catalog.product:update. Audit catalog.product.update.

Corps (partiel)

status
string
"ACTIVE" | "ARCHIVED". Un produit ARCHIVED est masqué des sélecteurs de devis/commande.

Requête

curl -s -X PATCH "$API/api/workspace/products/$ID" \
  -H "Cookie: $SESSION" \
  -H "Content-Type: application/json" \
  -d '{ "status": "ARCHIVED" }'

Réponse

{ "id": "prd_…", "reference": "REF-99", "status": "ARCHIVED" }

Workflows

Stock & alertes

OrderLine / MaintenanceOperationPart validée
   → décrément Product.stockQuantity
   → si stock ≤ stockThreshold → notification responsable achats
   → (futur) création SupplierQuote pré-remplie (réapprovisionnement)

Archivage produit

PATCH /products/[id] { status: "ARCHIVED" }
   ├──→ produit masqué dans le sélecteur de devis / commande
   └──→ visible en lecture dans l'historique contrats / factures passées

La suppression définitive reste un soft delete (Product.deletedAt), interdite si le produit est référencé dans un devis, une commande ou une facture.

Règles métier

  • Référence (reference) unique par organisation (contrainte DB).
  • TVA par défaut (defaultVatRate) éditable parmi les taux FR : 20 %, 10 %, 5,5 %, 2,1 %, 0 %.
  • Variante : prix surchargé (unitPriceHt) prime ; sinon héritage du produit parent.
  • Suppression hard interdite si produit référencé dans devis, commande ou facture — soft delete uniquement.
  • Stock négatif autorisé temporairement (back-order) — alerte visuelle déclenchée, aucun blocage automatique.
  • Un produit peut cumuler plusieurs modalités (ONE_SHOT + LEASE par exemple).