Diagrama de secuencia: Crear Reserva - MiguelAngelMarinMejia1/ArquitecturaDeSoftware-Proyecto GitHub Wiki
Crear una reserva es la funcionalidad más compleja del sistema. Involucra siete colaboradores, dos patrones creacionales, una transacción de base de datos y cinco invariantes de negocio que deben cumplirse antes de escribir nada.
sequenceDiagram
autonumber
actor Huesped
participant View as ReservationPageView<br/>(web) / APIView
participant Serial as ReservationCreateSerializer
participant Svc as ReservationService
participant CSvc as CustomerService
participant Gen as ConfirmationCodeGenerator
participant Builder as ReservationBuilder
participant Policy as PricingPolicy / TaxPolicy
participant Sel as selectors
participant DB as Base de datos
participant PFac as PaymentGatewayFactory
participant PSvc as PaymentService
participant ISvc as InvoiceService
participant NFac as NotifierFactory
participant Notif as BaseNotifier
Huesped->>View: POST datos de la reserva
View->>Serial: validar forma del payload
Serial-->>View: datos validados
View->>Svc: create_reservation(data)
activate Svc
Note over Svc,DB: @transaction.atomic
Svc->>CSvc: get_or_create_profile(data)
CSvc->>DB: buscar Customer por email
alt el huesped ya reservo antes
DB-->>CSvc: Customer existente
CSvc->>DB: actualizar datos de contacto
else primera vez
CSvc->>DB: crear Customer (user = NULL)
end
CSvc-->>Svc: customer
Svc->>DB: cargar habitaciones por id
alt alguna no existe
DB-->>Svc: faltan ids
Svc-->>View: RoomNotFoundError
View-->>Huesped: 404 Not Found
end
DB-->>Svc: rooms
Svc->>Gen: generate_unique(existe?)
Gen->>DB: comprobar unicidad del codigo
Gen-->>Svc: MDJ-XXXXXXXX
Svc->>Builder: for_customer().add_rooms().with_dates()<br/>.with_guests().with_confirmation_code()
Svc->>Builder: build()
activate Builder
Builder->>Builder: validar completitud
Builder->>Builder: validar al menos una habitacion
Builder->>Builder: validar rango de fechas
Builder->>Builder: validar capacidad (CapacityPolicy)
Builder->>Sel: is_room_available(room, entrada, salida)
Sel->>DB: buscar reservas solapadas
DB-->>Sel: resultado
Sel-->>Builder: disponible / ocupada
alt alguna validacion falla
Builder-->>Svc: excepcion de dominio
Svc-->>View: propaga
View-->>Huesped: 400 / 409
end
Builder->>Policy: quote(rooms, entrada, salida)
Policy->>Policy: tarifa por noche por habitacion
Policy->>Policy: subtotal, impuestos, total
Policy-->>Builder: PriceBreakdown
Builder-->>Svc: ReservationDraft (sin persistir)
deactivate Builder
Svc->>DB: guardar Reservation
Svc->>DB: bulk_create ReservationRoom
Svc->>PSvc: charge(reservation, metodo)
PSvc->>PFac: create()
PFac-->>PSvc: SimulatedGateway
PSvc->>PSvc: gateway.charge(total)
PSvc->>DB: crear Payment
alt pago rechazado
PSvc-->>Svc: PaymentDeclinedError
Note over Svc,DB: rollback completo
Svc-->>View: propaga
View-->>Huesped: 402 Payment Required
end
PSvc-->>Svc: payment
Svc->>ISvc: issue(payment)
ISvc->>DB: crear Invoice
ISvc-->>Svc: invoice
Svc->>DB: Reservation.status = CONFIRMED
Note over Svc,DB: commit de la transaccion
deactivate Svc
Svc->>NFac: create()
NFac-->>Svc: ConsoleNotifier / EmailNotifier
Svc->>Notif: send_confirmation(reservation)
Svc-->>View: reservation
View-->>Huesped: 201 Created + codigo de confirmacion
Las cinco validaciones ocurren antes de la primera escritura. Una reserva inválida nunca llega a tocar la base de datos, así que no hay estados intermedios que limpiar.
El Builder devuelve un ReservationDraft: la reserva y sus líneas de habitación, en memoria y sin
guardar. Quien decide cuándo y cómo persistir es el servicio, dentro de su transacción. Si el
Builder guardara por su cuenta, tendría dos responsabilidades y sería imposible construir una
reserva para simplemente cotizarla.
Reserva, líneas de habitación, pago y factura se escriben bajo @transaction.atomic. Si la pasarela
rechaza el cobro en el penúltimo paso, la reserva y sus líneas desaparecen. Nunca queda una
habitación bloqueada por una reserva que no se pagó.
transaction.on_commit() retrasa el envío hasta que la transacción confirma. Dos razones: si la
transacción falla no se envía un correo sobre una reserva que no existe, y si el servidor de correo
está caído eso no revierte una reserva ya pagada.
El Builder lo exige como dato obligatorio. Así, una reserva no puede existir sin su identificador público ni siquiera durante un instante.
| Paso | Archivo |
|---|---|
| Validación de forma | reservation/api/serializers.py |
| Orquestación |
reservation/services.py → ReservationService.create_reservation()
|
| Perfil del huésped |
reservation/services.py → CustomerService
|
| Código de confirmación | reservation/domain/codes.py |
| Construcción y validación | reservation/domain/builders.py |
| Cálculo de precios | reservation/domain/policies.py |
| Consulta de disponibilidad | reservation/selectors.py |
| Pasarela y notificador | reservation/infra/factories.py |
| Traducción a HTTP | reservation/api/exception_handler.py |