ldc-mesbr-app/tests/Unit/Domain/Models/Entities/CouponTest.php
2026-10-14 11:53:24 +02:00

508 lines
16 KiB
PHP

<?php
declare(strict_types=1);
namespace Tests\Unit\Domain\Models\Entities;
use Carbon\CarbonImmutable;
use DateTime;
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\CouponCode;
use Domain\Models\ValueObjects\Coupon\CouponDiffusion;
use Domain\Models\ValueObjects\Coupon\CouponId;
use Domain\Models\ValueObjects\Coupon\CouponLegalInformation;
use Domain\Models\ValueObjects\Coupon\CouponLegalInformationArray;
use Domain\Models\ValueObjects\Coupon\CouponMovement;
use Domain\Models\ValueObjects\Coupon\CouponMovementArray;
use Domain\Models\ValueObjects\Coupon\CouponName;
use Domain\Models\ValueObjects\Coupon\CouponPicture;
use Domain\Models\ValueObjects\Coupon\CouponProductArray;
use Domain\Models\ValueObjects\Coupon\CouponValidityInformation;
use Domain\Models\ValueObjects\Coupon\CouponValidityInformationArray;
use Domain\Models\ValueObjects\IncoCode;
use Domain\Models\ValueObjects\MoneyAmount;
use Domain\Models\ValueObjects\Period;
use Domain\Models\ValueObjects\PicturePath;
use Domain\Models\ValueObjects\ProcessingCode;
use Domain\Models\ValueObjects\ProcessingCodeArray;
use Ramsey\Uuid\Uuid;
use Shared\Enums\Country;
use Shared\Enums\Currency;
use Shared\ValueObjects\Money;
covers(Coupon::class);
describe('coupon', function (): void {
$code = new CouponCode('AAA01');
$name = new CouponName('Name');
$amount = new MoneyAmount(new Money(Currency::EUR, 1));
$picture = new CouponPicture(
new PicturePath('files/product.jpg'),
new PicturePath('files/thumbnail.jpg'),
new PicturePath('files/mobileThumbnail.jpg'),
);
$diffusion = new CouponDiffusion(new Period(new DateTime('2026-01-01'), new DateTime('2026-02-01')));
$validityInformations = new CouponValidityInformationArray([
new CouponValidityInformation(
'Lorem ipsum dolor sit amet consectetur adipiscing elit.',
Country::FRANCE,
)
]);
$legalInformations = new CouponLegalInformationArray([
new CouponLegalInformation(
'Lorem ipsum dolor sit amet consectetur adipiscing elit.',
Country::FRANCE,
)
]);
$processingCode = new ProcessingCodeArray([
new ProcessingCode('5425003944130', Country::FRANCE),
]);
$brandCode = new BrandCode('AAA01');
$createdBy = ActorId::generate();
$products = new CouponProductArray([new IncoCode(35784), new IncoCode(15522)]);
$movements = new CouponMovementArray([new CouponMovement(100)]);
$availabilityCalendar = new CouponAvailabilityCalendar([
new Period(
new DateTime('2026-08-25'),
new DateTime('2026-10-31'),
)]);
afterEach(function (): void {
CarbonImmutable::setTestNow();
});
it('creates a coupon', function () use (
$code,
$name,
$amount,
$picture,
$diffusion,
$validityInformations,
$legalInformations,
$processingCode,
$brandCode,
$createdBy,
$products,
$movements,
$availabilityCalendar,
): void {
// GIVEN
$id = CouponId::generate();
// WHEN
$coupon = Coupon::hydrate(
id: $id,
code: $code,
name: $name,
amount: $amount,
picture: $picture,
diffusion: $diffusion,
validityInformations: $validityInformations,
legalInformations: $legalInformations,
processingCode: $processingCode,
brandCode: $brandCode,
createdBy: $createdBy,
products: $products,
movements: $movements,
availabilityCalendar: $availabilityCalendar,
);
// THEN
expect($coupon->id())->toBe($id)
->and($coupon->code)->toBe($code)
->and($coupon->name)->toBe($name)
->and($coupon->amount)->toBe($amount)
->and($coupon->picture)->toBe($picture)
->and($coupon->diffusion)->toBe($diffusion)
->and($coupon->validityInformations)->toBe($validityInformations)
->and($coupon->legalInformations)->toBe($legalInformations)
->and($coupon->processingCode)->toBe($processingCode)
->and($coupon->brandCode)->toBe($brandCode)
->and($coupon->createdBy)->toBe($createdBy)
->and($coupon->products)->toBe($products)
->and($coupon->availabilityCalendar)->toBe($availabilityCalendar)
->and($coupon->movements)->toBe($movements)
->and($coupon->updatedAt)->toBeNull()
->and($coupon->updatedAt())->toBeNull();
});
it('hydrates a coupon without availability calendar', function () use (
$code,
$name,
$amount,
$picture,
$diffusion,
$validityInformations,
$legalInformations,
$processingCode,
$brandCode,
$createdBy,
$products,
$movements,
): void {
// GIVEN
$id = CouponId::generate();
// WHEN
$coupon = Coupon::hydrate(
id: $id,
code: $code,
name: $name,
amount: $amount,
picture: $picture,
diffusion: $diffusion,
validityInformations: $validityInformations,
legalInformations: $legalInformations,
processingCode: $processingCode,
brandCode: $brandCode,
createdBy: $createdBy,
products: $products,
movements: $movements,
);
// THEN
expect($coupon->availabilityCalendar)->toBeNull()
->and($coupon->products)->toBe($products);
});
it('hydrates a coupon without products', function () use (
$code,
$name,
$amount,
$picture,
$diffusion,
$validityInformations,
$legalInformations,
$processingCode,
$brandCode,
$createdBy,
$movements,
$availabilityCalendar,
): void {
// GIVEN
$id = CouponId::generate();
// WHEN
$coupon = Coupon::hydrate(
id: $id,
code: $code,
name: $name,
amount: $amount,
picture: $picture,
diffusion: $diffusion,
validityInformations: $validityInformations,
legalInformations: $legalInformations,
processingCode: $processingCode,
brandCode: $brandCode,
createdBy: $createdBy,
products: new CouponProductArray(),
movements: $movements,
availabilityCalendar: $availabilityCalendar,
);
// THEN
expect($coupon->products->value)->toBe([])
->and($coupon->availabilityCalendar)->toBe($availabilityCalendar);
});
it('throws when validity information contains an invalid item', function () use (
$code,
$name,
$amount,
$picture,
$diffusion,
$legalInformations,
$processingCode,
$brandCode,
$createdBy,
$products,
$movements,
$availabilityCalendar,
): void {
// GIVEN
$id = CouponId::generate();
// WHEN / THEN
expect(fn (): Coupon => Coupon::hydrate(
id: $id,
code: $code,
name: $name,
amount: $amount,
picture: $picture,
diffusion: $diffusion,
validityInformations: new CouponValidityInformationArray(['Not a CouponValidityInformation']),
legalInformations: $legalInformations,
processingCode: $processingCode,
brandCode: $brandCode,
createdBy: $createdBy,
products: $products,
movements: $movements,
availabilityCalendar: $availabilityCalendar,
))->toThrow(\DomainException::class, 'Value of CouponValidityInformationArray must be CouponValidityInformation instances.');
});
it('throws when legal information contains an invalid item', function () use (
$code,
$name,
$amount,
$picture,
$diffusion,
$validityInformations,
$processingCode,
$brandCode,
$createdBy,
$products,
$movements,
$availabilityCalendar,
): void {
// GIVEN
$id = CouponId::generate();
// WHEN / THEN
expect(fn (): Coupon => Coupon::hydrate(
id: $id,
code: $code,
name: $name,
amount: $amount,
picture: $picture,
diffusion: $diffusion,
validityInformations: $validityInformations,
legalInformations: new CouponLegalInformationArray(['Not a CouponLegalInformation']),
processingCode: $processingCode,
brandCode: $brandCode,
createdBy: $createdBy,
products: $products,
movements: $movements,
availabilityCalendar: $availabilityCalendar,
))->toThrow(\DomainException::class, 'Value of CouponLegalInformationArray must be CouponLegalInformation instances.');
});
it('hydrates a coupon with an explicit updatedAt date', function () use (
$code,
$name,
$amount,
$picture,
$diffusion,
$validityInformations,
$legalInformations,
$processingCode,
$brandCode,
$createdBy,
$products,
$movements,
$availabilityCalendar,
): void {
// GIVEN
$id = CouponId::generate();
$updatedAt = new \DateTimeImmutable('2026-09-22 10:00:00', new \DateTimeZone('UTC'));
// WHEN
$coupon = Coupon::hydrate(
$id,
code: $code,
name: $name,
amount: $amount,
picture: $picture,
diffusion: $diffusion,
validityInformations: $validityInformations,
legalInformations: $legalInformations,
processingCode: $processingCode,
brandCode: $brandCode,
createdBy: $createdBy,
products: $products,
movements: $movements,
availabilityCalendar: $availabilityCalendar,
updatedAt: $updatedAt,
);
// THEN
expect($coupon->updatedAt)->toBe($updatedAt)
->and($coupon->updatedAt())->toBe($updatedAt);
});
it('creates a new coupon with a freshly generated id', function () use (
$code,
$name,
$amount,
$picture,
$diffusion,
$validityInformations,
$legalInformations,
$processingCode,
$brandCode,
$createdBy,
$products,
$movements,
$availabilityCalendar,
): void {
// GIVEN / WHEN
$coupon = Coupon::create(
code: $code,
name: $name,
amount: $amount,
picture: $picture,
diffusion: $diffusion,
validityInformations: $validityInformations,
legalInformations: $legalInformations,
processingCode: $processingCode,
brandCode: $brandCode,
createdBy: $createdBy,
products: $products,
movements: $movements,
availabilityCalendar: $availabilityCalendar,
);
// THEN
expect($coupon->id())->toBeInstanceOf(CouponId::class)
->and($coupon->code)->toBe($code)
->and($coupon->name)->toBe($name)
->and($coupon->amount)->toBe($amount)
->and($coupon->picture)->toBe($picture)
->and($coupon->diffusion)->toBe($diffusion)
->and($coupon->validityInformations)->toBe($validityInformations)
->and($coupon->legalInformations)->toBe($legalInformations)
->and($coupon->processingCode)->toBe($processingCode)
->and($coupon->brandCode)->toBe($brandCode)
->and($coupon->createdBy)->toBe($createdBy)
->and($coupon->products)->toBe($products)
->and($coupon->movements)->toBe($movements)
->and($coupon->availabilityCalendar)->toBe($availabilityCalendar)
->and($coupon->updatedAt)->toBeNull()
->and($coupon->updatedAt())->toBeNull();
});
it('generates a different id for each created coupon', function () use (
$code,
$name,
$amount,
$picture,
$diffusion,
$validityInformations,
$legalInformations,
$processingCode,
$brandCode,
$createdBy,
$products,
$movements,
$availabilityCalendar,
): void {
// GIVEN / WHEN
$firstCoupon = Coupon::create(
code: $code,
name: $name,
amount: $amount,
picture: $picture,
diffusion: $diffusion,
validityInformations: $validityInformations,
legalInformations: $legalInformations,
processingCode: $processingCode,
brandCode: $brandCode,
createdBy: $createdBy,
products: $products,
movements: $movements,
availabilityCalendar: $availabilityCalendar,
);
$secondCoupon = Coupon::create(
code: $code,
name: $name,
amount: $amount,
picture: $picture,
diffusion: $diffusion,
validityInformations: $validityInformations,
legalInformations: $legalInformations,
processingCode: $processingCode,
brandCode: $brandCode,
createdBy: $createdBy,
products: $products,
movements: $movements,
availabilityCalendar: $availabilityCalendar,
);
// THEN
expect($firstCoupon->id()->equals($secondCoupon->id()))->toBeFalse();
});
it('returns the creation date extracted from the id', function () use (
$code,
$name,
$amount,
$picture,
$diffusion,
$validityInformations,
$legalInformations,
$processingCode,
$brandCode,
$createdBy,
$products,
$movements,
$availabilityCalendar,
): void {
// GIVEN
$expected = new \DateTimeImmutable('2024-06-15 12:34:56.789000', new \DateTimeZone('UTC'));
$id = new CouponId(Uuid::uuid7($expected));
$coupon = Coupon::hydrate(
$id,
code: $code,
name: $name,
amount: $amount,
picture: $picture,
diffusion: $diffusion,
validityInformations: $validityInformations,
legalInformations: $legalInformations,
processingCode: $processingCode,
brandCode: $brandCode,
createdBy: $createdBy,
products: $products,
movements: $movements,
availabilityCalendar: $availabilityCalendar,
);
// WHEN
$result = $coupon->createdAt();
// THEN
expect($result->format('Y-m-d H:i:s.v'))->toBe($expected->format('Y-m-d H:i:s.v'));
});
it('computes the quantity from its movements', function () use (
$code,
$name,
$amount,
$picture,
$diffusion,
$validityInformations,
$legalInformations,
$processingCode,
$brandCode,
$createdBy,
$products,
): void {
// GIVEN
$coupon = Coupon::create(
code: $code,
name: $name,
amount: $amount,
picture: $picture,
diffusion: $diffusion,
validityInformations: $validityInformations,
legalInformations: $legalInformations,
processingCode: $processingCode,
brandCode: $brandCode,
createdBy: $createdBy,
products: $products,
movements: new CouponMovementArray([
new CouponMovement(1000),
new CouponMovement(-200),
]),
);
// WHEN
$quantity = $coupon->quantity();
// THEN
expect($quantity)->toBe(800);
});
});