Les consultants déclarent les frais qu’ils avancent de leurs deniers ; les opérations les soldent. Un frais possède une catégorie, un montant brut, un montant de TVA facultatif, et un lien vers la mission à laquelle il appartient (qui détermine s’il est facturable au client). Il passe par pending, approved, paid, rejected ou cancelled.
Qui fait quoi
| Action | Rôle |
|---|---|
| Créer | Le consultant (les siens), un administrateur, ou un chef d’équipe pour son équipe |
| Modifier ou annuler | Le propriétaire ou un administrateur, tant que le statut est pending (annulation aussi depuis approved) |
| Approuver ou refuser | Administrateur ou chef d’équipe du consultant |
| Payer | Administrateur ou opérations |
1. Créer un frais
POST /expenses HTTP/1.1
Authorization: Bearer <access_token>
Content-Type: application/json
{
"date": "2026-01-14",
"category": "train",
"description": "Client site visit",
"amount": "120.00",
"vat_amount": "24.00",
"mission_id": "0190a1c2-...",
"billable": true
}
Renvoie 201 Created avec un ExpenseResponse. Points clés :
amountest le montant brut ;net_amountest dérivé et renvoyé automatiquement.categoryvaut l’une des valeurstrain,taxi,fuel,tolls,meal,hotel,office_supplies,software,telephony,other.billablemarque le frais pour une refacturation au client ; renseignezmission_idpour le rattacher à une mission.receiptest une data URL facultative (data:<mime>;base64,<data>) ; la réponse expose un booléenhas_receipt, et le justificatif complet uniquement surGET /expenses/{id}.
{
"id": "0190a1c2-...",
"consultant_id": "0190a1c2-...",
"consultant_full_name": "Ada Lovelace",
"date": "2026-01-14",
"category": "train",
"description": "Client site visit",
"amount": "120.00",
"vat_amount": "24.00",
"net_amount": "96.00",
"mission_id": "0190a1c2-...",
"mission_name": "Apollo",
"billable": true,
"has_receipt": false,
"status": "pending",
"created_at": "2026-01-14T12:00:00Z"
}
Un jeton avec le rôle consultant et sans profil lié ne peut pas créer de frais (422).
2. Modifier ou annuler avant le règlement
Tant que le statut est pending, le propriétaire ou un administrateur peut modifier le frais avec PUT /expenses/{id} (mêmes champs qu’à la création). L’annulation le retire :
POST /expenses/{id}/cancel HTTP/1.1
Authorization: Bearer <access_token>
L’annulation est autorisée depuis pending ou approved, mais plus une fois paid (409 sinon).
3. Approuver ou refuser
Un responsable examine un frais en attente :
POST /expenses/{id}/approve HTTP/1.1
Authorization: Bearer <access_token>
POST /expenses/{id}/reject HTTP/1.1
Authorization: Bearer <access_token>
Content-Type: application/json
{ "reason": "No receipt attached" }
Les deux renvoient 200 OK. Agir sur un frais qui n’est pas pending renvoie 409.
4. Payer
Les opérations soldent un frais approuvé :
POST /expenses/{id}/pay HTTP/1.1
Authorization: Bearer <access_token>
Renvoie 200 OK avec status désormais paid. Payer un frais qui n’est pas approved renvoie 409.
Le récapitulatif mensuel
GET /expenses/summary agrège les totaux par statut, éventuellement pour un mois et un consultant donné :
GET /expenses/summary?month=2026-01 HTTP/1.1
Authorization: Bearer <access_token>
{
"date_from": "2026-01-01",
"date_to": "2026-01-31",
"statuses": [
{ "status": "pending", "count": 3, "total": "420.00" },
{ "status": "paid", "count": 12, "total": "1850.00" }
]
}
Consulter les frais
GET /expenses est paginée et filtrable par consultant_id, status, category, mission_id, date_from/date_to, search et scope (mine/team). Voir Conventions.
Points d’entrée en un coup d’œil
| Action | Méthode | Chemin | Succès |
|---|---|---|---|
| Lister | GET | /expenses | 200 |
| Récapitulatif | GET | /expenses/summary | 200 |
| Récupérer | GET | /expenses/{id} | 200 |
| Créer | POST | /expenses | 201 |
| Modifier | PUT | /expenses/{id} | 200 |
| Annuler | POST | /expenses/{id}/cancel | 200 |
| Approuver | POST | /expenses/{id}/approve | 200 |
| Refuser | POST | /expenses/{id}/reject | 200 |
| Payer | POST | /expenses/{id}/pay | 200 |