2025-12-28 09:29:23 +00:00
|
|
|
<?php
|
|
|
|
|
|
|
|
|
|
namespace Blax\Shop\Tests\Feature;
|
|
|
|
|
|
|
|
|
|
use Blax\Shop\Enums\ProductType;
|
2025-12-28 09:48:22 +00:00
|
|
|
use Blax\Shop\Models\Cart;
|
2025-12-28 09:29:23 +00:00
|
|
|
use Blax\Shop\Models\Product;
|
|
|
|
|
use Blax\Shop\Tests\TestCase;
|
|
|
|
|
use Carbon\Carbon;
|
|
|
|
|
use Illuminate\Foundation\Testing\RefreshDatabase;
|
2025-12-28 09:48:22 +00:00
|
|
|
use Illuminate\Support\Str;
|
2025-12-28 09:29:23 +00:00
|
|
|
use PHPUnit\Framework\Attributes\Test;
|
2025-12-28 09:48:22 +00:00
|
|
|
use Workbench\App\Models\User;
|
2025-12-28 09:29:23 +00:00
|
|
|
|
|
|
|
|
class GetHasMoreAttributeTest extends TestCase
|
|
|
|
|
{
|
|
|
|
|
use RefreshDatabase;
|
|
|
|
|
|
2025-12-28 09:48:22 +00:00
|
|
|
protected function createUserWithCart(): array
|
|
|
|
|
{
|
|
|
|
|
$user = User::create([
|
|
|
|
|
'id' => Str::uuid(),
|
|
|
|
|
'name' => 'Test User',
|
|
|
|
|
'email' => 'test@example.com',
|
|
|
|
|
'password' => bcrypt('password'),
|
|
|
|
|
]);
|
|
|
|
|
|
|
|
|
|
$cart = Cart::factory()->forCustomer($user)->create();
|
|
|
|
|
|
|
|
|
|
return [$user, $cart];
|
|
|
|
|
}
|
|
|
|
|
|
2025-12-28 09:29:23 +00:00
|
|
|
#[Test]
|
|
|
|
|
public function it_returns_php_int_max_when_stock_management_is_disabled()
|
|
|
|
|
{
|
|
|
|
|
$product = Product::factory()->create([
|
|
|
|
|
'manage_stock' => false,
|
|
|
|
|
]);
|
|
|
|
|
|
|
|
|
|
$this->assertEquals(PHP_INT_MAX, $product->has_more);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[Test]
|
|
|
|
|
public function it_returns_available_stock_for_simple_product()
|
|
|
|
|
{
|
|
|
|
|
$product = Product::factory()->withStocks(50)->create();
|
|
|
|
|
|
|
|
|
|
$this->assertEquals(50, $product->has_more);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[Test]
|
|
|
|
|
public function it_returns_zero_when_no_stock_available()
|
|
|
|
|
{
|
|
|
|
|
$product = Product::factory()->create([
|
|
|
|
|
'manage_stock' => true,
|
|
|
|
|
]);
|
|
|
|
|
|
|
|
|
|
$this->assertEquals(0, $product->has_more);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[Test]
|
|
|
|
|
public function it_returns_remaining_stock_after_claims()
|
|
|
|
|
{
|
|
|
|
|
$product = Product::factory()->withStocks(100)->create();
|
|
|
|
|
|
|
|
|
|
// Claim 30 units
|
|
|
|
|
$product->claimStock(
|
|
|
|
|
quantity: 30,
|
|
|
|
|
from: now(),
|
|
|
|
|
until: now()->addDays(5)
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
$this->assertEquals(70, $product->has_more);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[Test]
|
|
|
|
|
public function it_returns_available_stock_for_booking_product()
|
|
|
|
|
{
|
|
|
|
|
$product = Product::factory()->create([
|
|
|
|
|
'type' => ProductType::BOOKING,
|
|
|
|
|
'manage_stock' => true,
|
|
|
|
|
]);
|
|
|
|
|
$product->increaseStock(10);
|
|
|
|
|
|
|
|
|
|
// Claim 3 units for a future period
|
|
|
|
|
$product->claimStock(
|
|
|
|
|
quantity: 3,
|
|
|
|
|
from: now()->addDays(5),
|
|
|
|
|
until: now()->addDays(10)
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
// Has more should reflect available stock at current time
|
|
|
|
|
$this->assertEquals(10, $product->has_more);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[Test]
|
|
|
|
|
public function it_returns_aggregated_availability_for_pool_product()
|
|
|
|
|
{
|
|
|
|
|
// Create pool product
|
|
|
|
|
$pool = Product::factory()->create([
|
|
|
|
|
'name' => 'Hotel Rooms',
|
|
|
|
|
'type' => ProductType::POOL,
|
|
|
|
|
'manage_stock' => false,
|
|
|
|
|
]);
|
|
|
|
|
|
|
|
|
|
// Create 3 single items with stock
|
|
|
|
|
$single1 = Product::factory()->create([
|
|
|
|
|
'name' => 'Room 101',
|
|
|
|
|
'type' => ProductType::BOOKING,
|
|
|
|
|
'manage_stock' => true,
|
|
|
|
|
]);
|
|
|
|
|
$single1->increaseStock(1);
|
|
|
|
|
|
|
|
|
|
$single2 = Product::factory()->create([
|
|
|
|
|
'name' => 'Room 102',
|
|
|
|
|
'type' => ProductType::BOOKING,
|
|
|
|
|
'manage_stock' => true,
|
|
|
|
|
]);
|
|
|
|
|
$single2->increaseStock(1);
|
|
|
|
|
|
|
|
|
|
$single3 = Product::factory()->create([
|
|
|
|
|
'name' => 'Room 103',
|
|
|
|
|
'type' => ProductType::BOOKING,
|
|
|
|
|
'manage_stock' => true,
|
|
|
|
|
]);
|
|
|
|
|
$single3->increaseStock(1);
|
|
|
|
|
|
|
|
|
|
// Attach singles to pool
|
|
|
|
|
foreach ([$single1, $single2, $single3] as $single) {
|
|
|
|
|
$pool->productRelations()->attach($single->id, [
|
|
|
|
|
'type' => \Blax\Shop\Enums\ProductRelationType::SINGLE->value,
|
|
|
|
|
]);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Pool should aggregate availability from all singles: 1 + 1 + 1 = 3
|
|
|
|
|
$this->assertEquals(3, $pool->has_more);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[Test]
|
|
|
|
|
public function it_returns_aggregated_availability_for_pool_with_claims()
|
|
|
|
|
{
|
|
|
|
|
// Create pool product
|
|
|
|
|
$pool = Product::factory()->create([
|
|
|
|
|
'name' => 'Hotel Rooms',
|
|
|
|
|
'type' => ProductType::POOL,
|
|
|
|
|
'manage_stock' => false,
|
|
|
|
|
]);
|
|
|
|
|
|
|
|
|
|
// Create 3 single items with stock
|
|
|
|
|
$singles = [];
|
|
|
|
|
for ($i = 1; $i <= 3; $i++) {
|
|
|
|
|
$single = Product::factory()->create([
|
|
|
|
|
'name' => "Room 10{$i}",
|
|
|
|
|
'type' => ProductType::BOOKING,
|
|
|
|
|
'manage_stock' => true,
|
|
|
|
|
]);
|
|
|
|
|
$single->increaseStock(1);
|
|
|
|
|
$singles[] = $single;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
foreach ($singles as $single) {
|
|
|
|
|
$pool->productRelations()->attach($single->id, [
|
|
|
|
|
'type' => \Blax\Shop\Enums\ProductRelationType::SINGLE->value,
|
|
|
|
|
]);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Claim single1 from now until next week (active claim)
|
|
|
|
|
$singles[0]->claimStock(
|
|
|
|
|
quantity: 1,
|
|
|
|
|
from: now(),
|
|
|
|
|
until: now()->addDays(7)
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
// Pool should show 2 available (singles 2 and 3)
|
|
|
|
|
$this->assertEquals(2, $pool->has_more);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[Test]
|
|
|
|
|
public function it_returns_aggregated_availability_for_pool_with_future_claims()
|
|
|
|
|
{
|
|
|
|
|
// Create pool product
|
|
|
|
|
$pool = Product::factory()->create([
|
|
|
|
|
'name' => 'Rental Cars',
|
|
|
|
|
'type' => ProductType::POOL,
|
|
|
|
|
'manage_stock' => false,
|
|
|
|
|
]);
|
|
|
|
|
|
|
|
|
|
// Create 2 single items with stock
|
|
|
|
|
$single1 = Product::factory()->create([
|
|
|
|
|
'name' => 'Car 1',
|
|
|
|
|
'type' => ProductType::BOOKING,
|
|
|
|
|
'manage_stock' => true,
|
|
|
|
|
]);
|
|
|
|
|
$single1->increaseStock(1);
|
|
|
|
|
|
|
|
|
|
$single2 = Product::factory()->create([
|
|
|
|
|
'name' => 'Car 2',
|
|
|
|
|
'type' => ProductType::BOOKING,
|
|
|
|
|
'manage_stock' => true,
|
|
|
|
|
]);
|
|
|
|
|
$single2->increaseStock(1);
|
|
|
|
|
|
|
|
|
|
foreach ([$single1, $single2] as $single) {
|
|
|
|
|
$pool->productRelations()->attach($single->id, [
|
|
|
|
|
'type' => \Blax\Shop\Enums\ProductRelationType::SINGLE->value,
|
|
|
|
|
]);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Claim single1 for a FUTURE period (not yet active)
|
|
|
|
|
$single1->claimStock(
|
|
|
|
|
quantity: 1,
|
|
|
|
|
from: now()->addDays(5),
|
|
|
|
|
until: now()->addDays(10)
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
// Pool should show 2 available (both cars available NOW, claim starts in future)
|
|
|
|
|
$this->assertEquals(2, $pool->has_more);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[Test]
|
|
|
|
|
public function it_returns_php_int_max_for_pool_with_unmanaged_singles()
|
|
|
|
|
{
|
|
|
|
|
// Create pool product
|
|
|
|
|
$pool = Product::factory()->create([
|
|
|
|
|
'name' => 'Digital Products Pool',
|
|
|
|
|
'type' => ProductType::POOL,
|
|
|
|
|
'manage_stock' => false,
|
|
|
|
|
]);
|
|
|
|
|
|
|
|
|
|
// Create single items WITHOUT stock management (unlimited)
|
|
|
|
|
$single1 = Product::factory()->create([
|
|
|
|
|
'name' => 'Digital Item 1',
|
|
|
|
|
'type' => ProductType::SIMPLE,
|
|
|
|
|
'manage_stock' => false,
|
|
|
|
|
]);
|
|
|
|
|
|
|
|
|
|
$single2 = Product::factory()->create([
|
|
|
|
|
'name' => 'Digital Item 2',
|
|
|
|
|
'type' => ProductType::SIMPLE,
|
|
|
|
|
'manage_stock' => false,
|
|
|
|
|
]);
|
|
|
|
|
|
|
|
|
|
foreach ([$single1, $single2] as $single) {
|
|
|
|
|
$pool->productRelations()->attach($single->id, [
|
|
|
|
|
'type' => \Blax\Shop\Enums\ProductRelationType::SINGLE->value,
|
|
|
|
|
]);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Pool with all unlimited singles should return a very large number
|
|
|
|
|
// (sum of PHP_INT_MAX values, which indicates unlimited availability)
|
|
|
|
|
$this->assertGreaterThanOrEqual(PHP_INT_MAX, $pool->has_more);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[Test]
|
|
|
|
|
public function it_returns_zero_for_empty_pool()
|
|
|
|
|
{
|
|
|
|
|
$pool = Product::factory()->create([
|
|
|
|
|
'name' => 'Empty Pool',
|
|
|
|
|
'type' => ProductType::POOL,
|
|
|
|
|
'manage_stock' => false,
|
|
|
|
|
]);
|
|
|
|
|
|
|
|
|
|
$this->assertEquals(0, $pool->has_more);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[Test]
|
|
|
|
|
public function it_returns_zero_when_all_stock_is_claimed()
|
|
|
|
|
{
|
|
|
|
|
$product = Product::factory()->withStocks(10)->create();
|
|
|
|
|
|
|
|
|
|
// Claim all 10 units
|
|
|
|
|
$product->claimStock(
|
|
|
|
|
quantity: 10,
|
|
|
|
|
from: now(),
|
|
|
|
|
until: now()->addDays(5)
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
$this->assertEquals(0, $product->has_more);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[Test]
|
|
|
|
|
public function it_correctly_handles_mixed_managed_and_unmanaged_pool_singles()
|
|
|
|
|
{
|
|
|
|
|
$pool = Product::factory()->create([
|
|
|
|
|
'name' => 'Mixed Pool',
|
|
|
|
|
'type' => ProductType::POOL,
|
|
|
|
|
'manage_stock' => false,
|
|
|
|
|
]);
|
|
|
|
|
|
|
|
|
|
// Single 1: managed stock
|
|
|
|
|
$single1 = Product::factory()->create([
|
|
|
|
|
'name' => 'Limited Item',
|
|
|
|
|
'type' => ProductType::SIMPLE,
|
|
|
|
|
'manage_stock' => true,
|
|
|
|
|
]);
|
|
|
|
|
$single1->increaseStock(5);
|
|
|
|
|
|
|
|
|
|
// Single 2: unmanaged stock (unlimited)
|
|
|
|
|
$single2 = Product::factory()->create([
|
|
|
|
|
'name' => 'Unlimited Item',
|
|
|
|
|
'type' => ProductType::SIMPLE,
|
|
|
|
|
'manage_stock' => false,
|
|
|
|
|
]);
|
|
|
|
|
|
|
|
|
|
foreach ([$single1, $single2] as $single) {
|
|
|
|
|
$pool->productRelations()->attach($single->id, [
|
|
|
|
|
'type' => \Blax\Shop\Enums\ProductRelationType::SINGLE->value,
|
|
|
|
|
]);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Pool should sum: 5 (limited) + PHP_INT_MAX (unlimited)
|
|
|
|
|
// Result will be very large, indicating effectively unlimited availability
|
|
|
|
|
$this->assertGreaterThanOrEqual(PHP_INT_MAX, $pool->has_more);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[Test]
|
|
|
|
|
public function it_returns_correct_stock_after_multiple_increases_and_decreases()
|
|
|
|
|
{
|
|
|
|
|
$product = Product::factory()->create([
|
|
|
|
|
'manage_stock' => true,
|
|
|
|
|
]);
|
|
|
|
|
|
|
|
|
|
$product->increaseStock(100);
|
|
|
|
|
$product->decreaseStock(20);
|
|
|
|
|
$product->increaseStock(50);
|
|
|
|
|
$product->decreaseStock(30);
|
|
|
|
|
|
|
|
|
|
// 100 - 20 + 50 - 30 = 100
|
|
|
|
|
$this->assertEquals(100, $product->has_more);
|
|
|
|
|
}
|
2025-12-28 09:48:22 +00:00
|
|
|
|
|
|
|
|
#[Test]
|
|
|
|
|
public function it_subtracts_cart_items_from_available_stock()
|
|
|
|
|
{
|
|
|
|
|
[$user, $cart] = $this->createUserWithCart();
|
|
|
|
|
|
|
|
|
|
$product = Product::factory()->withStocks(10)->withPrices(1, 1000)->create();
|
|
|
|
|
|
|
|
|
|
// Add 3 to cart
|
|
|
|
|
$cart->addToCart($product, 3);
|
|
|
|
|
|
|
|
|
|
// Use getHasMore with explicit cart - should show 7 remaining
|
|
|
|
|
$this->assertEquals(7, $product->getHasMore($cart));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[Test]
|
|
|
|
|
public function it_subtracts_cart_items_from_pool_availability()
|
|
|
|
|
{
|
|
|
|
|
[$user, $cart] = $this->createUserWithCart();
|
|
|
|
|
|
|
|
|
|
// Create pool product
|
|
|
|
|
$pool = Product::factory()->create([
|
|
|
|
|
'name' => 'Hotel Rooms',
|
|
|
|
|
'type' => ProductType::POOL,
|
|
|
|
|
'manage_stock' => false,
|
|
|
|
|
]);
|
|
|
|
|
|
|
|
|
|
// Create a price for the pool
|
|
|
|
|
$pool->prices()->create([
|
|
|
|
|
'unit_amount' => 10000,
|
|
|
|
|
'currency' => 'usd',
|
|
|
|
|
'is_default' => true,
|
|
|
|
|
]);
|
|
|
|
|
|
|
|
|
|
// Create 3 single items with stock
|
|
|
|
|
$singles = [];
|
|
|
|
|
for ($i = 1; $i <= 3; $i++) {
|
|
|
|
|
$single = Product::factory()->create([
|
|
|
|
|
'name' => "Room 10{$i}",
|
|
|
|
|
'type' => ProductType::BOOKING,
|
|
|
|
|
'manage_stock' => true,
|
|
|
|
|
]);
|
|
|
|
|
$single->increaseStock(1);
|
|
|
|
|
|
|
|
|
|
$single->prices()->create([
|
|
|
|
|
'unit_amount' => 10000,
|
|
|
|
|
'currency' => 'usd',
|
|
|
|
|
'is_default' => true,
|
|
|
|
|
]);
|
|
|
|
|
|
|
|
|
|
$singles[] = $single;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
foreach ($singles as $single) {
|
|
|
|
|
$pool->productRelations()->attach($single->id, [
|
|
|
|
|
'type' => \Blax\Shop\Enums\ProductRelationType::SINGLE->value,
|
|
|
|
|
]);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Pool should have 3 available initially
|
|
|
|
|
$this->assertEquals(3, $pool->getHasMore($cart));
|
|
|
|
|
|
|
|
|
|
// Add 2 rooms to cart
|
|
|
|
|
$cart->addToCart($pool, 1, [], now()->addDays(5), now()->addDays(10));
|
|
|
|
|
$cart->addToCart($pool, 1, [], now()->addDays(5), now()->addDays(10));
|
|
|
|
|
|
|
|
|
|
// Now pool should show 1 remaining
|
|
|
|
|
$this->assertEquals(1, $pool->getHasMore($cart));
|
|
|
|
|
|
|
|
|
|
// Add the last room
|
|
|
|
|
$cart->addToCart($pool, 1, [], now()->addDays(5), now()->addDays(10));
|
|
|
|
|
|
|
|
|
|
// Now pool should show 0 remaining
|
|
|
|
|
$this->assertEquals(0, $pool->getHasMore($cart));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[Test]
|
|
|
|
|
public function it_considers_date_range_for_booking_products()
|
|
|
|
|
{
|
|
|
|
|
[$user, $cart] = $this->createUserWithCart();
|
|
|
|
|
|
|
|
|
|
$product = Product::factory()->create([
|
|
|
|
|
'type' => ProductType::BOOKING,
|
|
|
|
|
'manage_stock' => true,
|
|
|
|
|
]);
|
|
|
|
|
$product->increaseStock(10);
|
|
|
|
|
|
|
|
|
|
$product->prices()->create([
|
|
|
|
|
'unit_amount' => 5000,
|
|
|
|
|
'currency' => 'usd',
|
|
|
|
|
'is_default' => true,
|
|
|
|
|
]);
|
|
|
|
|
|
|
|
|
|
// Claim 5 units for days 5-10
|
|
|
|
|
$product->claimStock(
|
|
|
|
|
quantity: 5,
|
|
|
|
|
from: now()->startOfDay()->addDays(5),
|
|
|
|
|
until: now()->endOfDay()->addDays(10)
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
// Without date range: should show current available (10)
|
|
|
|
|
$this->assertEquals(10, $product->getHasMore($cart));
|
|
|
|
|
|
|
|
|
|
// With date range during claim: should show 5 available
|
|
|
|
|
$this->assertEquals(5, $product->getHasMore($cart, now()->addDays(6), now()->addDays(8)));
|
|
|
|
|
|
|
|
|
|
// With date range outside claim: should show 10 available
|
|
|
|
|
$this->assertEquals(10, $product->getHasMore($cart, now()->addDays(15), now()->addDays(20)));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[Test]
|
|
|
|
|
public function it_uses_cart_dates_when_from_until_not_provided()
|
|
|
|
|
{
|
|
|
|
|
[$user, $cart] = $this->createUserWithCart();
|
|
|
|
|
|
|
|
|
|
$product = Product::factory()->create([
|
|
|
|
|
'type' => ProductType::BOOKING,
|
|
|
|
|
'manage_stock' => true,
|
|
|
|
|
]);
|
|
|
|
|
$product->increaseStock(10);
|
|
|
|
|
|
|
|
|
|
$product->prices()->create([
|
|
|
|
|
'unit_amount' => 5000,
|
|
|
|
|
'currency' => 'usd',
|
|
|
|
|
'is_default' => true,
|
|
|
|
|
]);
|
|
|
|
|
|
|
|
|
|
// Claim 4 units for days 5-10
|
|
|
|
|
$product->claimStock(
|
|
|
|
|
quantity: 4,
|
|
|
|
|
from: now()->startOfDay()->addDays(5),
|
|
|
|
|
until: now()->endOfDay()->addDays(10)
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
// Set cart dates to be during the claim period
|
|
|
|
|
$cart->update([
|
|
|
|
|
'from' => now()->addDays(6),
|
|
|
|
|
'until' => now()->addDays(8),
|
|
|
|
|
]);
|
|
|
|
|
$cart->refresh();
|
|
|
|
|
|
|
|
|
|
// Should use cart's from/until to determine availability (6 available during claim)
|
|
|
|
|
$this->assertEquals(6, $product->getHasMore($cart));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[Test]
|
|
|
|
|
public function it_combines_cart_items_and_date_range_for_pool_products()
|
|
|
|
|
{
|
|
|
|
|
[$user, $cart] = $this->createUserWithCart();
|
|
|
|
|
|
|
|
|
|
// Create pool product
|
|
|
|
|
$pool = Product::factory()->create([
|
|
|
|
|
'name' => 'Rental Cars',
|
|
|
|
|
'type' => ProductType::POOL,
|
|
|
|
|
'manage_stock' => false,
|
|
|
|
|
]);
|
|
|
|
|
|
|
|
|
|
$pool->prices()->create([
|
|
|
|
|
'unit_amount' => 15000,
|
|
|
|
|
'currency' => 'usd',
|
|
|
|
|
'is_default' => true,
|
|
|
|
|
]);
|
|
|
|
|
|
|
|
|
|
// Create 5 single items with stock
|
|
|
|
|
$singles = [];
|
|
|
|
|
for ($i = 1; $i <= 5; $i++) {
|
|
|
|
|
$single = Product::factory()->create([
|
|
|
|
|
'name' => "Car {$i}",
|
|
|
|
|
'type' => ProductType::BOOKING,
|
|
|
|
|
'manage_stock' => true,
|
|
|
|
|
]);
|
|
|
|
|
$single->increaseStock(1);
|
|
|
|
|
|
|
|
|
|
$single->prices()->create([
|
|
|
|
|
'unit_amount' => 15000,
|
|
|
|
|
'currency' => 'usd',
|
|
|
|
|
'is_default' => true,
|
|
|
|
|
]);
|
|
|
|
|
|
|
|
|
|
$singles[] = $single;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
foreach ($singles as $single) {
|
|
|
|
|
$pool->productRelations()->attach($single->id, [
|
|
|
|
|
'type' => \Blax\Shop\Enums\ProductRelationType::SINGLE->value,
|
|
|
|
|
]);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Claim 2 cars for days 5-10
|
|
|
|
|
$singles[0]->claimStock(
|
|
|
|
|
quantity: 1,
|
|
|
|
|
from: now()->startOfDay()->addDays(5),
|
|
|
|
|
until: now()->endOfDay()->addDays(10)
|
|
|
|
|
);
|
|
|
|
|
$singles[1]->claimStock(
|
|
|
|
|
quantity: 1,
|
|
|
|
|
from: now()->startOfDay()->addDays(5),
|
|
|
|
|
until: now()->endOfDay()->addDays(10)
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
// Set cart dates during claim period
|
|
|
|
|
$cart->update([
|
|
|
|
|
'from' => now()->addDays(6),
|
|
|
|
|
'until' => now()->addDays(8),
|
|
|
|
|
]);
|
|
|
|
|
$cart->refresh();
|
|
|
|
|
|
|
|
|
|
// During claim: 3 cars available (5 - 2 claimed)
|
|
|
|
|
$this->assertEquals(3, $pool->getHasMore($cart));
|
|
|
|
|
|
|
|
|
|
// Add 2 cars to cart
|
|
|
|
|
$cart->addToCart($pool, 1, [], now()->addDays(6), now()->addDays(8));
|
|
|
|
|
$cart->addToCart($pool, 1, [], now()->addDays(6), now()->addDays(8));
|
|
|
|
|
|
|
|
|
|
// Now should show 1 remaining (3 - 2 in cart)
|
|
|
|
|
$this->assertEquals(1, $pool->getHasMore($cart));
|
|
|
|
|
}
|
2025-12-28 09:29:23 +00:00
|
|
|
}
|