feat(checkout): track current cart purchase

This commit is contained in:
2026-08-21 14:05:33 -03:00
parent a34d5cba1a
commit afd69b8393
17 changed files with 258 additions and 23 deletions

View File

@@ -17,6 +17,7 @@ use App\Domains\Tenant\Models\Tenant;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Support\Facades\Queue;
use Illuminate\Support\Str;
use Illuminate\Validation\ValidationException;
use Tests\TestCase;
class StorePurchaseTest extends TestCase
@@ -128,6 +129,7 @@ class StorePurchaseTest extends TestCase
'user_id' => $user->id,
'status' => 'active',
'origin' => Cart::ORIGIN_USER,
'current_purchase_id' => $purchaseId,
'deleted_at' => null,
]);
$this->assertDatabaseHas('carrito_items', [
@@ -150,12 +152,31 @@ class StorePurchaseTest extends TestCase
->assertJsonCount(1, 'data.items')
->assertJsonPath('data.items.0.cantidad', 2);
$this->actingAs($user, 'sanctum')
$replacementResponse = $this->actingAs($user, 'sanctum')
->postJson('/api/tenants/sonder/compras/start-checkout', [
'cart_id' => $cartId,
])
->assertUnprocessable()
->assertJsonValidationErrors('cart_id');
->assertCreated();
$replacementPurchaseId = $replacementResponse->json('data.id');
$this->assertDatabaseHas('compras', [
'id' => $purchaseId,
'status' => Purchase::STATUS_SUPERSEDED,
]);
$this->assertDatabaseHas('carritos', [
'id' => $cartId,
'current_purchase_id' => $replacementPurchaseId,
]);
$this->assertDatabaseHas('stock_reservations', [
'inventory_id' => $inventory->id,
'purchase_id' => $replacementPurchaseId,
'quantity' => 2,
'status' => 'active',
]);
$this->assertDatabaseHas('inventories', [
'id' => $inventory->id,
'reserved_stock' => 2,
]);
$catalogItem->update([
'nombre' => 'Updated Product',
@@ -196,6 +217,7 @@ class StorePurchaseTest extends TestCase
'id' => $response->json('data.cart_id'),
'status' => 'checkout',
'origin' => Cart::ORIGIN_DIRECT_CHECKOUT,
'current_purchase_id' => $response->json('data.id'),
]);
$this->assertDatabaseHas('compra_items', [
'compra_id' => $response->json('data.id'),
@@ -455,6 +477,7 @@ class StorePurchaseTest extends TestCase
'id' => $purchase->cart_id,
'status' => 'active',
'origin' => Cart::ORIGIN_USER,
'current_purchase_id' => $purchase->id,
'deleted_at' => null,
]);
$this->assertDatabaseCount('carrito_items', 1);
@@ -469,6 +492,7 @@ class StorePurchaseTest extends TestCase
'id' => $activeCart->id,
'user_id' => $user->id,
'status' => 'active',
'current_purchase_id' => null,
'deleted_at' => null,
]);
$this->assertDatabaseHas('inventories', [
@@ -484,6 +508,60 @@ class StorePurchaseTest extends TestCase
$this->assertSame(1, $activeCart->items()->count());
}
public function test_it_reassigns_a_terminal_purchase_reservation_and_rejects_a_late_confirmation(): void
{
$this->createTenant('sonder', 'Sonder', 'sonder.com.ar');
$user = User::factory()->create();
$variant = $this->createVariantForTenant('sonder', 10, '50.00');
$previousPurchase = $this->createCheckoutPurchase($user, 'sonder', $variant, 2);
$cart = $previousPurchase->cart;
$previousPurchase->update([
'status' => Purchase::STATUS_PENDING_PAYMENT,
'payment_method' => 'transfer',
'expires_at' => now()->addMinutes(30),
]);
$currentPurchase = app(CheckoutService::class)->startCheckout(
$previousPurchase->tenant,
$user->id,
['cart_id' => $cart->id],
);
$this->assertDatabaseHas('compras', [
'id' => $previousPurchase->id,
'status' => Purchase::STATUS_SUPERSEDED,
'expires_at' => null,
]);
$this->assertDatabaseHas('carritos', [
'id' => $cart->id,
'current_purchase_id' => $currentPurchase->id,
]);
$this->assertDatabaseHas('stock_reservations', [
'purchase_id' => $currentPurchase->id,
'quantity' => 2,
'status' => 'active',
]);
try {
app(CheckoutService::class)->confirmPaidPurchase($previousPurchase->fresh());
$this->fail('A superseded purchase was allowed to commit the current reservation.');
} catch (ValidationException $exception) {
$this->assertArrayHasKey('purchase', $exception->errors());
}
$this->assertDatabaseHas('inventories', [
'id' => $variant->inventory_id,
'reserved_stock' => 2,
'sold_units' => 0,
]);
$this->assertDatabaseHas('stock_reservations', [
'purchase_id' => $currentPurchase->id,
'quantity' => 2,
'status' => 'active',
]);
}
public function test_it_expires_the_purchase_without_mutating_the_active_cart(): void
{
$this->createTenant('sonder', 'Sonder', 'sonder.com.ar');
@@ -511,6 +589,7 @@ class StorePurchaseTest extends TestCase
'id' => $activeCart->id,
'user_id' => $user->id,
'status' => 'active',
'current_purchase_id' => null,
'deleted_at' => null,
]);
$this->assertDatabaseHas('stock_reservations', [