Produits (Administration)
Base URL : /api/v1/admin/org/products
CRUD complet des produits et gestion des mouvements de stock. Pour la consultation publique, voir Produits (catalogue).
GET /admin/org/products
Liste admin des produits (actifs et inactifs).
Permissions : product.read
| Param | Type | Défaut | Description |
|---|---|---|---|
search | string | — | Recherche (nom, code) |
category_id | uuid | — | Filtrer par catégorie |
site_id | uuid | — | Filtrer par site |
is_active | string | — | "true" / "false" |
limit | integer | 20 | Éléments par page |
offset | integer | 0 | Décalage |
Réponse (200) :
{
"items": [
{
"id": "uuid",
"category_id": "uuid",
"code": "CAF",
"name": "Café",
"slug_date": null,
"meal_type": null,
"description": null,
"price_cents": 1000,
"price": 1000,
"price_formatted": "1 000 FCFA",
"stock_quantity": 50,
"is_active": true,
"available_days": [1, 2, 3, 4, 5],
"site_id": "uuid",
"reservation_deadline_days_before": null,
"reservation_deadline_time": null,
"image_path": null,
"low_stock_threshold": 10,
"created_at": "2025-01-10T10:00:00Z",
"updated_at": "2025-01-10T10:00:00Z",
"currency": "XOF"
}
],
"total": 42,
"summary": {
"total": 42,
"available": 38,
"low_stock": 3,
"out_of_stock": 1
},
"currency": "XOF"
}
GET /admin/org/products/{id}
Détail d'un produit. Permissions : product.read
Réponse : objet produit (même forme qu'un élément de liste).
POST /admin/org/products
Crée un produit.
Permissions : product.create
| Champ | Type | Requis | Description |
|---|---|---|---|
category_id | uuid | Oui | Catégorie |
name | string | Oui | Nom |
price_cents | integer | Oui | Prix |
code | string | Non | Code |
slug_date | date | Non | Date associée |
meal_type | string | Non | Vegetarian, Meat, Fish |
description | string | Non | Description |
stock_quantity | integer | Non | Stock initial |
is_active | boolean | Non | Actif |
available_days | integer[] | Non | Jours (1=lundi … 7=dimanche) |
site_id | uuid | Non | Site |
reservation_deadline_days_before | integer | Non | Délai réservation (jours) |
reservation_deadline_time | time | Non | Heure limite réservation |
image_path | string | Non | Chemin image |
low_stock_threshold | integer | Non | Seuil stock bas (défaut org) |
Réponse (201) : { "message": "Produit créé", "product": {...} }
PUT /admin/org/products/{id}
Met à jour un produit.
Permissions : product.update
Reprend les mêmes champs que la création, tous optionnels.
Certains champs (code, slug_date, meal_type, description, site_id, reservation_deadline_*, image_path) sont écrasés inconditionnellement : les omettre les efface (met à null). Les autres (name, price_cents, stock_quantity, is_active, available_days, low_stock_threshold, category_id) ne sont mis à jour que s'ils sont fournis. Ce n'est pas un vrai PATCH.
Réponse (200) : { "message": "Produit mis à jour", "product": {...} }
DELETE /admin/org/products/{id}
Permissions : product.delete
Réponse (200) : { "message": "Produit supprimé" }
Mouvements de stock
Chaque mouvement est tracé dans stock_movements avec un type, un delta, un motif et l'acteur.
POST /admin/org/products/{id}/adjust-stock
Ajustement manuel (inventaire).
Permissions : stock.adjust
{ "delta": -5, "reason": "Inventaire mensuel" }
delta peut être positif ou négatif. Le stock résultant ne peut pas être négatif.
Réponse (200) : { "message": "Stock ajusté" } — type correction.
POST /admin/org/products/{id}/purchase
Réapprovisionnement (achat fournisseur).
Permissions : stock.purchase
{
"delta": 50,
"reason": "Commande fournisseur",
"unit_cost_cents": 500,
"expires_at": "2025-07-01T00:00:00Z"
}
delta doit être > 0. Champs optionnels : unit_cost_cents, batch_id, expires_at.
Réponse (200) : { "message": "Réapprovisionnement enregistré" } — type purchase.
POST /admin/org/products/{id}/production
Production interne (plats préparés).
Permissions : stock.produce
{ "delta": 20, "reason": "Production du jour" }
delta doit être > 0.
Réponse (200) : { "message": "Production enregistrée" } — type production.
POST /admin/org/products/{id}/transfer
Transfert entre sites.
Permissions : stock.transfer
{ "delta": 10, "reason": "Réappro intersite" }
delta peut être positif ou négatif (négatif vérifié contre le stock).
Réponse (200) : { "message": "Transfert enregistré" } — type transfer.
GET /admin/org/products/{id}/movements
Historique des mouvements d'un produit.
Permissions : stock.read
| Param | Type | Défaut |
|---|---|---|
limit | integer | 20 |
offset | integer | 0 |
movement_type | string | — |
Réponse (200) :
{
"items": [
{
"id": "uuid",
"product_id": "uuid",
"product_name": "Café",
"product_code": "CAF",
"delta": 50,
"movement_type": "purchase",
"reason": "Commande fournisseur",
"performed_by": "uuid",
"performed_by_name": "Jean Mbeki",
"unit_cost_cents": 500,
"batch_id": null,
"expires_at": null,
"site_id": "uuid",
"site_name": "Buvette Principale",
"pos_id": null,
"pos_name": null,
"created_at": "2025-06-21T10:00:00Z"
}
],
"total": 1
}
Types de mouvement : purchase, production, sale, return, waste, expiry, transfer, correction, reservation.
GET /admin/org/movements
Mouvements de tous les produits de l'organisation.
Permissions : stock.read
| Param | Type | Description |
|---|---|---|
product_id | uuid | Filtrer par produit |
movement_type | string | Filtrer par type |
date_from | date | Début de plage |
date_to | date | Fin de plage |
site_id | uuid | Filtrer par site |
pos_id | uuid | Filtrer par point de vente |
limit / offset | integer | Pagination |
Réponse (200) : { "items": [...], "total": n } (mêmes champs que ci-dessus).
POST /admin/org/products/import
Importe des produits en lot (corps JSON, max 500).
Permissions : product.create
{
"products": [
{
"category_id": "uuid",
"name": "Thé vert",
"price_cents": 800,
"stock_quantity": 100,
"is_active": true
}
]
}
Réponse (200) : { "message": "1 produit importé", "created": 1, "products": [...], "currency": "XOF" }
Permissions
| Permission | Description |
|---|---|
product.read / product.create / product.update / product.delete | CRUD produit |
stock.read | Lecture des mouvements |
stock.adjust / stock.purchase / stock.produce / stock.transfer | Mouvements de stock |
product.manage | Super-permission couvrant stock.* et category.* |
Voir aussi
- Catégories
- Analytics — statistiques de stock (
stats/stock)