3.6 KiB
Dominio Purchase
Propósito
Implementa el ciclo de compra y checkout: crea la cabecera de compra desde un carrito, mantiene sus líneas vivas contra catálogo durante el checkout, inicia el pago y materializa el snapshot definitivo al confirmar, o cancela y vence la operación.
Modelo
Purchase: raíz de la compra; estadoscreated,pending_payment,in_review,paid,cancelled,rejectedyexpired, y referencia la reserva que respaldó ese intento de checkout. No guarda un vencimiento propio: expira como consecuencia del vencimiento de su reserva.PurchaseItem: snapshot definitivo del producto o variante, creado recién al confirmar la compra.TelepagosQryTelepagosPayment: datos del QR e intentos/resultados del proveedor.PurchasePaid: evento emitido una sola vez al pasar a pagada bajo bloqueo transaccional.
Servicios de checkout
CheckoutService es la fachada estable. Delega en:
StartCheckoutService: inicia la compra desde el carrito o crea un carrito técnico para compra directa, refresca el vencimiento de la reserva agregada y crea los snapshotsPurchaseItem.EditCheckoutService: modifica los datos del comprador antes del cierre.CompleteCheckoutService: completa, envía a revisión o materializa losPurchaseItemal confirmar el pago.ReleaseCheckoutService: cancela o vence una compra y aplica sus efectos comerciales; el scanner unificado del dominio Catalog detecta las reservas pendientes de vencimiento.SourceCartService: sincroniza o finaliza el carrito de checkout asociado a la compra.CatalogSelectionResolveryPurchaseItemSnapshotFactory: resuelven selecciones y generan snapshots.
Al iniciar checkout o elegir un medio de pago se refresca directamente StockReservation.expires_at, que es la única fuente de verdad y se expone como expires_at en la respuesta pública de la compra. El refresco sólo se permite mientras la reserva siga vigente; una fecha vencida bloquea todas las mutaciones aun antes de que corra el scheduler. Al materializar la expiración, la compra pagable, su carrito y la reserva pasan a expired dentro de la misma transacción. Al cancelar o reemplazar una compra recuperable, ésta se desvincula y el carrito conserva la misma reserva activa. Al informar una transferencia, la compra pasa de pending_payment a in_review y ese vencimiento se limpia. Si el comprador abandona el checkout durante la revisión, la compra y sus reservas permanecen intactas y se crea un carrito activo nuevo para que pueda seguir comprando. Adminapp puede confirmar o anular explícitamente la compra en revisión.
Las cantidades y variantes se editan mediante el dominio Cart. El endpoint autenticado PATCH /checkout-carts/{cart}/items/{cartItem} valida que el carrito pertenezca al usuario y a una compra editable. Cuando existe un cambio real, invalida atómicamente el intento de pago anterior, devuelve la misma reserva activa al carrito y sincroniza sus líneas con el contenido actualizado; Purchase no expone operaciones sobre líneas antes de la confirmación.
UserPurchaseLimitService controla límites de compra y CheckoutService conserva el punto de entrada para controladores e integraciones.
Endpoints
Bajo /tenants/{tenant:codigo}/compras, con auth:sanctum: listado, inicio, detalle, edición de ítems, datos del cliente, intención de pago, finalización, revisión y cancelación.
Dependencias y reglas
Depende de Cart, Catalog, Tenant, Auth e Integration; emite eventos consumidos por Ticket y Notification. Los cambios de estado e inventario deben ser transaccionales y usar los servicios del checkout, no actualizaciones directas del modelo.