2025-11-21 10:49:41 +00:00
|
|
|
<?php
|
|
|
|
|
|
|
|
|
|
namespace Blax\Shop\Tests\Feature;
|
|
|
|
|
|
2025-11-25 11:33:42 +00:00
|
|
|
use Blax\Shop\Exceptions\NotEnoughStockException;
|
2025-11-21 10:49:41 +00:00
|
|
|
use Blax\Shop\Models\Product;
|
|
|
|
|
use Blax\Shop\Models\ProductStock;
|
|
|
|
|
use Blax\Shop\Tests\TestCase;
|
2025-11-25 11:33:42 +00:00
|
|
|
use Carbon\Carbon;
|
2025-11-21 10:49:41 +00:00
|
|
|
use Illuminate\Foundation\Testing\RefreshDatabase;
|
|
|
|
|
|
|
|
|
|
class StockManagementTest extends TestCase
|
|
|
|
|
{
|
|
|
|
|
use RefreshDatabase;
|
|
|
|
|
|
|
|
|
|
/** @test */
|
2025-12-04 10:06:09 +00:00
|
|
|
public function it_can_claim_stock_for_a_product()
|
2025-11-21 10:49:41 +00:00
|
|
|
{
|
2025-11-25 11:33:42 +00:00
|
|
|
$product = Product::factory()
|
|
|
|
|
->withStocks(100)
|
|
|
|
|
->create();
|
2025-11-21 10:49:41 +00:00
|
|
|
|
2025-12-04 10:06:09 +00:00
|
|
|
$claim = $product->claimStock(
|
2025-11-21 10:49:41 +00:00
|
|
|
quantity: 10,
|
|
|
|
|
until: now()->addHours(2)
|
|
|
|
|
);
|
|
|
|
|
|
2025-12-04 10:06:09 +00:00
|
|
|
$this->assertNotNull($claim);
|
|
|
|
|
$this->assertEquals(10, $claim->quantity);
|
2025-11-25 11:33:42 +00:00
|
|
|
$this->assertEquals(90, $product->getAvailableStock());
|
2025-11-21 10:49:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/** @test */
|
2025-12-04 10:06:09 +00:00
|
|
|
public function it_cannot_claim_more_stock_than_available()
|
2025-11-21 10:49:41 +00:00
|
|
|
{
|
2025-11-25 11:33:42 +00:00
|
|
|
$product = Product::factory()
|
|
|
|
|
->withStocks(5)
|
|
|
|
|
->create();
|
2025-11-21 10:49:41 +00:00
|
|
|
|
2025-12-04 10:06:09 +00:00
|
|
|
$claim = null;
|
2025-11-25 11:33:42 +00:00
|
|
|
|
2025-12-04 10:06:09 +00:00
|
|
|
$this->assertThrows(fn() => $claim = $product->claimStock(15), NotEnoughStockException::class);
|
2025-11-21 10:49:41 +00:00
|
|
|
|
2025-12-04 10:06:09 +00:00
|
|
|
$this->assertNull($claim);
|
2025-11-25 11:33:42 +00:00
|
|
|
$this->assertEquals(5, $product->getAvailableStock());
|
2025-11-21 10:49:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/** @test */
|
2025-12-04 10:06:09 +00:00
|
|
|
public function it_can_release_claimed_stock()
|
2025-11-21 10:49:41 +00:00
|
|
|
{
|
2025-11-25 11:33:42 +00:00
|
|
|
$product = Product::factory()
|
|
|
|
|
->withStocks(100)
|
|
|
|
|
->create();
|
2025-11-21 10:49:41 +00:00
|
|
|
|
2025-12-04 10:06:09 +00:00
|
|
|
$claim = $product->claimStock(
|
2025-11-21 10:49:41 +00:00
|
|
|
quantity: 10,
|
2025-11-25 11:33:42 +00:00
|
|
|
until: now()->addHours(2)
|
2025-11-21 10:49:41 +00:00
|
|
|
);
|
|
|
|
|
|
2025-11-25 11:33:42 +00:00
|
|
|
$this->assertEquals(90, $product->getAvailableStock());
|
2025-11-21 10:49:41 +00:00
|
|
|
|
2025-12-04 10:06:09 +00:00
|
|
|
$claim->release();
|
2025-11-21 10:49:41 +00:00
|
|
|
|
2025-11-25 11:33:42 +00:00
|
|
|
$this->assertEquals(100, $product->refresh()->getAvailableStock());
|
2025-12-04 10:06:09 +00:00
|
|
|
$this->assertNotNull($claim->fresh()->released_at);
|
2025-11-21 10:49:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/** @test */
|
|
|
|
|
public function it_can_check_if_stock_is_pending()
|
|
|
|
|
{
|
2025-11-25 11:33:42 +00:00
|
|
|
$product = Product::factory()->withStocks(10)->create();
|
2025-11-21 10:49:41 +00:00
|
|
|
|
2025-12-04 10:06:09 +00:00
|
|
|
$claim = $product->claimStock(5);
|
2025-11-21 10:49:41 +00:00
|
|
|
|
2025-12-04 10:06:09 +00:00
|
|
|
$pending = ProductStock::pending()->where('id', $claim->id)->first();
|
2025-11-21 10:49:41 +00:00
|
|
|
|
|
|
|
|
$this->assertNotNull($pending);
|
|
|
|
|
$this->assertNull($pending->released_at);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/** @test */
|
|
|
|
|
public function it_can_check_if_stock_is_released()
|
|
|
|
|
{
|
2025-11-25 11:33:42 +00:00
|
|
|
$product = Product::factory()->withStocks(50)->create();
|
2025-11-21 10:49:41 +00:00
|
|
|
|
2025-12-04 10:06:09 +00:00
|
|
|
$claim = $product->claimStock(5);
|
2025-11-21 10:49:41 +00:00
|
|
|
|
2025-12-04 10:06:09 +00:00
|
|
|
$claim->release();
|
2025-11-21 10:49:41 +00:00
|
|
|
|
2025-12-04 10:06:09 +00:00
|
|
|
$released = ProductStock::released()->where('id', $claim->id)->first();
|
2025-11-21 10:49:41 +00:00
|
|
|
|
|
|
|
|
$this->assertNotNull($released);
|
|
|
|
|
$this->assertNotNull($released->released_at);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/** @test */
|
2025-12-04 10:06:09 +00:00
|
|
|
public function it_can_distinguish_temporary_and_permanent_claims()
|
2025-11-21 10:49:41 +00:00
|
|
|
{
|
2025-11-25 11:33:42 +00:00
|
|
|
$product = Product::factory()->withStocks(100)->create();
|
2025-11-21 10:49:41 +00:00
|
|
|
|
2025-12-04 10:06:09 +00:00
|
|
|
$permanentClaim = $product->claimStock(
|
2025-11-25 11:33:42 +00:00
|
|
|
quantity: 10
|
2025-11-21 10:49:41 +00:00
|
|
|
);
|
|
|
|
|
|
2025-12-04 10:06:09 +00:00
|
|
|
$temporaryClaim = $product->claimStock(
|
2025-11-21 10:49:41 +00:00
|
|
|
quantity: 5,
|
2025-11-25 11:33:42 +00:00
|
|
|
until: now()->addHours(1)
|
2025-11-21 10:49:41 +00:00
|
|
|
);
|
|
|
|
|
|
2025-12-04 10:06:09 +00:00
|
|
|
$this->assertTrue($permanentClaim->isPermanent());
|
|
|
|
|
$this->assertFalse($permanentClaim->isTemporary());
|
2025-11-21 10:49:41 +00:00
|
|
|
|
2025-12-04 10:06:09 +00:00
|
|
|
$this->assertTrue($temporaryClaim->isTemporary());
|
|
|
|
|
$this->assertFalse($temporaryClaim->isPermanent());
|
2025-11-21 10:49:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/** @test */
|
|
|
|
|
public function it_belongs_to_a_product()
|
|
|
|
|
{
|
2025-11-25 11:33:42 +00:00
|
|
|
$product = Product::factory()->withStocks(20)->create();
|
2025-11-21 10:49:41 +00:00
|
|
|
|
2025-12-04 10:06:09 +00:00
|
|
|
$claim = $product->claimStock(5);
|
2025-11-21 10:49:41 +00:00
|
|
|
|
2025-12-04 10:06:09 +00:00
|
|
|
$this->assertInstanceOf(Product::class, $claim->product);
|
|
|
|
|
$this->assertEquals($product->id, $claim->product->id);
|
2025-11-21 10:49:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/** @test */
|
|
|
|
|
public function product_has_many_stock_records()
|
|
|
|
|
{
|
2025-11-25 11:33:42 +00:00
|
|
|
$product = Product::factory()->withStocks(30)->create();
|
2025-11-21 10:49:41 +00:00
|
|
|
|
2025-11-25 11:33:42 +00:00
|
|
|
$product->increaseStock(10);
|
|
|
|
|
$product->increaseStock(10);
|
|
|
|
|
$product->increaseStock(50);
|
2025-11-21 10:49:41 +00:00
|
|
|
|
2025-11-25 11:33:42 +00:00
|
|
|
$this->assertCount(4, $product->stocks);
|
|
|
|
|
$this->assertInstanceOf(ProductStock::class, $product->stocks->first());
|
|
|
|
|
$this->assertEquals(30 + 10 + 10 + 50, $product->getAvailableStock());
|
2025-11-21 10:49:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/** @test */
|
2025-12-04 10:06:09 +00:00
|
|
|
public function it_can_get_active_stock_claims()
|
2025-11-21 10:49:41 +00:00
|
|
|
{
|
2025-11-25 11:33:42 +00:00
|
|
|
$product = Product::factory()->withStocks(100)->create();
|
2025-11-21 10:49:41 +00:00
|
|
|
|
2025-12-04 10:06:09 +00:00
|
|
|
$activeClaim = $product->claimStock(
|
2025-11-25 11:33:42 +00:00
|
|
|
quantity: 10,
|
|
|
|
|
until: now()->addHours(2)
|
|
|
|
|
);
|
|
|
|
|
|
2025-12-04 10:06:09 +00:00
|
|
|
$expiredClaim = $product->claimStock(
|
2025-11-25 11:33:42 +00:00
|
|
|
quantity: 5,
|
|
|
|
|
until: now()->subHours(1)
|
|
|
|
|
);
|
2025-11-21 10:49:41 +00:00
|
|
|
|
2025-12-04 10:06:09 +00:00
|
|
|
$activeClaims = $product->claims()->get();
|
2025-11-21 10:49:41 +00:00
|
|
|
|
2025-12-04 10:06:09 +00:00
|
|
|
$this->assertCount(1, $activeClaims);
|
|
|
|
|
$this->assertEquals($activeClaim->id, $activeClaims->first()->id);
|
2025-11-21 10:49:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/** @test */
|
|
|
|
|
public function it_cannot_release_stock_twice()
|
|
|
|
|
{
|
2025-11-25 11:33:42 +00:00
|
|
|
$product = Product::factory()->withStocks()->create();
|
2025-11-21 10:49:41 +00:00
|
|
|
|
2025-12-04 10:06:09 +00:00
|
|
|
$claim = $product->claimStock(5);
|
2025-11-21 10:49:41 +00:00
|
|
|
|
2025-12-04 10:06:09 +00:00
|
|
|
$this->assertTrue($claim->release());
|
|
|
|
|
$this->assertFalse($claim->release());
|
2025-11-21 10:49:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/** @test */
|
2025-12-04 10:06:09 +00:00
|
|
|
public function it_can_store_claim_note()
|
2025-11-21 10:49:41 +00:00
|
|
|
{
|
2025-11-25 11:33:42 +00:00
|
|
|
$product = Product::factory()->withStocks()->create();
|
|
|
|
|
|
|
|
|
|
$note = "Customer requested to hold this item for 2 days.";
|
2025-11-21 10:49:41 +00:00
|
|
|
|
2025-12-04 10:06:09 +00:00
|
|
|
$claim = $product->claimStock(
|
2025-11-21 10:49:41 +00:00
|
|
|
quantity: 5,
|
2025-11-25 11:33:42 +00:00
|
|
|
note: $note
|
2025-11-21 10:49:41 +00:00
|
|
|
);
|
|
|
|
|
|
2025-12-04 10:06:09 +00:00
|
|
|
$this->assertEquals($note, $claim->note);
|
2025-11-21 10:49:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/** @test */
|
|
|
|
|
public function it_calculates_available_stock_correctly()
|
|
|
|
|
{
|
2025-11-25 11:33:42 +00:00
|
|
|
$product = Product::factory()->withStocks(100)->create();
|
|
|
|
|
|
2025-12-04 10:06:09 +00:00
|
|
|
$claim1 = $product->claimStock(
|
2025-11-25 11:33:42 +00:00
|
|
|
quantity: 10,
|
|
|
|
|
until: now()->addHours(2)
|
|
|
|
|
);
|
2025-11-21 10:49:41 +00:00
|
|
|
|
2025-12-04 10:06:09 +00:00
|
|
|
$claim2 = $product->claimStock(
|
2025-11-25 11:33:42 +00:00
|
|
|
quantity: 5,
|
|
|
|
|
until: now()->addHours(1)
|
|
|
|
|
);
|
2025-11-21 10:49:41 +00:00
|
|
|
|
2025-12-04 10:06:09 +00:00
|
|
|
$claim1->refresh();
|
|
|
|
|
$claim2->refresh();
|
2025-11-21 10:49:41 +00:00
|
|
|
|
2025-11-25 11:33:42 +00:00
|
|
|
$this->assertEquals(85, $product->refresh()->getAvailableStock());
|
2025-11-21 10:49:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/** @test */
|
|
|
|
|
public function product_tracks_low_stock_threshold()
|
|
|
|
|
{
|
2025-11-25 16:02:39 +00:00
|
|
|
$product = Product::factory()
|
|
|
|
|
->withStocks(12)
|
|
|
|
|
->create([
|
|
|
|
|
'low_stock_threshold' => 10,
|
|
|
|
|
]);
|
2025-11-21 10:49:41 +00:00
|
|
|
|
|
|
|
|
$this->assertFalse($product->isLowStock());
|
|
|
|
|
|
|
|
|
|
$product->decreaseStock(8);
|
|
|
|
|
|
|
|
|
|
$this->assertTrue($product->fresh()->isLowStock());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/** @test */
|
|
|
|
|
public function it_updates_in_stock_status_automatically()
|
|
|
|
|
{
|
2025-11-25 16:02:39 +00:00
|
|
|
$product = Product::factory()
|
|
|
|
|
->withStocks(10)
|
|
|
|
|
->create();
|
2025-11-21 10:49:41 +00:00
|
|
|
|
2025-11-25 16:02:39 +00:00
|
|
|
$product->decreaseStock(10);
|
2025-11-21 10:49:41 +00:00
|
|
|
|
2025-11-25 16:02:39 +00:00
|
|
|
$this->assertFalse($product->fresh()->isInStock());
|
2025-11-21 10:49:41 +00:00
|
|
|
}
|
2025-12-04 11:35:39 +00:00
|
|
|
|
|
|
|
|
/** @test */
|
|
|
|
|
public function it_can_adjust_stock_with_from_parameter_for_claimed_type()
|
|
|
|
|
{
|
|
|
|
|
$product = Product::factory()->withStocks(100)->create();
|
|
|
|
|
$fromDate = now()->addDays(3);
|
|
|
|
|
$untilDate = now()->addDays(10);
|
|
|
|
|
|
|
|
|
|
$result = $product->adjustStock(
|
|
|
|
|
type: \Blax\Shop\Enums\StockType::CLAIMED,
|
|
|
|
|
quantity: 15,
|
|
|
|
|
until: $untilDate,
|
|
|
|
|
from: $fromDate
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
// adjustStock(CLAIMED) now returns ProductStock (delegates to claimStock)
|
|
|
|
|
$this->assertInstanceOf(\Blax\Shop\Models\ProductStock::class, $result);
|
|
|
|
|
|
|
|
|
|
// Now creates two entries: DECREASE (COMPLETED) + CLAIMED (PENDING)
|
|
|
|
|
$claimedStock = $product->stocks()->where('type', 'claimed')->first();
|
|
|
|
|
$this->assertNotNull($claimedStock);
|
|
|
|
|
$this->assertEquals(15, $claimedStock->quantity); // Positive quantity
|
|
|
|
|
$this->assertEquals($fromDate->format('Y-m-d H:i:s'), $claimedStock->claimed_from->format('Y-m-d H:i:s'));
|
|
|
|
|
$this->assertEquals($untilDate->format('Y-m-d H:i:s'), $claimedStock->expires_at->format('Y-m-d H:i:s'));
|
|
|
|
|
|
|
|
|
|
// Check for the DECREASE entry
|
|
|
|
|
$decreaseStock = $product->stocks()->where('type', 'decrease')->first();
|
|
|
|
|
$this->assertNotNull($decreaseStock);
|
|
|
|
|
$this->assertEquals(-15, $decreaseStock->quantity);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/** @test */
|
|
|
|
|
public function it_uses_now_as_default_from_date_for_claimed_type()
|
|
|
|
|
{
|
|
|
|
|
$product = Product::factory()->withStocks(100)->create();
|
|
|
|
|
|
|
|
|
|
$result = $product->adjustStock(
|
|
|
|
|
type: \Blax\Shop\Enums\StockType::CLAIMED,
|
|
|
|
|
quantity: 10
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
// adjustStock(CLAIMED) now returns ProductStock
|
|
|
|
|
$this->assertInstanceOf(\Blax\Shop\Models\ProductStock::class, $result);
|
|
|
|
|
|
|
|
|
|
$claimedStock = $product->stocks()->where('type', 'claimed')->first();
|
|
|
|
|
// claimed_from defaults to null when not provided (claim active immediately)
|
|
|
|
|
$this->assertNull($claimedStock->claimed_from);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/** @test */
|
|
|
|
|
public function it_does_not_set_claimed_from_for_non_claimed_types()
|
|
|
|
|
{
|
|
|
|
|
$product = Product::factory()->withStocks(100)->create();
|
|
|
|
|
|
|
|
|
|
$product->adjustStock(
|
|
|
|
|
type: \Blax\Shop\Enums\StockType::INCREASE,
|
|
|
|
|
quantity: 10,
|
|
|
|
|
from: now()->addDays(5)
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
$stock = $product->stocks()->where('type', 'increase')->first();
|
|
|
|
|
$this->assertNull($stock->claimed_from);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/** @test */
|
|
|
|
|
public function it_can_adjust_stock_with_note_parameter()
|
|
|
|
|
{
|
|
|
|
|
$product = Product::factory()->withStocks(100)->create();
|
|
|
|
|
$note = 'Customer requested extra units for bulk order #12345';
|
|
|
|
|
|
|
|
|
|
$result = $product->adjustStock(
|
|
|
|
|
type: \Blax\Shop\Enums\StockType::INCREASE,
|
|
|
|
|
quantity: 50,
|
|
|
|
|
note: $note
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
$this->assertTrue($result);
|
|
|
|
|
|
|
|
|
|
$stock = $product->stocks()->where('type', 'increase')->where('quantity', 50)->first();
|
|
|
|
|
$this->assertNotNull($stock);
|
|
|
|
|
$this->assertEquals($note, $stock->note);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/** @test */
|
|
|
|
|
public function it_can_adjust_stock_with_referencable_model()
|
|
|
|
|
{
|
|
|
|
|
$product = Product::factory()->withStocks(100)->create();
|
|
|
|
|
$referencedProduct = Product::factory()->create();
|
|
|
|
|
|
|
|
|
|
$result = $product->adjustStock(
|
|
|
|
|
type: \Blax\Shop\Enums\StockType::DECREASE,
|
|
|
|
|
quantity: 10,
|
|
|
|
|
referencable: $referencedProduct
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
$this->assertTrue($result);
|
|
|
|
|
|
|
|
|
|
$stock = $product->stocks()->where('type', 'decrease')->where('quantity', -10)->first();
|
|
|
|
|
$this->assertNotNull($stock);
|
|
|
|
|
$this->assertEquals(Product::class, $stock->reference_type);
|
|
|
|
|
$this->assertEquals($referencedProduct->id, $stock->reference_id);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/** @test */
|
|
|
|
|
public function it_can_adjust_stock_with_all_parameters_combined()
|
|
|
|
|
{
|
|
|
|
|
$product = Product::factory()->withStocks(100)->create();
|
|
|
|
|
$referencedProduct = Product::factory()->create();
|
|
|
|
|
$fromDate = now()->addDays(2);
|
|
|
|
|
$untilDate = now()->addDays(7);
|
|
|
|
|
$note = 'Reserved for special event booking';
|
|
|
|
|
|
|
|
|
|
$result = $product->adjustStock(
|
|
|
|
|
type: \Blax\Shop\Enums\StockType::CLAIMED,
|
|
|
|
|
quantity: 25,
|
|
|
|
|
until: $untilDate,
|
|
|
|
|
from: $fromDate,
|
|
|
|
|
note: $note,
|
|
|
|
|
referencable: $referencedProduct
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
// adjustStock(CLAIMED) now returns ProductStock
|
|
|
|
|
$this->assertInstanceOf(\Blax\Shop\Models\ProductStock::class, $result);
|
|
|
|
|
|
|
|
|
|
$stock = $product->stocks()->where('type', 'claimed')->first();
|
|
|
|
|
$this->assertNotNull($stock);
|
|
|
|
|
$this->assertEquals(25, $stock->quantity); // Positive quantity
|
|
|
|
|
$this->assertEquals('pending', $stock->status->value);
|
|
|
|
|
$this->assertEquals($fromDate->format('Y-m-d H:i:s'), $stock->claimed_from->format('Y-m-d H:i:s'));
|
|
|
|
|
$this->assertEquals($untilDate->format('Y-m-d H:i:s'), $stock->expires_at->format('Y-m-d H:i:s'));
|
|
|
|
|
$this->assertEquals($note, $stock->note);
|
|
|
|
|
$this->assertEquals(Product::class, $stock->reference_type);
|
|
|
|
|
$this->assertEquals($referencedProduct->id, $stock->reference_id);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/** @test */
|
|
|
|
|
public function it_adjusts_stock_with_correct_quantity_signs_based_on_type()
|
|
|
|
|
{
|
|
|
|
|
$product = Product::factory()->withStocks(100)->create();
|
|
|
|
|
|
|
|
|
|
// INCREASE should add stock (positive)
|
|
|
|
|
$product->adjustStock(
|
|
|
|
|
type: \Blax\Shop\Enums\StockType::INCREASE,
|
|
|
|
|
quantity: 20
|
|
|
|
|
);
|
|
|
|
|
$increaseStock = $product->stocks()->where('type', 'increase')->where('quantity', 20)->first();
|
|
|
|
|
$this->assertNotNull($increaseStock);
|
|
|
|
|
$this->assertEquals(20, $increaseStock->quantity);
|
|
|
|
|
|
|
|
|
|
// RETURN should add stock (positive)
|
|
|
|
|
$product->adjustStock(
|
|
|
|
|
type: \Blax\Shop\Enums\StockType::RETURN,
|
|
|
|
|
quantity: 15
|
|
|
|
|
);
|
|
|
|
|
$returnStock = $product->stocks()->where('type', 'return')->where('quantity', 15)->first();
|
|
|
|
|
$this->assertNotNull($returnStock);
|
|
|
|
|
$this->assertEquals(15, $returnStock->quantity);
|
|
|
|
|
|
|
|
|
|
// DECREASE should remove stock (negative)
|
|
|
|
|
$product->adjustStock(
|
|
|
|
|
type: \Blax\Shop\Enums\StockType::DECREASE,
|
|
|
|
|
quantity: 10
|
|
|
|
|
);
|
|
|
|
|
$decreaseStock = $product->stocks()->where('type', 'decrease')->where('quantity', -10)->first();
|
|
|
|
|
$this->assertNotNull($decreaseStock);
|
|
|
|
|
$this->assertEquals(-10, $decreaseStock->quantity);
|
|
|
|
|
|
|
|
|
|
// CLAIMED now creates two entries: DECREASE + CLAIMED (positive quantity)
|
|
|
|
|
$product->adjustStock(
|
|
|
|
|
type: \Blax\Shop\Enums\StockType::CLAIMED,
|
|
|
|
|
quantity: 5
|
|
|
|
|
);
|
|
|
|
|
$claimedStock = $product->stocks()->where('type', 'claimed')->where('quantity', 5)->first();
|
|
|
|
|
$this->assertNotNull($claimedStock);
|
|
|
|
|
$this->assertEquals(5, $claimedStock->quantity); // Now positive
|
|
|
|
|
|
|
|
|
|
// And also creates a DECREASE entry
|
|
|
|
|
$claimedDecrease = $product->stocks()->where('type', 'decrease')->where('quantity', -5)->first();
|
|
|
|
|
$this->assertNotNull($claimedDecrease);
|
|
|
|
|
$this->assertEquals(-5, $claimedDecrease->quantity);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/** @test */
|
|
|
|
|
public function it_returns_false_when_adjusting_stock_with_management_disabled()
|
|
|
|
|
{
|
|
|
|
|
$product = Product::factory()->create([
|
|
|
|
|
'manage_stock' => false,
|
|
|
|
|
]);
|
|
|
|
|
|
|
|
|
|
$result = $product->adjustStock(
|
|
|
|
|
type: \Blax\Shop\Enums\StockType::INCREASE,
|
|
|
|
|
quantity: 10
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
$this->assertFalse($result);
|
|
|
|
|
$this->assertCount(0, $product->stocks);
|
|
|
|
|
}
|
2025-11-21 10:49:41 +00:00
|
|
|
}
|