fix: 🐛 some fixes on the structure in sprint2

This commit is contained in:
K Muller 2026-10-02 11:23:41 +02:00 • committed by Corentin Huet
parent 567a5cd48e
commit a9147e27c7
19 changed files with 52 additions and 385 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\Campaign\CampaignCode;
use Domain\Models\ValueObjects\Campaign\CampaignCoupon;
@ -28,6 +29,7 @@ final readonly class Campaign implements AggregateRoot, HasTimestampIdentifier
public bool $printAllAtOnce,
public array $coupons,
public BrandCode $brandCode,
public ActorId $actorId,
public ?\DateTimeInterface $updatedAt = null,
) {
foreach ($this->coupons as $coupon) {
@ -62,6 +64,7 @@ final readonly class Campaign implements AggregateRoot, HasTimestampIdentifier
bool $printAllAtOnce,
array $coupons,
BrandCode $brandCode,
ActorId $actorId,
?\DateTimeInterface $updatedAt = null,
): Campaign {
return new self(
@ -72,6 +75,7 @@ final readonly class Campaign implements AggregateRoot, HasTimestampIdentifier
printAllAtOnce: $printAllAtOnce,
coupons: $coupons,
brandCode: $brandCode,
actorId: $actorId,
updatedAt: $updatedAt,
);
}
@ -87,6 +91,7 @@ final readonly class Campaign implements AggregateRoot, HasTimestampIdentifier
bool $printAllAtOnce,
array $coupons,
BrandCode $brandCode,
ActorId $actorId,
?\DateTimeInterface $updatedAt = null,
): self {
return new self(
@ -97,6 +102,7 @@ final readonly class Campaign implements AggregateRoot, HasTimestampIdentifier
printAllAtOnce: $printAllAtOnce,
coupons: $coupons,
brandCode: $brandCode,
actorId: $actorId,
updatedAt: $updatedAt,
);
}

View file

@ -47,7 +47,7 @@ final readonly class Coupon implements AggregateRoot, HasTimestampIdentifier
public ActorId $createdBy,
public array $products = [],
public ?CouponAvailabilityCalendar $availabilityCalendar = null,
public ?GS1 $gtin = null,
public ?GS1 $gs1 = null,
public ?\DateTimeInterface $updatedAt = null,
) {
foreach ($this->couponValidityInformation as $validityInformation) {
@ -97,7 +97,7 @@ final readonly class Coupon implements AggregateRoot, HasTimestampIdentifier
ActorId $createdBy,
array $products = [],
?CouponAvailabilityCalendar $availabilityCalendar = null,
?GS1 $gtin = null,
?GS1 $gs1 = null,
?\DateTimeInterface $updatedAt = null,
): Coupon {
return new self(
@ -115,7 +115,7 @@ final readonly class Coupon implements AggregateRoot, HasTimestampIdentifier
createdBy: $createdBy,
products: $products,
availabilityCalendar: $availabilityCalendar,
gtin: $gtin,
gs1: $gs1,
updatedAt: $updatedAt,
);
}
@ -140,7 +140,7 @@ final readonly class Coupon implements AggregateRoot, HasTimestampIdentifier
ActorId $createdBy,
array $products = [],
?CouponAvailabilityCalendar $availabilityCalendar = null,
?GS1 $gtin = null,
?GS1 $gs1 = null,
?\DateTimeInterface $updatedAt = null,
): self {
return new self(
@ -158,7 +158,7 @@ final readonly class Coupon implements AggregateRoot, HasTimestampIdentifier
createdBy: $createdBy,
products: $products,
availabilityCalendar: $availabilityCalendar,
gtin: $gtin,
gs1: $gs1,
updatedAt: $updatedAt,
);
}

View file

@ -1,61 +0,0 @@
<?php
declare(strict_types=1);
namespace Domain\Models\Entities;
use Domain\Models\ValueObjects\Tag\TagId;
use Domain\Models\ValueObjects\Tag\TagName;
use Shared\DDD\Models\AggregateRoot;
use Shared\DDD\Models\HasTimestampIdentifier;
/**
* @implements \Shared\DDD\Models\AggregateRoot<\Domain\Models\ValueObjects\Tag\TagId>
*/
final readonly class Tag implements AggregateRoot, HasTimestampIdentifier
{
private function __construct(
public TagId $id,
public TagName $value,
public ?\DateTimeInterface $updatedAt = null,
) {
}
public function id(): TagId
{
return $this->id;
}
public function createdAt(): \DateTimeInterface
{
return $this->id->toDateTime();
}
public function updatedAt(): ?\DateTimeInterface
{
return $this->updatedAt;
}
public static function create(
TagName $value,
?\DateTimeInterface $updatedAt = null,
): Tag {
return new self(
id: TagId::generate(),
value: $value,
updatedAt: $updatedAt,
);
}
public static function hydrate(
TagId $id,
TagName $value,
?\DateTimeInterface $updatedAt = null,
): self {
return new self(
id: $id,
value: $value,
updatedAt: $updatedAt,
);
}
}

