Réservation — machine à états
Concepts fondateurs (ADR-D21)
Section intitulée « Concepts fondateurs (ADR-D21) »Reservation et Stay sont deux agrégats distincts :
Reservation= contrat logique entre le client et l’établissement. Existe de la création jusqu’à la clôture/annulation.Stay= occurrence physique d’hébergement. Créé au check-in, contient le folio de séjour.
Une réservation peut ne jamais générer de Stay (no-show, annulation) ou en générer plusieurs (modify + check-in du séjour modifié).
Machine à états
Section intitulée « Machine à états » ┌──────────────┐ create │ Tentative │ ──────────► │ │──── confirm ────────────────────┐ └──────────────┘ ▼ ┌──────────────┐ cancel ◄─────────────────────────── │ Confirmed │ └──────────────┘ │ ┌──────────────┐ │ check-in ┌───► │ NoShow │ ▼ markNoShow │ └──────────────┘ ┌──────────────┐ └─────────────────────── │ CheckedIn │ └──────────────┘ │ ┌──────────────┐ │ check-out ┌───► │ Walked │ ▼ │ └──────────────┘ ┌──────────────┐ └─────────────────────── │ CheckedOut │ └──────────────┘ │ │ close (Night Audit) ▼ ┌──────────────┐ │ Closed │ └──────────────┘États terminaux : Closed, Cancelled, NoShow. Walked est un état intermédiaire (séjour débuté mais le client est parti sans payer — action UI absente en V1).
Transitions clés
Section intitulée « Transitions clés »| Transition | Déclencheur | Invariants |
|---|---|---|
create | CreateReservationUseCase | dispo ≥ quantité demandée (advisory xact lock) |
confirm | ConfirmReservationOrchestrator | SnapshotRate calculé et figé (immuable après) ; DepositPolicy snapshotée |
check-in | CheckInOrchestrator | Stay créé atomiquement (même TX que le Folio) ; unité physique assignée ; pre-assignment consommé si existant (consumedAt persisté) |
check-out | CheckOutOrchestrator | Stay clôturé ; unité libérée (I3) |
cancel | Direct ou via saga Temporal | Rate plan snapshoté à Confirmed utilisé pour calculer l’éventuelle pénalité |
markNoShow | Night Audit ou manuel | Arrhes acquises si depositNature = 'arrhes' (MandateFiscalProfile) |
close | Night Audit (après check-out + solde folio) | Grand total NF203 mis à jour |
Journal versions append-only (NF203)
Section intitulée « Journal versions append-only (NF203) »Chaque transition publie une entrée dans pms.reservation_versions (GRANT INSERT only) :
reservation_versions { id, reservation_id, tenant_id, version_number, -- séquence croissante state, -- état après transition actor, -- userId ou SYSTEM occurred_at, -- timestamp serveur payload, -- snapshot complet de l'agrégat (JSON) hmac -- signature NF203}L’API expose la timeline via GET /v1/reservations/:id/versions (ADR-G5), avec cancellationPolicySnapshot inclus dans le payload.
SnapshotRate — immuabilité tarifaire
Section intitulée « SnapshotRate — immuabilité tarifaire »À la confirmation, le tarif est calculé nuit par nuit et figé dans SnapshotRate :
- Le tarif utilisé pour la facturation est toujours celui de la confirmation
- Aucune variation de
RatePlanpostérieure ne modifie la réservation confirmée - Le modify d’une réservation confirmée recalcule et refige un nouveau snapshot
Pré-assignation d’unité (ADR-00D81)
Section intitulée « Pré-assignation d’unité (ADR-00D81) »La pré-assignation est optionnelle et n’engage pas le stock par type (inventory_daily reste inchangé). Elle représente le souhait du réceptionniste d’affecter une unité physique spécifique sans verrouiller la dispo globale.
Règles :
- EXCLUDE GiST
[check_in_date, check_out_date)fait foi pour l’unicité (erreur Postgres 23P01 si doublon) - La garde mémoire de l’agrégat (
preAssignments[]) est best-effort UX uniquement - Consommation atomique au check-in (même TX que la transition)
- Cancel et no-show libèrent les pre-assignations actives
Politique d’annulation
Section intitulée « Politique d’annulation »La CancellationPolicy est snapshotée depuis le RatePlan à la confirmation. Lors d’un cancel :
- La politique snapshotée est appliquée (jamais la politique actuelle du rate plan)
- Si pénalité : une ligne
chargeNature = 'penalty'est postée au folio - La ligne
penaltyest exclue duvoid-all(DEFAULT_EXCLUDE = ['penalty']) — trace de pénalité inaltérable
Réservation multi-unité
Section intitulée « Réservation multi-unité »Une réservation peut inclure plusieurs types d’unités et quantités (units: [{ unitTypeId, quantity }]). La dispo est vérifiée pour chaque type indépendamment sous advisory xact lock.
Long stay (contrats saisonniers, T23)
Section intitulée « Long stay (contrats saisonniers, T23) »Sous-module reservation/long-stay/ : contrats saisonniers avec échéancier de paiement. Les installments sont postés automatiquement par le Night Audit (postDueInstallments, ADR-0019).
Occupancy camping
Section intitulée « Occupancy camping »La réservation camping porte un objet occupancy (adults, childrenAges, pets, vehicles, electricity) qui alimente le calcul tarifaire per_person des rate plans camping.