fix(cart): reconcile expired cart mutations
This commit is contained in:
@@ -186,7 +186,7 @@ class CartControllerTest extends TestCase
|
||||
$this->travelBack();
|
||||
}
|
||||
|
||||
public function test_it_expires_abandoned_cart_reservations_without_deleting_the_cart(): void
|
||||
public function test_it_expires_a_cart_reservation_and_automatically_replaces_the_cart(): void
|
||||
{
|
||||
config()->set('catalog.stock_reservation_expiration_minutes', 30);
|
||||
$tenant = $this->createTenant('acme');
|
||||
@@ -208,10 +208,6 @@ class CartControllerTest extends TestCase
|
||||
->expectsOutput('Expired cart reservations: 0')
|
||||
->assertSuccessful();
|
||||
|
||||
$this->postJson('/api/tenants/acme/cart/restart')
|
||||
->assertUnprocessable()
|
||||
->assertJsonValidationErrors('cart');
|
||||
|
||||
$this->travel(31)->minutes();
|
||||
|
||||
$this->artisan('reservations:expire')
|
||||
@@ -241,28 +237,13 @@ class CartControllerTest extends TestCase
|
||||
'quantity' => 2,
|
||||
]);
|
||||
|
||||
$this->getJson('/api/tenants/acme/cart')
|
||||
$currentCart = $this->getJson('/api/tenants/acme/cart')
|
||||
->assertOk()
|
||||
->assertJsonPath('data.id', $cartId)
|
||||
->assertJsonPath('data.status', Cart::STATUS_EXPIRED);
|
||||
|
||||
$this->postJson('/api/tenants/acme/cart/items', [
|
||||
'catalog_item_id' => $item->id,
|
||||
'cantidad' => 1,
|
||||
])
|
||||
->assertUnprocessable()
|
||||
->assertExactJson([
|
||||
'code' => 'stock_reservation.expired',
|
||||
'message' => __('api.cart.reservation_expired'),
|
||||
]);
|
||||
|
||||
$restart = $this->postJson('/api/tenants/acme/cart/restart')
|
||||
->assertOk()
|
||||
->assertJsonPath('code', 'cart.restarted')
|
||||
->assertJsonPath('data.status', Cart::STATUS_ACTIVE)
|
||||
->assertJsonPath('data.items', [])
|
||||
->assertJsonMissingPath('data.stock_reservation')
|
||||
->assertJsonMissingPath('data.current_stock_reservation_id');
|
||||
$newCartId = $restart->json('data.id');
|
||||
$newCartId = $currentCart->json('data.id');
|
||||
|
||||
$this->assertNotSame($cartId, $newCartId);
|
||||
$this->assertDatabaseHas('carritos', [
|
||||
@@ -276,6 +257,14 @@ class CartControllerTest extends TestCase
|
||||
'current_stock_reservation_id' => null,
|
||||
]);
|
||||
|
||||
$this->postJson('/api/tenants/acme/cart/items', [
|
||||
'catalog_item_id' => $item->id,
|
||||
'cantidad' => 1,
|
||||
])
|
||||
->assertOk()
|
||||
->assertJsonPath('data.id', $newCartId)
|
||||
->assertJsonPath('data.items.0.cantidad', 1);
|
||||
|
||||
$this->artisan('reservations:expire')
|
||||
->expectsOutput('Expired purchases: 0')
|
||||
->expectsOutput('Expired cart reservations: 0')
|
||||
@@ -284,6 +273,88 @@ class CartControllerTest extends TestCase
|
||||
$this->travelBack();
|
||||
}
|
||||
|
||||
public function test_it_replaces_an_overdue_cart_before_the_expiration_job_runs(): void
|
||||
{
|
||||
config()->set('catalog.stock_reservation_expiration_minutes', 30);
|
||||
$tenant = $this->createTenant('acme');
|
||||
$user = User::factory()->create();
|
||||
$item = $this->createDirectItem($tenant, 10, '49.90');
|
||||
|
||||
$original = $this->actingAs($user, 'sanctum')
|
||||
->postJson('/api/tenants/acme/cart/items', [
|
||||
'catalog_item_id' => $item->id,
|
||||
'cantidad' => 2,
|
||||
])->assertOk();
|
||||
$originalCartId = $original->json('data.id');
|
||||
|
||||
$this->travel(31)->minutes();
|
||||
|
||||
$replacement = $this->postJson('/api/tenants/acme/cart/items', [
|
||||
'catalog_item_id' => $item->id,
|
||||
'cantidad' => 1,
|
||||
])
|
||||
->assertOk()
|
||||
->assertJsonPath('data.status', Cart::STATUS_ACTIVE)
|
||||
->assertJsonPath('data.items.0.cantidad', 1);
|
||||
|
||||
$this->assertNotSame($originalCartId, $replacement->json('data.id'));
|
||||
$this->assertDatabaseHas('carritos', [
|
||||
'id' => $originalCartId,
|
||||
'status' => Cart::STATUS_ABANDONED,
|
||||
]);
|
||||
$this->assertDatabaseHas('inventories', [
|
||||
'id' => $item->inventory_id,
|
||||
'reserved_stock' => 1,
|
||||
]);
|
||||
|
||||
$this->travelBack();
|
||||
}
|
||||
|
||||
public function test_expired_cart_mutations_return_the_expiration_error_instead_of_not_found(): void
|
||||
{
|
||||
config()->set('catalog.stock_reservation_expiration_minutes', 30);
|
||||
$tenant = $this->createTenant('acme');
|
||||
$user = User::factory()->create();
|
||||
[$item, $firstVariant] = $this->createVariantItem($tenant, 10, '49.90');
|
||||
$secondInventory = Inventory::query()->create(['real_stock' => 10]);
|
||||
$secondVariant = $item->variants()->create(['inventory_id' => $secondInventory->id]);
|
||||
|
||||
$cartItemId = $this->actingAs($user, 'sanctum')
|
||||
->postJson('/api/tenants/acme/cart/items', [
|
||||
'catalog_item_id' => $item->id,
|
||||
'variant_id' => $firstVariant->id,
|
||||
'cantidad' => 2,
|
||||
])
|
||||
->assertOk()
|
||||
->json('data.items.0.id');
|
||||
|
||||
$this->travel(31)->minutes();
|
||||
|
||||
$expectedError = [
|
||||
'code' => 'stock_reservation.expired',
|
||||
'message' => __('api.cart.reservation_expired'),
|
||||
];
|
||||
|
||||
$this->patchJson("/api/tenants/acme/cart/items/{$cartItemId}", [
|
||||
'cantidad' => 3,
|
||||
])
|
||||
->assertUnprocessable()
|
||||
->assertExactJson($expectedError);
|
||||
|
||||
$this->patchJson("/api/tenants/acme/cart/items/{$cartItemId}", [
|
||||
'cantidad' => 2,
|
||||
'variant_id' => $secondVariant->id,
|
||||
])
|
||||
->assertUnprocessable()
|
||||
->assertExactJson($expectedError);
|
||||
|
||||
$this->deleteJson("/api/tenants/acme/cart/items/{$cartItemId}")
|
||||
->assertUnprocessable()
|
||||
->assertExactJson($expectedError);
|
||||
|
||||
$this->travelBack();
|
||||
}
|
||||
|
||||
public function test_it_filters_item_images_when_the_tenant_disables_them(): void
|
||||
{
|
||||
$tenant = $this->createTenant('acme');
|
||||
|
||||
Reference in New Issue
Block a user