View file

@ -9,17 +9,7 @@ use Domain\Models\ValueObjects\Period;
final readonly class CouponDiffusion
{
public function __construct(
/** @var Period[] */
public array $periods,
public Period $period,
) {
if ($this->periods === []) {
throw new \DomainException('Diffusion requires at least one period.');
}
foreach ($this->periods as $period) {
if (!$period instanceof Period) {
throw new \DomainException('CouponDiffusion periods must be Period instances.');
}
}
}
}

View file

@ -7,7 +7,6 @@ namespace Domain\Models\ValueObjects\RequestedCoupon;
use Domain\Models\ValueObjects\Coupon\CouponValidity;
use Domain\Models\ValueObjects\Coupon\CouponValidityInformation;
use Domain\Models\ValueObjects\CouponName;
use Domain\Models\ValueObjects\CouponPicture;
use Domain\Models\ValueObjects\GS1;
use Domain\Models\ValueObjects\IncoCode;
use Domain\Models\ValueObjects\MoneyAmount;
@ -35,7 +34,6 @@ final readonly class RequestedCoupon
public Period $diffusion,
public MoneyAmount $moneyAmount,
public ProcessingCode $processingCode,
public CouponPicture $couponPicture,
public CouponValidity $couponValidity,
public array $couponValidityInformation,
public array $products = [],

View file

@ -1,16 +0,0 @@
<?php
declare(strict_types=1);
namespace Domain\Models\ValueObjects\Tag;
use Ramsey\Uuid\Uuid;
use Shared\DDD\Models\Uuidv7EntityId;
final readonly class TagId extends Uuidv7EntityId
{
public static function generate(): self
{
return new self(Uuid::uuid7());
}
}

View file

@ -1,16 +0,0 @@
<?php
declare(strict_types=1);
namespace Domain\Models\ValueObjects\Tag;
final readonly class TagName
{
public function __construct(
public string $value,
) {
if (mb_trim($this->value) === '') {
throw new \DomainException('Tag name cannot be empty.');
}
}
}

View file

