refactor: ♻️ align Coupon entity with UML cardinalities

This commit is contained in:
Corentin Huet 2026-09-24 11:28:29 +02:00
parent 01b4a049b2
commit e5e64d69be
2 changed files with 110 additions and 30 deletions

View file

@ -4,6 +4,7 @@ declare(strict_types=1);
namespace Domain\Models\Entities;
use Domain\Models\ValueObjects\Actor\ActorId;
use Domain\Models\ValueObjects\Brand\BrandCode;
use Domain\Models\ValueObjects\Coupon\CouponAvailabilityCalendar;
use Domain\Models\ValueObjects\Coupon\CouponDiffusion;
@ -36,10 +37,12 @@ final readonly class Coupon implements AggregateRoot, HasTimestampIdentifier
public CouponDiffusion $diffusion,
public CouponAvailabilityCalendar $availability,
public CouponValidity $validity,
public CouponLegalInformation $legal,
public GS1 $gtin,
/** @var array<int, CouponLegalInformation> $legal */
public array $legal,
public ProcessingCode $code,
public BrandCode $brandCode,
public ActorId $createdBy,
public ?GS1 $gtin = null,
public ?\DateTimeInterface $updatedAt = null,
) {
}
@ -59,6 +62,9 @@ final readonly class Coupon implements AggregateRoot, HasTimestampIdentifier
return $this->updatedAt;
}
/**
* @param array<int, CouponLegalInformation> $legal
*/
public static function create(
CouponName $name,
bool $status,
@ -69,10 +75,11 @@ final readonly class Coupon implements AggregateRoot, HasTimestampIdentifier
CouponDiffusion $diffusion,
CouponAvailabilityCalendar $availability,
CouponValidity $validity,
CouponLegalInformation $legal,
GS1 $gtin,
array $legal,
ProcessingCode $code,
BrandCode $brandCode,
ActorId $createdBy,
?GS1 $gtin = null,
?\DateTimeInterface $updatedAt = null,
): Coupon {
return new self(
@ -87,13 +94,17 @@ final readonly class Coupon implements AggregateRoot, HasTimestampIdentifier
availability: $availability,
validity: $validity,
legal: $legal,
gtin: $gtin,
code: $code,
brandCode: $brandCode,
createdBy: $createdBy,
gtin: $gtin,
updatedAt: $updatedAt,
);
}
/**
* @param array<int, CouponLegalInformation> $legal
*/
public static function hydrate(
CouponId $id,
CouponName $name,
@ -105,10 +116,11 @@ final readonly class Coupon implements AggregateRoot, HasTimestampIdentifier
CouponDiffusion $diffusion,
CouponAvailabilityCalendar $availability,
CouponValidity $validity,
CouponLegalInformation $legal,
GS1 $gtin,
array $legal,
ProcessingCode $code,
BrandCode $brandCode,
ActorId $createdBy,
?GS1 $gtin = null,
?\DateTimeInterface $updatedAt = null,
): self {
return new self(
@ -123,9 +135,10 @@ final readonly class Coupon implements AggregateRoot, HasTimestampIdentifier
availability: $availability,
validity: $validity,
legal: $legal,
gtin: $gtin,
code: $code,
brandCode: $brandCode,
createdBy: $createdBy,
gtin: $gtin,
updatedAt: $updatedAt,
);
}

View file

