refactor(stock): propagate reservation expiration
This commit is contained in:
@@ -38,6 +38,16 @@ class Cart extends Model
|
||||
|
||||
protected $table = 'carritos';
|
||||
|
||||
public const STATUS_ACTIVE = 'active';
|
||||
|
||||
public const STATUS_CHECKOUT = 'checkout';
|
||||
|
||||
public const STATUS_CONVERTED = 'converted';
|
||||
|
||||
public const STATUS_EXPIRED = 'expired';
|
||||
|
||||
public const STATUS_ABANDONED = 'abandoned';
|
||||
|
||||
public const ORIGIN_USER = 'user';
|
||||
|
||||
public const ORIGIN_DIRECT_CHECKOUT = 'direct_checkout';
|
||||
|
||||
@@ -4,6 +4,7 @@ namespace App\Domains\Cart\Services;
|
||||
|
||||
use App\Domains\Auth\Models\User;
|
||||
use App\Domains\Cart\Models\Cart;
|
||||
use App\Domains\Catalog\Exceptions\StockReservationExpiredException;
|
||||
use App\Domains\Catalog\Models\StockReservation;
|
||||
use App\Domains\Catalog\Services\ExpireStockReservationsService;
|
||||
use App\Domains\Tenant\Models\Tenant;
|
||||
@@ -126,7 +127,7 @@ class CartService
|
||||
}
|
||||
|
||||
$cart->update([
|
||||
'status' => 'abandoned',
|
||||
'status' => Cart::STATUS_ABANDONED,
|
||||
'current_purchase_id' => null,
|
||||
]);
|
||||
|
||||
@@ -161,7 +162,7 @@ class CartService
|
||||
{
|
||||
$cart = new Cart([
|
||||
'tenant_codigo' => $tenant->codigo,
|
||||
'status' => 'active',
|
||||
'status' => Cart::STATUS_ACTIVE,
|
||||
]);
|
||||
|
||||
$cart->setRelation('items', collect());
|
||||
@@ -262,12 +263,14 @@ class CartService
|
||||
{
|
||||
return Cart::query()
|
||||
->where('tenant_codigo', $tenant->codigo)
|
||||
->where('status', 'active')
|
||||
->where('origin', Cart::ORIGIN_USER)
|
||||
->whereIn('status', [Cart::STATUS_ACTIVE, Cart::STATUS_EXPIRED])
|
||||
->when(
|
||||
$identity['user_id'] !== null,
|
||||
fn ($query) => $query->where('user_id', $identity['user_id']),
|
||||
fn ($query) => $query->where('guest_token', $identity['guest_token']),
|
||||
)
|
||||
->orderByRaw('CASE WHEN status = ? THEN 0 ELSE 1 END', [Cart::STATUS_ACTIVE])
|
||||
->first();
|
||||
}
|
||||
|
||||
@@ -290,9 +293,18 @@ class CartService
|
||||
*/
|
||||
protected function findOrCreateCart(Tenant $tenant, array $identity): Cart
|
||||
{
|
||||
$cart = $this->findCart($tenant, $identity);
|
||||
if ($cart?->status === Cart::STATUS_EXPIRED) {
|
||||
throw new StockReservationExpiredException;
|
||||
}
|
||||
if ($cart !== null) {
|
||||
return $cart;
|
||||
}
|
||||
|
||||
$attributes = [
|
||||
'tenant_codigo' => $tenant->codigo,
|
||||
'status' => 'active',
|
||||
'status' => Cart::STATUS_ACTIVE,
|
||||
'origin' => Cart::ORIGIN_USER,
|
||||
];
|
||||
|
||||
if ($identity['user_id'] !== null) {
|
||||
|
||||
@@ -141,7 +141,7 @@ class ExpireStockReservationsService
|
||||
$cart = Cart::query()
|
||||
->whereKey($cartId)
|
||||
->where('current_stock_reservation_id', $reservationId)
|
||||
->where('status', 'active')
|
||||
->where('status', Cart::STATUS_ACTIVE)
|
||||
->lockForUpdate()
|
||||
->first();
|
||||
if ($cart === null) {
|
||||
@@ -155,6 +155,7 @@ class ExpireStockReservationsService
|
||||
}
|
||||
|
||||
$this->reservations->expire($reservation);
|
||||
$cart->update(['status' => Cart::STATUS_EXPIRED]);
|
||||
|
||||
return 'cart_reservations';
|
||||
});
|
||||
|
||||
@@ -129,13 +129,25 @@ class ReleaseCheckoutService
|
||||
return;
|
||||
}
|
||||
|
||||
if ($cart->status === 'active') {
|
||||
if ($targetStatus === Purchase::STATUS_EXPIRED
|
||||
&& in_array($cart->status, [Cart::STATUS_ACTIVE, Cart::STATUS_CHECKOUT], true)) {
|
||||
Cart::query()
|
||||
->whereKey($cart->getKey())
|
||||
->where('current_purchase_id', $purchase->getKey())
|
||||
->where('current_stock_reservation_id', $purchase->stock_reservation_id)
|
||||
->update([
|
||||
'status' => Cart::STATUS_EXPIRED,
|
||||
'current_purchase_id' => null,
|
||||
]);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if ($cart->status === Cart::STATUS_ACTIVE) {
|
||||
$cartUpdate = [
|
||||
'current_purchase_id' => null,
|
||||
'current_stock_reservation_id' => null,
|
||||
];
|
||||
if ($targetStatus !== Purchase::STATUS_EXPIRED) {
|
||||
$cartUpdate['current_stock_reservation_id'] = null;
|
||||
}
|
||||
|
||||
Cart::query()
|
||||
->whereKey($cart->getKey())
|
||||
@@ -145,12 +157,12 @@ class ReleaseCheckoutService
|
||||
return;
|
||||
}
|
||||
|
||||
if ($cart->status !== 'checkout') {
|
||||
if ($cart->status !== Cart::STATUS_CHECKOUT) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (! $cart->trashed()) {
|
||||
$cart->update(['status' => 'converted']);
|
||||
$cart->update(['status' => Cart::STATUS_CONVERTED]);
|
||||
$cart->delete();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ namespace App\Domains\Purchase\Services\Checkout;
|
||||
|
||||
use App\Domains\Cart\Models\Cart;
|
||||
use App\Domains\Cart\Models\CartItem;
|
||||
use App\Domains\Catalog\Exceptions\StockReservationExpiredException;
|
||||
use App\Domains\Catalog\Models\CatalogItem;
|
||||
use App\Domains\Catalog\Models\Variant;
|
||||
use App\Domains\Catalog\Services\CatalogInventoryService;
|
||||
@@ -329,7 +330,11 @@ class StartCheckoutService
|
||||
throw new NotFoundHttpException('Cart not found for tenant.');
|
||||
}
|
||||
|
||||
if ($cart->status !== 'active') {
|
||||
if ($cart->status === Cart::STATUS_EXPIRED) {
|
||||
throw new StockReservationExpiredException;
|
||||
}
|
||||
|
||||
if ($cart->status !== Cart::STATUS_ACTIVE) {
|
||||
throw ValidationException::withMessages([
|
||||
'cart_id' => __('api.purchase.inactive_cart'),
|
||||
]);
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
public function up(): void
|
||||
{
|
||||
$expiredReservationIds = fn ($query) => $query
|
||||
->select('id')
|
||||
->from('stock_reservations')
|
||||
->where('status', 'expired');
|
||||
|
||||
DB::table('compras')
|
||||
->whereIn('status', ['created', 'pending_payment'])
|
||||
->whereIn('stock_reservation_id', $expiredReservationIds)
|
||||
->update(['status' => 'expired']);
|
||||
|
||||
DB::table('carritos')
|
||||
->whereIn('status', ['active', 'checkout'])
|
||||
->whereIn('current_stock_reservation_id', $expiredReservationIds)
|
||||
->update(['status' => 'expired']);
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
// Terminal business states cannot be reversed without inventing their prior state.
|
||||
}
|
||||
};
|
||||
Reference in New Issue
Block a user