Sites et points de vente
Base URL : /api/v1/admin/org
Gestion des sites (établissements physiques), des points de vente (POS) et des sessions de caisse.
Sites
GET /admin/org/sites
Liste paginée des sites.
Permissions : site.read
| Param | Type | Défaut |
|---|---|---|
limit | integer | 20 |
offset | integer | 0 |
Réponse (200) :
{
"items": [
{
"id": "uuid",
"name": "Buvette Principale",
"code": "BP",
"address": "Bloc A, Rez-de-chaussée",
"city": "Lomé",
"country": "TG",
"contact_phone": "+22890123456",
"contact_email": null,
"opening_hours": {
"monday": { "open": "07:00", "close": "18:00", "closed": false }
},
"timezone": "Africa/Lome",
"is_active": true,
"settings": {},
"notification_config": null,
"created_at": "2025-01-15T10:00:00Z",
"updated_at": "2025-06-01T14:30:00Z"
}
],
"total": 2
}
GET /admin/org/sites/{id}
Détail d'un site. Permissions : site.read
Réponse : objet Site brut.
POST /admin/org/sites
Crée un site. L'opening_hours et le timezone sont recopiés de l'organisation (business_hours).
Permissions : site.create
| Champ | Type | Requis | Description |
|---|---|---|---|
name | string | Oui | Nom du site (non vide) |
code | string | Non | Code |
address | string | Non | Adresse |
city | string | Non | Ville |
country | string | Non | Pays (défaut "TG") |
contact_phone | string | Non | Téléphone |
contact_email | string | Non |
Réponse (201) : { "message": "Site créé", "site": {...} }
PUT /admin/org/sites/{id}
Met à jour un site (mêmes champs que la création ; country n'est pas réécrit).
Permissions : site.update
Réponse (200) : { "message": "Site mis à jour", "site": {...} }
DELETE /admin/org/sites/{id}
Permissions : site.delete
Réponse (200) : { "message": "Site supprimé" }
Points de vente (POS)
Structure
| Champ | Type | Description |
|---|---|---|
id | uuid | Identifiant |
site_id | uuid | Site de rattachement |
name | string | Nom |
code | string? | Code |
kind | string | "Fixed" ou "Mobile" |
opening_hours | object | Horaires par jour (noms de jours anglais) |
is_currently_open | boolean | Ouvert actuellement |
created_at / updated_at | datetime | Horodatage |
kindkind est sérialisé en PascalCase : "Fixed" ou "Mobile" (pas "fixed"/"kiosk").
GET /admin/org/points-of-sale
Permissions : pos.read
| Param | Type | Défaut | Description |
|---|---|---|---|
site_id | uuid | — | Si fourni, retourne tous les POS du site (pagination ignorée) |
limit | integer | 20 | |
offset | integer | 0 |
Réponse (200) : { "items": [PointOfSale], "total": n }
GET /admin/org/points-of-sale/{id}
Permissions : pos.read — Réponse : objet PointOfSale brut.
POST /admin/org/points-of-sale
Permissions : pos.create
{
"site_id": "uuid",
"name": "Terminal Bar",
"code": "TB01",
"kind": "Fixed",
"opening_hours": {}
}
Champs requis : site_id, name, kind.
Réponse (201) : { "message": "Point de vente créé", "pos": {...} }
PUT /admin/org/points-of-sale/{id}
Permissions : pos.update
{ "name": "Terminal Bar - Rénové", "kind": "Fixed" }
Réponse (200) : { "message": "Point de vente mis à jour", "pos": {...} }
DELETE /admin/org/points-of-sale/{id}
Permissions : pos.delete
Réponse (200) : { "message": "Point de vente supprimé" }
POST /admin/org/points-of-sale/{id}/toggle-open
Bascule l'état ouvert/fermé du point de vente.
Permissions : pos.update
Réponse (200) : { "message": "Statut modifié" }
Sessions de caisse (Registers)
Structure Register
| Champ | Type | Description |
|---|---|---|
id | uuid | Identifiant |
pos_id | uuid | Point de vente (sérialisé pos_id) |
status | string | "open" ou "closed" |
opened_at | datetime | Ouverture |
closed_at | datetime? | Fermeture |
opening_balance_cents | integer | Fonds de caisse initial |
closing_balance_cents | integer? | Solde compté |
expected_cash_cents | integer? | Espèces attendues (calcul système) |
actual_cash_cents | integer? | Espèces comptées |
discrepancy_cents | integer? | Écart (actual − expected) |
opened_by / closed_by | uuid? | Opérateurs |
notes | string? | Notes |
GET /admin/org/points-of-sale/{pos_id}/registers
Liste des sessions d'un POS.
Permissions : register.read
| Param | Type | Défaut |
|---|---|---|
status | string | — |
limit | integer | 20 |
offset | integer | 0 |
Réponse (200) : { "items": [Register], "total": n }
POST /admin/org/points-of-sale/{pos_id}/registers/open
Ouvre une session de caisse.
Permissions : register.open
{ "opening_balance_cents": 5000, "notes": "Ouverture matinale" }
opening_balance_cents est requis. Rejette si une caisse est déjà ouverte sur ce POS.
Réponse (201) : { "message": "Caisse ouverte", "register": {...} } (avec opening_balance, opening_balance_formatted, currency).
GET /admin/org/registers/{id}
Détail d'une session de caisse (arrêté de caisse).
Permissions : register.read
Réponse (200) :
{
"register": {
"id": "uuid",
"pos_id": "uuid",
"point_of_sale_name": "Terminal Bar",
"status": "closed",
"opened_at": "2025-07-15T06:00:00Z",
"closed_at": "2025-07-15T18:00:00Z",
"opening_balance_cents": 5000,
"opening_balance": 5000,
"opening_balance_formatted": "5 000 FCFA",
"closing_balance_cents": 45000,
"expected_cash_cents": 45200,
"actual_cash_cents": 45000,
"discrepancy_cents": -200,
"notes": "Fermeture soir",
"currency": "XOF"
}
}
Les champs monétaires optionnels (closing_balance, expected_cash, actual_cash, discrepancy) n'apparaissent que lorsqu'ils sont définis.
POST /admin/org/registers/{id}/close
Ferme une session de caisse.
Permissions : register.close
{
"actual_cash_cents": 45000,
"expected_cash_cents": 45200,
"notes": "Fermeture soir"
}
| Champ | Type | Requis | Description |
|---|---|---|---|
actual_cash_cents | integer | Oui | Espèces comptées |
expected_cash_cents | integer | Oui | Espèces attendues |
notes | string | Non | Notes |
Réponse (200) : { "message": "Caisse fermée", "register": {...} }
Il n'existe pas d'endpoint de liste globale /registers ni de /registers/{id}/cash-movement. Les sessions se consultent via le POS (/points-of-sale/{pos_id}/registers) ou par identifiant (/registers/{id}).
Permissions
| Permission | Description |
|---|---|
site.read / site.create / site.update / site.delete | CRUD site |
pos.read / pos.create / pos.update / pos.delete | CRUD point de vente |
register.read / register.open / register.close | Sessions de caisse |
site.manage | Super-permission couvrant pos.* et register.* |