xpeditis2.0/docs/features/csv-bookings.md
2026-09-07 21:40:49 +02:00

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;

Template MJML dans apps/backend/src/infrastructure/email/templates/.

Variables disponibles :

  • bookingNumber — numéro de réservation
  • magicLink — URL avec token
  • expiresIn — durée de validité ("1 heure")
  • carrierName — nom du carrier