From 80da7ec333e5ebb0bc0f303c719ea59adcf40558 Mon Sep 17 00:00:00 2001 From: K Muller Date: Fri, 25 Sep 2026 11:54:47 +0200 Subject: [PATCH] fix: :bug: add Quantity and WarningQuantity as VO --- .../Models/Entities/RequestedCoupon.php | 10 ++-- .../ValueObjects/Campaign/CampaignCoupon.php | 6 +-- .../RequestedCouponQuantity.php | 16 +++++++ .../ValueObjects/WarningThresholdQuantity.php | 16 +++++++ .../Find/FindCampaignRequestTest.php | 6 ++- .../List/ListCampaignsRequestTest.php | 10 ++-- .../Reject/RejectCampaignRequestTest.php | 6 ++- .../Models/Entities/CampaignRequestTest.php | 6 ++- .../Domain/Models/Entities/CampaignTest.php | 46 +++++++++++++++++-- .../Models/Entities/RequestedCouponTest.php | 14 +++--- .../Campaign/CampaignCouponTest.php | 26 ++--------- .../RequestedCouponQuantityTest.php | 39 ++++++++++++++++ .../WarningThresholdQuantityTest.php | 39 ++++++++++++++++ 13 files changed, 188 insertions(+), 52 deletions(-) create mode 100644 src/Domain/Models/ValueObjects/RequestedCoupon/RequestedCouponQuantity.php create mode 100644 src/Domain/Models/ValueObjects/WarningThresholdQuantity.php create mode 100644 tests/Unit/Domain/Models/ValueObjects/RequestedCoupon/RequestedCouponQuantityTest.php create mode 100644 tests/Unit/Domain/Models/ValueObjects/WarningThresholdQuantityTest.php diff --git a/src/Domain/Models/Entities/RequestedCoupon.php b/src/Domain/Models/Entities/RequestedCoupon.php index 3ea6715..43c9c05 100644 --- a/src/Domain/Models/Entities/RequestedCoupon.php +++ b/src/Domain/Models/Entities/RequestedCoupon.php @@ -13,8 +13,10 @@ use Domain\Models\ValueObjects\MoneyAmount; use Domain\Models\ValueObjects\Period; use Domain\Models\ValueObjects\ProcessingCode; use Domain\Models\ValueObjects\RequestedCoupon\RequestedCouponId; +use Domain\Models\ValueObjects\RequestedCoupon\RequestedCouponQuantity; use Shared\DDD\Models\AggregateRoot; use Shared\DDD\Models\HasTimestampIdentifier; +use Domain\Models\ValueObjects\WarningThresholdQuantity; /** * @implements \Shared\DDD\Models\AggregateRoot<\Domain\Models\ValueObjects\RequestedCoupon\RequestedCouponId> @@ -25,8 +27,8 @@ final readonly class RequestedCoupon implements AggregateRoot, HasTimestampIdent public RequestedCouponId $id, public CouponName $name, public CouponProductName $productName, - public int $quantity, - public int $warningThresholdQuantity, + public RequestedCouponQuantity $quantity, + public WarningThresholdQuantity $warningThresholdQuantity, public Period $period, public MoneyAmount $moneyAmount, public ProcessingCode $processingCode, @@ -56,8 +58,8 @@ final readonly class RequestedCoupon implements AggregateRoot, HasTimestampIdent RequestedCouponId $id, CouponName $name, CouponProductName $productName, - int $quantity, - int $warningThresholdQuantity, + RequestedCouponQuantity $quantity, + WarningThresholdQuantity $warningThresholdQuantity, Period $period, MoneyAmount $moneyAmount, ProcessingCode $processingCode, diff --git a/src/Domain/Models/ValueObjects/Campaign/CampaignCoupon.php b/src/Domain/Models/ValueObjects/Campaign/CampaignCoupon.php index 2e7ca71..a3ed524 100644 --- a/src/Domain/Models/ValueObjects/Campaign/CampaignCoupon.php +++ b/src/Domain/Models/ValueObjects/Campaign/CampaignCoupon.php @@ -7,17 +7,15 @@ namespace Domain\Models\ValueObjects\Campaign; use Domain\Models\ValueObjects\PrintRules; use Domain\Models\ValueObjects\ProcessingCode; use Domain\Models\ValueObjects\Stock\StockId; +use Domain\Models\ValueObjects\WarningThresholdQuantity; final readonly class CampaignCoupon { public function __construct( public ProcessingCode $code, public StockId $qty, - public int $warningThresholdQty, + public WarningThresholdQuantity $warningThresholdQty, public ?PrintRules $printRules = null, ) { - if ($this->warningThresholdQty <= 0) { - throw new \DomainException('Campaign Coupon warningThresholdQty must be positive.'); - } } } diff --git a/src/Domain/Models/ValueObjects/RequestedCoupon/RequestedCouponQuantity.php b/src/Domain/Models/ValueObjects/RequestedCoupon/RequestedCouponQuantity.php new file mode 100644 index 0000000..9794fc2 --- /dev/null +++ b/src/Domain/Models/ValueObjects/RequestedCoupon/RequestedCouponQuantity.php @@ -0,0 +1,16 @@ +value <= 0) { + throw new \DomainException('Quantity should be more than 0.'); + } + } +} diff --git a/src/Domain/Models/ValueObjects/WarningThresholdQuantity.php b/src/Domain/Models/ValueObjects/WarningThresholdQuantity.php new file mode 100644 index 0000000..682608e --- /dev/null +++ b/src/Domain/Models/ValueObjects/WarningThresholdQuantity.php @@ -0,0 +1,16 @@ +value < 0) { + throw new \DomainException('Warning threshold quantity cannot be negative.'); + } + } +} diff --git a/tests/Unit/Application/UseCases/CampaignRequest/Find/FindCampaignRequestTest.php b/tests/Unit/Application/UseCases/CampaignRequest/Find/FindCampaignRequestTest.php index 9f3667d..1697e85 100644 --- a/tests/Unit/Application/UseCases/CampaignRequest/Find/FindCampaignRequestTest.php +++ b/tests/Unit/Application/UseCases/CampaignRequest/Find/FindCampaignRequestTest.php @@ -35,6 +35,8 @@ use Domain\Models\ValueObjects\PicturePath; use Domain\Models\ValueObjects\PrintRules; use Domain\Models\ValueObjects\ProcessingCode; use Domain\Models\ValueObjects\RequestedCoupon\RequestedCouponId; +use Domain\Models\ValueObjects\RequestedCoupon\RequestedCouponQuantity; +use Domain\Models\ValueObjects\WarningThresholdQuantity; use Domain\Ports\Repositories\BrandRepository; use Domain\Ports\Repositories\CampaignRequestRepository; use Shared\DDD\UseCases\Input as BaseInput; @@ -52,8 +54,8 @@ describe('find campaign request use case', function (): void { RequestedCouponId::generate(), new CouponName('Coupon A'), new CouponProductName('Product A'), - 100, - 10, + new RequestedCouponQuantity(100), + new WarningThresholdQuantity(10), new Period(new DateTime('2026-01-01'), new DateTime('2026-02-01')), new MoneyAmount(new Money(Currency::EUR, 300)), new ProcessingCode('PC1'), diff --git a/tests/Unit/Application/UseCases/CampaignRequest/List/ListCampaignsRequestTest.php b/tests/Unit/Application/UseCases/CampaignRequest/List/ListCampaignsRequestTest.php index 8775d10..866a348 100644 --- a/tests/Unit/Application/UseCases/CampaignRequest/List/ListCampaignsRequestTest.php +++ b/tests/Unit/Application/UseCases/CampaignRequest/List/ListCampaignsRequestTest.php @@ -29,6 +29,8 @@ use Domain\Models\ValueObjects\PicturePath; use Domain\Models\ValueObjects\PrintRules; use Domain\Models\ValueObjects\ProcessingCode; use Domain\Models\ValueObjects\RequestedCoupon\RequestedCouponId; +use Domain\Models\ValueObjects\RequestedCoupon\RequestedCouponQuantity; +use Domain\Models\ValueObjects\WarningThresholdQuantity; use Domain\Ports\Repositories\CampaignRequestRepository; use Shared\DDD\UseCases\Input as BaseInput; use Shared\Enums\Currency; @@ -46,8 +48,8 @@ describe('list campaigns request use case', function (): void { RequestedCouponId::generate(), new CouponName('Coupon A'), new CouponProductName('Product A'), - 100, - 10, + new RequestedCouponQuantity(100), + new WarningThresholdQuantity(10), new Period(new DateTime('2026-01-01'), new DateTime('2026-02-01')), new MoneyAmount(new Money(Currency::EUR, 300)), new ProcessingCode('PC1'), @@ -60,8 +62,8 @@ describe('list campaigns request use case', function (): void { RequestedCouponId::generate(), new CouponName('Coupon B'), new CouponProductName('Product B'), - 100, - 10, + new RequestedCouponQuantity(100), + new WarningThresholdQuantity(10), new Period(new DateTime('2026-01-01'), new DateTime('2026-02-01')), new MoneyAmount(new Money(Currency::EUR, 300)), new ProcessingCode('PC2'), diff --git a/tests/Unit/Application/UseCases/CampaignRequest/Reject/RejectCampaignRequestTest.php b/tests/Unit/Application/UseCases/CampaignRequest/Reject/RejectCampaignRequestTest.php index 7581f27..5c3abc4 100644 --- a/tests/Unit/Application/UseCases/CampaignRequest/Reject/RejectCampaignRequestTest.php +++ b/tests/Unit/Application/UseCases/CampaignRequest/Reject/RejectCampaignRequestTest.php @@ -32,6 +32,8 @@ use Domain\Models\ValueObjects\PicturePath; use Domain\Models\ValueObjects\PrintRules; use Domain\Models\ValueObjects\ProcessingCode; use Domain\Models\ValueObjects\RequestedCoupon\RequestedCouponId; +use Domain\Models\ValueObjects\RequestedCoupon\RequestedCouponQuantity; +use Domain\Models\ValueObjects\WarningThresholdQuantity; use Domain\Ports\Repositories\CampaignRequestRepository; use Shared\DDD\UseCases\Input as BaseInput; use Shared\Enums\Currency; @@ -51,8 +53,8 @@ describe('reject campaign request use case', function (): void { RequestedCouponId::generate(), new CouponName('Coupon A'), new CouponProductName('Product A'), - 100, - 10, + new RequestedCouponQuantity(100), + new WarningThresholdQuantity(10), new Period(new DateTime('2026-01-01'), new DateTime('2026-02-01')), new MoneyAmount(new Money(Currency::EUR, 300)), new ProcessingCode('PC1'), diff --git a/tests/Unit/Domain/Models/Entities/CampaignRequestTest.php b/tests/Unit/Domain/Models/Entities/CampaignRequestTest.php index 0cb2349..5b86beb 100644 --- a/tests/Unit/Domain/Models/Entities/CampaignRequestTest.php +++ b/tests/Unit/Domain/Models/Entities/CampaignRequestTest.php @@ -32,6 +32,8 @@ use Shared\ValueObjects\Email; use Shared\ValueObjects\Money; use Carbon\CarbonImmutable; use Domain\Models\ValueObjects\CountryAuthorized; +use Domain\Models\ValueObjects\RequestedCoupon\RequestedCouponQuantity; +use Domain\Models\ValueObjects\WarningThresholdQuantity; covers(CampaignRequest::class); @@ -45,8 +47,8 @@ describe('campaign request', function (): void { RequestedCouponId::generate(), new CouponName('Coupon A'), new CouponProductName('Product A'), - 100, - 10, + new RequestedCouponQuantity(100), + new WarningThresholdQuantity(10), new Period(new DateTime('2026-01-01'), new DateTime('2026-02-01')), new MoneyAmount(new Money(Currency::EUR, 300)), new ProcessingCode('PC1'), diff --git a/tests/Unit/Domain/Models/Entities/CampaignTest.php b/tests/Unit/Domain/Models/Entities/CampaignTest.php index e50c295..37511b7 100644 --- a/tests/Unit/Domain/Models/Entities/CampaignTest.php +++ b/tests/Unit/Domain/Models/Entities/CampaignTest.php @@ -19,6 +19,7 @@ use Domain\Models\ValueObjects\ProcessingCode; use Domain\Models\ValueObjects\Stock\StockId; use Domain\Models\ValueObjects\Tag\TagId; use Domain\Models\ValueObjects\Tag\TagName; +use Domain\Models\ValueObjects\WarningThresholdQuantity; use Ramsey\Uuid\Uuid; covers(Campaign::class); @@ -43,7 +44,14 @@ describe('campaign', function (): void { $publication = \boolval(0); $printAllAtOnce = \boolval(1); $availableIn = new CountryAuthorized(Country::FRANCE); - $coupons = [new CampaignCoupon(new ProcessingCode('PC1'), StockId::generate(), 100, new PrintRules(maxPerCustomer: 3))]; + $coupons = [ + new CampaignCoupon( + new ProcessingCode('PC1'), + StockId::generate(), + new WarningThresholdQuantity(100), + new PrintRules(maxPerCustomer: 3) + ) + ]; $brand = new BrandCode('AAA01'); // WHEN @@ -109,7 +117,14 @@ describe('campaign', function (): void { $publication = \boolval(0); $printAllAtOnce = \boolval(1); $availableIn = new CountryAuthorized(Country::FRANCE); - $coupons = [new CampaignCoupon(new ProcessingCode('PC1'), StockId::generate(), 100, new PrintRules(maxPerCustomer: 3))]; + $coupons = [ + new CampaignCoupon( + new ProcessingCode('PC1'), + StockId::generate(), + new WarningThresholdQuantity(100), + new PrintRules(maxPerCustomer: 3) + ) + ]; $brand = new BrandCode('AAA01'); $updatedAt = new \DateTimeImmutable('2026-09-22 10:00:00', new \DateTimeZone('UTC')); @@ -139,7 +154,14 @@ describe('campaign', function (): void { $publication = \boolval(0); $printAllAtOnce = \boolval(1); $availableIn = new CountryAuthorized(Country::FRANCE); - $coupons = [new CampaignCoupon(new ProcessingCode('PC1'), StockId::generate(), 100, new PrintRules(maxPerCustomer: 3))]; + $coupons = [ + new CampaignCoupon( + new ProcessingCode('PC1'), + StockId::generate(), + new WarningThresholdQuantity(100), + new PrintRules(maxPerCustomer: 3) + ) + ]; $brand = new BrandCode('AAA01'); // WHEN @@ -175,7 +197,14 @@ describe('campaign', function (): void { $publication = \boolval(0); $printAllAtOnce = \boolval(1); $availableIn = new CountryAuthorized(Country::FRANCE); - $coupons = [new CampaignCoupon(new ProcessingCode('PC1'), StockId::generate(), 100, new PrintRules(maxPerCustomer: 3))]; + $coupons = [ + new CampaignCoupon( + new ProcessingCode('PC1'), + StockId::generate(), + new WarningThresholdQuantity(100), + new PrintRules(maxPerCustomer: 3) + ) + ]; $brand = new BrandCode('AAA01'); // WHEN @@ -216,7 +245,14 @@ describe('campaign', function (): void { \boolval(0), \boolval(1), new CountryAuthorized(Country::FRANCE), - [new CampaignCoupon(new ProcessingCode('PC1'), StockId::generate(), 100, new PrintRules(maxPerCustomer: 3))], + [ + new CampaignCoupon( + new ProcessingCode('PC1'), + StockId::generate(), + new WarningThresholdQuantity(100), + new PrintRules(maxPerCustomer: 3) + ) + ], new BrandCode('AAA01') ); diff --git a/tests/Unit/Domain/Models/Entities/RequestedCouponTest.php b/tests/Unit/Domain/Models/Entities/RequestedCouponTest.php index b69de01..c365232 100644 --- a/tests/Unit/Domain/Models/Entities/RequestedCouponTest.php +++ b/tests/Unit/Domain/Models/Entities/RequestedCouponTest.php @@ -17,6 +17,8 @@ use Domain\Models\ValueObjects\Period; use Domain\Models\ValueObjects\PicturePath; use Domain\Models\ValueObjects\ProcessingCode; use Domain\Models\ValueObjects\RequestedCoupon\RequestedCouponId; +use Domain\Models\ValueObjects\RequestedCoupon\RequestedCouponQuantity; +use Domain\Models\ValueObjects\WarningThresholdQuantity; use Ramsey\Uuid\Uuid; use Shared\Enums\Currency; use Shared\ValueObjects\DateTime; @@ -34,8 +36,8 @@ describe('requested coupon', function (): void { $id = RequestedCouponId::generate(); $name = new CouponName('Coupon A'); $productName = new CouponProductName('Product A'); - $quantity = 100; - $warningThresholdQuantity = 10; + $quantity = new RequestedCouponQuantity(100); + $warningThresholdQuantity = new WarningThresholdQuantity(10); $period = new Period(new DateTime('2026-01-01'), new DateTime('2026-02-01')); $moneyAmount = new MoneyAmount(new Money(Currency::EUR, 300)); $processingCode = new ProcessingCode('PC1'); @@ -83,8 +85,8 @@ describe('requested coupon', function (): void { RequestedCouponId::generate(), new CouponName('Coupon A'), new CouponProductName('Product A'), - 100, - 10, + new RequestedCouponQuantity(100), + new WarningThresholdQuantity(10), new Period(new DateTime('2026-01-01'), new DateTime('2026-02-01')), new MoneyAmount(new Money(Currency::EUR, 300)), new ProcessingCode('PC1'), @@ -107,8 +109,8 @@ describe('requested coupon', function (): void { $id, new CouponName('Coupon A'), new CouponProductName('Product A'), - 100, - 10, + new RequestedCouponQuantity(100), + new WarningThresholdQuantity(10), new Period(new DateTime('2026-01-01'), new DateTime('2026-02-01')), new MoneyAmount(new Money(Currency::EUR, 300)), new ProcessingCode('PC1'), diff --git a/tests/Unit/Domain/Models/ValueObjects/Campaign/CampaignCouponTest.php b/tests/Unit/Domain/Models/ValueObjects/Campaign/CampaignCouponTest.php index 9d1b6ba..340d03c 100644 --- a/tests/Unit/Domain/Models/ValueObjects/Campaign/CampaignCouponTest.php +++ b/tests/Unit/Domain/Models/ValueObjects/Campaign/CampaignCouponTest.php @@ -8,6 +8,7 @@ use Domain\Models\ValueObjects\Campaign\CampaignCoupon; use Domain\Models\ValueObjects\PrintRules; use Domain\Models\ValueObjects\ProcessingCode; use Domain\Models\ValueObjects\Stock\StockId; +use Domain\Models\ValueObjects\WarningThresholdQuantity; covers(CampaignCoupon::class); @@ -17,7 +18,7 @@ describe('campaign coupon', function (): void { $code = new ProcessingCode('PC1'); $qty = StockId::generate(); $printRules = new PrintRules(maxPerCustomer: 3); - $warningThresholdQty = 100; + $warningThresholdQty = new WarningThresholdQuantity(100); // WHEN $campaignCoupon = new CampaignCoupon($code, $qty, $warningThresholdQty, $printRules); @@ -33,7 +34,7 @@ describe('campaign coupon', function (): void { // GIVEN $code = new ProcessingCode('PC1'); $qty = StockId::generate(); - $warningThresholdQty = 100; + $warningThresholdQty = new WarningThresholdQuantity(100); // WHEN $campaignCoupon = new CampaignCoupon($code, $qty, $warningThresholdQty); @@ -43,25 +44,4 @@ describe('campaign coupon', function (): void { ->and($campaignCoupon->qty)->toBe($qty) ->and($campaignCoupon->warningThresholdQty)->toBe($warningThresholdQty); }); - - it('rejects invalid campaign coupon', function (): void { - // GIVEN - $code = new ProcessingCode('PC1'); - $qty = StockId::generate(); - $printRules = new PrintRules(maxPerCustomer: 3); - $warningThresholdQty = -100; - - // GIVEN / THEN - expect(fn (): CampaignCoupon => new CampaignCoupon($code, $qty, $warningThresholdQty, $printRules))->toThrow(\DomainException::class); - }); - - it('rejects invalid campaign coupon whitout print rules', function (): void { - // GIVEN - $code = new ProcessingCode('PC1'); - $qty = StockId::generate(); - $warningThresholdQty = -100; - - // GIVEN / THEN - expect(fn (): CampaignCoupon => new CampaignCoupon($code, $qty, $warningThresholdQty))->toThrow(\DomainException::class); - }); }); diff --git a/tests/Unit/Domain/Models/ValueObjects/RequestedCoupon/RequestedCouponQuantityTest.php b/tests/Unit/Domain/Models/ValueObjects/RequestedCoupon/RequestedCouponQuantityTest.php new file mode 100644 index 0000000..5197b8d --- /dev/null +++ b/tests/Unit/Domain/Models/ValueObjects/RequestedCoupon/RequestedCouponQuantityTest.php @@ -0,0 +1,39 @@ +toBeInstanceOf(RequestedCouponQuantity::class) + ->and($quantity->value)->toBe($value); + }); + + it('rejects a quantity of zero', function (): void { + // WHEN + $action = fn (): RequestedCouponQuantity => new RequestedCouponQuantity(0); + + // THEN + expect($action)->toThrow(\DomainException::class, 'Quantity should be more than 0.'); + }); + + it('rejects a negative quantity', function (): void { + // WHEN + $action = fn (): RequestedCouponQuantity => new RequestedCouponQuantity(-1); + + // THEN + expect($action)->toThrow(\DomainException::class, 'Quantity should be more than 0.'); + }); +}); diff --git a/tests/Unit/Domain/Models/ValueObjects/WarningThresholdQuantityTest.php b/tests/Unit/Domain/Models/ValueObjects/WarningThresholdQuantityTest.php new file mode 100644 index 0000000..318c519 --- /dev/null +++ b/tests/Unit/Domain/Models/ValueObjects/WarningThresholdQuantityTest.php @@ -0,0 +1,39 @@ +toBeInstanceOf(WarningThresholdQuantity::class) + ->and($threshold->value)->toBe($value); + }); + + it('accepts a zero value, meaning no warning', function (): void { + // WHEN + $threshold = new WarningThresholdQuantity(0); + + // THEN + expect($threshold->value)->toBe(0); + }); + + it('rejects a negative value', function (): void { + // WHEN + $action = fn (): WarningThresholdQuantity => new WarningThresholdQuantity(-1); + + // THEN + expect($action)->toThrow(\DomainException::class, 'Warning threshold quantity cannot be negative.'); + }); +});