diff --git a/app/Domains/Cart/documentacion/README.md b/app/Domains/Cart/documentacion/README.md index 3cde77a..0645713 100644 --- a/app/Domains/Cart/documentacion/README.md +++ b/app/Domains/Cart/documentacion/README.md @@ -12,6 +12,7 @@ Gestiona el carrito activo de un tenant tanto para visitantes como para usuarios ## Servicios - `CartService`: obtiene el carrito, modifica ítems y administra la cookie del token invitado. +- `ExpireCartReservationsService`: libera como conjunto las reservas vencidas de carritos activos sin eliminar el contenido del carrito. - `GuestCartMergeService`: incorpora el carrito invitado al usuario cuando este se autentica. ## Endpoints @@ -33,6 +34,6 @@ Depende de `Catalog` para productos y variantes, de `Tenant` para aislar datos y Un carrito puede pasar a `checkout`. Las compras directas usan un carrito técnico con `origin=direct_checkout`; los carritos normales conservan `origin=user` y pueden restaurarse al cancelar o vencer la compra. -Cada edición sincroniza una única reserva para el carrito completo. Si varios ítems o bundles consumen el mismo inventario, se persiste una sola línea con la cantidad agregada. Al editar durante checkout, la compra anterior queda `superseded`, se desvincula y el carrito conserva la misma reserva activa con sus líneas actualizadas. +Cada edición sincroniza una única reserva para el carrito completo. Si varios ítems o bundles consumen el mismo inventario, se persiste una sola línea con la cantidad agregada. Al editar durante checkout, la compra anterior queda `superseded`, su reserva se libera con el motivo correspondiente y se crea otra para el carrito actualizado. -El comando unificado `php artisan reservations:expire` recorre una sola vez las reservas activas cuyo `expires_at` haya vencido. Cuando pertenecen a un carrito, conserva la reserva y sus líneas como historial, libera el stock como conjunto y cambia el carrito asociado a `expired` sin eliminar sus ítems. Al volver a resolver ese carrito desde la API, el anterior pasa automáticamente a `abandoned` y se crea uno activo y vacío para la misma identidad. El cliente nunca necesita reiniciarlo explícitamente. La API también materializa este vencimiento al acceder al carrito aunque el comando programado todavía no haya corrido. +El comando unificado `php artisan reservations:expire` procesa primero las compras vencidas y luego las reservas activas de carrito cuyo `expires_at` haya vencido. Se ejecuta cada minuto mediante el scheduler, conserva la reserva y sus líneas como historial, libera el stock como conjunto y deja intactos el carrito y sus ítems. diff --git a/app/Domains/Catalog/documentacion/README.md b/app/Domains/Catalog/documentacion/README.md index c484772..42ff288 100644 --- a/app/Domains/Catalog/documentacion/README.md +++ b/app/Domains/Catalog/documentacion/README.md @@ -9,7 +9,7 @@ Modela y publica la oferta comercial del tenant: productos, variantes, categorí - `CatalogItem` es la raíz del producto y se relaciona con tenant, categoría, marca, inventario, variantes, atributos, adjuntos y grupos destacados. - `Variant`, `ItemAttribute`, `Attribute`, `AttributeOption` y `VariantDefinition` describen opciones comercializables. - `Inventory` administra stock disponible, reservado y comprado. -- `StockReservation` representa la reserva completa de un carrito o checkout, con estados `active`, `committed`, `released` y `expired`. Su `expires_at` es el único reloj del bloqueo. Al expirar, también pasan a `expired` la compra pagable y el carrito asociados dentro de la misma transacción. Sus estados terminales nunca se reactivan ni se reemplazan implícitamente. Sus `StockReservationLine` agregan la cantidad requerida por inventario, incluso cuando varios ítems o bundles consumen el mismo stock. +- `StockReservation` representa la reserva completa de un carrito o checkout, con estados `active`, `committed`, `released` y `expired`. Sus `StockReservationLine` agregan la cantidad requerida por inventario, incluso cuando varios ítems o bundles consumen el mismo stock. - `Category` soporta jerarquía y categorías globales o propias del tenant. - `FeaturedGroup` y `FeaturedItem` organizan secciones destacadas. - `BundleComponent` representa los componentes de un paquete. @@ -19,7 +19,6 @@ Modela y publica la oferta comercial del tenant: productos, variantes, categorí - `CatalogService`: alta, búsqueda, detalle, listado por categoría y eliminación. - `CatalogInventoryService`: consulta, reserva, libera y confirma inventario. - `StockReservationService`: sincroniza el carrito como conjunto, bloquea todos sus inventarios en orden estable y mantiene el ledger agregado consistente con `Inventory.reserved_stock`. -- `ExpireStockReservationsService`: detecta en un único recorrido reservas vencidas de compras, carritos y huérfanas, y delega los efectos comerciales sin mezclar esas reglas con la liberación física del inventario. - `FeaturedGroupService`: pagina los ítems destacados para la tienda. - `OnTicketFeaturedGroupService`: administra grupos destacados del panel para sitios de tickets. diff --git a/app/Domains/Purchase/documentacion/README.md b/app/Domains/Purchase/documentacion/README.md index 7410245..10f0d23 100644 --- a/app/Domains/Purchase/documentacion/README.md +++ b/app/Domains/Purchase/documentacion/README.md @@ -6,7 +6,7 @@ Implementa el ciclo de compra y checkout: crea la cabecera de compra desde un ca ## Modelo -- `Purchase`: raíz de la compra; estados `created`, `pending_payment`, `in_review`, `paid`, `cancelled`, `rejected` y `expired`, y referencia la reserva que respaldó ese intento de checkout. No guarda un vencimiento propio: expira como consecuencia del vencimiento de su reserva. +- `Purchase`: raíz de la compra; estados `created`, `pending_payment`, `in_review`, `paid`, `cancelled`, `rejected` y `expired`, y referencia la reserva que respaldó ese intento de checkout. - `PurchaseItem`: snapshot definitivo del producto o variante, creado recién al confirmar la compra. - `TelepagosQr` y `TelepagosPayment`: datos del QR e intentos/resultados del proveedor. - `PurchasePaid`: evento emitido una sola vez al pasar a pagada bajo bloqueo transaccional. @@ -24,7 +24,7 @@ Implementa el ciclo de compra y checkout: crea la cabecera de compra desde un ca 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. +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, libera su reserva completa y crea otra para 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.