Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018BAUeCFpDkRD6tU5wGsc1C
5.1 KiB
Réservations CSV & Portail Carrier
Vue d'ensemble
Le système de réservation CSV permet aux admins de créer des réservations en important des fichiers CSV et d'envoyer automatiquement un lien magique aux transporteurs pour qu'ils acceptent ou rejettent via un portail dédié.
Workflow complet
1. Admin upload CSV → création csv_bookings
2. Admin assigne un carrier à la réservation
3. Système envoie email avec magic link (expiry 1h)
4. Carrier clique → authentification automatique (token URL)
5. Carrier voit les détails → Accept ou Reject
6. Activité logguée dans carrier_activities
7. Admin voit le statut mis à jour en dashboard
API — Réservations CSV (Admin)
| Méthode | Route | Description |
|---|---|---|
| GET | /api/v1/csv-bookings | Liste des réservations CSV |
| POST | /api/v1/csv-bookings | Créer une réservation CSV |
| GET | /api/v1/csv-bookings/:id | Détail d'une réservation |
| PATCH | /api/v1/csv-bookings/:id | Mettre à jour |
| DELETE | /api/v1/csv-bookings/:id | Supprimer |
| POST | /api/v1/csv-bookings/:id/assign-carrier | Assigner un carrier |
| POST | /api/v1/csv-bookings/:id/send-magic-link | Envoyer le lien magique |
API — Portail Carrier
| Méthode | Route | Description |
|---|---|---|
| GET | /api/v1/carrier/auth | Auth via magic link token |
| GET | /api/v1/carrier/booking | Voir la réservation assignée |
| POST | /api/v1/carrier/booking/accept | Accepter |
| POST | /api/v1/carrier/booking/reject | Rejeter |
| POST | /api/v1/carrier/booking/documents | Uploader des documents |
Authentification portail carrier
Le lien magique contient un token unique :
https://app.xpeditis.com/carrier/auth?token=xxxxxxxx
Le token est stocké dans csv_bookings.carrier_magic_link_token (hashé).
Expiry : 1 heure. Si expiré, l'admin doit renvoyer un nouveau lien.
Statuts des réservations CSV
Valeurs réelles de l'énumération CsvBookingStatus (domain/entities/csv-booking.entity.ts) :
| Statut | Description |
|---|---|
| PENDING_PAYMENT | Réservation créée, commission non payée |
| PENDING_BANK_TRANSFER | Virement déclaré, en attente de validation par l'administration |
| PENDING | Commission payée, en attente de réponse du transporteur |
| ACCEPTED | Le transporteur a accepté |
| REJECTED | Le transporteur a refusé |
| CANCELLED | Annulée par l'utilisateur |
Suppression d'une réservation impayée
DELETE /api/v1/csv-bookings/:id supprime définitivement une réservation dont la commission n'a pas été payée, c'est-à-dire au seul statut PENDING_PAYMENT. Seul le propriétaire peut le faire ; une réservation appartenant à quelqu'un d'autre répond 404, sans se distinguer d'une réservation inexistante.
Une fois la commission payée, la réservation est partie chez le transporteur et porte une trace comptable : elle ne peut plus qu'être annulée (PATCH :id/cancel), jamais effacée. L'API répond alors 400.
PENDING_BANK_TRANSFER est volontairement exclu : le virement déclaré peut être en cours d'acheminement, et supprimer la réservation priverait l'administration de ce qu'elle doit rapprocher à sa réception. Étendre la règle à ce statut est une décision comptable, pas technique — il suffit d'ajouter le statut à DELETABLE_STATUSES dans l'entité.
Les documents déjà téléversés restent dans le stockage objet, conformément à la politique appliquée à la suppression d'un document isolé (conservation pour l'audit). Le quota de réservations n'est pas affecté : il ne compte que les expéditions payées.
Côté interface, l'action « Supprimer » n'apparaît dans le menu d'une ligne que pour les réservations impayées, à côté de « Modifier » et « Payer ». Elle demande une confirmation qui nomme la réservation concernée.
Pages frontend
| Route | Description |
|---|---|
| /dashboard/bookings | Liste des réservations (voir, modifier, payer, supprimer) |
| /dashboard/csv-bookings | Liste admin des réservations CSV |
| /carrier/auth | Page d'auth carrier (via magic link) |
| /carrier/booking | Dashboard carrier (accept/reject) |
| /carrier/documents | Upload documents carrier |
Import CSV (upload admin)
Le fichier CSV peut être uploadé via POST /api/v1/admin/csv-rates/upload.
Format des colonnes requis : voir ../csv-system/CSV_RATE_SYSTEM.md.
Profils carrier
Les carriers qui utilisent le portail ont un CarrierProfile lié à leur Organization.
Chaque action (accept, reject, document upload) est tracée dans carrier_activities.
SELECT ca.action, ca.created_at, cb.booking_number
FROM carrier_activities ca
JOIN csv_bookings cb ON cb.id = ca.csv_booking_id
WHERE ca.carrier_profile_id = 'xxx'
ORDER BY ca.created_at DESC;
Email magic link
Template MJML dans apps/backend/src/infrastructure/email/templates/.
Variables disponibles :
bookingNumber— numéro de réservationmagicLink— URL avec tokenexpiresIn— durée de validité ("1 heure")carrierName— nom du carrier