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.

Flujo completo

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
Loading

Decisiones que explica el diagrama

El Builder valida antes de que exista nada en la base de datos

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.

build() no persiste

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.

Todo ocurre dentro de una transacción

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ó.

La notificación se envía después del commit

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 código de confirmación se genera antes de construir

El Builder lo exige como dato obligatorio. Así, una reserva no puede existir sin su identificador público ni siquiera durante un instante.

Trazabilidad con el código

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
⚠️ **GitHub.com Fallback** ⚠️