Ir al contenido
DocuGraph

ecommerce-angular-spring

BE-07 Órdenes y máquina de estados

  • Depende de: BE-05, BE-06, US-06, US-08, DS-02.
  • Módulo: orders (hexagonal).
  • Relevo 2026-09-21: BE-06 está DONE. Mañana empezar aquí; no reimplementar webhooks.

Implementar la orden como agregado con transiciones de estado válidas e inmutables en sus ítems.

  • Estados en spec: PENDING_PAYMENT, PAID, SHIPPED, CANCELLED. En código/BD el pendiente ya es PENDING (ver relevo).
  • Al consumir checkout.PaymentSucceeded (BE-06) la orden pasa a PAID y se emite orders.OrderPaid.
  • Al consumir checkout.PaymentFailed o cancelMyOrder en pendiente: CANCELLED (el stock lo libera inventory / BE-06).
  • Puertos de cliente listMyOrders, getMyOrder, cancelMyOrder.
  • Puertos admin adminListOrders, adminUpdateOrderStatus.

Criterios de aceptación (DoD de esta tarea)

Sección titulada «Criterios de aceptación (DoD de esta tarea)»
  • Transición inválida = 409 ProblemDetail.
  • Un cliente no accede a órdenes ajenas.
  • Los ítems conservan precio snapshot.
  • OrderPaid se emite al pasar a PAID.
  • Validar la firma del webhook y persistir webhook_events: BE-06 (DONE).
  • Relay outbox (published_at, reintentos): BE-12. Los tests de esta tarea invocan el caso de uso de órdenes directo; el camino vivo webhook→PAID no cierra hasta BE-12.
  • UI de «Mis órdenes»: FE-07.

Unitarias de la máquina de estados; integración de repositorio (incl. transiciones a PAID y 409).

Arrancar con get_context(mode=task, taskId=BE-07).

Hecho ya (no rehacer):

  • Checkout crea la orden en PENDING vía CreatePendingOrderPort (ExposedOrderCreationAdapter). Enum real: PENDING, PAID, SHIPPED, DELIVERED, CANCELLED. Alinear el spec PENDING_PAYMENT a PENDING del esquema; no duplicar estados en BD.
  • order_items.unit_price_cents ya es snapshot al crear la orden.
  • BE-06 ya confirma o libera la reserva en la misma transacción del webhook. confirmReservation solo toca filas PENDING (segundo call = no-op). Al pasar a PAID emitir orders.OrderPaid; no volver a decrementar stock.
  • Eventos a consumir (outbox_events, aggregateType=checkout, published_at NULL):
    • checkout.PaymentSucceeded → JSON eventId, paymentId, orderId, amountCents, occurredAt
    • checkout.PaymentFailed → JSON eventId, paymentId, orderId, reason, occurredAt
  • No existe relay (BE-12). OutboxEventPublisher solo inserta. El handler de órdenes se prueba sin relay; el E2E local (ngrok → webhook → orden PAID) queda bloqueado hasta despachar outbox.
  • OpenAPI (DS-02): listMyOrders, getMyOrder, cancelMyOrder, adminListOrders, adminUpdateOrderStatus.
  • Runtime local: API :8081 perfil local, Postgres :5433. Una orden de auditoría puede estar PENDING con pago SUCCEEDED: ese hueco es esta tarea.