Structurez les commandes et les lignes de commande pour suivre les achats des utilisateurs.
Dans cette leçon, tu vas apprendre à modéliser deux entités clés d’un site e-commerce : les commandes et leurs lignes de commande. L’objectif est de créer des collection types Strapi qui garantissent :
Ceci servira de fondation à la gestion du panier, à la génération des factures, et à l’historique des achats dans ton app Remix + Strapi 5 headless.
commande
On commence par le fichier de schéma Strapi. Il se trouve typiquement dans
src/api/commande/content-types/commande/schema.json
.
1{2"kind": "collectionType",3"collectionName": "commandes",4"info": {5"singularName": "commande",6"pluralName": "commandes",7"displayName": "Commande"8},9"options": {10"draftAndPublish": false11},12"attributes": {13"totalPrice": {14"type": "integer"15},16"lines": {17"type": "relation",18"relation": "oneToMany",19"target": "api::ligne-de-commande.ligne-de-commande"20},21"user": {22"type": "relation",23"relation": "manyToOne",24"target": "plugin::users-permissions.user",25"inversedBy": "orders"26},27"orderStatus": {28"type": "enumeration",29"enum": ["en attente de paiement","payé"],30"default": "en attente de paiement",31"required": true32}33}34}
totalPrice
stocke la somme de toutes les lignes.lines
crée une relation 1⇾n vers ligne-de-commande
.user
relie chaque commande à un utilisateur Strapi natif.orderStatus
est un enum qui contrôle le flux de paiement.On désactive draftAndPublish
car une commande doit être validée
immédiatement : pas de brouillon.
ligne-de-commande
Ensuite, on modélise chaque article acheté. Le fichier est
src/api/ligne-de-commande/content-types/ligne-de-commande/schema.json
.
1{2"kind": "collectionType",3"collectionName": "ligne_de_commandes",4"info": {5"singularName": "ligne-de-commande",6"pluralName": "ligne-de-commandes",7"displayName": "Ligne de commande"8},9"options": {10"draftAndPublish": true11},12"attributes": {13"produit": {14"type": "relation",15"relation": "oneToOne",16"target": "api::produit.produit"17},18"quantity": {19"type": "integer",20"default": 1,21"required": true22},23"price": {24"type": "integer",25"default": 026}27}28}
produit
est un lien 1⇾1 vers ton contenu produit
.quantity
et price
permettent de conserver l’historique,
même si le prix du produit change plus tard.draftAndPublish
est activé pour pouvoir ébaucher des lignes
pendant le processus de checkout.Pense à calculer totalPrice
en backend via une fonction
lifecycle (beforeCreate
, beforeUpdate
) pour éviter les manipulations
côté client.
La relation oneToMany
sur commande.lines
s’appuie sur la clé
étrangère générée dans ligne-de-commande
. Strapi synchronise
automatiquement les IDs.
En REST, tu pourras obtenir une commande complète avec :
1GET /api/commandes?populate=lines.produit,user
populate
garantit que tes données associées
(produit, user) sont incluses.Pour exploiter ces modèles dans ton app Remix, crée des types TypeScript puis un loader :
1export interface LigneCommande {2id: number3produit: { id: number; name: string; price: number }4quantity: number5price: number6}78export interface Commande {9id: number10totalPrice: number11orderStatus: "en attente de paiement" | "payé"12lines: LigneCommande[]13user: { id: number; username: string }14}
1import type { LoaderArgs } from "@remix-run/node"2import { json } from "@remix-run/node"34export const loader = async ({ params, request }: LoaderArgs) => {5const res = await fetch(6`${process.env.API_URL}/commandes/${params.id}?populate=lines.produit,user`7)8const data = await res.json()9return json<Commande>(data.data)10}
1import { useLoaderData } from "@remix-run/react"23export default function CommandePage() {4const commande = useLoaderData<Commande>()5return (6<div>7<h2>Détails de la commande #{commande.id}</h2>8<ul>9{commande.lines.map((line) => (10<li key={line.id}>11{line.produit.name} × {line.quantity} = {line.price} €12</li>13))}14</ul>15<p>Total : {commande.totalPrice} €</p>16<p>Status : {commande.orderStatus}</p>17</div>18)19}
N’oublie pas de sécuriser la route avec authentification Remix.
draftAndPublish: false
pour les commandes en production.totalPrice
côté serveur pour fiabilité.populate
permet de récupérer les relations en un seul appel.Ajouter un statut “expédié”
Mets à jour l’énumération orderStatus
pour inclure "expédié"
puis teste le endpoint REST pour valider ton schéma.
Appliquer une remise
Ajoute un champ discountCode
(relation vers un nouveau
promo-code
) et un champ discountAmount
.
Modifie le totalPrice
pour en tenir compte.
Page utilisateur
Crée une route Remix /mon-compte/commandes
qui liste toutes les commandes de l’utilisateur connecté.
Filtre via ?filters[user][id][$eq]=:userId
.
Pour aller plus loin, explore la leçon suivante sur la gestion du panier en React Context.