BFRI cart
This commit is contained in:
parent
6beecf597c
commit
7cd11728b1
|
|
@ -957,47 +957,46 @@ class Cart extends Model
|
|||
throw new InvalidDateRangeException("The 'from' date must be before the 'until' date. Got from: {$from->format('Y-m-d H:i:s')}, until: {$until->format('Y-m-d H:i:s')}");
|
||||
}
|
||||
|
||||
// Check booking product availability if dates are provided
|
||||
// For booking products (non-pool), validate against total stock capacity
|
||||
// Date-based validation will happen at checkout
|
||||
if (
|
||||
$is_booking
|
||||
&& !$is_pool
|
||||
&& !$cartable->isAvailableForBooking($from, $until, $quantity)
|
||||
&& $cartable->manage_stock
|
||||
) {
|
||||
throw new NotEnoughStockException(
|
||||
"Product '{$cartable->name}' is not available for the requested period ({$from->format('Y-m-d')} to {$until->format('Y-m-d')})."
|
||||
);
|
||||
}
|
||||
|
||||
// Check pool product availability if dates are provided
|
||||
if ($is_pool) {
|
||||
$maxQuantity = $cartable->getPoolMaxQuantity($from, $until);
|
||||
|
||||
// Subtract items already in cart for the same period
|
||||
// Only count items that are actually valid (have a price allocated)
|
||||
$totalStock = $cartable->getAvailableStock();
|
||||
$itemsInCart = $this->items()
|
||||
->where('purchasable_id', $cartable->getKey())
|
||||
->where('purchasable_type', get_class($cartable))
|
||||
->get()
|
||||
->filter(function ($item) use ($from, $until) {
|
||||
// Don't count items marked as unavailable (null price)
|
||||
if ($item->price === null) {
|
||||
return false;
|
||||
}
|
||||
// Only count items with overlapping dates
|
||||
if (!$item->from || !$item->until) {
|
||||
return false;
|
||||
}
|
||||
// Check for overlap
|
||||
return !($item->until < $from || $item->from > $until);
|
||||
})
|
||||
->sum('quantity');
|
||||
|
||||
$availableForThisRequest = $maxQuantity === PHP_INT_MAX ? PHP_INT_MAX : max(0, $maxQuantity - $itemsInCart);
|
||||
$availableForThisRequest = max(0, $totalStock - $itemsInCart);
|
||||
|
||||
// Only validate if pool has limited availability AND quantity exceeds it
|
||||
if ($quantity > $availableForThisRequest) {
|
||||
throw new NotEnoughStockException(
|
||||
"Product '{$cartable->name}' has only {$availableForThisRequest} items available. Requested: {$quantity}"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Check pool product availability against total capacity (NOT date-restricted)
|
||||
// Date-based validation will happen at checkout, allowing users to add items
|
||||
// and then adjust dates to find available periods
|
||||
if ($is_pool) {
|
||||
$totalCapacity = $cartable->getPoolTotalCapacity(); // Total capacity ignoring claims
|
||||
|
||||
// Subtract items already in cart for this pool
|
||||
$itemsInCart = $this->items()
|
||||
->where('purchasable_id', $cartable->getKey())
|
||||
->where('purchasable_type', get_class($cartable))
|
||||
->sum('quantity');
|
||||
|
||||
$availableForThisRequest = $totalCapacity === PHP_INT_MAX ? PHP_INT_MAX : max(0, $totalCapacity - $itemsInCart);
|
||||
|
||||
// Only prevent adding if it exceeds total pool capacity
|
||||
if ($availableForThisRequest !== PHP_INT_MAX && $quantity > $availableForThisRequest) {
|
||||
throw new NotEnoughStockException(
|
||||
"Pool product '{$cartable->name}' has only {$availableForThisRequest} items available for the requested period ({$from->format('Y-m-d')} to {$until->format('Y-m-d')}). Requested: {$quantity}"
|
||||
"Pool product '{$cartable->name}' has only {$availableForThisRequest} items available. Requested: {$quantity}"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -167,8 +167,8 @@ trait HasStocks
|
|||
*
|
||||
* @param StockType $type The type of adjustment (INCREASE/RETURN add stock, DECREASE/CLAIMED remove stock)
|
||||
* @param int $quantity Amount to adjust (always positive, type determines direction)
|
||||
* @param \DateTimeInterface|null $until Optional expiration date (when stock expires or claim ends)
|
||||
* @param \DateTimeInterface|null $from Optional start date (used for CLAIMED type, defaults to now())
|
||||
* @param DateTimeInterface|null $until Optional expiration date (when stock expires or claim ends)
|
||||
* @param DateTimeInterface|null $from Optional start date (used for CLAIMED type, defaults to now())
|
||||
* @param StockStatus|null $status Optional status (defaults to COMPLETED, or PENDING for CLAIMED type)
|
||||
* @param string|null $note Optional note for documentation purposes
|
||||
* @param Model|null $referencable Optional polymorphic reference to related model
|
||||
|
|
@ -244,8 +244,8 @@ trait HasStocks
|
|||
*
|
||||
* @param int $quantity Amount to claim
|
||||
* @param mixed $reference Optional reference model (Order, Booking, Cart, etc.)
|
||||
* @param \DateTimeInterface|null $from When claim starts (null = immediately)
|
||||
* @param \DateTimeInterface|null $until When claim expires (null = permanent)
|
||||
* @param DateTimeInterface|null $from When claim starts (null = immediately)
|
||||
* @param DateTimeInterface|null $until When claim expires (null = permanent)
|
||||
* @param string|null $note Optional note about the claim
|
||||
* @return \Blax\Shop\Models\ProductStock|null The claim entry, or null if insufficient stock
|
||||
*/
|
||||
|
|
@ -366,7 +366,7 @@ trait HasStocks
|
|||
/**
|
||||
* Get future claimed stock starting from a specific date or all where claimed_at is future
|
||||
*
|
||||
* @param \DateTimeInterface|null $from Optional start date to filter claims
|
||||
* @param DateTimeInterface|null $from Optional start date to filter claims
|
||||
* @return int Total future claimed quantity (always positive)
|
||||
*/
|
||||
public function getFutureClaimedStock(?DateTimeInterface $from = null): int
|
||||
|
|
@ -500,7 +500,7 @@ trait HasStocks
|
|||
* - Available on day 12: 70 (only claim 2 active)
|
||||
* - Available on day 20: 100 (no claims active)
|
||||
*
|
||||
* @param \DateTimeInterface $date The date to check availability for
|
||||
* @param DateTimeInterface $date The date to check availability for
|
||||
* @return int Available stock on that date (PHP_INT_MAX if stock management disabled)
|
||||
*/
|
||||
public function availableOnDate(DateTimeInterface $date): int
|
||||
|
|
@ -519,8 +519,8 @@ trait HasStocks
|
|||
* - 'min_available' => Shows the lowest available stock in the date range
|
||||
* - 'dates' => An array of dates with their respective available stock
|
||||
*
|
||||
* @param \DateTimeInterface $from Start date of the range (optional, defaults to today)
|
||||
* @param \DateTimeInterface $until End date of the range (optional, defaults to 30 days)
|
||||
* @param DateTimeInterface $from Start date of the range (optional, defaults to today)
|
||||
* @param DateTimeInterface $until End date of the range (optional, defaults to 30 days)
|
||||
* @return array Associative array with 'max_available', 'min_available', and 'dates'
|
||||
*/
|
||||
public function calendarAvailability(
|
||||
|
|
@ -696,8 +696,8 @@ trait HasStocks
|
|||
/**
|
||||
* Get calendar availability for pool products by aggregating all single items
|
||||
*
|
||||
* @param \DateTimeInterface|null $from
|
||||
* @param \DateTimeInterface|null $until
|
||||
* @param DateTimeInterface|null $from
|
||||
* @param DateTimeInterface|null $until
|
||||
* @return array
|
||||
*/
|
||||
protected function getPoolCalendarAvailability(
|
||||
|
|
@ -788,7 +788,7 @@ trait HasStocks
|
|||
/**
|
||||
* Get day availability for pool products by aggregating all single items
|
||||
*
|
||||
* @param \DateTimeInterface|null $date
|
||||
* @param DateTimeInterface|null $date
|
||||
* @return array
|
||||
*/
|
||||
protected function getPoolDayAvailability(?DateTimeInterface $date = null): array
|
||||
|
|
@ -851,23 +851,19 @@ trait HasStocks
|
|||
}
|
||||
|
||||
/**
|
||||
* Get remaining available stock, accounting for cart items and date range
|
||||
* Get remaining available stock that can be added to cart
|
||||
*
|
||||
* This method calculates how many more units can be added to a cart:
|
||||
* - For pool products: aggregates availability from all single items minus cart items
|
||||
* - For booking products: considers the date range for availability
|
||||
* - Subtracts items already in the provided cart
|
||||
* - For pool products: total capacity minus cart items (NOT date-restricted)
|
||||
* - For booking products: total stock minus cart items (NOT date-restricted)
|
||||
* - The idea is that users can add items freely and adjust dates later
|
||||
* - Date-based validation happens at checkout, not when adding to cart
|
||||
*
|
||||
* @param \Blax\Shop\Models\Cart|null $cart Optional cart to subtract items from
|
||||
* @param \DateTimeInterface|null $from Optional start date for booking availability
|
||||
* @param \DateTimeInterface|null $until Optional end date for booking availability
|
||||
* @return int Available quantity (PHP_INT_MAX if unlimited)
|
||||
*/
|
||||
public function getHasMore(
|
||||
$cart = null,
|
||||
?\DateTimeInterface $from = null,
|
||||
?\DateTimeInterface $until = null
|
||||
): int {
|
||||
public function getHasMore($cart = null): int
|
||||
{
|
||||
// Try to get current cart from facade if not provided
|
||||
if ($cart === null) {
|
||||
try {
|
||||
|
|
@ -878,24 +874,17 @@ trait HasStocks
|
|||
}
|
||||
}
|
||||
|
||||
// Get from/until from cart if not provided
|
||||
if ($cart && $from === null && $until === null) {
|
||||
$from = $cart->from;
|
||||
$until = $cart->until;
|
||||
}
|
||||
|
||||
if (method_exists($this, 'isPool') && $this->isPool()) {
|
||||
return $this->getPoolHasMore($cart, $from, $until);
|
||||
return $this->getPoolHasMore($cart);
|
||||
}
|
||||
|
||||
if ($this->manage_stock === false) {
|
||||
return PHP_INT_MAX;
|
||||
}
|
||||
|
||||
// Get base available stock (considering date range for bookings)
|
||||
$baseAvailable = ($from && $until && method_exists($this, 'isBooking') && $this->isBooking())
|
||||
? $this->getMinAvailableInRange($from, $until)
|
||||
: $this->getAvailableStock();
|
||||
// Get total stock capacity (not date-restricted)
|
||||
// This allows users to add items and adjust dates later
|
||||
$baseAvailable = $this->getAvailableStock();
|
||||
|
||||
// Subtract items already in cart for this product
|
||||
if ($cart) {
|
||||
|
|
@ -911,36 +900,36 @@ trait HasStocks
|
|||
}
|
||||
|
||||
/**
|
||||
* Get remaining availability for pool products, accounting for cart and dates
|
||||
* Get remaining availability for pool products
|
||||
*
|
||||
* Returns total pool capacity minus items already in cart.
|
||||
* Does NOT consider date-based availability - that's validated at checkout.
|
||||
*
|
||||
* @param \Blax\Shop\Models\Cart|null $cart
|
||||
* @param \DateTimeInterface|null $from
|
||||
* @param \DateTimeInterface|null $until
|
||||
* @return int
|
||||
*/
|
||||
protected function getPoolHasMore(
|
||||
$cart = null,
|
||||
?\DateTimeInterface $from = null,
|
||||
?\DateTimeInterface $until = null
|
||||
): int {
|
||||
if (!$this->relationLoaded('singleProducts')) {
|
||||
$this->load('singleProducts');
|
||||
protected function getPoolHasMore($cart = null): int
|
||||
{
|
||||
// Get total pool capacity (NOT date-restricted)
|
||||
if (method_exists($this, 'getPoolTotalCapacity')) {
|
||||
$totalCapacity = $this->getPoolTotalCapacity();
|
||||
} else {
|
||||
// Fallback if method doesn't exist
|
||||
if (!$this->relationLoaded('singleProducts')) {
|
||||
$this->load('singleProducts');
|
||||
}
|
||||
|
||||
$totalCapacity = 0;
|
||||
foreach ($this->singleProducts as $single) {
|
||||
if (!$single->manage_stock) {
|
||||
return PHP_INT_MAX;
|
||||
}
|
||||
$totalCapacity += $single->getAvailableStock();
|
||||
}
|
||||
}
|
||||
|
||||
$totalAvailable = 0;
|
||||
|
||||
foreach ($this->singleProducts as $single) {
|
||||
$singleAvailable = $single->getHasMore(null, $from, $until);
|
||||
|
||||
if ($singleAvailable === PHP_INT_MAX) {
|
||||
return PHP_INT_MAX;
|
||||
}
|
||||
|
||||
$totalAvailable += $singleAvailable;
|
||||
|
||||
if ($totalAvailable >= PHP_INT_MAX || $totalAvailable < 0) {
|
||||
return PHP_INT_MAX;
|
||||
}
|
||||
if ($totalCapacity === PHP_INT_MAX) {
|
||||
return PHP_INT_MAX;
|
||||
}
|
||||
|
||||
// Subtract pool items already in cart
|
||||
|
|
@ -950,20 +939,64 @@ trait HasStocks
|
|||
->where('purchasable_type', get_class($this))
|
||||
->sum('quantity');
|
||||
|
||||
$totalAvailable = max(0, $totalAvailable - $inCart);
|
||||
$totalCapacity = max(0, $totalCapacity - $inCart);
|
||||
}
|
||||
|
||||
return $totalAvailable;
|
||||
return $totalCapacity;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get available stock for a specific date range
|
||||
*
|
||||
* Use this method when you need to check date-based availability
|
||||
* (e.g., for showing a calendar, or at checkout validation)
|
||||
*
|
||||
* @param DateTimeInterface $from
|
||||
* @param DateTimeInterface $until
|
||||
* @param \Blax\Shop\Models\Cart|null $cart Optional cart to subtract items from
|
||||
* @return int
|
||||
*/
|
||||
public function getAvailableForDateRange(
|
||||
DateTimeInterface $from,
|
||||
DateTimeInterface $until,
|
||||
$cart = null
|
||||
): int {
|
||||
if ($this->manage_stock === false) {
|
||||
return PHP_INT_MAX;
|
||||
}
|
||||
|
||||
if (method_exists($this, 'isPool') && $this->isPool()) {
|
||||
// For pools, get min availability across all singles for the date range
|
||||
if (method_exists($this, 'getPoolMaxQuantity')) {
|
||||
$available = $this->getPoolMaxQuantity($from, $until);
|
||||
} else {
|
||||
$available = $this->getMinAvailableInRange($from, $until);
|
||||
}
|
||||
} else {
|
||||
$available = $this->getMinAvailableInRange($from, $until);
|
||||
}
|
||||
|
||||
// Subtract items already in cart for this product
|
||||
if ($cart) {
|
||||
$inCart = $cart->items()
|
||||
->where('purchasable_id', $this->getKey())
|
||||
->where('purchasable_type', get_class($this))
|
||||
->sum('quantity');
|
||||
|
||||
$available = max(0, $available - $inCart);
|
||||
}
|
||||
|
||||
return $available;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get minimum available stock across a date range
|
||||
*
|
||||
* @param \DateTimeInterface $from
|
||||
* @param \DateTimeInterface $until
|
||||
* @param DateTimeInterface $from
|
||||
* @param DateTimeInterface $until
|
||||
* @return int
|
||||
*/
|
||||
protected function getMinAvailableInRange(\DateTimeInterface $from, \DateTimeInterface $until): int
|
||||
protected function getMinAvailableInRange(DateTimeInterface $from, DateTimeInterface $until): int
|
||||
{
|
||||
$availability = $this->calendarAvailability($from, $until);
|
||||
|
||||
|
|
@ -982,10 +1015,10 @@ trait HasStocks
|
|||
/**
|
||||
* Attribute accessor for has_more
|
||||
*
|
||||
* Returns available stock accounting for:
|
||||
* - Current cart (from Cart facade)
|
||||
* - Cart's from/until dates for bookings
|
||||
* - Pool product aggregation
|
||||
* Returns available stock that can still be added to cart:
|
||||
* - Total capacity minus items already in cart
|
||||
* - Does NOT consider date-based restrictions
|
||||
* - Date validation happens at checkout
|
||||
*
|
||||
* @return int Available quantity (PHP_INT_MAX if unlimited)
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -530,7 +530,7 @@ class CartAddToCartPoolPricingTest extends TestCase
|
|||
}
|
||||
|
||||
#[Test]
|
||||
public function it_throws_exception_when_pool_not_available_for_booking_period()
|
||||
public function it_allows_adding_pool_to_cart_when_claimed_but_validates_at_checkout()
|
||||
{
|
||||
ProductPrice::factory()->create([
|
||||
'purchasable_id' => $this->poolProduct->id,
|
||||
|
|
@ -547,14 +547,15 @@ class CartAddToCartPoolPricingTest extends TestCase
|
|||
$this->singleItem1->claimStock(1, null, $from, $until);
|
||||
$this->singleItem2->claimStock(1, null, $from, $until);
|
||||
|
||||
// Try to add pool for same period
|
||||
$this->expectException(\Blax\Shop\Exceptions\NotEnoughStockException::class);
|
||||
$this->expectExceptionMessage('has only 0 items available');
|
||||
// Adding to cart should succeed (lenient - uses total capacity)
|
||||
$this->cart->addToCart($this->poolProduct, 1, [], $from, $until);
|
||||
|
||||
// But checkout validation should fail
|
||||
$this->assertFalse($this->cart->validateForCheckout(false));
|
||||
}
|
||||
|
||||
#[Test]
|
||||
public function it_throws_exception_when_booking_product_not_available_for_period()
|
||||
public function it_allows_adding_booking_to_cart_when_claimed_but_validates_at_checkout()
|
||||
{
|
||||
$bookingProduct = Product::factory()->create([
|
||||
'name' => 'Meeting Room',
|
||||
|
|
@ -577,10 +578,11 @@ class CartAddToCartPoolPricingTest extends TestCase
|
|||
// Claim the booking product for the period
|
||||
$bookingProduct->claimStock(1, null, $from, $until);
|
||||
|
||||
// Try to add for overlapping period
|
||||
$this->expectException(\Blax\Shop\Exceptions\NotEnoughStockException::class);
|
||||
$this->expectExceptionMessage('not available for the requested period');
|
||||
// Adding to cart should succeed (lenient - uses total capacity)
|
||||
$this->cart->addToCart($bookingProduct, 1, [], $from, $until);
|
||||
|
||||
// But checkout validation should fail
|
||||
$this->assertFalse($this->cart->validateForCheckout(false));
|
||||
}
|
||||
|
||||
#[Test]
|
||||
|
|
|
|||
|
|
@ -117,15 +117,15 @@ class CartServiceBookingTest extends TestCase
|
|||
// Book all stock first
|
||||
$this->bookingProduct->claimStock(10, null, $from, $until);
|
||||
|
||||
$this->expectException(NotEnoughStockException::class);
|
||||
// Adding to cart should now succeed (lenient - uses total capacity)
|
||||
// Date-based validation happens at validateBookings/checkout
|
||||
$cart->addToCart($this->bookingProduct, 5, [], $from, $until);
|
||||
|
||||
$errors = Cart::validateBookings();
|
||||
|
||||
// validateBookings should detect the stock conflict
|
||||
$this->assertNotEmpty($errors);
|
||||
$this->assertStringContainsString('not available for the selected period', $errors[0]);
|
||||
|
||||
$this->assertEquals(0, $cart->getTotal());
|
||||
}
|
||||
|
||||
#[Test]
|
||||
|
|
|
|||
|
|
@ -239,9 +239,12 @@ class CheckoutStockValidationTest extends TestCase
|
|||
$from2 = Carbon::tomorrow()->addDay()->startOfDay();
|
||||
$until2 = Carbon::tomorrow()->addDays(2)->startOfDay();
|
||||
|
||||
// This should fail because dates overlap and all stock is claimed
|
||||
$this->expectException(NotEnoughStockException::class);
|
||||
// Adding to cart should succeed (lenient - uses total capacity)
|
||||
// Date-based validation happens at checkout
|
||||
$cart2->addToCart($this->pool, 1, [], $from2, $until2);
|
||||
|
||||
// But checkout validation should fail because dates overlap and all stock is claimed
|
||||
$this->assertFalse($cart2->validateForCheckout(false));
|
||||
}
|
||||
|
||||
#[Test]
|
||||
|
|
|
|||
|
|
@ -137,7 +137,7 @@ class GetHasMoreAttributeTest extends TestCase
|
|||
}
|
||||
|
||||
#[Test]
|
||||
public function it_returns_aggregated_availability_for_pool_with_claims()
|
||||
public function it_returns_total_capacity_for_pool_regardless_of_claims()
|
||||
{
|
||||
// Create pool product
|
||||
$pool = Product::factory()->create([
|
||||
|
|
@ -171,8 +171,10 @@ class GetHasMoreAttributeTest extends TestCase
|
|||
until: now()->addDays(7)
|
||||
);
|
||||
|
||||
// Pool should show 2 available (singles 2 and 3)
|
||||
$this->assertEquals(2, $pool->has_more);
|
||||
// Pool should show 3 available (TOTAL capacity, claims don't affect has_more)
|
||||
// This allows users to add items to cart and adjust dates later
|
||||
// Date-based validation happens at checkout
|
||||
$this->assertEquals(3, $pool->has_more);
|
||||
}
|
||||
|
||||
#[Test]
|
||||
|
|
@ -287,7 +289,7 @@ class GetHasMoreAttributeTest extends TestCase
|
|||
'manage_stock' => false,
|
||||
]);
|
||||
|
||||
// Single 1: managed stock
|
||||
// Single 1: managed stock (5 units)
|
||||
$single1 = Product::factory()->create([
|
||||
'name' => 'Limited Item',
|
||||
'type' => ProductType::SIMPLE,
|
||||
|
|
@ -295,7 +297,7 @@ class GetHasMoreAttributeTest extends TestCase
|
|||
]);
|
||||
$single1->increaseStock(5);
|
||||
|
||||
// Single 2: unmanaged stock (unlimited)
|
||||
// Single 2: unmanaged stock (unlimited - but only 1 item)
|
||||
$single2 = Product::factory()->create([
|
||||
'name' => 'Unlimited Item',
|
||||
'type' => ProductType::SIMPLE,
|
||||
|
|
@ -308,9 +310,12 @@ class GetHasMoreAttributeTest extends TestCase
|
|||
]);
|
||||
}
|
||||
|
||||
// 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);
|
||||
// Pool with mixed managed/unmanaged singles:
|
||||
// - Single1 has 5 stock (capacity = 5)
|
||||
// - Single2 is unmanaged (no stock entries, capacity contribution = 0)
|
||||
// Total pool capacity = 5
|
||||
// The unmanaged single doesn't add to pool capacity because it's just 1 item
|
||||
$this->assertEquals(5, $pool->has_more);
|
||||
}
|
||||
|
||||
#[Test]
|
||||
|
|
@ -405,7 +410,7 @@ class GetHasMoreAttributeTest extends TestCase
|
|||
}
|
||||
|
||||
#[Test]
|
||||
public function it_considers_date_range_for_booking_products()
|
||||
public function it_returns_total_stock_for_booking_products()
|
||||
{
|
||||
[$user, $cart] = $this->createUserWithCart();
|
||||
|
||||
|
|
@ -428,18 +433,17 @@ class GetHasMoreAttributeTest extends TestCase
|
|||
until: now()->endOfDay()->addDays(10)
|
||||
);
|
||||
|
||||
// Without date range: should show current available (10)
|
||||
// has_more should show total stock (NOT date-restricted)
|
||||
// This allows adding items to cart and adjusting dates later
|
||||
$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)));
|
||||
// Use getAvailableForDateRange for date-specific availability
|
||||
$this->assertEquals(5, $product->getAvailableForDateRange(now()->addDays(6), now()->addDays(8), $cart));
|
||||
$this->assertEquals(10, $product->getAvailableForDateRange(now()->addDays(15), now()->addDays(20), $cart));
|
||||
}
|
||||
|
||||
#[Test]
|
||||
public function it_uses_cart_dates_when_from_until_not_provided()
|
||||
public function it_returns_total_stock_regardless_of_cart_dates()
|
||||
{
|
||||
[$user, $cart] = $this->createUserWithCart();
|
||||
|
||||
|
|
@ -469,12 +473,13 @@ class GetHasMoreAttributeTest extends TestCase
|
|||
]);
|
||||
$cart->refresh();
|
||||
|
||||
// Should use cart's from/until to determine availability (6 available during claim)
|
||||
$this->assertEquals(6, $product->getHasMore($cart));
|
||||
// has_more should return total stock (NOT restricted by cart dates)
|
||||
// Date validation happens at checkout
|
||||
$this->assertEquals(10, $product->getHasMore($cart));
|
||||
}
|
||||
|
||||
#[Test]
|
||||
public function it_combines_cart_items_and_date_range_for_pool_products()
|
||||
public function it_returns_total_capacity_for_pool_regardless_of_cart_dates()
|
||||
{
|
||||
[$user, $cart] = $this->createUserWithCart();
|
||||
|
||||
|
|
@ -535,14 +540,15 @@ class GetHasMoreAttributeTest extends TestCase
|
|||
]);
|
||||
$cart->refresh();
|
||||
|
||||
// During claim: 3 cars available (5 - 2 claimed)
|
||||
$this->assertEquals(3, $pool->getHasMore($cart));
|
||||
// has_more should show TOTAL capacity (5), NOT date-restricted (3)
|
||||
// This allows adding items freely; date validation happens at checkout
|
||||
$this->assertEquals(5, $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));
|
||||
// Now should show 3 remaining (5 total - 2 in cart)
|
||||
$this->assertEquals(3, $pool->getHasMore($cart));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -759,11 +759,21 @@ class PoolProductionBugTest extends TestCase
|
|||
$this->assertEquals(4000 + (10001 * 2) + (10002 * 2), $cart->getTotal());
|
||||
|
||||
// Now try to add another item - this should fail because capacity is full (4 items, 4 capacity)
|
||||
$this->expectException(\Blax\Shop\Exceptions\NotEnoughStockException::class);
|
||||
$cart->addToCart(
|
||||
$pool,
|
||||
1
|
||||
);
|
||||
// This can throw either NotEnoughStockException or HasNoPriceException depending on
|
||||
// which validation runs first. HasNoPriceException is thrown when no single items
|
||||
// have available capacity to provide a price.
|
||||
$exceptionThrown = false;
|
||||
try {
|
||||
$cart->addToCart(
|
||||
$pool,
|
||||
1
|
||||
);
|
||||
} catch (\Blax\Shop\Exceptions\NotEnoughStockException $e) {
|
||||
$exceptionThrown = true;
|
||||
} catch (\Blax\Shop\Exceptions\HasNoPriceException $e) {
|
||||
$exceptionThrown = true;
|
||||
}
|
||||
$this->assertTrue($exceptionThrown, 'Expected either NotEnoughStockException or HasNoPriceException');
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
Loading…
Reference in New Issue