fix(purchase): unify expired checkout errors

This commit is contained in:
2026-08-20 17:01:06 -03:00
parent ae6149df84
commit 9fd34f900f
11 changed files with 174 additions and 18 deletions

View File

@@ -5,6 +5,7 @@ namespace App\Domains\Purchase\Services\Checkout;
use App\Domains\Cart\Models\CartItem;
use App\Domains\Catalog\Services\StockReservationService;
use App\Domains\Purchase\Models\Purchase;
use App\Domains\Purchase\Services\PurchaseStateGuard;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\DB;
use Illuminate\Validation\ValidationException;
@@ -15,12 +16,14 @@ class CompleteCheckoutService
private readonly StockReservationService $reservations,
private readonly SourceCartService $sourceCart,
private readonly PurchaseItemSnapshotFactory $snapshots,
private readonly PurchaseStateGuard $purchaseState,
) {}
public function complete(Purchase $purchase): Purchase
{
return DB::transaction(function () use ($purchase): Purchase {
$purchase = $this->lockPurchase($purchase);
$this->purchaseState->assertNotExpired($purchase);
if ($purchase->payment_method === null) {
throw ValidationException::withMessages([
@@ -45,6 +48,7 @@ class CompleteCheckoutService
{
return DB::transaction(function () use ($purchase): Purchase {
$purchase = $this->lockPurchase($purchase);
$this->purchaseState->assertNotExpired($purchase);
if ($purchase->status === Purchase::STATUS_PAID) {
return $this->loadPurchase($purchase);
@@ -70,6 +74,7 @@ class CompleteCheckoutService
{
DB::transaction(function () use ($purchase): void {
$purchase = $this->lockPurchase($purchase);
$this->purchaseState->assertNotExpired($purchase);
if ($purchase->status === Purchase::STATUS_PAID) {
return;

View File

@@ -6,6 +6,7 @@ use App\Domains\Catalog\Models\Variant;
use App\Domains\Catalog\Services\CatalogInventoryService;
use App\Domains\Purchase\Models\Purchase;
use App\Domains\Purchase\Models\PurchaseItem;
use App\Domains\Purchase\Services\PurchaseStateGuard;
use App\Domains\Purchase\Services\UserPurchaseLimitService;
use Illuminate\Support\Facades\DB;
use Illuminate\Validation\ValidationException;
@@ -20,6 +21,7 @@ class EditCheckoutService
private readonly SourceCartService $sourceCart,
private readonly PurchaseItemSnapshotFactory $snapshots,
private readonly PurchaseResponseLoader $responses,
private readonly PurchaseStateGuard $purchaseState,
) {}
/** @param array<string, string> $customerData */
@@ -27,6 +29,7 @@ class EditCheckoutService
{
return DB::transaction(function () use ($purchase, $customerData): Purchase {
$purchase = $this->lockPurchase($purchase);
$this->purchaseState->assertNotExpired($purchase);
$this->assertEditable($purchase);
$purchase->update($customerData);
@@ -50,6 +53,7 @@ class EditCheckoutService
$updateVariant,
): Purchase {
$purchase = $this->lockPurchase($purchase);
$this->purchaseState->assertNotExpired($purchase);
if ($purchase->status !== Purchase::STATUS_CREATED || $this->hasExpired($purchase)) {
throw ValidationException::withMessages([
@@ -182,6 +186,7 @@ class EditCheckoutService
{
return DB::transaction(function () use ($purchase): Purchase {
$purchase = $this->lockPurchase($purchase);
$this->purchaseState->assertNotExpired($purchase);
$this->assertEditable($purchase);
if (! $purchase->tenant()->firstOrFail()->checkout_editing_policy->allowsModification()) {
@@ -208,6 +213,7 @@ class EditCheckoutService
{
return DB::transaction(function () use ($purchase, $purchaseItem): Purchase {
$purchase = $this->lockPurchase($purchase);
$this->purchaseState->assertNotExpired($purchase);
$this->assertEditable($purchase);
if (! $purchase->tenant()->firstOrFail()->checkout_editing_policy->allowsRemoval()) {

View File

@@ -5,6 +5,7 @@ namespace App\Domains\Purchase\Services\Checkout;
use App\Domains\Catalog\Models\StockReservation;
use App\Domains\Catalog\Services\StockReservationService;
use App\Domains\Purchase\Models\Purchase;
use App\Domains\Purchase\Services\PurchaseStateGuard;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;
use Illuminate\Validation\ValidationException;
@@ -14,6 +15,8 @@ class ReleaseCheckoutService
{
public function __construct(
private readonly StockReservationService $reservations,
private readonly SourceCartService $sourceCart,
private readonly PurchaseStateGuard $purchaseState,
) {}
public function cancel(Purchase $purchase): Purchase
@@ -70,6 +73,10 @@ class ReleaseCheckoutService
return DB::transaction(function () use ($purchase, $targetStatus): Purchase {
$purchase = $this->lockPurchase($purchase);
if ($targetStatus !== Purchase::STATUS_EXPIRED) {
$this->purchaseState->assertNotExpired($purchase);
}
if ($purchase->status === Purchase::STATUS_PAID) {
if ($targetStatus === Purchase::STATUS_EXPIRED) {
return $this->loadPurchase($purchase);