where('status', StockReservation::STATUS_ACTIVE) ->whereNull('purchase_id') ->whereNotNull('cart_item_id') ->whereNotNull('expires_at') ->where('expires_at', '<=', now()) ->where('cart_item_id', '>', $lastCartItemId) ->whereHas('cartItem.cart', fn ($query) => $query->where('status', 'active')) ->select('cart_item_id') ->distinct() ->orderBy('cart_item_id') ->limit(500) ->pluck('cart_item_id'); foreach ($cartItemIds as $cartItemId) { $lastCartItemId = (int) $cartItemId; if ($this->expireCartItem($lastCartItemId)) { $expiredItems++; } } } while ($cartItemIds->count() === 500); return $expiredItems; } private function expireCartItem(int $cartItemId): bool { /** @var CartItem|null $candidate */ $candidate = CartItem::query()->select(['id', 'cart_id'])->find($cartItemId); if ($candidate === null) { return false; } return DB::transaction(function () use ($candidate, $cartItemId): bool { /** @var Cart|null $cart */ $cart = Cart::query() ->whereKey($candidate->cart_id) ->where('status', 'active') ->lockForUpdate() ->first(); if ($cart === null) { return false; } /** @var CartItem|null $cartItem */ $cartItem = $cart->items() ->whereKey($cartItemId) ->lockForUpdate() ->first(); if ($cartItem === null) { return false; } $reservations = StockReservation::query() ->where('cart_item_id', $cartItem->getKey()) ->where('status', StockReservation::STATUS_ACTIVE) ->orderBy('inventory_id') ->lockForUpdate() ->get(); if ( $reservations->isEmpty() || $reservations->contains( fn (StockReservation $reservation): bool => $reservation->purchase_id !== null || $reservation->expires_at === null || $reservation->expires_at->isFuture(), ) ) { return false; } $inventories = Inventory::query() ->whereKey($reservations->pluck('inventory_id')) ->orderBy('id') ->lockForUpdate() ->get() ->keyBy('id'); foreach ($reservations as $reservation) { $inventory = $inventories->get($reservation->inventory_id) ?? throw new \InvalidArgumentException('No se encontro el inventario reservado.'); $inventory->release((int) $reservation->quantity); $reservation->update([ 'quantity' => 0, 'status' => StockReservation::STATUS_EXPIRED, 'expires_at' => null, 'released_at' => now(), ]); } $cartItem->delete(); if (! $cart->items()->exists()) { $cart->update(['status' => 'expired']); $cart->delete(); } return true; }); } }