refactor(stock): make reservation expiration authoritative
This commit is contained in:
@@ -336,7 +336,6 @@ class Cart extends Model
|
||||
], true)) {
|
||||
$currentPurchase->update([
|
||||
'status' => Purchase::STATUS_SUPERSEDED,
|
||||
'expires_at' => null,
|
||||
]);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,86 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Domains\Cart\Services;
|
||||
|
||||
use App\Domains\Cart\Models\Cart;
|
||||
use App\Domains\Catalog\Models\StockReservation;
|
||||
use App\Domains\Catalog\Services\StockReservationService;
|
||||
use App\Domains\Purchase\Models\Purchase;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
|
||||
class ExpireCartReservationsService
|
||||
{
|
||||
public function __construct(
|
||||
private readonly StockReservationService $reservations,
|
||||
) {}
|
||||
|
||||
public function expireOverdue(): int
|
||||
{
|
||||
$expired = 0;
|
||||
$lastReservationId = 0;
|
||||
|
||||
do {
|
||||
$reservationIds = StockReservation::query()
|
||||
->where('status', StockReservation::STATUS_ACTIVE)
|
||||
->whereNotNull('expires_at')
|
||||
->where('expires_at', '<=', now())
|
||||
->where('id', '>', $lastReservationId)
|
||||
->whereHas('currentCart', fn ($query) => $query->where('status', 'active'))
|
||||
->whereDoesntHave('purchase', fn ($query) => $query->whereIn('status', [
|
||||
Purchase::STATUS_CREATED,
|
||||
Purchase::STATUS_PENDING_PAYMENT,
|
||||
Purchase::STATUS_IN_REVIEW,
|
||||
]))
|
||||
->orderBy('id')
|
||||
->limit(500)
|
||||
->pluck('id');
|
||||
|
||||
foreach ($reservationIds as $reservationId) {
|
||||
$lastReservationId = (int) $reservationId;
|
||||
|
||||
if ($this->expireReservation($lastReservationId)) {
|
||||
$expired++;
|
||||
}
|
||||
}
|
||||
} while ($reservationIds->count() === 500);
|
||||
|
||||
return $expired;
|
||||
}
|
||||
|
||||
private function expireReservation(int $reservationId): bool
|
||||
{
|
||||
$cartId = Cart::query()
|
||||
->where('current_stock_reservation_id', $reservationId)
|
||||
->where('status', 'active')
|
||||
->value('id');
|
||||
if ($cartId === null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return DB::transaction(function () use ($cartId, $reservationId): bool {
|
||||
/** @var Cart|null $cart */
|
||||
$cart = Cart::query()
|
||||
->whereKey($cartId)
|
||||
->where('current_stock_reservation_id', $reservationId)
|
||||
->where('status', 'active')
|
||||
->lockForUpdate()
|
||||
->first();
|
||||
if ($cart === null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/** @var StockReservation|null $reservation */
|
||||
$reservation = StockReservation::query()->lockForUpdate()->find($reservationId);
|
||||
if ($reservation === null
|
||||
|| $reservation->status !== StockReservation::STATUS_ACTIVE
|
||||
|| $reservation->expires_at === null
|
||||
|| $reservation->expires_at->isFuture()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$this->reservations->expire($reservation);
|
||||
|
||||
return true;
|
||||
});
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user