@ -8,6 +8,7 @@ use Carbon\CarbonImmutable;
use Domain\Enums\BarcodeFormat;
use Domain\Enums\Country;
use Domain\Models\Entities\Coupon;
use Domain\Models\ValueObjects\Actor\ActorId;
use Domain\Models\ValueObjects\Brand\BrandCode;
use Domain\Models\ValueObjects\Coupon\CouponAvailabilityCalendar;
use Domain\Models\ValueObjects\Coupon\CouponDiffusion;
@ -46,10 +47,11 @@ describe('coupon', function (): void {
$diffusion = new CouponDiffusion(['2026-08-25', '2026-10-31']);
$availability = new CouponAvailabilityCalendar(['2026-08-25', '2026-10-31']);
$validity = new CouponValidity(30, new DateTime('2026-11-30'));
$legal = new CouponLegalInformation('Lorem ipsum dolor sit amet consectetur adipiscing elit.', Country::FR);
$gtin = new GS1('110101010', BarcodeFormat::EAN13);
$legal = [new CouponLegalInformation('Lorem ipsum dolor sit amet consectetur adipiscing elit.', Country::FR)];
$code = new ProcessingCode('5425003944130');
$brandCode = new BrandCode('AAA01');
$createdBy = ActorId::generate();
$gtin = new GS1('110101010', BarcodeFormat::EAN13);
// WHEN
$coupon = Coupon::hydrate(
@ -64,9 +66,10 @@ describe('coupon', function (): void {
$availability,
$validity,
$legal,
$gtin,
$code,
$brandCode
$brandCode,
$createdBy,
$gtin,
);
// THEN
@ -81,9 +84,64 @@ describe('coupon', function (): void {
->and($coupon->availability)->toBe($availability)
->and($coupon->validity)->toBe($validity)
->and($coupon->legal)->toBe($legal)
->and($coupon->gtin)->toBe($gtin)
->and($coupon->code)->toBe($code)
->and($coupon->brandCode)->toBe($brandCode)
->and($coupon->createdBy)->toBe($createdBy)
->and($coupon->gtin)->toBe($gtin)
->and($coupon->updatedAt)->toBeNull()
->and($coupon->updatedAt())->toBeNull();
});
it('creates a coupon without gs1', function (): void {
// GIVEN
$id = CouponId::generate();
$name = new CouponName('Name');
$status = \boolval(0);
$productName = new CouponProductName('Lorem ipsum');
$amount = new MoneyAmount(new Money(Currency::EUR, 1));
$picture = new CouponPicture(new PicturePath('files/product.jpg'), new PicturePath('files/thumbnail.jpg'));
$product = new CouponProduct('Lorem ipsum', [], []);
$diffusion = new CouponDiffusion(['2026-08-25', '2026-10-31']);
$availability = new CouponAvailabilityCalendar(['2026-08-25', '2026-10-31']);
$validity = new CouponValidity(30, new DateTime('2026-11-30'));
$legal = [new CouponLegalInformation('Lorem ipsum dolor sit amet consectetur adipiscing elit.', Country::FR)];
$code = new ProcessingCode('5425003944130');
$brandCode = new BrandCode('AAA01');
$createdBy = ActorId::generate();
// WHEN
$coupon = Coupon::hydrate(
$id,
$name,
$status,
$productName,
$amount,
$picture,
$product,
$diffusion,
$availability,
$validity,
$legal,
$code,
$brandCode,
$createdBy,
);
// THEN
expect($coupon->id())->toBe($id)
->and($coupon->name)->toBe($name)
->and($coupon->status)->toBe($status)
->and($coupon->productName)->toBe($productName)
->and($coupon->amount)->toBe($amount)
->and($coupon->picture)->toBe($picture)
->and($coupon->product)->toBe($product)
->and($coupon->diffusion)->toBe($diffusion)
->and($coupon->availability)->toBe($availability)
->and($coupon->validity)->toBe($validity)
->and($coupon->legal)->toBe($legal)
->and($coupon->code)->toBe($code)
->and($coupon->brandCode)->toBe($brandCode)
->and($coupon->createdBy)->toBe($createdBy)
->and($coupon->updatedAt)->toBeNull()
->and($coupon->updatedAt())->toBeNull();
});
@ -100,10 +158,11 @@ describe('coupon', function (): void {
$diffusion = new CouponDiffusion(['2026-08-25', '2026-10-31']);
$availability = new CouponAvailabilityCalendar(['2026-08-25', '2026-10-31']);
$validity = new CouponValidity(30, new DateTime('2026-11-30'));
$legal = new CouponLegalInformation('Lorem ipsum dolor sit amet consectetur adipiscing elit.', Country::FR);
$gtin = new GS1('110101010', BarcodeFormat::EAN13);
$legal = [new CouponLegalInformation('Lorem ipsum dolor sit amet consectetur adipiscing elit.', Country::FR)];
$code = new ProcessingCode('5425003944130');
$brandCode = new BrandCode('AAA01');
$gtin = new GS1('110101010', BarcodeFormat::EAN13);
$createdBy = ActorId::generate();
$updatedAt = new \DateTimeImmutable('2026-09-22 10:00:00', new \DateTimeZone('UTC'));
// WHEN
@ -119,9 +178,10 @@ describe('coupon', function (): void {
$availability,
$validity,
$legal,
$gtin,
$code,
$brandCode,
$createdBy,
$gtin,
$updatedAt
);
@ -141,10 +201,11 @@ describe('coupon', function (): void {
$diffusion = new CouponDiffusion(['2026-08-25', '2026-10-31']);
$availability = new CouponAvailabilityCalendar(['2026-08-25', '2026-10-31']);
$validity = new CouponValidity(30, new DateTime('2026-11-30'));
$legal = new CouponLegalInformation('Lorem ipsum dolor sit amet consectetur adipiscing elit.', Country::FR);
$gtin = new GS1('110101010', BarcodeFormat::EAN13);
$legal = [new CouponLegalInformation('Lorem ipsum dolor sit amet consectetur adipiscing elit.', Country::FR)];
$code = new ProcessingCode('5425003944130');
$brandCode = new BrandCode('AAA01');
$createdBy = ActorId::generate();
$gtin = new GS1('110101010', BarcodeFormat::EAN13);
// WHEN
$coupon = Coupon::create(
@ -158,9 +219,10 @@ describe('coupon', function (): void {
$availability,
$validity,
$legal,
$gtin,
$code,
$brandCode
$brandCode,
$createdBy,
$gtin,
);
// THEN
@ -175,9 +237,10 @@ describe('coupon', function (): void {
->and($coupon->availability)->toBe($availability)
->and($coupon->validity)->toBe($validity)
->and($coupon->legal)->toBe($legal)
->and($coupon->gtin)->toBe($gtin)
->and($coupon->code)->toBe($code)
->and($coupon->brandCode)->toBe($brandCode)
->and($coupon->createdBy)->toBe($createdBy)
->and($coupon->gtin)->toBe($gtin)
->and($coupon->updatedAt)->toBeNull()
->and($coupon->updatedAt())->toBeNull();
});
@ -193,10 +256,11 @@ describe('coupon', function (): void {
$diffusion = new CouponDiffusion(['2026-08-25', '2026-10-31']);
$availability = new CouponAvailabilityCalendar(['2026-08-25', '2026-10-31']);
$validity = new CouponValidity(30, new DateTime('2026-11-30'));
$legal = new CouponLegalInformation('Lorem ipsum dolor sit amet consectetur adipiscing elit.', Country::FR);
$gtin = new GS1('110101010', BarcodeFormat::EAN13);
$legal = [new CouponLegalInformation('Lorem ipsum dolor sit amet consectetur adipiscing elit.', Country::FR)];
$code = new ProcessingCode('5425003944130');
$brandCode = new BrandCode('AAA01');
$createdBy = ActorId::generate();
$gtin = new GS1('110101010', BarcodeFormat::EAN13);
// WHEN
$firstCoupon = Coupon::create(
@ -210,9 +274,10 @@ describe('coupon', function (): void {
$availability,
$validity,
$legal,
$gtin,
$code,
$brandCode
$brandCode,
$createdBy,
$gtin
);
$secondCoupon = Coupon::create(
$name,
@ -225,9 +290,10 @@ describe('coupon', function (): void {
$availability,
$validity,
$legal,
$gtin,
$code,
$brandCode
$brandCode,
$createdBy,
$gtin
);
// THEN
@ -249,10 +315,11 @@ describe('coupon', function (): void {
new CouponDiffusion(['2026-08-25', '2026-10-31']),
new CouponAvailabilityCalendar(['2026-08-25', '2026-10-31']),
new CouponValidity(30, new DateTime('2026-11-30')),
new CouponLegalInformation('Lorem ipsum dolor sit amet consectetur adipiscing elit.', Country::FR),
new GS1('110101010', BarcodeFormat::EAN13),
[new CouponLegalInformation('Lorem ipsum dolor sit amet consectetur adipiscing elit.', Country::FR)],
new ProcessingCode('5425003944130'),
new BrandCode('AAA01')
new BrandCode('AAA01'),
ActorId::generate(),
new GS1('110101010', BarcodeFormat::EAN13),
);
// WHEN