@ -18,11 +18,9 @@ use Domain\Models\ValueObjects\CampaignRequest\CampaignRequestType;
use Domain\Models\ValueObjects\Coupon\CouponValidity;
use Domain\Models\ValueObjects\Coupon\CouponValidityInformation;
use Domain\Models\ValueObjects\CouponName;
use Domain\Models\ValueObjects\CouponPicture;
use Domain\Models\ValueObjects\IncoCode;
use Domain\Models\ValueObjects\MoneyAmount;
use Domain\Models\ValueObjects\Period;
use Domain\Models\ValueObjects\PicturePath;
use Domain\Models\ValueObjects\PrintRules;
use Domain\Models\ValueObjects\ProcessingCode;
use Domain\Models\ValueObjects\RequestedCoupon\RequestedCoupon;
@ -49,11 +47,6 @@ beforeEach(function (): void {
diffusion: new Period(new DateTime('2026-01-01'), new DateTime('2026-02-01')),
moneyAmount: new MoneyAmount(new Money(Currency::EUR, 300)),
processingCode: new ProcessingCode('PC1'),
couponPicture: new CouponPicture(
new PicturePath('coupons/product.jpg'),
new PicturePath('coupons/thumbnail.jpg'),
new PicturePath('coupons/inactive_thumbnail.jpg')
),
couponValidity: new CouponValidity(30, new DateTime('2026-02-01')),
couponValidityInformation: [
new CouponValidityInformation('Lorem ipsum dolor sit amet consectetur adipiscing elit.', Country::FRANCE),

View file

@ -26,7 +26,6 @@ use Domain\Models\ValueObjects\CampaignRequest\RejectionReason;
use Domain\Models\ValueObjects\Coupon\CouponValidity;
use Domain\Models\ValueObjects\Coupon\CouponValidityInformation;
use Domain\Models\ValueObjects\CouponName;
use Domain\Models\ValueObjects\CouponPicture;
use Domain\Models\ValueObjects\GS1;
use Domain\Models\ValueObjects\IncoCode;
use Domain\Models\ValueObjects\MoneyAmount;
@ -56,11 +55,6 @@ describe('find campaign request use case', function (): void {
new Period(new DateTime('2026-01-01'), new DateTime('2026-02-01')),
new MoneyAmount(new Money(Currency::EUR, 300)),
new ProcessingCode('PC1'),
new CouponPicture(
new PicturePath('coupons/product.jpg'),
new PicturePath('coupons/thumbnail.jpg'),
new PicturePath('coupons/inactive_thumbnail.jpg')
),
new CouponValidity(30, new DateTime('2026-02-01')),
[
new CouponValidityInformation('Lorem ipsum dolor sit amet consectetur adipiscing elit.', Country::FRANCE),

View file

@ -20,12 +20,10 @@ use Domain\Models\ValueObjects\CampaignRequest\CampaignRequestType;
use Domain\Models\ValueObjects\Coupon\CouponValidity;
use Domain\Models\ValueObjects\Coupon\CouponValidityInformation;
use Domain\Models\ValueObjects\CouponName;
use Domain\Models\ValueObjects\CouponPicture;
use Domain\Models\ValueObjects\GS1;
use Domain\Models\ValueObjects\IncoCode;
use Domain\Models\ValueObjects\MoneyAmount;
use Domain\Models\ValueObjects\Period;
use Domain\Models\ValueObjects\PicturePath;
use Domain\Models\ValueObjects\PrintRules;
use Domain\Models\ValueObjects\ProcessingCode;
use Domain\Models\ValueObjects\RequestedCoupon\RequestedCoupon;
@ -49,11 +47,6 @@ describe('list campaigns request use case', function (): void {
new Period(new DateTime('2026-01-01'), new DateTime('2026-02-01')),
new MoneyAmount(new Money(Currency::EUR, 300)),
new ProcessingCode('PC1'),
new CouponPicture(
new PicturePath('coupons/product.jpg'),
new PicturePath('coupons/thumbnail.jpg'),
new PicturePath('coupons/inactive_thumbnail.jpg')
),
new CouponValidity(30, new DateTime('2026-02-01')),
[
new CouponValidityInformation('Lorem ipsum dolor sit amet consectetur adipiscing elit.', Country::FRANCE),
@ -71,11 +64,6 @@ describe('list campaigns request use case', function (): void {
new Period(new DateTime('2026-01-01'), new DateTime('2026-02-01')),
new MoneyAmount(new Money(Currency::EUR, 300)),
new ProcessingCode('PC2'),
new CouponPicture(
new PicturePath('coupons/product.jpg'),
new PicturePath('coupons/thumbnail.jpg'),
new PicturePath('coupons/inactive_thumbnail.jpg')
),
new CouponValidity(30, new DateTime('2026-02-01')),
[
new CouponValidityInformation('Lorem ipsum dolor sit amet consectetur adipiscing elit.', Country::FRANCE),

View file

@ -23,12 +23,10 @@ use Domain\Models\ValueObjects\CampaignRequest\RejectionReason;
use Domain\Models\ValueObjects\Coupon\CouponValidity;
use Domain\Models\ValueObjects\Coupon\CouponValidityInformation;
use Domain\Models\ValueObjects\CouponName;
use Domain\Models\ValueObjects\CouponPicture;
use Domain\Models\ValueObjects\GS1;
use Domain\Models\ValueObjects\IncoCode;
use Domain\Models\ValueObjects\MoneyAmount;
use Domain\Models\ValueObjects\Period;
use Domain\Models\ValueObjects\PicturePath;
use Domain\Models\ValueObjects\PrintRules;
use Domain\Models\ValueObjects\ProcessingCode;
use Domain\Models\ValueObjects\RequestedCoupon\RequestedCoupon;
@ -50,11 +48,6 @@ describe('reject campaign request use case', function (): void {
new Period(new DateTime('2026-01-01'), new DateTime('2026-02-01')),
new MoneyAmount(new Money(Currency::EUR, 300)),
new ProcessingCode('PC1'),
new CouponPicture(
new PicturePath('coupons/product.jpg'),
new PicturePath('coupons/thumbnail.jpg'),
new PicturePath('coupons/inactive_thumbnail.jpg')
),
new CouponValidity(30, new DateTime('2026-02-01')),
[
new CouponValidityInformation('Lorem ipsum dolor sit amet consectetur adipiscing elit.', Country::FRANCE),

View file

@ -18,12 +18,10 @@ use Domain\Models\ValueObjects\CampaignRequest\RejectionReason;
use Domain\Models\ValueObjects\Coupon\CouponValidity;
use Domain\Models\ValueObjects\Coupon\CouponValidityInformation;
use Domain\Models\ValueObjects\CouponName;
use Domain\Models\ValueObjects\CouponPicture;
use Domain\Models\ValueObjects\GS1;
use Domain\Models\ValueObjects\IncoCode;
use Domain\Models\ValueObjects\MoneyAmount;
use Domain\Models\ValueObjects\Period;
use Domain\Models\ValueObjects\PicturePath;
use Domain\Models\ValueObjects\PrintRules;
use Domain\Models\ValueObjects\ProcessingCode;
use Domain\Models\ValueObjects\RequestedCoupon\RequestedCoupon;
@ -45,11 +43,6 @@ describe('campaign request', function (): void {
new Period(new DateTime('2026-01-01'), new DateTime('2026-02-01')),
new MoneyAmount(new Money(Currency::EUR, 300)),
new ProcessingCode('PC1'),
new CouponPicture(
new PicturePath('coupons/product.jpg'),
new PicturePath('coupons/thumbnail.jpg'),
new PicturePath('coupons/inactive_thumbnail.jpg')
),
new CouponValidity(30, new DateTime('2026-02-01')),
[
new CouponValidityInformation('Lorem ipsum dolor sit amet consectetur adipiscing elit.', Country::FRANCE),

View file

@ -7,6 +7,7 @@ namespace Tests\Unit\Domain\Models\Entities;
use Carbon\CarbonImmutable;
use Shared\Enums\Country;
use Domain\Models\Entities\Campaign;
use Domain\Models\ValueObjects\Actor\ActorId;
use Domain\Models\ValueObjects\Brand\BrandCode;
use Domain\Models\ValueObjects\Campaign\CampaignCode;
use Domain\Models\ValueObjects\Campaign\CampaignCoupon;
@ -36,6 +37,7 @@ describe('campaign', function (): void {
)
];
$this->brandCode = new BrandCode('AAA01');
$this->actorId = ActorId::generate();
});
afterEach(function (): void {
@ -55,6 +57,7 @@ describe('campaign', function (): void {
$this->printAllAtOnce,
$this->coupons,
$this->brandCode,
$this->actorId
);
// THEN
@ -82,6 +85,7 @@ describe('campaign', function (): void {
$this->printAllAtOnce,
[],
$this->brandCode,
$this->actorId
);
// THEN
@ -102,6 +106,7 @@ describe('campaign', function (): void {
$this->printAllAtOnce,
$this->coupons,
$this->brandCode,
$this->actorId,
$updatedAt
);
@ -118,7 +123,8 @@ describe('campaign', function (): void {
$this->publication,
$this->printAllAtOnce,
$this->coupons,
$this->brandCode
$this->brandCode,
$this->actorId
);
// THEN
@ -141,7 +147,8 @@ describe('campaign', function (): void {
$this->publication,
$this->printAllAtOnce,
$this->coupons,
$this->brandCode
$this->brandCode,
$this->actorId
);
$secondCampaign = Campaign::create(
$this->code,
@ -149,7 +156,8 @@ describe('campaign', function (): void {
$this->publication,
$this->printAllAtOnce,
$this->coupons,
$this->brandCode
$this->brandCode,
$this->actorId
);
// THEN
@ -167,7 +175,8 @@ describe('campaign', function (): void {
$this->publication,
$this->printAllAtOnce,
$this->coupons,
$this->brandCode
$this->brandCode,
$this->actorId
);
// WHEN
@ -190,7 +199,8 @@ describe('campaign', function (): void {
$this->publication,
$this->printAllAtOnce,
$coupons,
$this->brandCode
$this->brandCode,
$this->actorId
))->toThrow(\DomainException::class, 'Campaign coupons must be CampaignCoupon instances.');
});
});

View file

@ -42,7 +42,7 @@ describe('coupon', function (): void {
new PicturePath('files/thumbnail.jpg'),
new PicturePath('files/inactive_thumbnail.jpg')
);
$this->diffusion = new CouponDiffusion([new Period(new DateTime('2026-01-01'), new DateTime('2026-02-01'))]);
$this->diffusion = new CouponDiffusion(new Period(new DateTime('2026-01-01'), new DateTime('2026-02-01')));
$this->validity = new CouponValidity(30, new DateTime('2026-02-01'));
$this->couponValidityInformation = [
new CouponValidityInformation(
@ -61,7 +61,7 @@ describe('coupon', function (): void {
$this->createdBy = ActorId::generate();
$this->products = [new IncoCode(35784), new IncoCode(15522)];
$this->availabilityCalendar = new CouponAvailabilityCalendar([new Period(new DateTime('2026-08-25'), new DateTime('2026-10-31'))]);
$this->gtin = new GS1('110101010', BarcodeFormat::EAN13);
$this->gs1 = new GS1('110101010', BarcodeFormat::EAN13);
});
afterEach(function (): void {
@ -88,7 +88,7 @@ describe('coupon', function (): void {
$this->createdBy,
$this->products,
$this->availabilityCalendar,
$this->gtin,
$this->gs1,
);
// THEN
@ -106,7 +106,7 @@ describe('coupon', function (): void {
->and($coupon->createdBy)->toBe($this->createdBy)
->and($coupon->products)->toBe($this->products)
->and($coupon->availabilityCalendar)->toBe($this->availabilityCalendar)
->and($coupon->gtin)->toBe($this->gtin)
->and($coupon->gs1)->toBe($this->gs1)
->and($coupon->updatedAt)->toBeNull()
->and($coupon->updatedAt())->toBeNull();
});
@ -136,7 +136,7 @@ describe('coupon', function (): void {
// THEN
expect($coupon->products)->toBe($this->products)
->and($coupon->availabilityCalendar)->toBe($this->availabilityCalendar)
->and($coupon->gtin)->toBeNull();
->and($coupon->gs1)->toBeNull();
});
it('hydrates a coupon without availability calendar', function (): void {
@ -158,13 +158,13 @@ describe('coupon', function (): void {
brandCode: $this->brandCode,
createdBy: $this->createdBy,
products: $this->products,
gtin: $this->gtin
gs1: $this->gs1
);
// THEN
expect($coupon->availabilityCalendar)->toBeNull()
->and($coupon->products)->toBe($this->products)
->and($coupon->gtin)->toBe($this->gtin);
->and($coupon->gs1)->toBe($this->gs1);
});
it('hydrates a coupon without products', function (): void {
@ -186,13 +186,13 @@ describe('coupon', function (): void {
brandCode: $this->brandCode,
createdBy: $this->createdBy,
availabilityCalendar: $this->availabilityCalendar,
gtin: $this->gtin
gs1: $this->gs1
);
// THEN
expect($coupon->products)->toBe([])
->and($coupon->availabilityCalendar)->toBe($this->availabilityCalendar)
->and($coupon->gtin)->toBe($this->gtin);
->and($coupon->gs1)->toBe($this->gs1);
});
it('hydrates a coupon with only required fields', function (): void {
@ -219,7 +219,7 @@ describe('coupon', function (): void {
expect($coupon->id())->toBe($id)
->and($coupon->products)->toBe([])
->and($coupon->availabilityCalendar)->toBeNull()
->and($coupon->gtin)->toBeNull()
->and($coupon->gs1)->toBeNull()
->and($coupon->updatedAt)->toBeNull()
->and($coupon->updatedAt())->toBeNull();
});
@ -244,7 +244,7 @@ describe('coupon', function (): void {
$this->createdBy,
$this->products,
$this->availabilityCalendar,
$this->gtin,
$this->gs1,
);
// THEN
@ -272,7 +272,7 @@ describe('coupon', function (): void {
$this->createdBy,
$this->products,
$this->availabilityCalendar,
$this->gtin,
$this->gs1,
))->toThrow(\DomainException::class, 'Coupon validity information must be CouponValidityInformation instances.');
});
@ -296,7 +296,7 @@ describe('coupon', function (): void {
$this->createdBy,
$this->products,
$this->availabilityCalendar,
$this->gtin,
$this->gs1,
))->toThrow(\DomainException::class, 'Coupon legal information must be CouponLegalInformation instances.');
});
@ -321,7 +321,7 @@ describe('coupon', function (): void {
$this->createdBy,
$this->products,
$this->availabilityCalendar,
$this->gtin,
$this->gs1,
$updatedAt
);
@ -346,7 +346,7 @@ describe('coupon', function (): void {
$this->createdBy,
$this->products,
$this->availabilityCalendar,
$this->gtin,
$this->gs1,
);
// THEN
@ -364,7 +364,7 @@ describe('coupon', function (): void {
->and($coupon->createdBy)->toBe($this->createdBy)
->and($coupon->products)->toBe($this->products)
->and($coupon->availabilityCalendar)->toBe($this->availabilityCalendar)
->and($coupon->gtin)->toBe($this->gtin)
->and($coupon->gs1)->toBe($this->gs1)
->and($coupon->updatedAt)->toBeNull()
->and($coupon->updatedAt())->toBeNull();
});
@ -385,7 +385,7 @@ describe('coupon', function (): void {
$this->createdBy,
$this->products,
$this->availabilityCalendar,
$this->gtin,
$this->gs1,
);
$secondCoupon = Coupon::create(
$this->code,
@ -401,7 +401,7 @@ describe('coupon', function (): void {
$this->createdBy,
$this->products,
$this->availabilityCalendar,
$this->gtin,
$this->gs1,
);
// THEN
@ -427,7 +427,7 @@ describe('coupon', function (): void {
$this->createdBy,
$this->products,
$this->availabilityCalendar,
$this->gtin,
$this->gs1,
);
// WHEN

View file

@ -1,99 +0,0 @@
<?php
declare(strict_types=1);
namespace Tests\Unit\Domain\Models\Entities;
use Carbon\CarbonImmutable;
use Domain\Models\ValueObjects\Tag\TagId;
use Domain\Models\ValueObjects\Tag\TagName;
use Domain\Models\Entities\Tag;
use Ramsey\Uuid\Uuid;
covers(Tag::class);
describe('tag', function (): void {
beforeEach(function (): void {
$this->value = new TagName('Name');
});
afterEach(function (): void {
CarbonImmutable::setTestNow();
});
it('creates a tag', function (): void {
// GIVEN
$id = TagId::generate();
// WHEN
$tag = Tag::hydrate(
$id,
$this->value,
);
// THEN
expect($tag->id())->toBe($id)
->and($tag->value)->toBe($this->value)
->and($tag->updatedAt)->toBeNull()
->and($tag->updatedAt())->toBeNull();
});
it('creates a tag with an explicit updatedAt date', function (): void {
// GIVEN
$id = TagId::generate();
$updatedAt = new \DateTimeImmutable('2026-09-22 10:00:00', new \DateTimeZone('UTC'));
// WHEN
$tag = Tag::hydrate(
$id,
$this->value,
$updatedAt
);
// THEN
expect($tag->updatedAt)->toBe($updatedAt)
->and($tag->updatedAt())->toBe($updatedAt);
});
it('creates a new tag with a freshly generated id', function (): void {
// GIVEN / WHEN
$tag = Tag::create(
$this->value,
);
// THEN
expect($tag->id())->toBeInstanceOf(TagId::class)
->and($tag->value)->toBe($this->value)
->and($tag->updatedAt)->toBeNull()
->and($tag->updatedAt())->toBeNull();
});
it('generates a different id for each created tag', function (): void {
// GIVEN / WHEN
$firstTag = Tag::create(
$this->value
);
$secondTag = Tag::create(
$this->value
);
// THEN
expect($firstTag->id()->equals($secondTag->id()))->toBeFalse();
});
it('returns the creation date extracted from the id', function (): void {
// GIVEN
$expected = new \DateTimeImmutable('2024-06-15 12:34:56.789000', new \DateTimeZone('UTC'));
$id = new TagId(Uuid::uuid7($expected));
$tag = Tag::hydrate(
$id,
$this->value,
);
// WHEN
$result = $tag->createdAt();
// THEN
expect($result->format('Y-m-d H:i:s.v'))->toBe($expected->format('Y-m-d H:i:s.v'));
});
});

View file

@ -13,45 +13,23 @@ covers(CouponDiffusion::class);
describe('coupon diffusion', function (): void {
it('creates a valid coupon diffusion with one period', function (): void {
// GIVEN
$periods = [
new Period(new DateTime('2026-01-01'), new DateTime('2026-02-01')),
];
$period = new Period(new DateTime('2026-01-01'), new DateTime('2026-02-01'));
// WHEN
$couponDiffusion = new CouponDiffusion($periods);
$couponDiffusion = new CouponDiffusion($period);
// THEN
expect($couponDiffusion->periods)->toBe($periods);
expect($couponDiffusion->period)->toBe($period);
});
it('creates a valid coupon diffusion with several periods', function (): void {
// GIVEN
$periods = [
new Period(new DateTime('2026-01-01'), new DateTime('2026-02-01')),
new Period(new DateTime('2026-03-01'), new DateTime('2026-04-01')),
];
$period = new Period(new DateTime('2026-01-01'), new DateTime('2026-02-01'));
// WHEN
$couponDiffusion = new CouponDiffusion($periods);
$couponDiffusion = new CouponDiffusion($period);
// THEN
expect($couponDiffusion->periods)->toBe($periods);
});
it('rejects a coupon diffusion without period', function (): void {
// GIVEN
$periods = [];
// GIVEN / THEN
expect(fn (): CouponDiffusion => new CouponDiffusion($periods))->toThrow(\DomainException::class);
});
it('rejects a coupon diffusion with a non-period element', function (): void {
// GIVEN
$periods = ['2026-08-25', '2026-10-31'];
// WHEN / THEN
expect(fn (): CouponDiffusion => new CouponDiffusion($periods))
->toThrow(\DomainException::class, 'CouponDiffusion periods must be Period instances.');
expect($couponDiffusion->period)->toBe($period);
});
});

View file

@ -10,12 +10,10 @@ use Domain\Enums\BarcodeFormat;
use Domain\Models\ValueObjects\Coupon\CouponValidity;
use Domain\Models\ValueObjects\Coupon\CouponValidityInformation;
use Domain\Models\ValueObjects\CouponName;
use Domain\Models\ValueObjects\CouponPicture;
use Domain\Models\ValueObjects\GS1;
use Domain\Models\ValueObjects\IncoCode;
use Domain\Models\ValueObjects\MoneyAmount;
use Domain\Models\ValueObjects\Period;
use Domain\Models\ValueObjects\PicturePath;
use Domain\Models\ValueObjects\PrintRules;
use Domain\Models\ValueObjects\ProcessingCode;
use Domain\Models\ValueObjects\RequestedCoupon\RequestedCoupon;
@ -34,11 +32,6 @@ describe('requested coupon', function (): void {
$this->diffusion = new Period(new DateTime('2026-01-01'), new DateTime('2026-02-01'));
$this->moneyAmount = new MoneyAmount(new Money(Currency::EUR, 300));
$this->processingCode = new ProcessingCode('PC1');
$this->couponPicture = new CouponPicture(
new PicturePath('coupons/product.jpg'),
new PicturePath('coupons/thumbnail.jpg'),
new PicturePath('coupons/inactive_thumbnail.jpg')
);
$this->couponValidity = new CouponValidity(30, new DateTime('2026-02-01'));
$this->franceValidityInformation = new CouponValidityInformation(
'Lorem ipsum dolor sit amet consectetur adipiscing elit.',
@ -70,7 +63,6 @@ describe('requested coupon', function (): void {
$this->diffusion,
$this->moneyAmount,
$this->processingCode,
$this->couponPicture,
$this->couponValidity,
$this->couponValidityInformation,
$this->products,
@ -85,7 +77,6 @@ describe('requested coupon', function (): void {
->and($coupon->diffusion)->toBe($this->diffusion)
->and($coupon->moneyAmount)->toBe($this->moneyAmount)
->and($coupon->processingCode)->toBe($this->processingCode)
->and($coupon->couponPicture)->toBe($this->couponPicture)
->and($coupon->couponValidity)->toBe($this->couponValidity)
->and($coupon->couponValidityInformation)->toBe($this->couponValidityInformation)
->and($coupon->products)->toBe($this->products)
@ -102,7 +93,6 @@ describe('requested coupon', function (): void {
diffusion: $this->diffusion,
moneyAmount: $this->moneyAmount,
processingCode: $this->processingCode,
couponPicture: $this->couponPicture,
couponValidity: $this->couponValidity,
couponValidityInformation: $this->couponValidityInformation,
printRules: $this->printRules,
@ -125,7 +115,6 @@ describe('requested coupon', function (): void {
diffusion: $this->diffusion,
moneyAmount: $this->moneyAmount,
processingCode: $this->processingCode,
couponPicture: $this->couponPicture,
couponValidity: $this->couponValidity,
couponValidityInformation: $this->couponValidityInformation,
products: $this->products,
@ -148,7 +137,6 @@ describe('requested coupon', function (): void {
diffusion: $this->diffusion,
moneyAmount: $this->moneyAmount,
processingCode: $this->processingCode,
couponPicture: $this->couponPicture,
couponValidity: $this->couponValidity,
couponValidityInformation: $this->couponValidityInformation,
products: $this->products,
@ -171,7 +159,6 @@ describe('requested coupon', function (): void {
diffusion: $this->diffusion,
moneyAmount: $this->moneyAmount,
processingCode: $this->processingCode,
couponPicture: $this->couponPicture,
couponValidity: $this->couponValidity,
couponValidityInformation: $this->couponValidityInformation,
products: $this->products,
@ -194,7 +181,6 @@ describe('requested coupon', function (): void {
diffusion: $this->diffusion,
moneyAmount: $this->moneyAmount,
processingCode: $this->processingCode,
couponPicture: $this->couponPicture,
couponValidity: $this->couponValidity,
couponValidityInformation: $this->couponValidityInformation,
);
@ -214,7 +200,6 @@ describe('requested coupon', function (): void {
diffusion: $this->diffusion,
moneyAmount: $this->moneyAmount,
processingCode: $this->processingCode,
couponPicture: $this->couponPicture,
couponValidity: $this->couponValidity,
couponValidityInformation: [],
))->toThrow(\DomainException::class, 'A coupon requires validity information for France.');
@ -228,7 +213,6 @@ describe('requested coupon', function (): void {
$this->diffusion,
$this->moneyAmount,
$this->processingCode,
$this->couponPicture,
$this->couponValidity,
['Not a CouponValidityInformation'],
$this->products,
@ -249,7 +233,6 @@ describe('requested coupon', function (): void {
diffusion: $this->diffusion,
moneyAmount: $moneyAmount,
processingCode: $this->processingCode,
couponPicture: $this->couponPicture,
couponValidity: $this->couponValidity,
couponValidityInformation: $this->couponValidityInformation,
);
@ -269,7 +252,6 @@ describe('requested coupon', function (): void {
diffusion: $this->diffusion,
moneyAmount: $moneyAmount,
processingCode: $this->processingCode,
couponPicture: $this->couponPicture,
couponValidity: $this->couponValidity,
couponValidityInformation: $this->couponValidityInformation,
);
@ -286,7 +268,6 @@ describe('requested coupon', function (): void {
diffusion: $this->diffusion,
moneyAmount: new MoneyAmount(new Money(Currency::EUR, 0)),
processingCode: $this->processingCode,
couponPicture: $this->couponPicture,
couponValidity: $this->couponValidity,
couponValidityInformation: $this->couponValidityInformation,
))->toThrow(\DomainException::class, 'Coupon face value must be between 0.01€ and 3.00€');
@ -300,7 +281,6 @@ describe('requested coupon', function (): void {
diffusion: $this->diffusion,
moneyAmount: new MoneyAmount(new Money(Currency::EUR, 301)),
processingCode: $this->processingCode,
couponPicture: $this->couponPicture,
couponValidity: $this->couponValidity,
couponValidityInformation: $this->couponValidityInformation,
))->toThrow(\DomainException::class, 'Coupon face value must be between 0.01€ and 3.00€');
@ -314,7 +294,6 @@ describe('requested coupon', function (): void {
diffusion: $this->diffusion,
moneyAmount: $this->moneyAmount,
processingCode: $this->processingCode,
couponPicture: $this->couponPicture,
couponValidity: $this->couponValidity,
couponValidityInformation: [$this->franceValidityInformation],
gs1: $this->gs1,
@ -329,7 +308,6 @@ describe('requested coupon', function (): void {
diffusion: $this->diffusion,
moneyAmount: $this->moneyAmount,
processingCode: $this->processingCode,
couponPicture: $this->couponPicture,
couponValidity: $this->couponValidity,
couponValidityInformation: [$this->beneluxValidityInformation],
gs1: $this->gs1,
@ -344,7 +322,6 @@ describe('requested coupon', function (): void {
diffusion: $this->diffusion,
moneyAmount: $this->moneyAmount,
processingCode: $this->processingCode,
couponPicture: $this->couponPicture,
couponValidity: $this->couponValidity,
couponValidityInformation: [$this->franceValidityInformation],
);

View file

@ -1,28 +0,0 @@
<?php
declare(strict_types=1);
namespace Tests\Unit\Domain\Models\ValueObjects\Tag;
use Domain\Models\ValueObjects\Tag\TagId;
covers(TagId::class);
describe('brand id', function (): void {
it('generates a unique tag id', function (): void {
// WHEN
$id = TagId::generate();
// THEN
expect($id)->toBeInstanceOf(TagId::class);
});
it('generates different ids on each call', function (): void {
// WHEN
$first = TagId::generate();
$second = TagId::generate();
// THEN
expect((string) $first)->not->toBe((string) $second);
});
});

View file

@ -1,33 +0,0 @@
<?php
declare(strict_types=1);
namespace Tests\Unit\Domain\Models\ValueObjects\Tag;
use Domain\Models\ValueObjects\Tag\TagName;
covers(TagName::class);
describe('tag name', function (): void {
beforeEach(function (): void {
$this->value = 'Name';
$this->emptyValue = '';
});
it('creates a valid tag name', function (): void {
// GIVEN / WHEN
$name = new TagName(
$this->value
);
// THEN
expect($name->value)->toBe($this->value);
});
it('rejects invalid tag name', function (): void {
// GIVEN / WHEN / THEN
expect(fn (): TagName => new TagName(
$this->emptyValue
))->toThrow(\DomainException::class);
});
});