feat(purchase): restore in-review transfer lifecycle

This commit is contained in:
2026-08-21 16:15:55 -03:00
parent dc0fbe06b8
commit 5548fe8511
11 changed files with 130 additions and 14 deletions

View File

@@ -55,6 +55,10 @@ class CompleteCheckoutService
return $this->loadPurchase($purchase);
}
if ($purchase->status === Purchase::STATUS_IN_REVIEW) {
return $this->loadPurchase($purchase);
}
$this->purchaseState->lockCurrentCart($purchase);
if (
@@ -66,7 +70,10 @@ class CompleteCheckoutService
]);
}
$purchase->update(['expires_at' => null]);
$purchase->update([
'status' => Purchase::STATUS_IN_REVIEW,
'expires_at' => null,
]);
$this->reservations->syncPurchaseExpiration($purchase);
return $this->loadPurchase($purchase);
@@ -171,6 +178,7 @@ class CompleteCheckoutService
{
return in_array($purchase->status, [
Purchase::STATUS_PAID,
Purchase::STATUS_IN_REVIEW,
Purchase::STATUS_CANCELLED,
Purchase::STATUS_REJECTED,
Purchase::STATUS_EXPIRED,

View File

@@ -22,6 +22,11 @@ class ReleaseCheckoutService
return $this->release($purchase, Purchase::STATUS_CANCELLED);
}
public function cancelFromAdmin(Purchase $purchase): Purchase
{
return $this->release($purchase, Purchase::STATUS_CANCELLED, allowInReviewCancellation: true);
}
public function expire(Purchase $purchase): Purchase
{
return $this->release($purchase, Purchase::STATUS_EXPIRED);
@@ -61,9 +66,16 @@ class ReleaseCheckoutService
return $expiredCount;
}
private function release(Purchase $purchase, string $targetStatus): Purchase
{
return DB::transaction(function () use ($purchase, $targetStatus): Purchase {
private function release(
Purchase $purchase,
string $targetStatus,
bool $allowInReviewCancellation = false,
): Purchase {
return DB::transaction(function () use (
$purchase,
$targetStatus,
$allowInReviewCancellation,
): Purchase {
$purchase = $this->lockPurchase($purchase);
if ($purchase->status === Purchase::STATUS_PAID) {
@@ -76,6 +88,14 @@ class ReleaseCheckoutService
]);
}
if (
$purchase->status === Purchase::STATUS_IN_REVIEW
&& $targetStatus === Purchase::STATUS_CANCELLED
&& ! $allowInReviewCancellation
) {
return $this->createNewCartWithoutCancelling($purchase);
}
if ($this->isAlreadyReleased($purchase)) {
return $this->loadPurchase($purchase);
}
@@ -153,6 +173,33 @@ class ReleaseCheckoutService
}
}
private function createNewCartWithoutCancelling(Purchase $purchase): Purchase
{
return DB::transaction(function () use ($purchase): Purchase {
$purchase = $this->lockPurchase($purchase);
if ($purchase->status !== Purchase::STATUS_IN_REVIEW || $purchase->user_id === null) {
return $this->loadPurchase($purchase);
}
/** @var Cart|null $sourceCart */
$sourceCart = $purchase->cart()->withTrashed()->lockForUpdate()->first();
if ($sourceCart !== null && ! $sourceCart->trashed() && $sourceCart->status === 'active') {
$sourceCart->update(['status' => 'checkout']);
}
Cart::query()->firstOrCreate([
'tenant_codigo' => $purchase->tenant_codigo,
'user_id' => $purchase->user_id,
'guest_token' => null,
'status' => 'active',
'origin' => Cart::ORIGIN_USER,
]);
return $this->loadPurchase($purchase);
});
}
private function isAlreadyReleased(Purchase $purchase): bool
{
return in_array($purchase->status, [

View File

@@ -68,6 +68,11 @@ class CheckoutService
return $this->releaser->cancel($purchase);
}
public function cancelPurchaseFromAdmin(Purchase $purchase): Purchase
{
return $this->releaser->cancelFromAdmin($purchase);
}
public function expirePurchase(Purchase $purchase): Purchase
{
return $this->releaser->expire($purchase);

View File

@@ -51,6 +51,7 @@ class UserPurchaseLimitService
->whereIn('status', [
Purchase::STATUS_CREATED,
Purchase::STATUS_PENDING_PAYMENT,
Purchase::STATUS_IN_REVIEW,
Purchase::STATUS_PAID,
])
->when(
@@ -68,6 +69,7 @@ class UserPurchaseLimitService
->whereIn('status', [
Purchase::STATUS_CREATED,
Purchase::STATUS_PENDING_PAYMENT,
Purchase::STATUS_IN_REVIEW,
])
->whereDoesntHave('items')
->when(
@@ -133,6 +135,7 @@ class UserPurchaseLimitService
->whereIn('status', [
Purchase::STATUS_CREATED,
Purchase::STATUS_PENDING_PAYMENT,
Purchase::STATUS_IN_REVIEW,
Purchase::STATUS_PAID,
]))
->groupBy('source_catalog_item_id')
@@ -143,7 +146,11 @@ class UserPurchaseLimitService
->whereIn('catalog_item_id', $ids)
->whereHas('cart.purchases', fn ($query) => $query
->where('user_id', $userId)
->whereIn('status', [Purchase::STATUS_CREATED, Purchase::STATUS_PENDING_PAYMENT])
->whereIn('status', [
Purchase::STATUS_CREATED,
Purchase::STATUS_PENDING_PAYMENT,
Purchase::STATUS_IN_REVIEW,
])
->whereDoesntHave('items'))
->groupBy('catalog_item_id')
->pluck('quantity', 'catalog_item_id');