test: ✅ update on coupon Entity and related VO
This commit is contained in:
parent
fdbde84728
commit
680c71ea87
59 changed files with 2351 additions and 1701 deletions
|
|
@ -7,7 +7,6 @@ namespace Tests\Unit\Application\UseCases\Brand\Create;
|
|||
use Application\UseCases\Brand\Create\CreateBrand;
|
||||
use Application\UseCases\Brand\Create\Input;
|
||||
use Application\UseCases\Brand\Create\Output;
|
||||
use Domain\Exceptions\BrandCodeAlreadyExistsException;
|
||||
use Domain\Models\Entities\Brand;
|
||||
use Domain\Models\ValueObjects\Brand\BrandCode;
|
||||
use Domain\Models\ValueObjects\Brand\BrandName;
|
||||
|
|
@ -77,7 +76,7 @@ describe('create brand use case validation rules', function (): void {
|
|||
$action = fn (): Output => $useCase->execute($input);
|
||||
|
||||
// THEN
|
||||
expect($action)->toThrow(BrandCodeAlreadyExistsException::class);
|
||||
expect($action)->toThrow(\DomainException::class);
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -48,7 +48,7 @@ describe('update brand use case', function () use ($existingBrand): void {
|
|||
&& $saved->contact === $newContact
|
||||
&& $saved->code === $brand->code
|
||||
&& $saved->name === $brand->name
|
||||
&& $saved->updatedAt !== null,
|
||||
&& $saved->updatedAt instanceof \DateTimeInterface,
|
||||
));
|
||||
|
||||
$useCase = new UpdateBrand($repository);
|
||||
|
|
@ -77,7 +77,7 @@ describe('update brand use case', function () use ($existingBrand): void {
|
|||
&& $saved->rcs === $brand->rcs
|
||||
&& $saved->code === $brand->code
|
||||
&& $saved->name === $brand->name
|
||||
&& $saved->updatedAt !== null,
|
||||
&& $saved->updatedAt instanceof \DateTimeInterface,
|
||||
));
|
||||
|
||||
$useCase = new UpdateBrand($repository);
|
||||
|
|
|
|||
|
|
@ -8,21 +8,26 @@ use Application\UseCases\CampaignRequest\Create\CreateCampaignRequest;
|
|||
use Application\UseCases\CampaignRequest\Create\Input;
|
||||
use Application\UseCases\CampaignRequest\Create\Output;
|
||||
use DateTime;
|
||||
use Domain\Exceptions\BrandNotFoundException;
|
||||
use Domain\Models\Entities\CampaignRequest;
|
||||
use Domain\Models\ValueObjects\Brand\BrandCode;
|
||||
use Domain\Models\ValueObjects\Campaign\CampaignName;
|
||||
use Domain\Models\ValueObjects\CampaignRequest\Applicant;
|
||||
use Domain\Models\ValueObjects\CampaignRequest\CampaignRequestStatus;
|
||||
use Domain\Models\ValueObjects\CampaignRequest\CampaignRequestType;
|
||||
use Domain\Models\ValueObjects\Coupon\CouponValidity;
|
||||
use Domain\Models\ValueObjects\Coupon\CouponIncoCode;
|
||||
use Domain\Models\ValueObjects\Coupon\CouponLegalInformation;
|
||||
use Domain\Models\ValueObjects\Coupon\CouponLegalInformationArray;
|
||||
use Domain\Models\ValueObjects\Coupon\CouponName;
|
||||
use Domain\Models\ValueObjects\Coupon\CouponPicture;
|
||||
use Domain\Models\ValueObjects\Coupon\CouponProcessingCode;
|
||||
use Domain\Models\ValueObjects\Coupon\CouponProcessingCodeArray;
|
||||
use Domain\Models\ValueObjects\Coupon\CouponProductArray;
|
||||
use Domain\Models\ValueObjects\Coupon\CouponValidityInformation;
|
||||
use Domain\Models\ValueObjects\CouponName;
|
||||
use Domain\Models\ValueObjects\IncoCode;
|
||||
use Domain\Models\ValueObjects\Coupon\CouponValidityInformationArray;
|
||||
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;
|
||||
use Domain\Models\ValueObjects\RequestedCoupon\RequestedCouponQuantity;
|
||||
use Domain\Ports\Repositories\BrandRepository;
|
||||
|
|
@ -34,33 +39,44 @@ use Shared\ValueObjects\Money;
|
|||
|
||||
covers(CreateCampaignRequest::class, Input::class, Output::class);
|
||||
|
||||
beforeEach(function (): void {
|
||||
$this->input = new Input(
|
||||
describe('create campaign request use case', function (): void {
|
||||
$makeInput = fn (): Input => new Input(
|
||||
brandCode: new BrandCode('AAA01'),
|
||||
name: new CampaignName('Campaign name'),
|
||||
applicant: new Applicant('John', 'Doe', new Email('john.doe@example.com')),
|
||||
campaignType: CampaignRequestType::CLUB,
|
||||
requestedCoupon: new RequestedCoupon(
|
||||
name: new CouponName('Coupon A'),
|
||||
couponName: new CouponName('Coupon A'),
|
||||
quantity: new RequestedCouponQuantity(100),
|
||||
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'),
|
||||
couponValidity: new CouponValidity(30, new DateTime('2026-02-01')),
|
||||
couponValidityInformation: [
|
||||
couponPicture: new CouponPicture(
|
||||
new PicturePath('files/product.jpg'),
|
||||
new PicturePath('files/thumbnail.jpg'),
|
||||
new PicturePath('files/mobileThumbnail.jpg')
|
||||
),
|
||||
couponProcessingCodes: new CouponProcessingCodeArray([
|
||||
new CouponProcessingCode('ABC1234567890', Country::FRANCE),
|
||||
]),
|
||||
couponValidityInformations: new CouponValidityInformationArray([
|
||||
new CouponValidityInformation('Lorem ipsum dolor sit amet consectetur adipiscing elit.', Country::FRANCE),
|
||||
],
|
||||
products: [new IncoCode(35784), new IncoCode(15522)],
|
||||
new CouponValidityInformation('Lorem ipsum dolor sit amet consectetur adipiscing elit.', Country::BENELUX)
|
||||
]),
|
||||
couponLegalInformations: new CouponLegalInformationArray([
|
||||
new CouponLegalInformation('Lorem ipsum dolor sit amet consectetur adipiscing elit.', Country::FRANCE),
|
||||
new CouponLegalInformation('Lorem ipsum dolor sit amet consectetur adipiscing elit.', Country::BENELUX)
|
||||
]),
|
||||
couponProducts: new CouponProductArray([new CouponIncoCode(35784), new CouponIncoCode(15522)]),
|
||||
printRules: new PrintRules(maxPerCustomer: 3)
|
||||
),
|
||||
);
|
||||
});
|
||||
|
||||
describe('create campaign request use case', function (): void {
|
||||
it('creates a campaign request when the brand exists', function (): void {
|
||||
it('creates a campaign request when the brand exists', function () use ($makeInput): void {
|
||||
// GIVEN
|
||||
$input = $makeInput();
|
||||
|
||||
$brandRepository = \Mockery::mock(BrandRepository::class);
|
||||
$brandRepository->shouldReceive('existsByCode')->once()->with($this->input->brandCode)->andReturn(true);
|
||||
$brandRepository->shouldReceive('existsByCode')->once()->with($input->brandCode)->andReturn(true);
|
||||
|
||||
$campaignRequestRepository = \Mockery::mock(CampaignRequestRepository::class);
|
||||
$campaignRequestRepository->shouldReceive('save')->once()->with(\Mockery::type(CampaignRequest::class));
|
||||
|
|
@ -68,20 +84,20 @@ describe('create campaign request use case', function (): void {
|
|||
$useCase = new CreateCampaignRequest($campaignRequestRepository, $brandRepository);
|
||||
|
||||
// WHEN
|
||||
$result = $useCase->execute($this->input);
|
||||
$result = $useCase->execute($input);
|
||||
|
||||
// THEN
|
||||
expect($result)->toBeInstanceOf(Output::class)
|
||||
->and($result->status)->toBe(CampaignRequestStatus::CREATED)
|
||||
->and($result->brandCode)->toBe($this->input->brandCode);
|
||||
->and($result->brandCode)->toBe($input->brandCode);
|
||||
});
|
||||
});
|
||||
|
||||
describe('create campaign request use case validation rules', function (): void {
|
||||
it('throws when the brand does not exist', function (): void {
|
||||
it('throws when the brand does not exist', function () use ($makeInput): void {
|
||||
// GIVEN
|
||||
$input = $makeInput();
|
||||
|
||||
$brandRepository = \Mockery::mock(BrandRepository::class);
|
||||
$brandRepository->shouldReceive('existsByCode')->once()->with($this->input->brandCode)->andReturn(false);
|
||||
$brandRepository->shouldReceive('existsByCode')->once()->with($input->brandCode)->andReturn(false);
|
||||
|
||||
$campaignRequestRepository = \Mockery::mock(CampaignRequestRepository::class);
|
||||
$campaignRequestRepository->shouldNotReceive('save');
|
||||
|
|
@ -89,9 +105,9 @@ describe('create campaign request use case validation rules', function (): void
|
|||
$useCase = new CreateCampaignRequest($campaignRequestRepository, $brandRepository);
|
||||
|
||||
// WHEN
|
||||
$action = fn (): Output => $useCase->execute($this->input);
|
||||
$action = fn (): Output => $useCase->execute($input);
|
||||
|
||||
// THEN
|
||||
expect($action)->toThrow(BrandNotFoundException::class);
|
||||
expect($action)->toThrow(\DomainException::class);
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -10,8 +10,6 @@ use Application\UseCases\CampaignRequest\Find\Output\CampaignRequestFound;
|
|||
use Application\UseCases\CampaignRequest\Find\Output\CampaignRequestNotFound;
|
||||
use Application\UseCases\CampaignRequest\Find\Output\Output;
|
||||
use DateTime;
|
||||
use Domain\Enums\BarcodeFormat;
|
||||
use Domain\Exceptions\BrandNotFoundException;
|
||||
use Domain\Models\Entities\Brand;
|
||||
use Domain\Models\Entities\CampaignRequest;
|
||||
use Domain\Models\ValueObjects\Brand\BrandCode;
|
||||
|
|
@ -23,16 +21,20 @@ use Domain\Models\ValueObjects\CampaignRequest\CampaignRequestId;
|
|||
use Domain\Models\ValueObjects\CampaignRequest\CampaignRequestStatus;
|
||||
use Domain\Models\ValueObjects\CampaignRequest\CampaignRequestType;
|
||||
use Domain\Models\ValueObjects\CampaignRequest\RejectionReason;
|
||||
use Domain\Models\ValueObjects\Coupon\CouponValidity;
|
||||
use Domain\Models\ValueObjects\Coupon\CouponIncoCode;
|
||||
use Domain\Models\ValueObjects\Coupon\CouponLegalInformation;
|
||||
use Domain\Models\ValueObjects\Coupon\CouponLegalInformationArray;
|
||||
use Domain\Models\ValueObjects\Coupon\CouponName;
|
||||
use Domain\Models\ValueObjects\Coupon\CouponPicture;
|
||||
use Domain\Models\ValueObjects\Coupon\CouponProcessingCode;
|
||||
use Domain\Models\ValueObjects\Coupon\CouponProcessingCodeArray;
|
||||
use Domain\Models\ValueObjects\Coupon\CouponProductArray;
|
||||
use Domain\Models\ValueObjects\Coupon\CouponValidityInformation;
|
||||
use Domain\Models\ValueObjects\CouponName;
|
||||
use Domain\Models\ValueObjects\GS1;
|
||||
use Domain\Models\ValueObjects\IncoCode;
|
||||
use Domain\Models\ValueObjects\Coupon\CouponValidityInformationArray;
|
||||
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;
|
||||
use Domain\Models\ValueObjects\RequestedCoupon\RequestedCouponQuantity;
|
||||
use Domain\Ports\Repositories\BrandRepository;
|
||||
|
|
@ -47,44 +49,51 @@ use Shared\ValueObjects\Rcs;
|
|||
covers(FindCampaignRequest::class, Input::class, CampaignRequestFound::class, CampaignRequestNotFound::class);
|
||||
|
||||
describe('find campaign request use case', function (): void {
|
||||
beforeEach(function (): void {
|
||||
$this->requestedCoupon = new RequestedCoupon(
|
||||
new CouponName('Coupon A'),
|
||||
new RequestedCouponQuantity(100),
|
||||
new Period(new DateTime('2026-01-01'), new DateTime('2026-02-01')),
|
||||
new MoneyAmount(new Money(Currency::EUR, 300)),
|
||||
new ProcessingCode('PC1'),
|
||||
new CouponValidity(30, new DateTime('2026-02-01')),
|
||||
[
|
||||
new CouponValidityInformation('Lorem ipsum dolor sit amet consectetur adipiscing elit.', Country::FRANCE),
|
||||
new CouponValidityInformation('Lorem ipsum dolor sit amet consectetur adipiscing elit.', Country::BENELUX)
|
||||
],
|
||||
[new IncoCode(35784), new IncoCode(15522)],
|
||||
new PrintRules(maxPerCustomer: 3),
|
||||
new GS1('01234567890128', BarcodeFormat::EAN13)
|
||||
);
|
||||
});
|
||||
$requestedCoupon = new RequestedCoupon(
|
||||
couponName: new CouponName('Coupon A'),
|
||||
quantity: new RequestedCouponQuantity(100),
|
||||
diffusion: new Period(new DateTime('2026-01-01'), new DateTime('2026-02-01')),
|
||||
moneyAmount: new MoneyAmount(new Money(Currency::EUR, 300)),
|
||||
couponPicture: new CouponPicture(
|
||||
new PicturePath('files/product.jpg'),
|
||||
new PicturePath('files/thumbnail.jpg'),
|
||||
new PicturePath('files/mobileThumbnail.jpg')
|
||||
),
|
||||
couponProcessingCodes: new CouponProcessingCodeArray([
|
||||
new CouponProcessingCode('ABC1234567890', Country::FRANCE),
|
||||
]),
|
||||
couponValidityInformations: new CouponValidityInformationArray([
|
||||
new CouponValidityInformation('Lorem ipsum dolor sit amet consectetur adipiscing elit.', Country::FRANCE),
|
||||
new CouponValidityInformation('Lorem ipsum dolor sit amet consectetur adipiscing elit.', Country::BENELUX)
|
||||
]),
|
||||
couponLegalInformations: new CouponLegalInformationArray([
|
||||
new CouponLegalInformation('Lorem ipsum dolor sit amet consectetur adipiscing elit.', Country::FRANCE),
|
||||
new CouponLegalInformation('Lorem ipsum dolor sit amet consectetur adipiscing elit.', Country::BENELUX)
|
||||
]),
|
||||
couponProducts: new CouponProductArray([new CouponIncoCode(35784), new CouponIncoCode(15522)]),
|
||||
printRules: new PrintRules(maxPerCustomer: 3),
|
||||
);
|
||||
|
||||
it('finds a campaign request by its id, along with its brand', function (): void {
|
||||
it('finds a campaign request by its id, along with its brand', function () use ($requestedCoupon): void {
|
||||
// GIVEN
|
||||
$id = CampaignRequestId::generate();
|
||||
$brandCode = new BrandCode('AAA01');
|
||||
$campaignRequest = CampaignRequest::hydrate(
|
||||
$id,
|
||||
$brandCode,
|
||||
new CampaignName('Campaign A'),
|
||||
new Applicant('John', 'Doe', new Email('john.doe@example.com')),
|
||||
CampaignRequestType::CLUB,
|
||||
$this->requestedCoupon,
|
||||
CampaignRequestStatus::CREATED,
|
||||
id: $id,
|
||||
brandCode: $brandCode,
|
||||
name: new CampaignName('Campaign A'),
|
||||
applicant: new Applicant('John', 'Doe', new Email('john.doe@example.com')),
|
||||
campaignType: CampaignRequestType::CLUB,
|
||||
requestedCoupon: $requestedCoupon,
|
||||
status: CampaignRequestStatus::CREATED,
|
||||
);
|
||||
$brand = Brand::hydrate(
|
||||
BrandId::generate(),
|
||||
$brandCode,
|
||||
new BrandName('Brand A'),
|
||||
new PicturePath('brands/logo.jpg'),
|
||||
new Rcs('RCS PARIS 111 222 333'),
|
||||
new Email('contact@example.com'),
|
||||
id: BrandId::generate(),
|
||||
code: $brandCode,
|
||||
name: new BrandName('Brand A'),
|
||||
logo: new PicturePath('brands/logo.jpg'),
|
||||
rcs: new Rcs('RCS PARIS 111 222 333'),
|
||||
contact: new Email('contact@example.com'),
|
||||
);
|
||||
|
||||
$repository = \Mockery::mock(CampaignRequestRepository::class);
|
||||
|
|
@ -109,20 +118,20 @@ describe('find campaign request use case', function (): void {
|
|||
->and($result->rejectionReason)->toBeNull();
|
||||
});
|
||||
|
||||
it('finds a rejected campaign request with its rejection reason', function (): void {
|
||||
it('finds a rejected campaign request with its rejection reason', function () use ($requestedCoupon): void {
|
||||
// GIVEN
|
||||
$id = CampaignRequestId::generate();
|
||||
$code = new BrandCode('AAA01');
|
||||
$rejectionReason = new RejectionReason('Missing legal documents.');
|
||||
$campaignRequest = CampaignRequest::hydrate(
|
||||
$id,
|
||||
$code,
|
||||
new CampaignName('Campaign A'),
|
||||
new Applicant('John', 'Doe', new Email('john.doe@example.com')),
|
||||
CampaignRequestType::CLUB,
|
||||
$this->requestedCoupon,
|
||||
CampaignRequestStatus::REJECTED,
|
||||
$rejectionReason,
|
||||
id: $id,
|
||||
brandCode: $code,
|
||||
name: new CampaignName('Campaign A'),
|
||||
applicant: new Applicant('John', 'Doe', new Email('john.doe@example.com')),
|
||||
campaignType: CampaignRequestType::CLUB,
|
||||
requestedCoupon: $requestedCoupon,
|
||||
status: CampaignRequestStatus::REJECTED,
|
||||
rejectionReason: $rejectionReason,
|
||||
);
|
||||
|
||||
$repository = \Mockery::mock(CampaignRequestRepository::class);
|
||||
|
|
@ -131,12 +140,12 @@ describe('find campaign request use case', function (): void {
|
|||
$brandRepository = \Mockery::mock(BrandRepository::class);
|
||||
$brandRepository->shouldReceive('findByCode')->once()->with($code)->andReturn(
|
||||
Brand::hydrate(
|
||||
BrandId::generate(),
|
||||
$code,
|
||||
new BrandName('Brand A'),
|
||||
new PicturePath('brands/logo.jpg'),
|
||||
new Rcs('RCS PARIS 111 222 333'),
|
||||
new Email('contact@example.com'),
|
||||
id: BrandId::generate(),
|
||||
code: $code,
|
||||
name: new BrandName('Brand A'),
|
||||
logo: new PicturePath('brands/logo.jpg'),
|
||||
rcs: new Rcs('RCS PARIS 111 222 333'),
|
||||
contact: new Email('contact@example.com'),
|
||||
)
|
||||
);
|
||||
|
||||
|
|
@ -170,18 +179,18 @@ describe('find campaign request use case', function (): void {
|
|||
expect($result)->toBeInstanceOf(CampaignRequestNotFound::class);
|
||||
});
|
||||
|
||||
it('throws when the campaign request references a brand that no longer exists', function (): void {
|
||||
it('throws when the campaign request references a brand that no longer exists', function () use ($requestedCoupon): void {
|
||||
// GIVEN
|
||||
$id = CampaignRequestId::generate();
|
||||
$brandCode = new BrandCode('AAA01');
|
||||
$campaignRequest = CampaignRequest::hydrate(
|
||||
$id,
|
||||
$brandCode,
|
||||
new CampaignName('Campaign A'),
|
||||
new Applicant('John', 'Doe', new Email('john.doe@example.com')),
|
||||
CampaignRequestType::CLUB,
|
||||
$this->requestedCoupon,
|
||||
CampaignRequestStatus::CREATED,
|
||||
id: $id,
|
||||
brandCode: $brandCode,
|
||||
name: new CampaignName('Campaign A'),
|
||||
applicant: new Applicant('John', 'Doe', new Email('john.doe@example.com')),
|
||||
campaignType: CampaignRequestType::CLUB,
|
||||
requestedCoupon: $requestedCoupon,
|
||||
status: CampaignRequestStatus::CREATED,
|
||||
);
|
||||
|
||||
$repository = \Mockery::mock(CampaignRequestRepository::class);
|
||||
|
|
@ -196,7 +205,7 @@ describe('find campaign request use case', function (): void {
|
|||
$action = fn (): Output => $useCase->execute(new Input(id: $id));
|
||||
|
||||
// THEN
|
||||
expect($action)->toThrow(BrandNotFoundException::class);
|
||||
expect($action)->toThrow(\DomainException::class);
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -5,7 +5,6 @@ declare(strict_types=1);
|
|||
namespace Application\UseCases\CampaignRequest\List;
|
||||
|
||||
use DateTime;
|
||||
use Domain\Enums\BarcodeFormat;
|
||||
use Domain\Models\Entities\CampaignRequest;
|
||||
use Domain\Models\ValueObjects\Brand\BrandCode;
|
||||
use Domain\Models\ValueObjects\Campaign\CampaignName;
|
||||
|
|
@ -17,15 +16,20 @@ use Domain\Models\ValueObjects\CampaignRequest\CampaignRequestSortCriteria;
|
|||
use Domain\Models\ValueObjects\CampaignRequest\CampaignRequestSortField;
|
||||
use Domain\Models\ValueObjects\CampaignRequest\CampaignRequestStatus;
|
||||
use Domain\Models\ValueObjects\CampaignRequest\CampaignRequestType;
|
||||
use Domain\Models\ValueObjects\Coupon\CouponValidity;
|
||||
use Domain\Models\ValueObjects\Coupon\CouponIncoCode;
|
||||
use Domain\Models\ValueObjects\Coupon\CouponLegalInformation;
|
||||
use Domain\Models\ValueObjects\Coupon\CouponLegalInformationArray;
|
||||
use Domain\Models\ValueObjects\Coupon\CouponName;
|
||||
use Domain\Models\ValueObjects\Coupon\CouponPicture;
|
||||
use Domain\Models\ValueObjects\Coupon\CouponProcessingCode;
|
||||
use Domain\Models\ValueObjects\Coupon\CouponProcessingCodeArray;
|
||||
use Domain\Models\ValueObjects\Coupon\CouponProductArray;
|
||||
use Domain\Models\ValueObjects\Coupon\CouponValidityInformation;
|
||||
use Domain\Models\ValueObjects\CouponName;
|
||||
use Domain\Models\ValueObjects\GS1;
|
||||
use Domain\Models\ValueObjects\IncoCode;
|
||||
use Domain\Models\ValueObjects\Coupon\CouponValidityInformationArray;
|
||||
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;
|
||||
use Domain\Models\ValueObjects\RequestedCoupon\RequestedCouponQuantity;
|
||||
use Domain\Ports\Repositories\CampaignRequestRepository;
|
||||
|
|
@ -39,69 +43,85 @@ use Shared\ValueObjects\Pagination\Pagination;
|
|||
covers(ListCampaignsRequest::class, Input::class, Output::class, CampaignRequestListItem::class);
|
||||
|
||||
describe('list campaigns request use case', function (): void {
|
||||
beforeEach(function (): void {
|
||||
$this->couponA = new RequestedCoupon(
|
||||
new CouponName('Coupon A'),
|
||||
new RequestedCouponQuantity(100),
|
||||
new Period(new DateTime('2026-01-01'), new DateTime('2026-02-01')),
|
||||
new MoneyAmount(new Money(Currency::EUR, 300)),
|
||||
new ProcessingCode('PC1'),
|
||||
new CouponValidity(30, new DateTime('2026-02-01')),
|
||||
[
|
||||
new CouponValidityInformation('Lorem ipsum dolor sit amet consectetur adipiscing elit.', Country::FRANCE),
|
||||
new CouponValidityInformation('Lorem ipsum dolor sit amet consectetur adipiscing elit.', Country::BENELUX)
|
||||
],
|
||||
[new IncoCode(35784), new IncoCode(15522)],
|
||||
new PrintRules(maxPerCustomer: 3),
|
||||
new GS1('01234567890128', BarcodeFormat::EAN13)
|
||||
);
|
||||
$couponA = new RequestedCoupon(
|
||||
couponName: new CouponName('Coupon A'),
|
||||
quantity: new RequestedCouponQuantity(100),
|
||||
diffusion: new Period(new DateTime('2026-01-01'), new DateTime('2026-02-01')),
|
||||
moneyAmount: new MoneyAmount(new Money(Currency::EUR, 300)),
|
||||
couponPicture: new CouponPicture(
|
||||
new PicturePath('files/product.jpg'),
|
||||
new PicturePath('files/thumbnail.jpg'),
|
||||
new PicturePath('files/mobileThumbnail.jpg')
|
||||
),
|
||||
couponProcessingCodes: new CouponProcessingCodeArray([
|
||||
new CouponProcessingCode('ABC1234567890', Country::FRANCE),
|
||||
]),
|
||||
couponValidityInformations: new CouponValidityInformationArray([
|
||||
new CouponValidityInformation('Lorem ipsum dolor sit amet consectetur adipiscing elit.', Country::FRANCE),
|
||||
new CouponValidityInformation('Lorem ipsum dolor sit amet consectetur adipiscing elit.', Country::BENELUX)
|
||||
]),
|
||||
couponLegalInformations: new CouponLegalInformationArray([
|
||||
new CouponLegalInformation('Lorem ipsum dolor sit amet consectetur adipiscing elit.', Country::FRANCE),
|
||||
new CouponLegalInformation('Lorem ipsum dolor sit amet consectetur adipiscing elit.', Country::BENELUX)
|
||||
]),
|
||||
couponProducts: new CouponProductArray([new CouponIncoCode(35784), new CouponIncoCode(15522)]),
|
||||
printRules: new PrintRules(maxPerCustomer: 3),
|
||||
);
|
||||
|
||||
$this->couponB = new RequestedCoupon(
|
||||
new CouponName('Coupon B'),
|
||||
new RequestedCouponQuantity(100),
|
||||
new Period(new DateTime('2026-01-01'), new DateTime('2026-02-01')),
|
||||
new MoneyAmount(new Money(Currency::EUR, 300)),
|
||||
new ProcessingCode('PC2'),
|
||||
new CouponValidity(30, new DateTime('2026-02-01')),
|
||||
[
|
||||
new CouponValidityInformation('Lorem ipsum dolor sit amet consectetur adipiscing elit.', Country::FRANCE),
|
||||
new CouponValidityInformation('Lorem ipsum dolor sit amet consectetur adipiscing elit.', Country::BENELUX)
|
||||
],
|
||||
[new IncoCode(24514), new IncoCode(46259)],
|
||||
new PrintRules(maxPerCustomer: 3),
|
||||
new GS1('01234567890128', BarcodeFormat::EAN13)
|
||||
);
|
||||
$couponB = new RequestedCoupon(
|
||||
couponName: new CouponName('Coupon B'),
|
||||
quantity: new RequestedCouponQuantity(100),
|
||||
diffusion: new Period(new DateTime('2026-01-01'), new DateTime('2026-02-01')),
|
||||
moneyAmount: new MoneyAmount(new Money(Currency::EUR, 300)),
|
||||
couponPicture: new CouponPicture(
|
||||
new PicturePath('files/product.jpg'),
|
||||
new PicturePath('files/thumbnail.jpg'),
|
||||
new PicturePath('files/mobileThumbnail.jpg')
|
||||
),
|
||||
couponProcessingCodes: new CouponProcessingCodeArray([
|
||||
new CouponProcessingCode('ABC1234567890', Country::FRANCE),
|
||||
]),
|
||||
couponValidityInformations: new CouponValidityInformationArray([
|
||||
new CouponValidityInformation('Lorem ipsum dolor sit amet consectetur adipiscing elit.', Country::FRANCE),
|
||||
new CouponValidityInformation('Lorem ipsum dolor sit amet consectetur adipiscing elit.', Country::BENELUX)
|
||||
]),
|
||||
couponLegalInformations: new CouponLegalInformationArray([
|
||||
new CouponLegalInformation('Lorem ipsum dolor sit amet consectetur adipiscing elit.', Country::FRANCE),
|
||||
new CouponLegalInformation('Lorem ipsum dolor sit amet consectetur adipiscing elit.', Country::BENELUX)
|
||||
]),
|
||||
couponProducts: new CouponProductArray([new CouponIncoCode(35784), new CouponIncoCode(15522)]),
|
||||
printRules: new PrintRules(maxPerCustomer: 3),
|
||||
);
|
||||
|
||||
$this->pagination = Pagination::firstPage();
|
||||
$pagination = Pagination::firstPage();
|
||||
|
||||
$this->sort = new CampaignRequestSortCriteria(
|
||||
clauses: [
|
||||
new CampaignRequestSortClause(field: CampaignRequestSortField::CreatedAt, direction: \SortDirection::Descending),
|
||||
]
|
||||
);
|
||||
});
|
||||
$sort = new CampaignRequestSortCriteria(
|
||||
clauses: [
|
||||
new CampaignRequestSortClause(field: CampaignRequestSortField::CreatedAt, direction: \SortDirection::Descending),
|
||||
]
|
||||
);
|
||||
|
||||
it('maps repository campaigns request to list items, preserving pagination and sort', function (): void {
|
||||
it('maps repository campaigns request to list items, preserving pagination and sort', function () use ($couponA, $couponB, $pagination): void {
|
||||
// GIVEN
|
||||
$campaignRequest1 = CampaignRequest::hydrate(
|
||||
CampaignRequestId::generate(),
|
||||
new BrandCode('AAA01'),
|
||||
new CampaignName('Campaign A'),
|
||||
new Applicant('John', 'Doe', new Email('john.doe@example.com')),
|
||||
CampaignRequestType::CLUB,
|
||||
$this->couponA,
|
||||
CampaignRequestStatus::CREATED,
|
||||
id: CampaignRequestId::generate(),
|
||||
brandCode: new BrandCode('AAA01'),
|
||||
name: new CampaignName('Campaign A'),
|
||||
applicant: new Applicant('John', 'Doe', new Email('john.doe@example.com')),
|
||||
campaignType: CampaignRequestType::CLUB,
|
||||
requestedCoupon: $couponA,
|
||||
status: CampaignRequestStatus::CREATED,
|
||||
);
|
||||
$campaignRequest2 = CampaignRequest::hydrate(
|
||||
CampaignRequestId::generate(),
|
||||
new BrandCode('AAA02'),
|
||||
new CampaignName('Campaign B'),
|
||||
new Applicant('John', 'Doe', new Email('john.doe@example.com')),
|
||||
CampaignRequestType::CLUB,
|
||||
$this->couponB,
|
||||
CampaignRequestStatus::CREATED,
|
||||
id: CampaignRequestId::generate(),
|
||||
brandCode: new BrandCode('AAA02'),
|
||||
name: new CampaignName('Campaign B'),
|
||||
applicant: new Applicant('John', 'Doe', new Email('john.doe@example.com')),
|
||||
campaignType: CampaignRequestType::CLUB,
|
||||
requestedCoupon: $couponB,
|
||||
status: CampaignRequestStatus::CREATED,
|
||||
);
|
||||
$paginated = new Paginated($this->pagination, [$campaignRequest1, $campaignRequest2], 2);
|
||||
$paginated = new Paginated($pagination, [$campaignRequest1, $campaignRequest2], 2);
|
||||
|
||||
$sort = new CampaignRequestSortCriteria(
|
||||
clauses: [
|
||||
|
|
@ -110,12 +130,12 @@ describe('list campaigns request use case', function (): void {
|
|||
]
|
||||
);
|
||||
$filters = new CampaignRequestFilters($campaignRequest2->brandCode, CampaignRequestStatus::CREATED);
|
||||
$input = new Input(pagination: $this->pagination, sort: $sort, filters: $filters);
|
||||
$input = new Input(pagination: $pagination, sort: $sort, filters: $filters);
|
||||
|
||||
$repository = \Mockery::mock(CampaignRequestRepository::class);
|
||||
$repository->shouldReceive('findAll')
|
||||
->once()
|
||||
->with($this->pagination, CampaignRequestSortCriteria::class, CampaignRequestFilters::class)
|
||||
->with($pagination, CampaignRequestSortCriteria::class, CampaignRequestFilters::class)
|
||||
->andReturn($paginated);
|
||||
|
||||
$useCase = new ListCampaignsRequest($repository);
|
||||
|
|
@ -135,29 +155,29 @@ describe('list campaigns request use case', function (): void {
|
|||
->and($items[0]->campaignType)->toBe($campaignRequest1->campaignType)
|
||||
->and($items[0]->status)->toBe($campaignRequest1->status)
|
||||
->and($result->campaignsRequest->getTotal())->toBe(2)
|
||||
->and($result->campaignsRequest->getPagination())->toBe($this->pagination);
|
||||
->and($result->campaignsRequest->getPagination())->toBe($pagination);
|
||||
});
|
||||
|
||||
it('lists campaigns request with filters', function (): void {
|
||||
it('lists campaigns request with filters', function () use ($couponA, $pagination, $sort): void {
|
||||
// GIVEN
|
||||
$campaignRequest = CampaignRequest::hydrate(
|
||||
CampaignRequestId::generate(),
|
||||
new BrandCode('AAA01'),
|
||||
new CampaignName('Campaign A'),
|
||||
new Applicant('John', 'Doe', new Email('john.doe@example.com')),
|
||||
CampaignRequestType::CLUB,
|
||||
$this->couponA,
|
||||
CampaignRequestStatus::CREATED,
|
||||
id: CampaignRequestId::generate(),
|
||||
brandCode: new BrandCode('AAA01'),
|
||||
name: new CampaignName('Campaign A'),
|
||||
applicant: new Applicant('John', 'Doe', new Email('john.doe@example.com')),
|
||||
campaignType: CampaignRequestType::CLUB,
|
||||
requestedCoupon: $couponA,
|
||||
status: CampaignRequestStatus::CREATED,
|
||||
);
|
||||
$paginated = new Paginated($this->pagination, [$campaignRequest], 1);
|
||||
$paginated = new Paginated($pagination, [$campaignRequest], 1);
|
||||
|
||||
$filters = new CampaignRequestFilters($campaignRequest->brandCode, CampaignRequestStatus::CREATED);
|
||||
$input = new Input(pagination: $this->pagination, sort: $this->sort, filters: $filters);
|
||||
$input = new Input(pagination: $pagination, sort: $sort, filters: $filters);
|
||||
|
||||
$repository = \Mockery::mock(CampaignRequestRepository::class);
|
||||
$repository->shouldReceive('findAll')
|
||||
->once()
|
||||
->with($this->pagination, $this->sort, $filters)
|
||||
->with($pagination, $sort, $filters)
|
||||
->andReturn($paginated);
|
||||
|
||||
$useCase = new ListCampaignsRequest($repository);
|
||||
|
|
@ -173,10 +193,10 @@ describe('list campaigns request use case', function (): void {
|
|||
->and($items[0]->name)->toBe($campaignRequest->name)
|
||||
->and($items[0]->status)->toBe($campaignRequest->status)
|
||||
->and($result->campaignsRequest->getTotal())->toBe(1)
|
||||
->and($result->campaignsRequest->getPagination())->toBe($this->pagination);
|
||||
->and($result->campaignsRequest->getPagination())->toBe($pagination);
|
||||
});
|
||||
|
||||
it('lists campaigns request with sort but without filters', function (): void {
|
||||
it('lists campaigns request with sort but without filters', function () use ($couponA, $couponB, $pagination, $sort): void {
|
||||
// GIVEN
|
||||
$campaignRequest1 = CampaignRequest::hydrate(
|
||||
CampaignRequestId::generate(),
|
||||
|
|
@ -184,7 +204,7 @@ describe('list campaigns request use case', function (): void {
|
|||
new CampaignName('Campaign A'),
|
||||
new Applicant('John', 'Doe', new Email('john.doe@example.com')),
|
||||
CampaignRequestType::CLUB,
|
||||
$this->couponA,
|
||||
$couponA,
|
||||
CampaignRequestStatus::CREATED,
|
||||
);
|
||||
$campaignRequest2 = CampaignRequest::hydrate(
|
||||
|
|
@ -193,22 +213,22 @@ describe('list campaigns request use case', function (): void {
|
|||
new CampaignName('Campaign B'),
|
||||
new Applicant('John', 'Doe', new Email('john.doe@example.com')),
|
||||
CampaignRequestType::CLUB,
|
||||
$this->couponB,
|
||||
$couponB,
|
||||
CampaignRequestStatus::CREATED,
|
||||
);
|
||||
$paginated = new Paginated($this->pagination, [$campaignRequest2, $campaignRequest1], 2);
|
||||
$paginated = new Paginated($pagination, [$campaignRequest2, $campaignRequest1], 2);
|
||||
|
||||
$sort = new CampaignRequestSortCriteria(
|
||||
clauses: [
|
||||
new CampaignRequestSortClause(field: CampaignRequestSortField::BrandCode, direction: \SortDirection::Descending),
|
||||
]
|
||||
);
|
||||
$input = new Input(pagination: $this->pagination, sort: $sort);
|
||||
$input = new Input(pagination: $pagination, sort: $sort);
|
||||
|
||||
$repository = \Mockery::mock(CampaignRequestRepository::class);
|
||||
$repository->shouldReceive('findAll')
|
||||
->once()
|
||||
->with($this->pagination, $sort, null)
|
||||
->with($pagination, $sort, null)
|
||||
->andReturn($paginated);
|
||||
|
||||
$useCase = new ListCampaignsRequest($repository);
|
||||
|
|
@ -222,18 +242,18 @@ describe('list campaigns request use case', function (): void {
|
|||
->and($items[0]->brandCode)->toBe($campaignRequest2->brandCode)
|
||||
->and($items[1]->brandCode)->toBe($campaignRequest1->brandCode)
|
||||
->and($result->campaignsRequest->getTotal())->toBe(2)
|
||||
->and($result->campaignsRequest->getPagination())->toBe($this->pagination);
|
||||
->and($result->campaignsRequest->getPagination())->toBe($pagination);
|
||||
});
|
||||
|
||||
it('returns an empty list without error when there are no campaigns request', function (): void {
|
||||
it('returns an empty list without error when there are no campaigns request', function () use ($pagination, $sort): void {
|
||||
// GIVEN
|
||||
$paginated = new Paginated($this->pagination, [], 0);
|
||||
$input = new Input(pagination: $this->pagination, sort: $this->sort);
|
||||
$paginated = new Paginated($pagination, [], 0);
|
||||
$input = new Input(pagination: $pagination, sort: $sort);
|
||||
|
||||
$repository = \Mockery::mock(CampaignRequestRepository::class);
|
||||
$repository->shouldReceive('findAll')
|
||||
->once()
|
||||
->with($this->pagination, $this->sort, null)
|
||||
->with($pagination, $sort, null)
|
||||
->andReturn($paginated);
|
||||
|
||||
$useCase = new ListCampaignsRequest($repository);
|
||||
|
|
|
|||
|
|
@ -11,7 +11,6 @@ use Application\UseCases\CampaignRequest\Reject\Output\Output;
|
|||
use Application\UseCases\CampaignRequest\Reject\RejectCampaignRequest;
|
||||
use Carbon\CarbonImmutable;
|
||||
use DateTime;
|
||||
use Domain\Enums\BarcodeFormat;
|
||||
use Domain\Models\Entities\CampaignRequest;
|
||||
use Domain\Models\ValueObjects\Brand\BrandCode;
|
||||
use Domain\Models\ValueObjects\Campaign\CampaignName;
|
||||
|
|
@ -20,15 +19,20 @@ use Domain\Models\ValueObjects\CampaignRequest\CampaignRequestId;
|
|||
use Domain\Models\ValueObjects\CampaignRequest\CampaignRequestStatus;
|
||||
use Domain\Models\ValueObjects\CampaignRequest\CampaignRequestType;
|
||||
use Domain\Models\ValueObjects\CampaignRequest\RejectionReason;
|
||||
use Domain\Models\ValueObjects\Coupon\CouponValidity;
|
||||
use Domain\Models\ValueObjects\Coupon\CouponIncoCode;
|
||||
use Domain\Models\ValueObjects\Coupon\CouponLegalInformation;
|
||||
use Domain\Models\ValueObjects\Coupon\CouponLegalInformationArray;
|
||||
use Domain\Models\ValueObjects\Coupon\CouponName;
|
||||
use Domain\Models\ValueObjects\Coupon\CouponPicture;
|
||||
use Domain\Models\ValueObjects\Coupon\CouponProcessingCode;
|
||||
use Domain\Models\ValueObjects\Coupon\CouponProcessingCodeArray;
|
||||
use Domain\Models\ValueObjects\Coupon\CouponProductArray;
|
||||
use Domain\Models\ValueObjects\Coupon\CouponValidityInformation;
|
||||
use Domain\Models\ValueObjects\CouponName;
|
||||
use Domain\Models\ValueObjects\GS1;
|
||||
use Domain\Models\ValueObjects\IncoCode;
|
||||
use Domain\Models\ValueObjects\Coupon\CouponValidityInformationArray;
|
||||
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;
|
||||
use Domain\Models\ValueObjects\RequestedCoupon\RequestedCouponQuantity;
|
||||
use Domain\Ports\Repositories\CampaignRequestRepository;
|
||||
|
|
@ -40,29 +44,36 @@ use Shared\ValueObjects\Money;
|
|||
covers(RejectCampaignRequest::class, Input::class, CampaignRequestRejected::class, CampaignRequestNotFound::class);
|
||||
|
||||
describe('reject campaign request use case', function (): void {
|
||||
beforeEach(function (): void {
|
||||
$this->requestedCoupon = new RequestedCoupon(
|
||||
new CouponName('Coupon A'),
|
||||
new RequestedCouponQuantity(100),
|
||||
new Period(new DateTime('2026-01-01'), new DateTime('2026-02-01')),
|
||||
new MoneyAmount(new Money(Currency::EUR, 300)),
|
||||
new ProcessingCode('PC1'),
|
||||
new CouponValidity(30, new DateTime('2026-02-01')),
|
||||
[
|
||||
new CouponValidityInformation('Lorem ipsum dolor sit amet consectetur adipiscing elit.', Country::FRANCE),
|
||||
new CouponValidityInformation('Lorem ipsum dolor sit amet consectetur adipiscing elit.', Country::BENELUX)
|
||||
],
|
||||
[new IncoCode(35784), new IncoCode(15522)],
|
||||
new PrintRules(maxPerCustomer: 3),
|
||||
new GS1('01234567890128', BarcodeFormat::EAN13)
|
||||
);
|
||||
});
|
||||
$requestedCoupon = new RequestedCoupon(
|
||||
couponName: new CouponName('Coupon A'),
|
||||
quantity: new RequestedCouponQuantity(100),
|
||||
diffusion: new Period(new DateTime('2026-01-01'), new DateTime('2026-02-01')),
|
||||
moneyAmount: new MoneyAmount(new Money(Currency::EUR, 300)),
|
||||
couponPicture: new CouponPicture(
|
||||
new PicturePath('files/product.jpg'),
|
||||
new PicturePath('files/thumbnail.jpg'),
|
||||
new PicturePath('files/mobileThumbnail.jpg')
|
||||
),
|
||||
couponProcessingCodes: new CouponProcessingCodeArray([
|
||||
new CouponProcessingCode('ABC1234567890', Country::FRANCE),
|
||||
]),
|
||||
couponValidityInformations: new CouponValidityInformationArray([
|
||||
new CouponValidityInformation('Lorem ipsum dolor sit amet consectetur adipiscing elit.', Country::FRANCE),
|
||||
new CouponValidityInformation('Lorem ipsum dolor sit amet consectetur adipiscing elit.', Country::BENELUX)
|
||||
]),
|
||||
couponLegalInformations: new CouponLegalInformationArray([
|
||||
new CouponLegalInformation('Lorem ipsum dolor sit amet consectetur adipiscing elit.', Country::FRANCE),
|
||||
new CouponLegalInformation('Lorem ipsum dolor sit amet consectetur adipiscing elit.', Country::BENELUX)
|
||||
]),
|
||||
couponProducts: new CouponProductArray([new CouponIncoCode(35784), new CouponIncoCode(15522)]),
|
||||
printRules: new PrintRules(maxPerCustomer: 3),
|
||||
);
|
||||
|
||||
afterEach(function (): void {
|
||||
CarbonImmutable::setTestNow();
|
||||
});
|
||||
|
||||
it('rejects a campaign request and persists it', function (): void {
|
||||
it('rejects a campaign request and persists it', function () use ($requestedCoupon): void {
|
||||
// GIVEN
|
||||
CarbonImmutable::setTestNow('2026-06-15 12:00:00 UTC');
|
||||
$id = CampaignRequestId::generate();
|
||||
|
|
@ -72,7 +83,7 @@ describe('reject campaign request use case', function (): void {
|
|||
new CampaignName('Campaign A'),
|
||||
new Applicant('John', 'Doe', new Email('john.doe@example.com')),
|
||||
CampaignRequestType::CLUB,
|
||||
$this->requestedCoupon,
|
||||
$requestedCoupon,
|
||||
CampaignRequestStatus::CREATED,
|
||||
);
|
||||
$reason = new RejectionReason('Missing legal documents.');
|
||||
|
|
@ -82,7 +93,7 @@ describe('reject campaign request use case', function (): void {
|
|||
$repository->shouldReceive('save')->once()->with(\Mockery::on(
|
||||
fn (CampaignRequest $saved): bool => $saved->status === CampaignRequestStatus::REJECTED
|
||||
&& $saved->rejectionReason === $reason
|
||||
&& $saved->updatedAt !== null,
|
||||
&& $saved->updatedAt instanceof \DateTimeInterface,
|
||||
));
|
||||
|
||||
$useCase = new RejectCampaignRequest($repository);
|
||||
|
|
@ -115,7 +126,7 @@ describe('reject campaign request use case', function (): void {
|
|||
expect($result)->toBeInstanceOf(CampaignRequestNotFound::class);
|
||||
});
|
||||
|
||||
it('propagates the domain exception when the campaign request cannot be rejected', function (): void {
|
||||
it('propagates the domain exception when the campaign request cannot be rejected', function () use ($requestedCoupon): void {
|
||||
// GIVEN
|
||||
$id = CampaignRequestId::generate();
|
||||
$campaignRequest = CampaignRequest::hydrate(
|
||||
|
|
@ -124,7 +135,7 @@ describe('reject campaign request use case', function (): void {
|
|||
new CampaignName('Campaign A'),
|
||||
new Applicant('John', 'Doe', new Email('john.doe@example.com')),
|
||||
CampaignRequestType::CLUB,
|
||||
$this->requestedCoupon,
|
||||
$requestedCoupon,
|
||||
CampaignRequestStatus::TRANSFORMED,
|
||||
);
|
||||
|
||||
|
|
@ -142,19 +153,4 @@ describe('reject campaign request use case', function (): void {
|
|||
// THEN
|
||||
expect($action)->toThrow(\DomainException::class, 'Only a created campaign request can be rejected.');
|
||||
});
|
||||
|
||||
it('never touches the repository when a rejection reason is missing', function (): void {
|
||||
// GIVEN
|
||||
$repository = \Mockery::mock(CampaignRequestRepository::class);
|
||||
$repository->shouldNotReceive('findById');
|
||||
$repository->shouldNotReceive('save');
|
||||
|
||||
$useCase = new RejectCampaignRequest($repository);
|
||||
|
||||
// WHEN
|
||||
$action = fn (): Output => $useCase->execute(new Input(id: CampaignRequestId::generate()));
|
||||
|
||||
// THEN
|
||||
expect($action)->toThrow(\ArgumentCountError::class);
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,23 +0,0 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Tests\Unit\Shared\Enums;
|
||||
|
||||
use Domain\Enums\BarcodeFormat;
|
||||
|
||||
covers(BarcodeFormat::class);
|
||||
|
||||
describe('barcode format', function (): void {
|
||||
it('has the expected cases with their backing values', function (): void {
|
||||
// THEN
|
||||
expect(BarcodeFormat::EAN13->value)->toBe('ean')
|
||||
->and(BarcodeFormat::CODE128->value)->toBe('code128')
|
||||
->and(BarcodeFormat::GS1_128->value)->toBe('gs1');
|
||||
});
|
||||
|
||||
it('exposes its case name', function (): void {
|
||||
// THEN
|
||||
expect(BarcodeFormat::EAN13->name)->toBe('EAN13');
|
||||
});
|
||||
});
|
||||
|
|
@ -1,24 +0,0 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Tests\Unit\Domain\Exceptions;
|
||||
|
||||
use Domain\Exceptions\BrandCodeAlreadyExistsException;
|
||||
use Domain\Models\ValueObjects\Brand\BrandCode;
|
||||
|
||||
covers(BrandCodeAlreadyExistsException::class);
|
||||
|
||||
describe('brand code already exists exception', function (): void {
|
||||
it('get the correct message', function (): void {
|
||||
// GIVEN
|
||||
$code = new BrandCode('AAA01');
|
||||
|
||||
// WHEN
|
||||
$exception = new BrandCodeAlreadyExistsException($code);
|
||||
|
||||
// THEN
|
||||
expect($exception->getMessage())->toBe('Brand code "AAA01" already exists.')
|
||||
->and($exception)->toBeInstanceOf(\DomainException::class);
|
||||
});
|
||||
});
|
||||
|
|
@ -12,36 +12,34 @@ use Ramsey\Uuid\Uuid;
|
|||
covers(Actor::class);
|
||||
|
||||
describe('actor', function (): void {
|
||||
beforeEach(function (): void {
|
||||
$this->displayName = new ActorDisplayName('John Doe');
|
||||
});
|
||||
$displayName = new ActorDisplayName('John Doe');
|
||||
|
||||
it('hydrates an actor', function (): void {
|
||||
it('hydrates an actor', function () use ($displayName): void {
|
||||
// GIVEN
|
||||
$id = ActorId::generate();
|
||||
|
||||
// WHEN
|
||||
$actor = Actor::hydrate(
|
||||
$id,
|
||||
$this->displayName
|
||||
$displayName,
|
||||
);
|
||||
|
||||
// THEN
|
||||
expect($actor->id())->toBe($id)
|
||||
->and($actor->displayName)->toBe($this->displayName)
|
||||
->and($actor->displayName)->toBe($displayName)
|
||||
->and($actor->updatedAt)->toBeNull()
|
||||
->and($actor->updatedAt())->toBeNull();
|
||||
});
|
||||
|
||||
it('hydrates an actor with an explicit updatedAt date', function (): void {
|
||||
it('hydrates an actor with an explicit updatedAt date', function () use ($displayName): void {
|
||||
// GIVEN
|
||||
$updatedAt = new \DateTimeImmutable('2026-06-15 12:00:00', new \DateTimeZone('UTC'));
|
||||
|
||||
// WHEN
|
||||
$actor = Actor::hydrate(
|
||||
ActorId::generate(),
|
||||
$this->displayName,
|
||||
$updatedAt
|
||||
$displayName,
|
||||
$updatedAt,
|
||||
);
|
||||
|
||||
// THEN
|
||||
|
|
@ -49,13 +47,13 @@ describe('actor', function (): void {
|
|||
->and($actor->updatedAt())->toBe($updatedAt);
|
||||
});
|
||||
|
||||
it('returns the creation date extracted from the id', function (): void {
|
||||
it('returns the creation date extracted from the id', function () use ($displayName): void {
|
||||
// GIVEN
|
||||
$expected = new \DateTimeImmutable('2024-06-15 12:34:56.789000', new \DateTimeZone('UTC'));
|
||||
$id = new ActorId(Uuid::uuid7($expected));
|
||||
$actor = Actor::hydrate(
|
||||
$id,
|
||||
$this->displayName
|
||||
$displayName,
|
||||
);
|
||||
|
||||
// WHEN
|
||||
|
|
|
|||
|
|
@ -17,44 +17,42 @@ use Shared\ValueObjects\Rcs;
|
|||
covers(Brand::class);
|
||||
|
||||
describe('brand', function (): void {
|
||||
beforeEach(function (): void {
|
||||
$this->code = new BrandCode('AAA01');
|
||||
$this->name = new BrandName('Name');
|
||||
$this->logo = new PicturePath('files/picture.jpg');
|
||||
$this->rcs = new Rcs('RCS PARIS 111 222 333');
|
||||
$this->contact = new Email('contact@example.com');
|
||||
});
|
||||
$code = new BrandCode('AAA01');
|
||||
$name = new BrandName('Name');
|
||||
$logo = new PicturePath('files/picture.jpg');
|
||||
$rcs = new Rcs('RCS PARIS 111 222 333');
|
||||
$contact = new Email('contact@example.com');
|
||||
|
||||
afterEach(function (): void {
|
||||
CarbonImmutable::setTestNow();
|
||||
});
|
||||
|
||||
it('creates a brand', function (): void {
|
||||
it('creates a brand', function () use ($code, $name, $logo, $rcs, $contact): void {
|
||||
// GIVEN
|
||||
$id = BrandId::generate();
|
||||
|
||||
// WHEN
|
||||
$brand = Brand::hydrate(
|
||||
$id,
|
||||
$this->code,
|
||||
$this->name,
|
||||
$this->logo,
|
||||
$this->rcs,
|
||||
$this->contact
|
||||
$code,
|
||||
$name,
|
||||
$logo,
|
||||
$rcs,
|
||||
$contact,
|
||||
);
|
||||
|
||||
// THEN
|
||||
expect($brand->id())->toBe($id)
|
||||
->and($brand->code)->toBe($this->code)
|
||||
->and($brand->name)->toBe($this->name)
|
||||
->and($brand->logo)->toBe($this->logo)
|
||||
->and($brand->rcs)->toBe($this->rcs)
|
||||
->and($brand->contact)->toBe($this->contact)
|
||||
->and($brand->code)->toBe($code)
|
||||
->and($brand->name)->toBe($name)
|
||||
->and($brand->logo)->toBe($logo)
|
||||
->and($brand->rcs)->toBe($rcs)
|
||||
->and($brand->contact)->toBe($contact)
|
||||
->and($brand->updatedAt)->toBeNull()
|
||||
->and($brand->updatedAt())->toBeNull();
|
||||
});
|
||||
|
||||
it('creates a brand with an explicit updatedAt date', function (): void {
|
||||
it('creates a brand with an explicit updatedAt date', function () use ($code, $name, $logo, $rcs, $contact): void {
|
||||
// GIVEN
|
||||
$id = BrandId::generate();
|
||||
$updatedAt = new \DateTimeImmutable('2026-06-15 12:00:00', new \DateTimeZone('UTC'));
|
||||
|
|
@ -62,12 +60,12 @@ describe('brand', function (): void {
|
|||
// WHEN
|
||||
$brand = Brand::hydrate(
|
||||
$id,
|
||||
$this->code,
|
||||
$this->name,
|
||||
$this->logo,
|
||||
$this->rcs,
|
||||
$this->contact,
|
||||
$updatedAt
|
||||
$code,
|
||||
$name,
|
||||
$logo,
|
||||
$rcs,
|
||||
$contact,
|
||||
$updatedAt,
|
||||
);
|
||||
|
||||
// THEN
|
||||
|
|
@ -75,49 +73,49 @@ describe('brand', function (): void {
|
|||
->and($brand->updatedAt())->toBe($updatedAt);
|
||||
});
|
||||
|
||||
it('creates a new brand with a freshly generated id', function (): void {
|
||||
it('creates a new brand with a freshly generated id', function () use ($code, $name, $logo, $rcs, $contact): void {
|
||||
// GIVEN / WHEN
|
||||
$brand = Brand::create(
|
||||
$this->code,
|
||||
$this->name,
|
||||
$this->logo,
|
||||
$this->rcs,
|
||||
$this->contact
|
||||
$code,
|
||||
$name,
|
||||
$logo,
|
||||
$rcs,
|
||||
$contact,
|
||||
);
|
||||
|
||||
// THEN
|
||||
expect($brand->id())->toBeInstanceOf(BrandId::class)
|
||||
->and($brand->code)->toBe($this->code)
|
||||
->and($brand->name)->toBe($this->name)
|
||||
->and($brand->logo)->toBe($this->logo)
|
||||
->and($brand->rcs)->toBe($this->rcs)
|
||||
->and($brand->contact)->toBe($this->contact)
|
||||
->and($brand->code)->toBe($code)
|
||||
->and($brand->name)->toBe($name)
|
||||
->and($brand->logo)->toBe($logo)
|
||||
->and($brand->rcs)->toBe($rcs)
|
||||
->and($brand->contact)->toBe($contact)
|
||||
->and($brand->updatedAt)->toBeNull()
|
||||
->and($brand->updatedAt())->toBeNull();
|
||||
});
|
||||
|
||||
it('generates a different id for each created brand', function (): void {
|
||||
it('generates a different id for each created brand', function () use ($code, $name, $logo, $rcs, $contact): void {
|
||||
// GIVEN / WHEN
|
||||
$first = Brand::create(
|
||||
$this->code,
|
||||
$this->name,
|
||||
$this->logo,
|
||||
$this->rcs,
|
||||
$this->contact
|
||||
$code,
|
||||
$name,
|
||||
$logo,
|
||||
$rcs,
|
||||
$contact,
|
||||
);
|
||||
$second = Brand::create(
|
||||
$this->code,
|
||||
$this->name,
|
||||
$this->logo,
|
||||
$this->rcs,
|
||||
$this->contact
|
||||
$code,
|
||||
$name,
|
||||
$logo,
|
||||
$rcs,
|
||||
$contact,
|
||||
);
|
||||
|
||||
// THEN
|
||||
expect($first->id()->equals($second->id()))->toBeFalse();
|
||||
});
|
||||
|
||||
it('updates a brand logo and sets updatedAt timestamp', function (): void {
|
||||
it('updates a brand logo and sets updatedAt timestamp', function () use ($code, $name, $rcs, $contact): void {
|
||||
// GIVEN
|
||||
CarbonImmutable::setTestNow('2026-06-15 12:00:00 UTC');
|
||||
$id = BrandId::generate();
|
||||
|
|
@ -125,11 +123,11 @@ describe('brand', function (): void {
|
|||
$logoNew = new PicturePath('files/picture-new.jpg');
|
||||
$brand = Brand::hydrate(
|
||||
$id,
|
||||
$this->code,
|
||||
$this->name,
|
||||
$code,
|
||||
$name,
|
||||
$logoOld,
|
||||
$this->rcs,
|
||||
$this->contact
|
||||
$rcs,
|
||||
$contact,
|
||||
);
|
||||
|
||||
// WHEN
|
||||
|
|
@ -137,16 +135,16 @@ describe('brand', function (): void {
|
|||
|
||||
// THEN
|
||||
expect($brand->id())->toBe($id)
|
||||
->and($brand->code)->toBe($this->code)
|
||||
->and($brand->name)->toBe($this->name)
|
||||
->and($brand->code)->toBe($code)
|
||||
->and($brand->name)->toBe($name)
|
||||
->and($brand->logo)->toBe($logoNew)
|
||||
->and($brand->rcs)->toBe($this->rcs)
|
||||
->and($brand->contact)->toBe($this->contact)
|
||||
->and($brand->rcs)->toBe($rcs)
|
||||
->and($brand->contact)->toBe($contact)
|
||||
->and($brand->updatedAt)->not->toBeNull()
|
||||
->and($brand->updatedAt()?->format('Y-m-d H:i:s'))->toBe('2026-06-15 12:00:00');
|
||||
});
|
||||
|
||||
it('updates a brand rcs and sets updatedAt timestamp', function (): void {
|
||||
it('updates a brand rcs and sets updatedAt timestamp', function () use ($code, $name, $logo, $contact): void {
|
||||
// GIVEN
|
||||
CarbonImmutable::setTestNow('2026-06-15 14:30:00 UTC');
|
||||
$id = BrandId::generate();
|
||||
|
|
@ -154,11 +152,11 @@ describe('brand', function (): void {
|
|||
$rcsNew = new Rcs('RCS NANTES 444 555 666');
|
||||
$brand = Brand::hydrate(
|
||||
$id,
|
||||
$this->code,
|
||||
$this->name,
|
||||
$this->logo,
|
||||
$code,
|
||||
$name,
|
||||
$logo,
|
||||
$rcsOld,
|
||||
$this->contact
|
||||
$contact,
|
||||
);
|
||||
|
||||
// WHEN
|
||||
|
|
@ -166,16 +164,16 @@ describe('brand', function (): void {
|
|||
|
||||
// THEN
|
||||
expect($brand->id())->toBe($id)
|
||||
->and($brand->code)->toBe($this->code)
|
||||
->and($brand->name)->toBe($this->name)
|
||||
->and($brand->logo)->toBe($this->logo)
|
||||
->and($brand->code)->toBe($code)
|
||||
->and($brand->name)->toBe($name)
|
||||
->and($brand->logo)->toBe($logo)
|
||||
->and($brand->rcs)->toBe($rcsNew)
|
||||
->and($brand->contact)->toBe($this->contact)
|
||||
->and($brand->contact)->toBe($contact)
|
||||
->and($brand->updatedAt)->not->toBeNull()
|
||||
->and($brand->updatedAt()?->format('Y-m-d H:i:s'))->toBe('2026-06-15 14:30:00');
|
||||
});
|
||||
|
||||
it('updates a brand contact and sets updatedAt timestamp', function (): void {
|
||||
it('updates a brand contact and sets updatedAt timestamp', function () use ($code, $name, $logo, $rcs): void {
|
||||
// GIVEN
|
||||
CarbonImmutable::setTestNow('2026-06-15 16:45:00 UTC');
|
||||
$id = BrandId::generate();
|
||||
|
|
@ -183,11 +181,11 @@ describe('brand', function (): void {
|
|||
$contactNew = new Email('contact-new@example.com');
|
||||
$brand = Brand::hydrate(
|
||||
$id,
|
||||
$this->code,
|
||||
$this->name,
|
||||
$this->logo,
|
||||
$this->rcs,
|
||||
$contactOld
|
||||
$code,
|
||||
$name,
|
||||
$logo,
|
||||
$rcs,
|
||||
$contactOld,
|
||||
);
|
||||
|
||||
// WHEN
|
||||
|
|
@ -195,26 +193,26 @@ describe('brand', function (): void {
|
|||
|
||||
// THEN
|
||||
expect($brand->id())->toBe($id)
|
||||
->and($brand->code)->toBe($this->code)
|
||||
->and($brand->name)->toBe($this->name)
|
||||
->and($brand->logo)->toBe($this->logo)
|
||||
->and($brand->rcs)->toBe($this->rcs)
|
||||
->and($brand->code)->toBe($code)
|
||||
->and($brand->name)->toBe($name)
|
||||
->and($brand->logo)->toBe($logo)
|
||||
->and($brand->rcs)->toBe($rcs)
|
||||
->and($brand->contact)->toBe($contactNew)
|
||||
->and($brand->updatedAt)->not->toBeNull()
|
||||
->and($brand->updatedAt()?->format('Y-m-d H:i:s'))->toBe('2026-06-15 16:45:00');
|
||||
});
|
||||
|
||||
it('returns the creation date extracted from the id', function (): void {
|
||||
it('returns the creation date extracted from the id', function () use ($code, $name, $logo, $rcs, $contact): void {
|
||||
// GIVEN
|
||||
$expected = new \DateTimeImmutable('2024-06-15 12:34:56.789000', new \DateTimeZone('UTC'));
|
||||
$id = new BrandId(Uuid::uuid7($expected));
|
||||
$brand = Brand::hydrate(
|
||||
$id,
|
||||
$this->code,
|
||||
$this->name,
|
||||
$this->logo,
|
||||
$this->rcs,
|
||||
$this->contact
|
||||
$code,
|
||||
$name,
|
||||
$logo,
|
||||
$rcs,
|
||||
$contact,
|
||||
);
|
||||
|
||||
// WHEN
|
||||
|
|
|
|||
|
|
@ -6,7 +6,6 @@ namespace Tests\Unit\Domain\Models\Entities;
|
|||
|
||||
use Carbon\CarbonImmutable;
|
||||
use DateTime;
|
||||
use Domain\Enums\BarcodeFormat;
|
||||
use Domain\Models\Entities\CampaignRequest;
|
||||
use Domain\Models\ValueObjects\Brand\BrandCode;
|
||||
use Domain\Models\ValueObjects\Campaign\CampaignName;
|
||||
|
|
@ -15,15 +14,20 @@ use Domain\Models\ValueObjects\CampaignRequest\CampaignRequestId;
|
|||
use Domain\Models\ValueObjects\CampaignRequest\CampaignRequestStatus;
|
||||
use Domain\Models\ValueObjects\CampaignRequest\CampaignRequestType;
|
||||
use Domain\Models\ValueObjects\CampaignRequest\RejectionReason;
|
||||
use Domain\Models\ValueObjects\Coupon\CouponValidity;
|
||||
use Domain\Models\ValueObjects\Coupon\CouponIncoCode;
|
||||
use Domain\Models\ValueObjects\Coupon\CouponLegalInformation;
|
||||
use Domain\Models\ValueObjects\Coupon\CouponLegalInformationArray;
|
||||
use Domain\Models\ValueObjects\Coupon\CouponName;
|
||||
use Domain\Models\ValueObjects\Coupon\CouponPicture;
|
||||
use Domain\Models\ValueObjects\Coupon\CouponProcessingCode;
|
||||
use Domain\Models\ValueObjects\Coupon\CouponProcessingCodeArray;
|
||||
use Domain\Models\ValueObjects\Coupon\CouponProductArray;
|
||||
use Domain\Models\ValueObjects\Coupon\CouponValidityInformation;
|
||||
use Domain\Models\ValueObjects\CouponName;
|
||||
use Domain\Models\ValueObjects\GS1;
|
||||
use Domain\Models\ValueObjects\IncoCode;
|
||||
use Domain\Models\ValueObjects\Coupon\CouponValidityInformationArray;
|
||||
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;
|
||||
use Domain\Models\ValueObjects\RequestedCoupon\RequestedCouponQuantity;
|
||||
use Ramsey\Uuid\Uuid;
|
||||
|
|
@ -35,77 +39,90 @@ use Shared\ValueObjects\Money;
|
|||
covers(CampaignRequest::class);
|
||||
|
||||
describe('campaign request', function (): void {
|
||||
beforeEach(function (): void {
|
||||
$this->requestedCoupon = new RequestedCoupon(
|
||||
new CouponName('Coupon A'),
|
||||
new RequestedCouponQuantity(100),
|
||||
new Period(new DateTime('2026-01-01'), new DateTime('2026-02-01')),
|
||||
new MoneyAmount(new Money(Currency::EUR, 300)),
|
||||
new ProcessingCode('PC1'),
|
||||
new CouponValidity(30, new DateTime('2026-02-01')),
|
||||
[
|
||||
new CouponValidityInformation('Lorem ipsum dolor sit amet consectetur adipiscing elit.', Country::FRANCE),
|
||||
new CouponValidityInformation('Lorem ipsum dolor sit amet consectetur adipiscing elit.', Country::BENELUX)
|
||||
],
|
||||
[new IncoCode(35784), new IncoCode(15522)],
|
||||
new PrintRules(maxPerCustomer: 3),
|
||||
new GS1('01234567890128', BarcodeFormat::EAN13)
|
||||
);
|
||||
$this->code = new BrandCode('AAA01');
|
||||
$this->name = new CampaignName('Campaign A');
|
||||
$this->applicant = new Applicant('John', 'Doe', new Email('john.doe@example.com'));
|
||||
$this->campaignType = CampaignRequestType::CLUB;
|
||||
$this->requestedCoupon = $this->requestedCoupon;
|
||||
$this->status = CampaignRequestStatus::CREATED;
|
||||
$this->transformedStatus = CampaignRequestStatus::TRANSFORMED;
|
||||
$this->rejectedStatus = CampaignRequestStatus::REJECTED;
|
||||
$this->rejectionReason = new RejectionReason('Missing legal documents.');
|
||||
});
|
||||
$requestedCoupon = new RequestedCoupon(
|
||||
couponName: new CouponName('Coupon A'),
|
||||
quantity: new RequestedCouponQuantity(100),
|
||||
diffusion: new Period(new DateTime('2026-01-01'), new DateTime('2026-02-01')),
|
||||
moneyAmount: new MoneyAmount(new Money(Currency::EUR, 300)),
|
||||
couponPicture: new CouponPicture(
|
||||
new PicturePath('files/product.jpg'),
|
||||
new PicturePath('files/thumbnail.jpg'),
|
||||
new PicturePath('files/mobileThumbnail.jpg')
|
||||
),
|
||||
couponProcessingCodes: new CouponProcessingCodeArray([
|
||||
new CouponProcessingCode('ABC1234567890', Country::FRANCE),
|
||||
]),
|
||||
couponValidityInformations: new CouponValidityInformationArray([
|
||||
new CouponValidityInformation('Lorem ipsum dolor sit amet consectetur adipiscing elit.', Country::FRANCE),
|
||||
new CouponValidityInformation('Lorem ipsum dolor sit amet consectetur adipiscing elit.', Country::BENELUX)
|
||||
]),
|
||||
couponLegalInformations: new CouponLegalInformationArray([
|
||||
new CouponLegalInformation('Lorem ipsum dolor sit amet consectetur adipiscing elit.', Country::FRANCE),
|
||||
new CouponLegalInformation('Lorem ipsum dolor sit amet consectetur adipiscing elit.', Country::BENELUX)
|
||||
]),
|
||||
couponProducts: new CouponProductArray([new CouponIncoCode(35784), new CouponIncoCode(15522)]),
|
||||
printRules: new PrintRules(maxPerCustomer: 3),
|
||||
);
|
||||
$code = new BrandCode('AAA01');
|
||||
$name = new CampaignName('Campaign A');
|
||||
$applicant = new Applicant('John', 'Doe', new Email('john.doe@example.com'));
|
||||
$campaignType = CampaignRequestType::CLUB;
|
||||
$status = CampaignRequestStatus::CREATED;
|
||||
$transformedStatus = CampaignRequestStatus::TRANSFORMED;
|
||||
$rejectedStatus = CampaignRequestStatus::REJECTED;
|
||||
$rejectionReason = new RejectionReason('Missing legal documents.');
|
||||
|
||||
afterEach(function (): void {
|
||||
CarbonImmutable::setTestNow();
|
||||
});
|
||||
|
||||
it('hydrates a campaign request with all its fields', function (): void {
|
||||
it('hydrates a campaign request with all its fields', function () use ($code, $name, $applicant, $campaignType, $requestedCoupon, $status): void {
|
||||
// GIVEN
|
||||
$id = CampaignRequestId::generate();
|
||||
|
||||
// WHEN
|
||||
$campaignRequest = CampaignRequest::hydrate(
|
||||
$id,
|
||||
$this->code,
|
||||
$this->name,
|
||||
$this->applicant,
|
||||
$this->campaignType,
|
||||
$this->requestedCoupon,
|
||||
$this->status,
|
||||
$code,
|
||||
$name,
|
||||
$applicant,
|
||||
$campaignType,
|
||||
$requestedCoupon,
|
||||
$status,
|
||||
);
|
||||
|
||||
// THEN
|
||||
expect($campaignRequest->id())->toBe($id)
|
||||
->and($campaignRequest->brandCode)->toBe($this->code)
|
||||
->and($campaignRequest->name)->toBe($this->name)
|
||||
->and($campaignRequest->applicant)->toBe($this->applicant)
|
||||
->and($campaignRequest->campaignType)->toBe($this->campaignType)
|
||||
->and($campaignRequest->requestedCoupon)->toBe($this->requestedCoupon)
|
||||
->and($campaignRequest->status)->toBe($this->status)
|
||||
->and($campaignRequest->brandCode)->toBe($code)
|
||||
->and($campaignRequest->name)->toBe($name)
|
||||
->and($campaignRequest->applicant)->toBe($applicant)
|
||||
->and($campaignRequest->campaignType)->toBe($campaignType)
|
||||
->and($campaignRequest->requestedCoupon)->toBe($requestedCoupon)
|
||||
->and($campaignRequest->status)->toBe($status)
|
||||
->and($campaignRequest->updatedAt)->toBeNull()
|
||||
->and($campaignRequest->updatedAt())->toBeNull();
|
||||
});
|
||||
|
||||
it('hydrates a campaign request with an explicit updatedAt date', function (): void {
|
||||
it('hydrates a campaign request with an explicit updatedAt date', function () use (
|
||||
$code,
|
||||
$name,
|
||||
$applicant,
|
||||
$campaignType,
|
||||
$requestedCoupon,
|
||||
$status,
|
||||
): void {
|
||||
// GIVEN
|
||||
$updatedAt = new \DateTimeImmutable('2026-06-15 12:00:00', new \DateTimeZone('UTC'));
|
||||
|
||||
// WHEN
|
||||
$campaignRequest = CampaignRequest::hydrate(
|
||||
CampaignRequestId::generate(),
|
||||
$this->code,
|
||||
$this->name,
|
||||
$this->applicant,
|
||||
$this->campaignType,
|
||||
$this->requestedCoupon,
|
||||
$this->status,
|
||||
$code,
|
||||
$name,
|
||||
$applicant,
|
||||
$campaignType,
|
||||
$requestedCoupon,
|
||||
$status,
|
||||
null,
|
||||
$updatedAt,
|
||||
);
|
||||
|
|
@ -115,34 +132,49 @@ describe('campaign request', function (): void {
|
|||
->and($campaignRequest->updatedAt())->toBe($updatedAt);
|
||||
});
|
||||
|
||||
it('hydrates a rejected campaign request with a rejection reason', function (): void {
|
||||
it('hydrates a rejected campaign request with a rejection reason', function () use (
|
||||
$code,
|
||||
$name,
|
||||
$applicant,
|
||||
$campaignType,
|
||||
$requestedCoupon,
|
||||
$rejectedStatus,
|
||||
$rejectionReason,
|
||||
): void {
|
||||
// GIVEN / WHEN
|
||||
$campaignRequest = CampaignRequest::hydrate(
|
||||
CampaignRequestId::generate(),
|
||||
$this->code,
|
||||
$this->name,
|
||||
$this->applicant,
|
||||
$this->campaignType,
|
||||
$this->requestedCoupon,
|
||||
$this->rejectedStatus,
|
||||
$this->rejectionReason,
|
||||
$code,
|
||||
$name,
|
||||
$applicant,
|
||||
$campaignType,
|
||||
$requestedCoupon,
|
||||
$rejectedStatus,
|
||||
$rejectionReason,
|
||||
);
|
||||
|
||||
// THEN
|
||||
expect($campaignRequest->status)->toBe($this->rejectedStatus)
|
||||
->and($campaignRequest->rejectionReason)->toBe($this->rejectionReason);
|
||||
expect($campaignRequest->status)->toBe($rejectedStatus)
|
||||
->and($campaignRequest->rejectionReason)->toBe($rejectionReason);
|
||||
});
|
||||
|
||||
it('rejects a rejected campaign request without a rejection reason', function (): void {
|
||||
it('rejects a rejected campaign request without a rejection reason', function () use (
|
||||
$code,
|
||||
$name,
|
||||
$applicant,
|
||||
$campaignType,
|
||||
$requestedCoupon,
|
||||
$rejectedStatus,
|
||||
): void {
|
||||
// GIVEN / WHEN
|
||||
$action = fn (): CampaignRequest => CampaignRequest::hydrate(
|
||||
CampaignRequestId::generate(),
|
||||
$this->code,
|
||||
$this->name,
|
||||
$this->applicant,
|
||||
$this->campaignType,
|
||||
$this->requestedCoupon,
|
||||
$this->rejectedStatus,
|
||||
$code,
|
||||
$name,
|
||||
$applicant,
|
||||
$campaignType,
|
||||
$requestedCoupon,
|
||||
$rejectedStatus,
|
||||
);
|
||||
|
||||
// THEN
|
||||
|
|
@ -152,17 +184,25 @@ describe('campaign request', function (): void {
|
|||
);
|
||||
});
|
||||
|
||||
it('rejects a non-rejected campaign request with a rejection reason', function (): void {
|
||||
it('rejects a non-rejected campaign request with a rejection reason', function () use (
|
||||
$code,
|
||||
$name,
|
||||
$applicant,
|
||||
$campaignType,
|
||||
$requestedCoupon,
|
||||
$status,
|
||||
$rejectionReason,
|
||||
): void {
|
||||
// WHEN
|
||||
$action = fn (): CampaignRequest => CampaignRequest::hydrate(
|
||||
CampaignRequestId::generate(),
|
||||
$this->code,
|
||||
$this->name,
|
||||
$this->applicant,
|
||||
$this->campaignType,
|
||||
$this->requestedCoupon,
|
||||
$this->status,
|
||||
$this->rejectionReason,
|
||||
$code,
|
||||
$name,
|
||||
$applicant,
|
||||
$campaignType,
|
||||
$requestedCoupon,
|
||||
$status,
|
||||
$rejectionReason,
|
||||
);
|
||||
|
||||
// THEN
|
||||
|
|
@ -172,25 +212,33 @@ describe('campaign request', function (): void {
|
|||
);
|
||||
});
|
||||
|
||||
it('rejects a campaign request and sets the rejection reason and updatedAt', function (): void {
|
||||
it('rejects a campaign request and sets the rejection reason and updatedAt', function () use (
|
||||
$code,
|
||||
$name,
|
||||
$applicant,
|
||||
$campaignType,
|
||||
$requestedCoupon,
|
||||
$status,
|
||||
$rejectionReason,
|
||||
): void {
|
||||
// GIVEN
|
||||
CarbonImmutable::setTestNow('2026-06-15 12:00:00 UTC');
|
||||
$campaignRequest = CampaignRequest::hydrate(
|
||||
CampaignRequestId::generate(),
|
||||
$this->code,
|
||||
$this->name,
|
||||
$this->applicant,
|
||||
$this->campaignType,
|
||||
$this->requestedCoupon,
|
||||
$this->status,
|
||||
$code,
|
||||
$name,
|
||||
$applicant,
|
||||
$campaignType,
|
||||
$requestedCoupon,
|
||||
$status,
|
||||
);
|
||||
|
||||
// WHEN
|
||||
$rejected = $campaignRequest->reject($this->rejectionReason);
|
||||
$rejected = $campaignRequest->reject($rejectionReason);
|
||||
|
||||
// THEN
|
||||
expect($rejected->status)->toBe(CampaignRequestStatus::REJECTED)
|
||||
->and($rejected->rejectionReason)->toBe($this->rejectionReason)
|
||||
->and($rejected->rejectionReason)->toBe($rejectionReason)
|
||||
->and($rejected->id())->toBe($campaignRequest->id())
|
||||
->and($rejected->brandCode)->toBe($campaignRequest->brandCode)
|
||||
->and($rejected->name)->toBe($campaignRequest->name)
|
||||
|
|
@ -201,35 +249,50 @@ describe('campaign request', function (): void {
|
|||
->and($rejected->updatedAt()?->format('Y-m-d H:i:s'))->toBe('2026-06-15 12:00:00');
|
||||
});
|
||||
|
||||
it('rejects rejecting a transformed campaign request', function (): void {
|
||||
it('rejects rejecting a transformed campaign request', function () use (
|
||||
$code,
|
||||
$name,
|
||||
$applicant,
|
||||
$campaignType,
|
||||
$requestedCoupon,
|
||||
$transformedStatus,
|
||||
$rejectionReason,
|
||||
): void {
|
||||
// GIVEN
|
||||
$campaignRequest = CampaignRequest::hydrate(
|
||||
CampaignRequestId::generate(),
|
||||
$this->code,
|
||||
$this->name,
|
||||
$this->applicant,
|
||||
$this->campaignType,
|
||||
$this->requestedCoupon,
|
||||
$this->transformedStatus,
|
||||
$code,
|
||||
$name,
|
||||
$applicant,
|
||||
$campaignType,
|
||||
$requestedCoupon,
|
||||
$transformedStatus,
|
||||
);
|
||||
|
||||
// WHEN
|
||||
$action = fn (): CampaignRequest => $campaignRequest->reject($this->rejectionReason);
|
||||
$action = fn (): CampaignRequest => $campaignRequest->reject($rejectionReason);
|
||||
|
||||
// THEN
|
||||
expect($action)->toThrow(\DomainException::class, 'Only a created campaign request can be rejected.');
|
||||
});
|
||||
|
||||
it('rejects rejecting an already rejected campaign request', function (): void {
|
||||
it('rejects rejecting an already rejected campaign request', function () use (
|
||||
$code,
|
||||
$name,
|
||||
$applicant,
|
||||
$campaignType,
|
||||
$requestedCoupon,
|
||||
$rejectedStatus,
|
||||
): void {
|
||||
// GIVEN
|
||||
$campaignRequest = CampaignRequest::hydrate(
|
||||
CampaignRequestId::generate(),
|
||||
$this->code,
|
||||
$this->name,
|
||||
$this->applicant,
|
||||
$this->campaignType,
|
||||
$this->requestedCoupon,
|
||||
$this->rejectedStatus,
|
||||
$code,
|
||||
$name,
|
||||
$applicant,
|
||||
$campaignType,
|
||||
$requestedCoupon,
|
||||
$rejectedStatus,
|
||||
new RejectionReason('First reason.'),
|
||||
);
|
||||
|
||||
|
|
@ -240,18 +303,18 @@ describe('campaign request', function (): void {
|
|||
expect($action)->toThrow(\DomainException::class, 'Only a created campaign request can be rejected.');
|
||||
});
|
||||
|
||||
it('returns the creation date extracted from the id', function (): void {
|
||||
it('returns the creation date extracted from the id', function () use ($code, $name, $applicant, $campaignType, $requestedCoupon, $status): void {
|
||||
// GIVEN
|
||||
$expected = new \DateTimeImmutable('2024-06-15 12:34:56.789000', new \DateTimeZone('UTC'));
|
||||
$id = new CampaignRequestId(Uuid::uuid7($expected));
|
||||
$campaignRequest = CampaignRequest::hydrate(
|
||||
$id,
|
||||
$this->code,
|
||||
$this->name,
|
||||
$this->applicant,
|
||||
$this->campaignType,
|
||||
$this->requestedCoupon,
|
||||
$this->status,
|
||||
$code,
|
||||
$name,
|
||||
$applicant,
|
||||
$campaignType,
|
||||
$requestedCoupon,
|
||||
$status,
|
||||
);
|
||||
|
||||
// WHEN
|
||||
|
|
|
|||
|
|
@ -5,92 +5,83 @@ declare(strict_types=1);
|
|||
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;
|
||||
use Domain\Models\ValueObjects\Campaign\CampaignCouponArray;
|
||||
use Domain\Models\ValueObjects\Campaign\CampaignId;
|
||||
use Domain\Models\ValueObjects\Campaign\CampaignName;
|
||||
use Domain\Models\ValueObjects\Coupon\CouponQuantity;
|
||||
use Domain\Models\ValueObjects\Coupon\CouponCode;
|
||||
use Domain\Models\ValueObjects\PrintRules;
|
||||
use Domain\Models\ValueObjects\ProcessingCode;
|
||||
use Ramsey\Uuid\Uuid;
|
||||
|
||||
covers(Campaign::class);
|
||||
|
||||
describe('campaign', function (): void {
|
||||
beforeEach(function (): void {
|
||||
$this->code = new CampaignCode('Camp100');
|
||||
$this->name = new CampaignName('Name');
|
||||
$this->publication = \boolval(0);
|
||||
$this->printAllAtOnce = \boolval(1);
|
||||
$this->coupons = [
|
||||
new CampaignCoupon(
|
||||
new ProcessingCode('PC1'),
|
||||
new CouponQuantity(100),
|
||||
Country::FRANCE,
|
||||
new PrintRules(maxPerCustomer: 3)
|
||||
)
|
||||
];
|
||||
$this->brandCode = new BrandCode('AAA01');
|
||||
$this->actorId = ActorId::generate();
|
||||
});
|
||||
$code = new CampaignCode('Camp100');
|
||||
$name = new CampaignName('Name');
|
||||
$publication = \boolval(0);
|
||||
$printAllAtOnce = \boolval(1);
|
||||
$coupons = new CampaignCouponArray([
|
||||
new CampaignCoupon(
|
||||
new CouponCode('AAA01'),
|
||||
new PrintRules(maxPerCustomer: 3)
|
||||
)
|
||||
]);
|
||||
$brandCode = new BrandCode('AAA01');
|
||||
$actorId = ActorId::generate();
|
||||
|
||||
afterEach(function (): void {
|
||||
CarbonImmutable::setTestNow();
|
||||
});
|
||||
|
||||
it('creates a campaign', function (): void {
|
||||
it('creates a campaign', function () use (
|
||||
$code,
|
||||
$name,
|
||||
$publication,
|
||||
$printAllAtOnce,
|
||||
$coupons,
|
||||
$brandCode,
|
||||
$actorId,
|
||||
): void {
|
||||
// GIVEN
|
||||
$id = CampaignId::generate();
|
||||
|
||||
// WHEN
|
||||
$campaign = Campaign::hydrate(
|
||||
$id,
|
||||
$this->code,
|
||||
$this->name,
|
||||
$this->publication,
|
||||
$this->printAllAtOnce,
|
||||
$this->coupons,
|
||||
$this->brandCode,
|
||||
$this->actorId
|
||||
$code,
|
||||
$name,
|
||||
$publication,
|
||||
$printAllAtOnce,
|
||||
$coupons,
|
||||
$brandCode,
|
||||
$actorId
|
||||
);
|
||||
|
||||
// THEN
|
||||
expect($campaign->id())->toBe($id)
|
||||
->and($campaign->code)->toBe($this->code)
|
||||
->and($campaign->name)->toBe($this->name)
|
||||
->and($campaign->publication)->toBe($this->publication)
|
||||
->and($campaign->printAllAtOnce)->toBe($this->printAllAtOnce)
|
||||
->and($campaign->coupons)->toBe($this->coupons)
|
||||
->and($campaign->brandCode)->toBe($this->brandCode)
|
||||
->and($campaign->code)->toBe($code)
|
||||
->and($campaign->name)->toBe($name)
|
||||
->and($campaign->publication)->toBe($publication)
|
||||
->and($campaign->printAllAtOnce)->toBe($printAllAtOnce)
|
||||
->and($campaign->coupons)->toBe($coupons)
|
||||
->and($campaign->brandCode)->toBe($brandCode)
|
||||
->and($campaign->updatedAt)->toBeNull()
|
||||
->and($campaign->updatedAt())->toBeNull();
|
||||
});
|
||||
|
||||
it('creates a campaign without coupon', function (): void {
|
||||
// GIVEN
|
||||
$id = CampaignId::generate();
|
||||
|
||||
// WHEN
|
||||
$campaign = Campaign::hydrate(
|
||||
$id,
|
||||
$this->code,
|
||||
$this->name,
|
||||
$this->publication,
|
||||
$this->printAllAtOnce,
|
||||
[],
|
||||
$this->brandCode,
|
||||
$this->actorId
|
||||
);
|
||||
|
||||
// THEN
|
||||
expect($campaign->coupons)->toBe([]);
|
||||
});
|
||||
|
||||
it('creates a coupon with an explicit updatedAt date', function (): void {
|
||||
it('creates a coupon with an explicit updatedAt date', function () use (
|
||||
$code,
|
||||
$name,
|
||||
$publication,
|
||||
$printAllAtOnce,
|
||||
$coupons,
|
||||
$brandCode,
|
||||
$actorId,
|
||||
): void {
|
||||
// GIVEN
|
||||
$id = CampaignId::generate();
|
||||
$updatedAt = new \DateTimeImmutable('2026-09-22 10:00:00', new \DateTimeZone('UTC'));
|
||||
|
|
@ -98,13 +89,13 @@ describe('campaign', function (): void {
|
|||
// WHEN
|
||||
$campaign = Campaign::hydrate(
|
||||
$id,
|
||||
$this->code,
|
||||
$this->name,
|
||||
$this->publication,
|
||||
$this->printAllAtOnce,
|
||||
$this->coupons,
|
||||
$this->brandCode,
|
||||
$this->actorId,
|
||||
$code,
|
||||
$name,
|
||||
$publication,
|
||||
$printAllAtOnce,
|
||||
$coupons,
|
||||
$brandCode,
|
||||
$actorId,
|
||||
$updatedAt
|
||||
);
|
||||
|
||||
|
|
@ -113,68 +104,92 @@ describe('campaign', function (): void {
|
|||
->and($campaign->updatedAt())->toBe($updatedAt);
|
||||
});
|
||||
|
||||
it('creates a new campaign with a freshly generated id', function (): void {
|
||||
it('creates a new campaign with a freshly generated id', function () use (
|
||||
$code,
|
||||
$name,
|
||||
$publication,
|
||||
$printAllAtOnce,
|
||||
$coupons,
|
||||
$brandCode,
|
||||
$actorId,
|
||||
): void {
|
||||
// GIVEN / WHEN
|
||||
$campaign = Campaign::create(
|
||||
$this->code,
|
||||
$this->name,
|
||||
$this->publication,
|
||||
$this->printAllAtOnce,
|
||||
$this->coupons,
|
||||
$this->brandCode,
|
||||
$this->actorId
|
||||
$code,
|
||||
$name,
|
||||
$publication,
|
||||
$printAllAtOnce,
|
||||
$coupons,
|
||||
$brandCode,
|
||||
$actorId
|
||||
);
|
||||
|
||||
// THEN
|
||||
expect($campaign->id())->toBeInstanceOf(CampaignId::class)
|
||||
->and($campaign->code)->toBe($this->code)
|
||||
->and($campaign->name)->toBe($this->name)
|
||||
->and($campaign->publication)->toBe($this->publication)
|
||||
->and($campaign->printAllAtOnce)->toBe($this->printAllAtOnce)
|
||||
->and($campaign->coupons)->toBe($this->coupons)
|
||||
->and($campaign->brandCode)->toBe($this->brandCode)
|
||||
->and($campaign->code)->toBe($code)
|
||||
->and($campaign->name)->toBe($name)
|
||||
->and($campaign->publication)->toBe($publication)
|
||||
->and($campaign->printAllAtOnce)->toBe($printAllAtOnce)
|
||||
->and($campaign->coupons)->toBe($coupons)
|
||||
->and($campaign->brandCode)->toBe($brandCode)
|
||||
->and($campaign->updatedAt)->toBeNull()
|
||||
->and($campaign->updatedAt())->toBeNull();
|
||||
});
|
||||
|
||||
it('generates a different id for each created campaign', function (): void {
|
||||
it('generates a different id for each created campaign', function () use (
|
||||
$code,
|
||||
$name,
|
||||
$publication,
|
||||
$printAllAtOnce,
|
||||
$coupons,
|
||||
$brandCode,
|
||||
$actorId,
|
||||
): void {
|
||||
// GIVEN / WHEN
|
||||
$firstCampaign = Campaign::create(
|
||||
$this->code,
|
||||
$this->name,
|
||||
$this->publication,
|
||||
$this->printAllAtOnce,
|
||||
$this->coupons,
|
||||
$this->brandCode,
|
||||
$this->actorId
|
||||
$code,
|
||||
$name,
|
||||
$publication,
|
||||
$printAllAtOnce,
|
||||
$coupons,
|
||||
$brandCode,
|
||||
$actorId
|
||||
);
|
||||
$secondCampaign = Campaign::create(
|
||||
$this->code,
|
||||
$this->name,
|
||||
$this->publication,
|
||||
$this->printAllAtOnce,
|
||||
$this->coupons,
|
||||
$this->brandCode,
|
||||
$this->actorId
|
||||
$code,
|
||||
$name,
|
||||
$publication,
|
||||
$printAllAtOnce,
|
||||
$coupons,
|
||||
$brandCode,
|
||||
$actorId
|
||||
);
|
||||
|
||||
// THEN
|
||||
expect($firstCampaign->id()->equals($secondCampaign->id()))->toBeFalse();
|
||||
});
|
||||
|
||||
it('returns the creation date extracted from the id', function (): void {
|
||||
it('returns the creation date extracted from the id', function () use (
|
||||
$code,
|
||||
$name,
|
||||
$publication,
|
||||
$printAllAtOnce,
|
||||
$coupons,
|
||||
$brandCode,
|
||||
$actorId,
|
||||
): void {
|
||||
// GIVEN
|
||||
$expected = new \DateTimeImmutable('2024-06-15 12:34:56.789000', new \DateTimeZone('UTC'));
|
||||
$id = new CampaignId(Uuid::uuid7($expected));
|
||||
$campaign = Campaign::hydrate(
|
||||
$id,
|
||||
$this->code,
|
||||
$this->name,
|
||||
$this->publication,
|
||||
$this->printAllAtOnce,
|
||||
$this->coupons,
|
||||
$this->brandCode,
|
||||
$this->actorId
|
||||
$code,
|
||||
$name,
|
||||
$publication,
|
||||
$printAllAtOnce,
|
||||
$coupons,
|
||||
$brandCode,
|
||||
$actorId
|
||||
);
|
||||
|
||||
// WHEN
|
||||
|
|
@ -184,21 +199,20 @@ describe('campaign', function (): void {
|
|||
expect($result->format('Y-m-d H:i:s.v'))->toBe($expected->format('Y-m-d H:i:s.v'));
|
||||
});
|
||||
|
||||
it('rejects a campaign with a non-coupon element', function (): void {
|
||||
it('rejects a campaign with a non-coupon element', function () use ($code, $name, $publication, $printAllAtOnce, $brandCode, $actorId): void {
|
||||
// GIVEN
|
||||
$id = CampaignId::generate();
|
||||
$coupons = ['PC1'];
|
||||
$id = CampaignId::generate();
|
||||
|
||||
// WHEN / THEN
|
||||
expect(fn (): Campaign => Campaign::hydrate(
|
||||
$id,
|
||||
$this->code,
|
||||
$this->name,
|
||||
$this->publication,
|
||||
$this->printAllAtOnce,
|
||||
$coupons,
|
||||
$this->brandCode,
|
||||
$this->actorId
|
||||
))->toThrow(\DomainException::class, 'Campaign coupons must be CampaignCoupon instances.');
|
||||
$code,
|
||||
$name,
|
||||
$publication,
|
||||
$printAllAtOnce,
|
||||
new CampaignCouponArray(['PC1']),
|
||||
$brandCode,
|
||||
$actorId
|
||||
))->toThrow(\DomainException::class, 'Coupons must be CampaignCoupon instances.');
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -6,7 +6,6 @@ namespace Tests\Unit\Domain\Models\Entities;
|
|||
|
||||
use Carbon\CarbonImmutable;
|
||||
use DateTime;
|
||||
use Domain\Enums\BarcodeFormat;
|
||||
use Shared\Enums\Country;
|
||||
use Domain\Models\Entities\Coupon;
|
||||
use Domain\Models\ValueObjects\Actor\ActorId;
|
||||
|
|
@ -15,17 +14,22 @@ 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\CouponIncoCode;
|
||||
use Domain\Models\ValueObjects\Coupon\CouponLegalInformation;
|
||||
use Domain\Models\ValueObjects\Coupon\CouponValidity;
|
||||
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\CouponProcessingCode;
|
||||
use Domain\Models\ValueObjects\Coupon\CouponProcessingCodeArray;
|
||||
use Domain\Models\ValueObjects\Coupon\CouponProductArray;
|
||||
use Domain\Models\ValueObjects\Coupon\CouponQuantity;
|
||||
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\Coupon\CouponValidityInformationArray;
|
||||
use Domain\Models\ValueObjects\MoneyAmount;
|
||||
use Domain\Models\ValueObjects\Period;
|
||||
use Domain\Models\ValueObjects\PicturePath;
|
||||
use Domain\Models\ValueObjects\ProcessingCode;
|
||||
use Ramsey\Uuid\Uuid;
|
||||
use Shared\Enums\Currency;
|
||||
use Shared\ValueObjects\Money;
|
||||
|
|
@ -33,274 +37,277 @@ use Shared\ValueObjects\Money;
|
|||
covers(Coupon::class);
|
||||
|
||||
describe('coupon', function (): void {
|
||||
beforeEach(function (): void {
|
||||
$this->code = new CouponCode('COU01');
|
||||
$this->name = new CouponName('Name');
|
||||
$this->amount = new MoneyAmount(new Money(Currency::EUR, 1));
|
||||
$this->picture = new CouponPicture(
|
||||
new PicturePath('files/product.jpg'),
|
||||
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->validity = new CouponValidity(30, new DateTime('2026-02-01'));
|
||||
$this->couponValidityInformation = [
|
||||
new CouponValidityInformation(
|
||||
'Lorem ipsum dolor sit amet consectetur adipiscing elit.',
|
||||
Country::FRANCE
|
||||
)
|
||||
];
|
||||
$this->couponLegalInformation = [
|
||||
new CouponLegalInformation(
|
||||
'Lorem ipsum dolor sit amet consectetur adipiscing elit.',
|
||||
Country::FRANCE
|
||||
)
|
||||
];
|
||||
$this->processingCode = new ProcessingCode('5425003944130');
|
||||
$this->brandCode = new BrandCode('AAA01');
|
||||
$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->gs1 = new GS1('110101010', BarcodeFormat::EAN13);
|
||||
});
|
||||
$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 CouponProcessingCodeArray([
|
||||
new CouponProcessingCode('5425003944130', Country::FRANCE),
|
||||
]);
|
||||
$brandCode = new BrandCode('AAA01');
|
||||
$createdBy = ActorId::generate();
|
||||
$products = new CouponProductArray([new CouponIncoCode(35784), new CouponIncoCode(15522)]);
|
||||
$movements = new CouponMovementArray([new CouponMovement(100)]);
|
||||
$quantity = new CouponQuantity(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 (): void {
|
||||
it('creates a coupon', function () use (
|
||||
$code,
|
||||
$name,
|
||||
$amount,
|
||||
$picture,
|
||||
$diffusion,
|
||||
$validityInformations,
|
||||
$legalInformations,
|
||||
$processingCode,
|
||||
$brandCode,
|
||||
$createdBy,
|
||||
$products,
|
||||
$movements,
|
||||
$quantity,
|
||||
$availabilityCalendar,
|
||||
): void {
|
||||
// GIVEN
|
||||
$id = CouponId::generate();
|
||||
|
||||
// WHEN
|
||||
$coupon = Coupon::hydrate(
|
||||
$id,
|
||||
$this->code,
|
||||
$this->name,
|
||||
$this->amount,
|
||||
$this->picture,
|
||||
$this->diffusion,
|
||||
$this->validity,
|
||||
$this->couponValidityInformation,
|
||||
$this->couponLegalInformation,
|
||||
$this->processingCode,
|
||||
$this->brandCode,
|
||||
$this->createdBy,
|
||||
$this->products,
|
||||
$this->availabilityCalendar,
|
||||
$this->gs1,
|
||||
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,
|
||||
quantity: $quantity,
|
||||
availabilityCalendar: $availabilityCalendar,
|
||||
);
|
||||
|
||||
// THEN
|
||||
expect($coupon->id())->toBe($id)
|
||||
->and($coupon->code)->toBe($this->code)
|
||||
->and($coupon->name)->toBe($this->name)
|
||||
->and($coupon->amount)->toBe($this->amount)
|
||||
->and($coupon->picture)->toBe($this->picture)
|
||||
->and($coupon->diffusion)->toBe($this->diffusion)
|
||||
->and($coupon->validity)->toBe($this->validity)
|
||||
->and($coupon->couponValidityInformation)->toBe($this->couponValidityInformation)
|
||||
->and($coupon->couponLegalInformation)->toBe($this->couponLegalInformation)
|
||||
->and($coupon->processingCode)->toBe($this->processingCode)
|
||||
->and($coupon->brandCode)->toBe($this->brandCode)
|
||||
->and($coupon->createdBy)->toBe($this->createdBy)
|
||||
->and($coupon->products)->toBe($this->products)
|
||||
->and($coupon->availabilityCalendar)->toBe($this->availabilityCalendar)
|
||||
->and($coupon->gs1)->toBe($this->gs1)
|
||||
->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 gs1', function (): void {
|
||||
it('hydrates a coupon without availability calendar', function () use (
|
||||
$code,
|
||||
$name,
|
||||
$amount,
|
||||
$picture,
|
||||
$diffusion,
|
||||
$validityInformations,
|
||||
$legalInformations,
|
||||
$processingCode,
|
||||
$brandCode,
|
||||
$createdBy,
|
||||
$products,
|
||||
$movements,
|
||||
$quantity,
|
||||
): void {
|
||||
// GIVEN
|
||||
$id = CouponId::generate();
|
||||
|
||||
// WHEN
|
||||
$coupon = Coupon::hydrate(
|
||||
id: $id,
|
||||
code: $this->code,
|
||||
name: $this->name,
|
||||
amount: $this->amount,
|
||||
picture: $this->picture,
|
||||
diffusion: $this->diffusion,
|
||||
validity: $this->validity,
|
||||
couponValidityInformation: $this->couponValidityInformation,
|
||||
couponLegalInformation: $this->couponLegalInformation,
|
||||
processingCode: $this->processingCode,
|
||||
brandCode: $this->brandCode,
|
||||
createdBy: $this->createdBy,
|
||||
products: $this->products,
|
||||
availabilityCalendar: $this->availabilityCalendar
|
||||
);
|
||||
|
||||
// THEN
|
||||
expect($coupon->products)->toBe($this->products)
|
||||
->and($coupon->availabilityCalendar)->toBe($this->availabilityCalendar)
|
||||
->and($coupon->gs1)->toBeNull();
|
||||
});
|
||||
|
||||
it('hydrates a coupon without availability calendar', function (): void {
|
||||
// GIVEN
|
||||
$id = CouponId::generate();
|
||||
|
||||
// WHEN
|
||||
$coupon = Coupon::hydrate(
|
||||
id: $id,
|
||||
code: $this->code,
|
||||
name: $this->name,
|
||||
amount: $this->amount,
|
||||
picture: $this->picture,
|
||||
diffusion: $this->diffusion,
|
||||
validity: $this->validity,
|
||||
couponValidityInformation: $this->couponValidityInformation,
|
||||
couponLegalInformation: $this->couponLegalInformation,
|
||||
processingCode: $this->processingCode,
|
||||
brandCode: $this->brandCode,
|
||||
createdBy: $this->createdBy,
|
||||
products: $this->products,
|
||||
gs1: $this->gs1
|
||||
code: $code,
|
||||
name: $name,
|
||||
amount: $amount,
|
||||
picture: $picture,
|
||||
diffusion: $diffusion,
|
||||
validityInformations: $validityInformations,
|
||||
legalInformations: $legalInformations,
|
||||
processingCode: $processingCode,
|
||||
brandCode: $brandCode,
|
||||
createdBy: $createdBy,
|
||||
products: $products,
|
||||
movements: $movements,
|
||||
quantity: $quantity,
|
||||
);
|
||||
|
||||
// THEN
|
||||
expect($coupon->availabilityCalendar)->toBeNull()
|
||||
->and($coupon->products)->toBe($this->products)
|
||||
->and($coupon->gs1)->toBe($this->gs1);
|
||||
->and($coupon->products)->toBe($products);
|
||||
});
|
||||
|
||||
it('hydrates a coupon without products', function (): void {
|
||||
it('hydrates a coupon without products', function () use (
|
||||
$code,
|
||||
$name,
|
||||
$amount,
|
||||
$picture,
|
||||
$diffusion,
|
||||
$validityInformations,
|
||||
$legalInformations,
|
||||
$processingCode,
|
||||
$brandCode,
|
||||
$createdBy,
|
||||
$movements,
|
||||
$quantity,
|
||||
$availabilityCalendar,
|
||||
): void {
|
||||
// GIVEN
|
||||
$id = CouponId::generate();
|
||||
|
||||
// WHEN
|
||||
$coupon = Coupon::hydrate(
|
||||
id: $id,
|
||||
code: $this->code,
|
||||
name: $this->name,
|
||||
amount: $this->amount,
|
||||
picture: $this->picture,
|
||||
diffusion: $this->diffusion,
|
||||
validity: $this->validity,
|
||||
couponValidityInformation: $this->couponValidityInformation,
|
||||
couponLegalInformation: $this->couponLegalInformation,
|
||||
processingCode: $this->processingCode,
|
||||
brandCode: $this->brandCode,
|
||||
createdBy: $this->createdBy,
|
||||
availabilityCalendar: $this->availabilityCalendar,
|
||||
gs1: $this->gs1
|
||||
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,
|
||||
quantity: $quantity,
|
||||
availabilityCalendar: $availabilityCalendar,
|
||||
);
|
||||
|
||||
// THEN
|
||||
expect($coupon->products)->toBe([])
|
||||
->and($coupon->availabilityCalendar)->toBe($this->availabilityCalendar)
|
||||
->and($coupon->gs1)->toBe($this->gs1);
|
||||
expect($coupon->products->value)->toBe([])
|
||||
->and($coupon->availabilityCalendar)->toBe($availabilityCalendar);
|
||||
});
|
||||
|
||||
it('hydrates a coupon with only required fields', function (): void {
|
||||
it('throws when validity information contains an invalid item', function () use (
|
||||
$code,
|
||||
$name,
|
||||
$amount,
|
||||
$picture,
|
||||
$diffusion,
|
||||
$legalInformations,
|
||||
$processingCode,
|
||||
$brandCode,
|
||||
$createdBy,
|
||||
$products,
|
||||
$movements,
|
||||
$quantity,
|
||||
$availabilityCalendar,
|
||||
): void {
|
||||
// GIVEN
|
||||
$id = CouponId::generate();
|
||||
|
||||
// WHEN
|
||||
$coupon = Coupon::hydrate(
|
||||
// WHEN / THEN
|
||||
expect(fn (): Coupon => Coupon::hydrate(
|
||||
id: $id,
|
||||
code: $this->code,
|
||||
name: $this->name,
|
||||
amount: $this->amount,
|
||||
picture: $this->picture,
|
||||
diffusion: $this->diffusion,
|
||||
validity: $this->validity,
|
||||
couponValidityInformation: $this->couponValidityInformation,
|
||||
couponLegalInformation: $this->couponLegalInformation,
|
||||
processingCode: $this->processingCode,
|
||||
brandCode: $this->brandCode,
|
||||
createdBy: $this->createdBy,
|
||||
);
|
||||
|
||||
// THEN
|
||||
expect($coupon->id())->toBe($id)
|
||||
->and($coupon->products)->toBe([])
|
||||
->and($coupon->availabilityCalendar)->toBeNull()
|
||||
->and($coupon->gs1)->toBeNull()
|
||||
->and($coupon->updatedAt)->toBeNull()
|
||||
->and($coupon->updatedAt())->toBeNull();
|
||||
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,
|
||||
quantity: $quantity,
|
||||
availabilityCalendar: $availabilityCalendar,
|
||||
))->toThrow(\DomainException::class, 'Value of CouponValidityInformationArray must be CouponValidityInformation instances.');
|
||||
});
|
||||
|
||||
it('accepts empty validity and legal information lists', function (): void {
|
||||
// GIVEN
|
||||
$id = CouponId::generate();
|
||||
|
||||
// WHEN
|
||||
$coupon = Coupon::hydrate(
|
||||
$id,
|
||||
$this->code,
|
||||
$this->name,
|
||||
$this->amount,
|
||||
$this->picture,
|
||||
$this->diffusion,
|
||||
$this->validity,
|
||||
[],
|
||||
[],
|
||||
$this->processingCode,
|
||||
$this->brandCode,
|
||||
$this->createdBy,
|
||||
$this->products,
|
||||
$this->availabilityCalendar,
|
||||
$this->gs1,
|
||||
);
|
||||
|
||||
// THEN
|
||||
expect($coupon->couponValidityInformation)->toBe([])
|
||||
->and($coupon->couponLegalInformation)->toBe([]);
|
||||
});
|
||||
|
||||
it('throws when validity information contains an invalid item', function (): void {
|
||||
it('throws when legal information contains an invalid item', function () use (
|
||||
$code,
|
||||
$name,
|
||||
$amount,
|
||||
$picture,
|
||||
$diffusion,
|
||||
$validityInformations,
|
||||
$processingCode,
|
||||
$brandCode,
|
||||
$createdBy,
|
||||
$products,
|
||||
$movements,
|
||||
$quantity,
|
||||
$availabilityCalendar,
|
||||
): void {
|
||||
// GIVEN
|
||||
$id = CouponId::generate();
|
||||
|
||||
// WHEN / THEN
|
||||
expect(fn () => Coupon::hydrate(
|
||||
$id,
|
||||
$this->code,
|
||||
$this->name,
|
||||
$this->amount,
|
||||
$this->picture,
|
||||
$this->diffusion,
|
||||
$this->validity,
|
||||
['Not a CouponValidityInformation'],
|
||||
$this->couponLegalInformation,
|
||||
$this->processingCode,
|
||||
$this->brandCode,
|
||||
$this->createdBy,
|
||||
$this->products,
|
||||
$this->availabilityCalendar,
|
||||
$this->gs1,
|
||||
))->toThrow(\DomainException::class, 'Coupon validity information must be CouponValidityInformation instances.');
|
||||
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,
|
||||
quantity: $quantity,
|
||||
availabilityCalendar: $availabilityCalendar,
|
||||
))->toThrow(\DomainException::class, 'Value of CouponLegalInformationArray must be CouponLegalInformation instances.');
|
||||
});
|
||||
|
||||
it('throws when legal information contains an invalid item', function (): void {
|
||||
// GIVEN
|
||||
$id = CouponId::generate();
|
||||
|
||||
// WHEN / THEN
|
||||
expect(fn () => Coupon::hydrate(
|
||||
$id,
|
||||
$this->code,
|
||||
$this->name,
|
||||
$this->amount,
|
||||
$this->picture,
|
||||
$this->diffusion,
|
||||
$this->validity,
|
||||
$this->couponValidityInformation,
|
||||
['Not a CouponLegalInformation'],
|
||||
$this->processingCode,
|
||||
$this->brandCode,
|
||||
$this->createdBy,
|
||||
$this->products,
|
||||
$this->availabilityCalendar,
|
||||
$this->gs1,
|
||||
))->toThrow(\DomainException::class, 'Coupon legal information must be CouponLegalInformation instances.');
|
||||
});
|
||||
|
||||
it('hydrates a coupon with an explicit updatedAt date', function (): void {
|
||||
it('hydrates a coupon with an explicit updatedAt date', function () use (
|
||||
$code,
|
||||
$name,
|
||||
$amount,
|
||||
$picture,
|
||||
$diffusion,
|
||||
$validityInformations,
|
||||
$legalInformations,
|
||||
$processingCode,
|
||||
$brandCode,
|
||||
$createdBy,
|
||||
$products,
|
||||
$movements,
|
||||
$quantity,
|
||||
$availabilityCalendar,
|
||||
): void {
|
||||
// GIVEN
|
||||
$id = CouponId::generate();
|
||||
$updatedAt = new \DateTimeImmutable('2026-09-22 10:00:00', new \DateTimeZone('UTC'));
|
||||
|
|
@ -308,21 +315,21 @@ describe('coupon', function (): void {
|
|||
// WHEN
|
||||
$coupon = Coupon::hydrate(
|
||||
$id,
|
||||
$this->code,
|
||||
$this->name,
|
||||
$this->amount,
|
||||
$this->picture,
|
||||
$this->diffusion,
|
||||
$this->validity,
|
||||
$this->couponValidityInformation,
|
||||
$this->couponLegalInformation,
|
||||
$this->processingCode,
|
||||
$this->brandCode,
|
||||
$this->createdBy,
|
||||
$this->products,
|
||||
$this->availabilityCalendar,
|
||||
$this->gs1,
|
||||
$updatedAt
|
||||
code: $code,
|
||||
name: $name,
|
||||
amount: $amount,
|
||||
picture: $picture,
|
||||
diffusion: $diffusion,
|
||||
validityInformations: $validityInformations,
|
||||
legalInformations: $legalInformations,
|
||||
processingCode: $processingCode,
|
||||
brandCode: $brandCode,
|
||||
createdBy: $createdBy,
|
||||
products: $products,
|
||||
movements: $movements,
|
||||
quantity: $quantity,
|
||||
availabilityCalendar: $availabilityCalendar,
|
||||
updatedAt: $updatedAt,
|
||||
);
|
||||
|
||||
// THEN
|
||||
|
|
@ -330,104 +337,149 @@ describe('coupon', function (): void {
|
|||
->and($coupon->updatedAt())->toBe($updatedAt);
|
||||
});
|
||||
|
||||
it('creates a new coupon with a freshly generated id', function (): void {
|
||||
it('creates a new coupon with a freshly generated id', function () use (
|
||||
$code,
|
||||
$name,
|
||||
$amount,
|
||||
$picture,
|
||||
$diffusion,
|
||||
$validityInformations,
|
||||
$legalInformations,
|
||||
$processingCode,
|
||||
$brandCode,
|
||||
$createdBy,
|
||||
$products,
|
||||
$movements,
|
||||
$quantity,
|
||||
$availabilityCalendar,
|
||||
): void {
|
||||
// GIVEN / WHEN
|
||||
$coupon = Coupon::create(
|
||||
$this->code,
|
||||
$this->name,
|
||||
$this->amount,
|
||||
$this->picture,
|
||||
$this->diffusion,
|
||||
$this->validity,
|
||||
$this->couponValidityInformation,
|
||||
$this->couponLegalInformation,
|
||||
$this->processingCode,
|
||||
$this->brandCode,
|
||||
$this->createdBy,
|
||||
$this->products,
|
||||
$this->availabilityCalendar,
|
||||
$this->gs1,
|
||||
code: $code,
|
||||
name: $name,
|
||||
amount: $amount,
|
||||
picture: $picture,
|
||||
diffusion: $diffusion,
|
||||
validityInformations: $validityInformations,
|
||||
legalInformations: $legalInformations,
|
||||
processingCode: $processingCode,
|
||||
brandCode: $brandCode,
|
||||
createdBy: $createdBy,
|
||||
products: $products,
|
||||
movements: $movements,
|
||||
quantity: $quantity,
|
||||
availabilityCalendar: $availabilityCalendar,
|
||||
);
|
||||
|
||||
// THEN
|
||||
expect($coupon->id())->toBeInstanceOf(CouponId::class)
|
||||
->and($coupon->code)->toBe($this->code)
|
||||
->and($coupon->name)->toBe($this->name)
|
||||
->and($coupon->amount)->toBe($this->amount)
|
||||
->and($coupon->picture)->toBe($this->picture)
|
||||
->and($coupon->diffusion)->toBe($this->diffusion)
|
||||
->and($coupon->validity)->toBe($this->validity)
|
||||
->and($coupon->couponValidityInformation)->toBe($this->couponValidityInformation)
|
||||
->and($coupon->couponLegalInformation)->toBe($this->couponLegalInformation)
|
||||
->and($coupon->processingCode)->toBe($this->processingCode)
|
||||
->and($coupon->brandCode)->toBe($this->brandCode)
|
||||
->and($coupon->createdBy)->toBe($this->createdBy)
|
||||
->and($coupon->products)->toBe($this->products)
|
||||
->and($coupon->availabilityCalendar)->toBe($this->availabilityCalendar)
|
||||
->and($coupon->gs1)->toBe($this->gs1)
|
||||
->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->quantity)->toBe($quantity)
|
||||
->and($coupon->availabilityCalendar)->toBe($availabilityCalendar)
|
||||
->and($coupon->updatedAt)->toBeNull()
|
||||
->and($coupon->updatedAt())->toBeNull();
|
||||
});
|
||||
|
||||
it('generates a different id for each created coupon', function (): void {
|
||||
it('generates a different id for each created coupon', function () use (
|
||||
$code,
|
||||
$name,
|
||||
$amount,
|
||||
$picture,
|
||||
$diffusion,
|
||||
$validityInformations,
|
||||
$legalInformations,
|
||||
$processingCode,
|
||||
$brandCode,
|
||||
$createdBy,
|
||||
$products,
|
||||
$movements,
|
||||
$quantity,
|
||||
$availabilityCalendar,
|
||||
): void {
|
||||
// GIVEN / WHEN
|
||||
$firstCoupon = Coupon::create(
|
||||
$this->code,
|
||||
$this->name,
|
||||
$this->amount,
|
||||
$this->picture,
|
||||
$this->diffusion,
|
||||
$this->validity,
|
||||
$this->couponValidityInformation,
|
||||
$this->couponLegalInformation,
|
||||
$this->processingCode,
|
||||
$this->brandCode,
|
||||
$this->createdBy,
|
||||
$this->products,
|
||||
$this->availabilityCalendar,
|
||||
$this->gs1,
|
||||
code: $code,
|
||||
name: $name,
|
||||
amount: $amount,
|
||||
picture: $picture,
|
||||
diffusion: $diffusion,
|
||||
validityInformations: $validityInformations,
|
||||
legalInformations: $legalInformations,
|
||||
processingCode: $processingCode,
|
||||
brandCode: $brandCode,
|
||||
createdBy: $createdBy,
|
||||
products: $products,
|
||||
movements: $movements,
|
||||
quantity: $quantity,
|
||||
availabilityCalendar: $availabilityCalendar,
|
||||
);
|
||||
$secondCoupon = Coupon::create(
|
||||
$this->code,
|
||||
$this->name,
|
||||
$this->amount,
|
||||
$this->picture,
|
||||
$this->diffusion,
|
||||
$this->validity,
|
||||
$this->couponValidityInformation,
|
||||
$this->couponLegalInformation,
|
||||
$this->processingCode,
|
||||
$this->brandCode,
|
||||
$this->createdBy,
|
||||
$this->products,
|
||||
$this->availabilityCalendar,
|
||||
$this->gs1,
|
||||
code: $code,
|
||||
name: $name,
|
||||
amount: $amount,
|
||||
picture: $picture,
|
||||
diffusion: $diffusion,
|
||||
validityInformations: $validityInformations,
|
||||
legalInformations: $legalInformations,
|
||||
processingCode: $processingCode,
|
||||
brandCode: $brandCode,
|
||||
createdBy: $createdBy,
|
||||
products: $products,
|
||||
movements: $movements,
|
||||
quantity: $quantity,
|
||||
availabilityCalendar: $availabilityCalendar,
|
||||
);
|
||||
|
||||
// THEN
|
||||
expect($firstCoupon->id()->equals($secondCoupon->id()))->toBeFalse();
|
||||
});
|
||||
|
||||
it('returns the creation date extracted from the id', function (): void {
|
||||
it('returns the creation date extracted from the id', function () use (
|
||||
$code,
|
||||
$name,
|
||||
$amount,
|
||||
$picture,
|
||||
$diffusion,
|
||||
$validityInformations,
|
||||
$legalInformations,
|
||||
$processingCode,
|
||||
$brandCode,
|
||||
$createdBy,
|
||||
$products,
|
||||
$movements,
|
||||
$quantity,
|
||||
$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,
|
||||
$this->code,
|
||||
$this->name,
|
||||
$this->amount,
|
||||
$this->picture,
|
||||
$this->diffusion,
|
||||
$this->validity,
|
||||
$this->couponValidityInformation,
|
||||
$this->couponLegalInformation,
|
||||
$this->processingCode,
|
||||
$this->brandCode,
|
||||
$this->createdBy,
|
||||
$this->products,
|
||||
$this->availabilityCalendar,
|
||||
$this->gs1,
|
||||
code: $code,
|
||||
name: $name,
|
||||
amount: $amount,
|
||||
picture: $picture,
|
||||
diffusion: $diffusion,
|
||||
validityInformations: $validityInformations,
|
||||
legalInformations: $legalInformations,
|
||||
processingCode: $processingCode,
|
||||
brandCode: $brandCode,
|
||||
createdBy: $createdBy,
|
||||
products: $products,
|
||||
movements: $movements,
|
||||
quantity: $quantity,
|
||||
availabilityCalendar: $availabilityCalendar,
|
||||
);
|
||||
|
||||
// WHEN
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ namespace Tests\Unit\Domain\Models\Entities;
|
|||
use Domain\Models\Entities\Stock;
|
||||
use Domain\Models\ValueObjects\Actor\ActorId;
|
||||
use Domain\Models\ValueObjects\Campaign\CampaignCode;
|
||||
use Domain\Models\ValueObjects\ProcessingCode;
|
||||
use Domain\Models\ValueObjects\Coupon\CouponCode;
|
||||
use Domain\Models\ValueObjects\Stock\StockAdjustment;
|
||||
use Domain\Models\ValueObjects\Stock\StockAmount;
|
||||
use Domain\Models\ValueObjects\Stock\StockId;
|
||||
|
|
@ -16,40 +16,38 @@ use Ramsey\Uuid\Uuid;
|
|||
covers(Stock::class);
|
||||
|
||||
describe('stock', function (): void {
|
||||
beforeEach(function (): void {
|
||||
$this->stockAmount = new StockAmount(10);
|
||||
$this->campaignCode = new CampaignCode('AAA01');
|
||||
$this->processingCode = new ProcessingCode('PC1');
|
||||
$this->stockAdjustment = [new StockAdjustment(5, 'Inventory correction', ActorId::generate())];
|
||||
});
|
||||
$stockAmount = new StockAmount(10);
|
||||
$campaignCode = new CampaignCode('AAA01');
|
||||
$couponCode = new CouponCode('AAA01');
|
||||
$stockAdjustment = [new StockAdjustment(5, 'Inventory correction', ActorId::generate())];
|
||||
|
||||
it('hydrates a stock', function (): void {
|
||||
it('hydrates a stock', function () use ($stockAmount, $campaignCode, $couponCode, $stockAdjustment): void {
|
||||
// GIVEN
|
||||
$id = StockId::generate();
|
||||
|
||||
// WHEN
|
||||
$stock = Stock::hydrate(
|
||||
$id,
|
||||
$this->stockAmount,
|
||||
$this->campaignCode,
|
||||
$this->processingCode,
|
||||
$this->stockAdjustment
|
||||
$stockAmount,
|
||||
$campaignCode,
|
||||
$couponCode,
|
||||
$stockAdjustment,
|
||||
);
|
||||
|
||||
// THEN
|
||||
expect($stock->id())->toBe($id)
|
||||
->and($stock->stockAmount)->toBe($this->stockAmount)
|
||||
->and($stock->campaignCode)->toBe($this->campaignCode)
|
||||
->and($stock->processingCode)->toBe($this->processingCode)
|
||||
->and($stock->stockAdjustment)->toBe($this->stockAdjustment)
|
||||
->and($stock->stockAmount)->toBe($stockAmount)
|
||||
->and($stock->campaignCode)->toBe($campaignCode)
|
||||
->and($stock->couponCode)->toBe($couponCode)
|
||||
->and($stock->stockAdjustment)->toBe($stockAdjustment)
|
||||
->and($stock->updatedAt)->toBeNull()
|
||||
->and($stock->updatedAt())->toBeNull();
|
||||
});
|
||||
|
||||
it('hydrates a stock with several stock adjustments', function (): void {
|
||||
it('hydrates a stock with several stock adjustments', function () use ($stockAmount, $campaignCode, $couponCode): void {
|
||||
// GIVEN
|
||||
$id = StockId::generate();
|
||||
$stockAdjustment = [
|
||||
$id = StockId::generate();
|
||||
$severalAdjustments = [
|
||||
new StockAdjustment(5, 'Inventory correction', ActorId::generate()),
|
||||
new StockAdjustment(10, 'Inventory correction', ActorId::generate()),
|
||||
];
|
||||
|
|
@ -57,70 +55,70 @@ describe('stock', function (): void {
|
|||
// WHEN
|
||||
$stock = Stock::hydrate(
|
||||
$id,
|
||||
$this->stockAmount,
|
||||
$this->campaignCode,
|
||||
$this->processingCode,
|
||||
$stockAdjustment,
|
||||
$stockAmount,
|
||||
$campaignCode,
|
||||
$couponCode,
|
||||
$severalAdjustments,
|
||||
);
|
||||
|
||||
// THEN
|
||||
expect($stock->id())->toBe($id)
|
||||
->and($stock->stockAmount)->toBe($this->stockAmount)
|
||||
->and($stock->campaignCode)->toBe($this->campaignCode)
|
||||
->and($stock->processingCode)->toBe($this->processingCode)
|
||||
->and($stock->stockAdjustment)->toBe($stockAdjustment)
|
||||
->and($stock->stockAmount)->toBe($stockAmount)
|
||||
->and($stock->campaignCode)->toBe($campaignCode)
|
||||
->and($stock->couponCode)->toBe($couponCode)
|
||||
->and($stock->stockAdjustment)->toBe($severalAdjustments)
|
||||
->and($stock->updatedAt)->toBeNull()
|
||||
->and($stock->updatedAt())->toBeNull();
|
||||
});
|
||||
|
||||
it('hydrates a stock without stock adjustement', function (): void {
|
||||
it('hydrates a stock without stock adjustement', function () use ($stockAmount, $campaignCode, $couponCode): void {
|
||||
// GIVEN
|
||||
$id = StockId::generate();
|
||||
|
||||
// WHEN
|
||||
$stock = Stock::hydrate(
|
||||
$id,
|
||||
$this->stockAmount,
|
||||
$this->campaignCode,
|
||||
$this->processingCode
|
||||
$stockAmount,
|
||||
$campaignCode,
|
||||
$couponCode,
|
||||
);
|
||||
|
||||
// THEN
|
||||
expect($stock->id())->toBe($id)
|
||||
->and($stock->stockAmount)->toBe($this->stockAmount)
|
||||
->and($stock->campaignCode)->toBe($this->campaignCode)
|
||||
->and($stock->processingCode)->toBe($this->processingCode)
|
||||
->and($stock->stockAmount)->toBe($stockAmount)
|
||||
->and($stock->campaignCode)->toBe($campaignCode)
|
||||
->and($stock->couponCode)->toBe($couponCode)
|
||||
->and($stock->stockAdjustment)->toBe([])
|
||||
->and($stock->updatedAt)->toBeNull()
|
||||
->and($stock->updatedAt())->toBeNull();
|
||||
});
|
||||
|
||||
it('rejects a stock with a non-stock-adjustment element', function (): void {
|
||||
it('rejects a stock with a non-stock-adjustment element', function () use ($stockAmount, $campaignCode, $couponCode): void {
|
||||
// GIVEN
|
||||
$id = StockId::generate();
|
||||
$stockAdjustment = [new StockAmount(5)];
|
||||
$id = StockId::generate();
|
||||
$invalidAdjustment = [new StockAmount(5)];
|
||||
|
||||
// WHEN / THEN
|
||||
expect(fn (): Stock => Stock::hydrate(
|
||||
$id,
|
||||
$this->stockAmount,
|
||||
$this->campaignCode,
|
||||
$this->processingCode,
|
||||
$stockAdjustment,
|
||||
$stockAmount,
|
||||
$campaignCode,
|
||||
$couponCode,
|
||||
$invalidAdjustment,
|
||||
))->toThrow(\DomainException::class, 'Stock adjustment must be StockAdjustment instances.');
|
||||
});
|
||||
|
||||
it('hydrates a stock with an explicit updatedAt date', function (): void {
|
||||
it('hydrates a stock with an explicit updatedAt date', function () use ($stockAmount, $campaignCode, $couponCode, $stockAdjustment): void {
|
||||
// GIVEN
|
||||
$updatedAt = new \DateTimeImmutable('2026-06-15 12:00:00', new \DateTimeZone('UTC'));
|
||||
|
||||
// WHEN
|
||||
$stock = Stock::hydrate(
|
||||
StockId::generate(),
|
||||
$this->stockAmount,
|
||||
$this->campaignCode,
|
||||
$this->processingCode,
|
||||
$this->stockAdjustment,
|
||||
$stockAmount,
|
||||
$campaignCode,
|
||||
$couponCode,
|
||||
$stockAdjustment,
|
||||
$updatedAt,
|
||||
);
|
||||
|
||||
|
|
@ -129,16 +127,16 @@ describe('stock', function (): void {
|
|||
->and($stock->updatedAt())->toBe($updatedAt);
|
||||
});
|
||||
|
||||
it('returns the creation date extracted from the id', function (): void {
|
||||
it('returns the creation date extracted from the id', function () use ($stockAmount, $campaignCode, $couponCode, $stockAdjustment): void {
|
||||
// GIVEN
|
||||
$expected = new \DateTimeImmutable('2024-06-15 12:34:56.789000', new \DateTimeZone('UTC'));
|
||||
$id = new StockId(Uuid::uuid7($expected));
|
||||
$stock = Stock::hydrate(
|
||||
$id,
|
||||
$this->stockAmount,
|
||||
$this->campaignCode,
|
||||
$this->processingCode,
|
||||
$this->stockAdjustment
|
||||
$stockAmount,
|
||||
$campaignCode,
|
||||
$couponCode,
|
||||
$stockAdjustment
|
||||
);
|
||||
|
||||
// WHEN
|
||||
|
|
|
|||
|
|
@ -9,25 +9,22 @@ use Domain\Models\ValueObjects\Actor\ActorDisplayName;
|
|||
covers(ActorDisplayName::class);
|
||||
|
||||
describe('actor displayname', function (): void {
|
||||
beforeEach(function (): void {
|
||||
$this->value = 'Johnny';
|
||||
$this->emptyValue = '';
|
||||
});
|
||||
$value = 'Johnny';
|
||||
$emptyValue = '';
|
||||
|
||||
it('creates a valid actor displayname', function (): void {
|
||||
it('creates a valid actor displayname', function () use ($value): void {
|
||||
// GIVEN / WHEN
|
||||
$name = new ActorDisplayName(
|
||||
$this->value
|
||||
$value
|
||||
);
|
||||
|
||||
// THEN
|
||||
expect($name->value)->toBe($this->value);
|
||||
expect($name->value)->toBe($value);
|
||||
});
|
||||
|
||||
it('rejects invalid actor displayname', function (): void {
|
||||
it('rejects invalid actor displayname', function () use ($emptyValue): void {
|
||||
// GIVEN / WHEN / THEN
|
||||
expect(fn (): ActorDisplayName => new ActorDisplayName(
|
||||
$this->emptyValue
|
||||
))->toThrow(\DomainException::class);
|
||||
expect(fn (): ActorDisplayName => new ActorDisplayName($emptyValue))
|
||||
->toThrow(\DomainException::class);
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -9,26 +9,21 @@ use Domain\Models\ValueObjects\Brand\BrandName;
|
|||
covers(BrandName::class);
|
||||
|
||||
describe('brand name', function (): void {
|
||||
beforeEach(function (): void {
|
||||
$this->value = 'Name';
|
||||
$this->emptyValue = '';
|
||||
});
|
||||
$value = 'Name';
|
||||
$emptyValue = '';
|
||||
|
||||
it('creates a valid brand name', function (): void {
|
||||
it('creates a valid brand name', function () use ($value): void {
|
||||
// GIVEN / WHEN
|
||||
$name = new BrandName(
|
||||
$this->value
|
||||
);
|
||||
$name = new BrandName($value);
|
||||
|
||||
// THEN
|
||||
expect($name->value)->toBe($this->value);
|
||||
expect($name->value)->toBe($value);
|
||||
});
|
||||
|
||||
it('rejects invalid brand name', function (): void {
|
||||
it('rejects invalid brand name', function () use ($emptyValue): void {
|
||||
// GIVEN / WHEN / THEN
|
||||
expect(fn (): BrandName => new BrandName(
|
||||
$this->emptyValue
|
||||
))->toThrow(\DomainException::class);
|
||||
expect(fn (): BrandName => new BrandName($emptyValue))
|
||||
->toThrow(\DomainException::class);
|
||||
});
|
||||
|
||||
it('rejects a name that exceeds the maximum allowed length', function (): void {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,34 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Tests\Unit\Domain\Models\ValueObjects\Brand;
|
||||
|
||||
use Domain\Models\ValueObjects\Brand\BrandSortCriteria;
|
||||
use Domain\Models\ValueObjects\Brand\BrandSortField;
|
||||
|
||||
covers(BrandSortCriteria::class);
|
||||
|
||||
describe('brand sort criteria', function (): void {
|
||||
it('sorts by name ascending by default', function (): void {
|
||||
// GIVEN / WHEN
|
||||
$criteria = new BrandSortCriteria();
|
||||
|
||||
// THEN
|
||||
expect($criteria->field)->toBe(BrandSortField::Name)
|
||||
->and($criteria->direction)->toBe(\SortDirection::Ascending);
|
||||
});
|
||||
|
||||
it('keeps the given field and direction', function (): void {
|
||||
// GIVEN
|
||||
$field = BrandSortField::Name;
|
||||
$direction = \SortDirection::Descending;
|
||||
|
||||
// WHEN
|
||||
$criteria = new BrandSortCriteria($field, $direction);
|
||||
|
||||
// THEN
|
||||
expect($criteria->field)->toBe($field)
|
||||
->and($criteria->direction)->toBe($direction);
|
||||
});
|
||||
});
|
||||
|
|
@ -9,23 +9,20 @@ use Domain\Models\ValueObjects\Campaign\CampaignCode;
|
|||
covers(CampaignCode::class);
|
||||
|
||||
describe('campaign code', function (): void {
|
||||
beforeEach(function (): void {
|
||||
$this->code = 'Name';
|
||||
$this->emptyCode = '';
|
||||
});
|
||||
$code = 'Name';
|
||||
$emptyCode = '';
|
||||
|
||||
it('creates a valid campaign code', function (): void {
|
||||
it('creates a valid campaign code', function () use ($code): void {
|
||||
// GIVEN / WHEN
|
||||
$name = new CampaignCode($this->code);
|
||||
$name = new CampaignCode($code);
|
||||
|
||||
// THEN
|
||||
expect($name->code)->toBe($this->code);
|
||||
expect($name->code)->toBe($code);
|
||||
});
|
||||
|
||||
it('rejects invalid campaign code', function (): void {
|
||||
it('rejects invalid campaign code', function () use ($emptyCode): void {
|
||||
// GIVEN / WHEN / THEN
|
||||
expect(fn (): CampaignCode => new CampaignCode(
|
||||
$this->emptyCode
|
||||
))->toThrow(\DomainException::class);
|
||||
expect(fn (): CampaignCode => new CampaignCode($emptyCode))
|
||||
->toThrow(\DomainException::class);
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -0,0 +1,57 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Tests\Unit\Domain\Models\ValueObjects\Campaign;
|
||||
|
||||
use Domain\Models\ValueObjects\Campaign\CampaignCoupon;
|
||||
use Domain\Models\ValueObjects\Campaign\CampaignCouponArray;
|
||||
use Domain\Models\ValueObjects\Coupon\CouponCode;
|
||||
use Domain\Models\ValueObjects\PrintRules;
|
||||
|
||||
covers(CampaignCouponArray::class);
|
||||
|
||||
describe('campaign coupon array', function (): void {
|
||||
$coupon = new CampaignCoupon(
|
||||
new CouponCode('AAA01'),
|
||||
new PrintRules(maxPerCustomer: 3),
|
||||
);
|
||||
|
||||
it('creates an array with valid coupons', function () use ($coupon): void {
|
||||
// GIVEN
|
||||
$coupons = [$coupon, $coupon];
|
||||
|
||||
// WHEN
|
||||
$array = new CampaignCouponArray($coupons);
|
||||
|
||||
// THEN
|
||||
expect($array->value)->toBe($coupons);
|
||||
});
|
||||
|
||||
it('rejects an empty array', function (): void {
|
||||
// GIVEN / WHEN
|
||||
$action = fn (): CampaignCouponArray => new CampaignCouponArray([]);
|
||||
|
||||
// THEN
|
||||
expect($action)->toThrow(\DomainException::class, 'Coupons requires at least one CampaignCoupon.');
|
||||
});
|
||||
|
||||
it('rejects a non-coupon element', function (): void {
|
||||
// GIVEN / WHEN
|
||||
$action = fn (): CampaignCouponArray => new CampaignCouponArray(['PC1']);
|
||||
|
||||
// THEN
|
||||
expect($action)->toThrow(\DomainException::class, 'Coupons must be CampaignCoupon instances.');
|
||||
});
|
||||
|
||||
it('rejects a non-coupon element mixed with valid coupons', function () use ($coupon): void {
|
||||
// GIVEN
|
||||
$coupons = [$coupon, 'PC1'];
|
||||
|
||||
// WHEN
|
||||
$action = fn (): CampaignCouponArray => new CampaignCouponArray($coupons);
|
||||
|
||||
// THEN
|
||||
expect($action)->toThrow(\DomainException::class, 'Coupons must be CampaignCoupon instances.');
|
||||
});
|
||||
});
|
||||
|
|
@ -5,78 +5,34 @@ declare(strict_types=1);
|
|||
namespace Tests\Unit\Domain\Models\ValueObjects\Campaign;
|
||||
|
||||
use Domain\Models\ValueObjects\Campaign\CampaignCoupon;
|
||||
use Domain\Models\ValueObjects\Coupon\CouponQuantity;
|
||||
use Domain\Models\ValueObjects\Coupon\CouponCode;
|
||||
use Domain\Models\ValueObjects\PrintRules;
|
||||
use Domain\Models\ValueObjects\ProcessingCode;
|
||||
use Shared\Enums\Country;
|
||||
|
||||
covers(CampaignCoupon::class);
|
||||
|
||||
describe('campaign coupon', function (): void {
|
||||
beforeEach(function (): void {
|
||||
$this->processingCode = new ProcessingCode('PC1');
|
||||
$this->quantity = new CouponQuantity(10);
|
||||
$this->availableIn = Country::FRANCE;
|
||||
$this->printRules = new PrintRules(maxPerCustomer: 3);
|
||||
});
|
||||
$couponCode = new CouponCode('AAA01');
|
||||
$printRules = new PrintRules(maxPerCustomer: 3);
|
||||
|
||||
it('creates a valid campaign coupon', function (): void {
|
||||
it('creates a valid campaign coupon', function () use ($couponCode, $printRules): void {
|
||||
// GIVEN / WHEN
|
||||
$campaignCoupon = new CampaignCoupon(
|
||||
$this->processingCode,
|
||||
$this->quantity,
|
||||
$this->availableIn,
|
||||
$this->printRules
|
||||
couponCode: $couponCode,
|
||||
printRules: $printRules,
|
||||
);
|
||||
|
||||
// THEN
|
||||
expect($campaignCoupon->processingCode)->toBe($this->processingCode)
|
||||
->and($campaignCoupon->quantity)->toBe($this->quantity)
|
||||
->and($campaignCoupon->availableIn)->toBe($this->availableIn)
|
||||
->and($campaignCoupon->printRules)->toBe($this->printRules);
|
||||
expect($campaignCoupon->couponCode)->toBe($couponCode)
|
||||
->and($campaignCoupon->printRules)->toBe($printRules);
|
||||
});
|
||||
|
||||
it('creates a valid campaign coupon whitout warning threshold quantity', function (): void {
|
||||
it('creates a valid campaign coupon whitout print rules', function () use ($couponCode): void {
|
||||
// GIVEN / WHEN
|
||||
$campaignCoupon = new CampaignCoupon(
|
||||
processingCode: $this->processingCode,
|
||||
quantity: $this->quantity,
|
||||
availableIn: $this->availableIn,
|
||||
printRules: $this->printRules
|
||||
couponCode: $couponCode,
|
||||
);
|
||||
|
||||
// THEN
|
||||
expect($campaignCoupon->processingCode)->toBe($this->processingCode)
|
||||
->and($campaignCoupon->quantity)->toBe($this->quantity)
|
||||
->and($campaignCoupon->availableIn)->toBe($this->availableIn)
|
||||
->and($campaignCoupon->printRules)->toBe($this->printRules);
|
||||
});
|
||||
|
||||
it('creates a valid campaign coupon whitout print rules', function (): void {
|
||||
// GIVEN / WHEN
|
||||
$campaignCoupon = new CampaignCoupon(
|
||||
processingCode: $this->processingCode,
|
||||
quantity: $this->quantity,
|
||||
availableIn: $this->availableIn,
|
||||
);
|
||||
|
||||
// THEN
|
||||
expect($campaignCoupon->processingCode)->toBe($this->processingCode)
|
||||
->and($campaignCoupon->quantity)->toBe($this->quantity)
|
||||
->and($campaignCoupon->availableIn)->toBe($this->availableIn);
|
||||
});
|
||||
|
||||
it('creates a valid campaign coupon whitout warning threshold quantity and print rules', function (): void {
|
||||
// GIVEN / WHEN
|
||||
$campaignCoupon = new CampaignCoupon(
|
||||
processingCode: $this->processingCode,
|
||||
quantity: $this->quantity,
|
||||
availableIn: $this->availableIn
|
||||
);
|
||||
|
||||
// THEN
|
||||
expect($campaignCoupon->processingCode)->toBe($this->processingCode)
|
||||
->and($campaignCoupon->quantity)->toBe($this->quantity)
|
||||
->and($campaignCoupon->availableIn)->toBe($this->availableIn);
|
||||
expect($campaignCoupon->couponCode)->toBe($couponCode);
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -9,23 +9,20 @@ use Domain\Models\ValueObjects\Campaign\CampaignName;
|
|||
covers(CampaignName::class);
|
||||
|
||||
describe('campaign name', function (): void {
|
||||
beforeEach(function (): void {
|
||||
$this->value = 'Name';
|
||||
$this->emptyValue = '';
|
||||
});
|
||||
$value = 'Name';
|
||||
$emptyValue = '';
|
||||
|
||||
it('creates a valid campaign name', function (): void {
|
||||
it('creates a valid campaign name', function () use ($value): void {
|
||||
// GIVEN / WHEN
|
||||
$name = new CampaignName($this->value);
|
||||
$name = new CampaignName($value);
|
||||
|
||||
// THEN
|
||||
expect($name->value)->toBe($this->value);
|
||||
expect($name->value)->toBe($value);
|
||||
});
|
||||
|
||||
it('rejects invalid campaign name', function (): void {
|
||||
it('rejects invalid campaign name', function () use ($emptyValue): void {
|
||||
// GIVEN / WHEN / THEN
|
||||
expect(fn (): CampaignName => new CampaignName(
|
||||
$this->emptyValue
|
||||
))->toThrow(\DomainException::class);
|
||||
expect(fn (): CampaignName => new CampaignName($emptyValue))
|
||||
->toThrow(\DomainException::class);
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -10,33 +10,31 @@ use Shared\ValueObjects\Email;
|
|||
covers(Applicant::class);
|
||||
|
||||
describe('applicant', function (): void {
|
||||
beforeEach(function (): void {
|
||||
$this->firstname = 'John';
|
||||
$this->lastname = 'Doe';
|
||||
$this->email = new Email('john.doe@example.com');
|
||||
});
|
||||
$firstname = 'John';
|
||||
$lastname = 'Doe';
|
||||
$email = new Email('john.doe@example.com');
|
||||
|
||||
it('creates a valid applicant', function (): void {
|
||||
it('creates a valid applicant', function () use ($firstname, $lastname, $email): void {
|
||||
// GIVEN / WHEN
|
||||
$applicant = new Applicant(
|
||||
$this->firstname,
|
||||
$this->lastname,
|
||||
$this->email
|
||||
$firstname,
|
||||
$lastname,
|
||||
$email,
|
||||
);
|
||||
|
||||
// THEN
|
||||
expect($applicant)->toBeInstanceOf(Applicant::class)
|
||||
->and($applicant->firstname)->toBe($this->firstname)
|
||||
->and($applicant->lastname)->toBe($this->lastname)
|
||||
->and($applicant->email)->toBe($this->email);
|
||||
->and($applicant->firstname)->toBe($firstname)
|
||||
->and($applicant->lastname)->toBe($lastname)
|
||||
->and($applicant->email)->toBe($email);
|
||||
});
|
||||
|
||||
it('rejects an empty or whitespace-only firstname', function (string $firstname): void {
|
||||
it('rejects an empty or whitespace-only firstname', function (string $invalidFirstname) use ($lastname, $email): void {
|
||||
// WHEN
|
||||
$action = fn (): Applicant => new Applicant(
|
||||
$firstname,
|
||||
$this->lastname,
|
||||
$this->email
|
||||
$invalidFirstname,
|
||||
$lastname,
|
||||
$email,
|
||||
);
|
||||
|
||||
// THEN
|
||||
|
|
@ -46,42 +44,42 @@ describe('applicant', function (): void {
|
|||
'spaces' => ' ',
|
||||
]);
|
||||
|
||||
it('rejects a firstname that exceeds the maximum allowed length', function (): void {
|
||||
it('rejects a firstname that exceeds the maximum allowed length', function () use ($lastname, $email): void {
|
||||
// GIVEN
|
||||
$firstname = str_repeat('a', 201);
|
||||
$tooLongFirstname = str_repeat('a', 201);
|
||||
|
||||
// WHEN
|
||||
$action = fn (): Applicant => new Applicant(
|
||||
$firstname,
|
||||
$this->lastname,
|
||||
$this->email
|
||||
$tooLongFirstname,
|
||||
$lastname,
|
||||
$email,
|
||||
);
|
||||
|
||||
// THEN
|
||||
expect($action)->toThrow(\DomainException::class, 'Applicant firstname exceeds the maximum allowed length.');
|
||||
});
|
||||
|
||||
it('accepts a firstname of exactly the maximum length', function (): void {
|
||||
it('accepts a firstname of exactly the maximum length', function () use ($lastname, $email): void {
|
||||
// GIVEN
|
||||
$firstname = str_repeat('a', 200);
|
||||
$maxLengthFirstname = str_repeat('a', 200);
|
||||
|
||||
// WHEN
|
||||
$applicant = new Applicant(
|
||||
$firstname,
|
||||
$this->lastname,
|
||||
$this->email
|
||||
$maxLengthFirstname,
|
||||
$lastname,
|
||||
$email,
|
||||
);
|
||||
|
||||
// THEN
|
||||
expect(mb_strlen($applicant->firstname))->toBe(200);
|
||||
});
|
||||
|
||||
it('rejects an empty or whitespace-only lastname', function (string $lastname): void {
|
||||
it('rejects an empty or whitespace-only lastname', function (string $invalidLastname) use ($firstname, $email): void {
|
||||
// WHEN
|
||||
$action = fn (): Applicant => new Applicant(
|
||||
$this->firstname,
|
||||
$lastname,
|
||||
$this->email
|
||||
$firstname,
|
||||
$invalidLastname,
|
||||
$email,
|
||||
);
|
||||
|
||||
// THEN
|
||||
|
|
@ -91,30 +89,30 @@ describe('applicant', function (): void {
|
|||
'spaces' => ' ',
|
||||
]);
|
||||
|
||||
it('rejects a lastname that exceeds the maximum allowed length', function (): void {
|
||||
it('rejects a lastname that exceeds the maximum allowed length', function () use ($firstname, $email): void {
|
||||
// GIVEN
|
||||
$lastname = str_repeat('a', 201);
|
||||
$tooLongLastname = str_repeat('a', 201);
|
||||
|
||||
// WHEN
|
||||
$action = fn (): Applicant => new Applicant(
|
||||
$this->firstname,
|
||||
$lastname,
|
||||
$this->email
|
||||
$firstname,
|
||||
$tooLongLastname,
|
||||
$email,
|
||||
);
|
||||
|
||||
// THEN
|
||||
expect($action)->toThrow(\DomainException::class, 'Applicant lastname exceeds the maximum allowed length.');
|
||||
});
|
||||
|
||||
it('accepts a lastname of exactly the maximum length', function (): void {
|
||||
it('accepts a lastname of exactly the maximum length', function () use ($firstname, $email): void {
|
||||
// GIVEN
|
||||
$lastname = str_repeat('a', 200);
|
||||
$maxLengthLastname = str_repeat('a', 200);
|
||||
|
||||
// WHEN
|
||||
$applicant = new Applicant(
|
||||
$this->firstname,
|
||||
$lastname,
|
||||
$this->email
|
||||
$firstname,
|
||||
$maxLengthLastname,
|
||||
$email,
|
||||
);
|
||||
|
||||
// THEN
|
||||
|
|
|
|||
|
|
@ -11,43 +11,41 @@ use Domain\Models\ValueObjects\CampaignRequest\CampaignRequestStatus;
|
|||
covers(CampaignRequestFilters::class);
|
||||
|
||||
describe('campaign request filters', function (): void {
|
||||
beforeEach(function (): void {
|
||||
$this->brandCode = new BrandCode('AAA01');
|
||||
$this->status = CampaignRequestStatus::CREATED;
|
||||
});
|
||||
$brandCode = new BrandCode('AAA01');
|
||||
$status = CampaignRequestStatus::CREATED;
|
||||
|
||||
it('creates filters with both fields set', function (): void {
|
||||
it('creates filters with both fields set', function () use ($brandCode, $status): void {
|
||||
// GIVEN / WHEN
|
||||
$filters = new CampaignRequestFilters(
|
||||
brandCode: $this->brandCode,
|
||||
status: $this->status
|
||||
brandCode: $brandCode,
|
||||
status: $status,
|
||||
);
|
||||
|
||||
// THEN
|
||||
expect($filters->brandCode)->toBe($this->brandCode)
|
||||
->and($filters->status)->toBe($this->status);
|
||||
expect($filters->brandCode)->toBe($brandCode)
|
||||
->and($filters->status)->toBe($status);
|
||||
});
|
||||
|
||||
it('creates filters with only brandCode set', function (): void {
|
||||
it('creates filters with only brandCode set', function () use ($brandCode): void {
|
||||
// GIVEN / WHEN
|
||||
$filters = new CampaignRequestFilters(
|
||||
brandCode: $this->brandCode
|
||||
brandCode: $brandCode,
|
||||
);
|
||||
|
||||
// THEN
|
||||
expect($filters->brandCode)->toBe($this->brandCode)
|
||||
expect($filters->brandCode)->toBe($brandCode)
|
||||
->and($filters->status)->toBeNull();
|
||||
});
|
||||
|
||||
it('creates filters with only status set', function (): void {
|
||||
it('creates filters with only status set', function () use ($status): void {
|
||||
// GIVEN / WHEN
|
||||
$filters = new CampaignRequestFilters(
|
||||
status: $this->status
|
||||
status: $status,
|
||||
);
|
||||
|
||||
// THEN
|
||||
expect($filters->brandCode)->toBeNull()
|
||||
->and($filters->status)->toBe($this->status);
|
||||
->and($filters->status)->toBe($status);
|
||||
});
|
||||
|
||||
it('rejects filters without any field set', function (): void {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,25 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Tests\Unit\Domain\Models\ValueObjects\CampaignRequest;
|
||||
|
||||
use Domain\Models\ValueObjects\CampaignRequest\CampaignRequestSortClause;
|
||||
use Domain\Models\ValueObjects\CampaignRequest\CampaignRequestSortField;
|
||||
|
||||
covers(CampaignRequestSortClause::class);
|
||||
|
||||
describe('campaign request sort clause', function (): void {
|
||||
it('keeps the given field and direction', function (): void {
|
||||
// GIVEN
|
||||
$field = CampaignRequestSortField::cases()[0];
|
||||
$direction = \SortDirection::Descending;
|
||||
|
||||
// WHEN
|
||||
$clause = new CampaignRequestSortClause($field, $direction);
|
||||
|
||||
// THEN
|
||||
expect($clause->field)->toBe($field)
|
||||
->and($clause->direction)->toBe($direction);
|
||||
});
|
||||
});
|
||||
|
|
@ -11,48 +11,42 @@ use Domain\Models\ValueObjects\CampaignRequest\CampaignRequestSortField;
|
|||
covers(CampaignRequestSortCriteria::class);
|
||||
|
||||
describe('campaign request sort criteria', function (): void {
|
||||
beforeEach(function (): void {
|
||||
$this->singleClauses = [
|
||||
new CampaignRequestSortClause(field: CampaignRequestSortField::BrandCode, direction: \SortDirection::Ascending),
|
||||
];
|
||||
$this->clauses = [
|
||||
new CampaignRequestSortClause(field: CampaignRequestSortField::BrandCode, direction: \SortDirection::Ascending),
|
||||
new CampaignRequestSortClause(field: CampaignRequestSortField::Status, direction: \SortDirection::Descending),
|
||||
];
|
||||
$this->invalidClauses = [CampaignRequestSortField::BrandCode];
|
||||
$this->emptyClauses = [];
|
||||
});
|
||||
$singleClauses = [
|
||||
new CampaignRequestSortClause(field: CampaignRequestSortField::BrandCode, direction: \SortDirection::Ascending),
|
||||
];
|
||||
$clauses = [
|
||||
new CampaignRequestSortClause(field: CampaignRequestSortField::BrandCode, direction: \SortDirection::Ascending),
|
||||
new CampaignRequestSortClause(field: CampaignRequestSortField::Status, direction: \SortDirection::Descending),
|
||||
];
|
||||
$invalidClauses = [CampaignRequestSortField::BrandCode];
|
||||
$emptyClauses = [];
|
||||
|
||||
|
||||
it('creates a valid campaign request sort criteria with one clause', function (): void {
|
||||
it('creates a valid campaign request sort criteria with one clause', function () use ($singleClauses): void {
|
||||
// GIVEN / WHEN
|
||||
$campaignRequestSortCriteria = new CampaignRequestSortCriteria(
|
||||
$this->singleClauses
|
||||
);
|
||||
$campaignRequestSortCriteria = new CampaignRequestSortCriteria($singleClauses);
|
||||
|
||||
// THEN
|
||||
expect($campaignRequestSortCriteria->clauses)->toBe($this->singleClauses);
|
||||
expect($campaignRequestSortCriteria->clauses)->toBe($singleClauses);
|
||||
});
|
||||
|
||||
it('creates a valid campaign request sort criteria with several clauses', function (): void {
|
||||
it('creates a valid campaign request sort criteria with several clauses', function () use ($clauses): void {
|
||||
// GIVEN / WHEN
|
||||
$campaignRequestSortCriteria = new CampaignRequestSortCriteria(
|
||||
$this->clauses
|
||||
);
|
||||
$campaignRequestSortCriteria = new CampaignRequestSortCriteria($clauses);
|
||||
|
||||
// THEN
|
||||
expect($campaignRequestSortCriteria->clauses)->toBe($this->clauses);
|
||||
expect($campaignRequestSortCriteria->clauses)->toBe($clauses);
|
||||
});
|
||||
|
||||
it('rejects a campaign request sort criteria without clause', function (): void {
|
||||
it('rejects a campaign request sort criteria without clause', function () use ($emptyClauses): void {
|
||||
// GIVEN / WHEN / THEN
|
||||
expect(fn (): CampaignRequestSortCriteria => new CampaignRequestSortCriteria($this->emptyClauses))
|
||||
expect(fn (): CampaignRequestSortCriteria => new CampaignRequestSortCriteria($emptyClauses))
|
||||
->toThrow(\DomainException::class, 'Campaign Request Sort Criteria requires at least one clause.');
|
||||
});
|
||||
|
||||
it('rejects a campaign request sort criteria with a non-clause element', function (): void {
|
||||
it('rejects a campaign request sort criteria with a non-clause element', function () use ($invalidClauses): void {
|
||||
// GIVEN / WHEN / THEN
|
||||
expect(fn (): CampaignRequestSortCriteria => new CampaignRequestSortCriteria($this->invalidClauses))
|
||||
expect(fn (): CampaignRequestSortCriteria => new CampaignRequestSortCriteria($invalidClauses))
|
||||
->toThrow(\DomainException::class, 'CampaignRequestSortCriteria clauses must be CampaignRequestSortClause instances.');
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -9,22 +9,20 @@ use Domain\Models\ValueObjects\CampaignRequest\RejectionReason;
|
|||
covers(RejectionReason::class);
|
||||
|
||||
describe('rejection reason', function (): void {
|
||||
beforeEach(function (): void {
|
||||
$this->value = 'Missing legal documents.';
|
||||
});
|
||||
$value = 'Missing legal documents.';
|
||||
|
||||
it('creates a valid rejection reason', function (): void {
|
||||
it('creates a valid rejection reason', function () use ($value): void {
|
||||
// GIVEN / WHEN
|
||||
$reason = new RejectionReason($this->value);
|
||||
$reason = new RejectionReason($value);
|
||||
|
||||
// THEN
|
||||
expect($reason)->toBeInstanceOf(RejectionReason::class)
|
||||
->and($reason->value)->toBe($this->value);
|
||||
->and($reason->value)->toBe($value);
|
||||
});
|
||||
|
||||
it('rejects an empty or whitespace-only reason', function (string $value): void {
|
||||
it('rejects an empty or whitespace-only reason', function (string $invalidValue): void {
|
||||
// WHEN
|
||||
$action = fn (): RejectionReason => new RejectionReason($value);
|
||||
$action = fn (): RejectionReason => new RejectionReason($invalidValue);
|
||||
|
||||
// THEN
|
||||
expect($action)->toThrow(\DomainException::class, 'Rejection reason cannot be empty.');
|
||||
|
|
|
|||
|
|
@ -11,49 +11,41 @@ use DateTime;
|
|||
covers(CouponAvailabilityCalendar::class);
|
||||
|
||||
describe('coupon availability calendar', function (): void {
|
||||
beforeEach(function (): void {
|
||||
$this->singlePeriods = [
|
||||
new Period(new DateTime('2026-01-01'), new DateTime('2026-02-01')),
|
||||
];
|
||||
$this->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')),
|
||||
];
|
||||
$this->invalidPeriods = ['2026-08-25', '2026-10-31'];
|
||||
$this->emptyPeriods = [];
|
||||
});
|
||||
$singlePeriods = [
|
||||
new Period(new DateTime('2026-01-01'), new DateTime('2026-02-01')),
|
||||
];
|
||||
$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')),
|
||||
];
|
||||
$invalidPeriods = ['2026-08-25', '2026-10-31'];
|
||||
$emptyPeriods = [];
|
||||
|
||||
it('creates a valid coupon availability calendar with one period', function (): void {
|
||||
it('creates a valid coupon availability calendar with one period', function () use ($singlePeriods): void {
|
||||
// GIVEN / WHEN
|
||||
$couponAvailabilityCalendar = new CouponAvailabilityCalendar(
|
||||
$this->singlePeriods
|
||||
);
|
||||
$couponAvailabilityCalendar = new CouponAvailabilityCalendar($singlePeriods);
|
||||
|
||||
// THEN
|
||||
expect($couponAvailabilityCalendar->periods)->toBe($this->singlePeriods);
|
||||
expect($couponAvailabilityCalendar->periods)->toBe($singlePeriods);
|
||||
});
|
||||
|
||||
it('creates a valid coupon availability calendar with several periods', function (): void {
|
||||
it('creates a valid coupon availability calendar with several periods', function () use ($periods): void {
|
||||
// GIVEN / WHEN
|
||||
$couponAvailabilityCalendar = new CouponAvailabilityCalendar(
|
||||
$this->periods
|
||||
);
|
||||
$couponAvailabilityCalendar = new CouponAvailabilityCalendar($periods);
|
||||
|
||||
// THEN
|
||||
expect($couponAvailabilityCalendar->periods)->toBe($this->periods);
|
||||
expect($couponAvailabilityCalendar->periods)->toBe($periods);
|
||||
});
|
||||
|
||||
it('rejects a coupon availability calendar without period', function (): void {
|
||||
it('rejects a coupon availability calendar without period', function () use ($emptyPeriods): void {
|
||||
// GIVEN / WHEN / THEN
|
||||
expect(fn (): CouponAvailabilityCalendar => new CouponAvailabilityCalendar(
|
||||
$this->emptyPeriods
|
||||
))->toThrow(\DomainException::class);
|
||||
expect(fn (): CouponAvailabilityCalendar => new CouponAvailabilityCalendar($emptyPeriods))
|
||||
->toThrow(\DomainException::class);
|
||||
});
|
||||
|
||||
it('rejects a coupon availability calendar with a non-period element', function (): void {
|
||||
it('rejects a coupon availability calendar with a non-period element', function () use ($invalidPeriods): void {
|
||||
// GIVEN / WHEN / THEN
|
||||
expect(fn (): CouponAvailabilityCalendar => new CouponAvailabilityCalendar(
|
||||
$this->invalidPeriods
|
||||
))->toThrow(\DomainException::class, 'CouponAvailabilityCalendar periods must be Period instances.');
|
||||
expect(fn (): CouponAvailabilityCalendar => new CouponAvailabilityCalendar($invalidPeriods))
|
||||
->toThrow(\DomainException::class, 'CouponAvailabilityCalendar periods must be Period instances.');
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -11,15 +11,13 @@ use DateTime;
|
|||
covers(CouponDiffusion::class);
|
||||
|
||||
describe('coupon diffusion', function (): void {
|
||||
beforeEach(function (): void {
|
||||
$this->period = 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'));
|
||||
|
||||
it('creates a valid coupon diffusion with one period', function (): void {
|
||||
it('creates a valid coupon diffusion with one period', function () use ($period): void {
|
||||
// GIVEN / WHEN
|
||||
$couponDiffusion = new CouponDiffusion($this->period);
|
||||
$couponDiffusion = new CouponDiffusion($period);
|
||||
|
||||
// THEN
|
||||
expect($couponDiffusion->period)->toBe($this->period);
|
||||
expect($couponDiffusion->period)->toBe($period);
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -0,0 +1,28 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Tests\Unit\Domain\Models\ValueObjects;
|
||||
|
||||
use Domain\Models\ValueObjects\Coupon\CouponIncoCode;
|
||||
|
||||
covers(CouponIncoCode::class);
|
||||
|
||||
describe('inco code', function (): void {
|
||||
$value = 1010100101;
|
||||
$zeroValue = 0;
|
||||
|
||||
it('creates a valid inco code', function () use ($value): void {
|
||||
// GIVEN / WHEN
|
||||
$incoCode = new CouponIncoCode($value);
|
||||
|
||||
// THEN
|
||||
expect($incoCode->value)->toBe($value);
|
||||
});
|
||||
|
||||
it('rejects invalid inco code', function () use ($zeroValue): void {
|
||||
// GIVEN / WHEN / THEN
|
||||
expect(fn (): CouponIncoCode => new CouponIncoCode($zeroValue))
|
||||
->toThrow(\DomainException::class);
|
||||
});
|
||||
});
|
||||
|
|
@ -0,0 +1,88 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Tests\Unit\Domain\Models\ValueObjects\Coupon;
|
||||
|
||||
use Domain\Models\ValueObjects\Coupon\CouponLegalInformation;
|
||||
use Domain\Models\ValueObjects\Coupon\CouponLegalInformationArray;
|
||||
use Shared\Enums\Country;
|
||||
|
||||
covers(CouponLegalInformationArray::class);
|
||||
|
||||
describe('coupon legal information array', function (): void {
|
||||
$franceInformation = new CouponLegalInformation('Mentions légales France.', Country::FRANCE);
|
||||
$beneluxInformation = new CouponLegalInformation('Legal information Benelux.', Country::BENELUX);
|
||||
|
||||
it('creates an array containing a France legal information', function () use ($franceInformation): void {
|
||||
// GIVEN
|
||||
$informations = [$franceInformation];
|
||||
|
||||
// WHEN
|
||||
$array = new CouponLegalInformationArray($informations);
|
||||
|
||||
// THEN
|
||||
expect($array->value)->toBe($informations);
|
||||
});
|
||||
|
||||
it('accepts additional countries next to France', function () use ($franceInformation, $beneluxInformation): void {
|
||||
// GIVEN
|
||||
$informations = [$beneluxInformation, $franceInformation];
|
||||
|
||||
// WHEN
|
||||
$array = new CouponLegalInformationArray($informations);
|
||||
|
||||
// THEN
|
||||
expect($array->value)->toBe($informations);
|
||||
});
|
||||
|
||||
it('rejects an empty array', function (): void {
|
||||
// GIVEN / WHEN
|
||||
$action = fn (): CouponLegalInformationArray => new CouponLegalInformationArray([]);
|
||||
|
||||
// THEN
|
||||
expect($action)->toThrow(
|
||||
\DomainException::class,
|
||||
'CouponLegalInformations requires at least one CouponLegalInformation.',
|
||||
);
|
||||
});
|
||||
|
||||
it('rejects a non legal information element', function (): void {
|
||||
// GIVEN / WHEN
|
||||
$action = fn (): CouponLegalInformationArray => new CouponLegalInformationArray(['legal']);
|
||||
|
||||
// THEN
|
||||
expect($action)->toThrow(
|
||||
\DomainException::class,
|
||||
'Value of CouponLegalInformationArray must be CouponLegalInformation instances.',
|
||||
);
|
||||
});
|
||||
|
||||
it('rejects a non legal information element mixed with valid ones', function () use ($franceInformation): void {
|
||||
// GIVEN
|
||||
$informations = [$franceInformation, 'legal'];
|
||||
|
||||
// WHEN
|
||||
$action = fn (): CouponLegalInformationArray => new CouponLegalInformationArray($informations);
|
||||
|
||||
// THEN
|
||||
expect($action)->toThrow(
|
||||
\DomainException::class,
|
||||
'Value of CouponLegalInformationArray must be CouponLegalInformation instances.',
|
||||
);
|
||||
});
|
||||
|
||||
it('rejects an array without France legal information', function () use ($beneluxInformation): void {
|
||||
// GIVEN
|
||||
$informations = [$beneluxInformation];
|
||||
|
||||
// WHEN
|
||||
$action = fn (): CouponLegalInformationArray => new CouponLegalInformationArray($informations);
|
||||
|
||||
// THEN
|
||||
expect($action)->toThrow(
|
||||
\DomainException::class,
|
||||
'CouponLegalInformations requires a CouponLegalInformation for France.',
|
||||
);
|
||||
});
|
||||
});
|
||||
|
|
@ -10,29 +10,39 @@ use Domain\Models\ValueObjects\Coupon\CouponLegalInformation;
|
|||
covers(CouponLegalInformation::class);
|
||||
|
||||
describe('coupon legal information', function (): void {
|
||||
beforeEach(function (): void {
|
||||
$this->legalText = 'Lorem ipsum dolor sit amet consectetur adipiscing elit.';
|
||||
$this->emptyLegalText = '';
|
||||
$this->forLocale = Country::FRANCE;
|
||||
});
|
||||
$legalText = 'Lorem ipsum dolor sit amet consectetur adipiscing elit.';
|
||||
$emptyLegalText = '';
|
||||
$forLocale = Country::FRANCE;
|
||||
|
||||
it('creates a valid coupon legal information', function (): void {
|
||||
it('creates a valid coupon legal information FRANCE', function () use ($legalText, $forLocale): void {
|
||||
// GIVEN / WHEN
|
||||
$couponLegalInformation = new CouponLegalInformation(
|
||||
$this->legalText,
|
||||
$this->forLocale
|
||||
$legalText,
|
||||
$forLocale,
|
||||
);
|
||||
|
||||
// THEN
|
||||
expect($couponLegalInformation->legalText)->toBe($this->legalText)
|
||||
->and($couponLegalInformation->forLocale)->toBe($this->forLocale);
|
||||
expect($couponLegalInformation->legalText)->toBe($legalText)
|
||||
->and($couponLegalInformation->forLocale)->toBe($forLocale);
|
||||
});
|
||||
|
||||
it('rejects invalid coupon legal information', function (): void {
|
||||
it('creates a valid coupon legal information BENELUX', function () use ($legalText): void {
|
||||
// GIVEN / WHEN
|
||||
$couponLegalInformation = new CouponLegalInformation(
|
||||
$legalText,
|
||||
Country::BENELUX,
|
||||
);
|
||||
|
||||
// THEN
|
||||
expect($couponLegalInformation->legalText)->toBe($legalText)
|
||||
->and($couponLegalInformation->forLocale)->toBe(Country::BENELUX);
|
||||
});
|
||||
|
||||
it('rejects invalid coupon legal information', function () use ($emptyLegalText, $forLocale): void {
|
||||
// GIVEN / WHEN / THEN
|
||||
expect(fn (): CouponLegalInformation => new CouponLegalInformation(
|
||||
$this->emptyLegalText,
|
||||
$this->forLocale
|
||||
$emptyLegalText,
|
||||
$forLocale,
|
||||
))->toThrow(\DomainException::class);
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -0,0 +1,61 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Tests\Unit\Domain\Models\ValueObjects\Coupon;
|
||||
|
||||
use Domain\Models\ValueObjects\Coupon\CouponMovement;
|
||||
use Domain\Models\ValueObjects\Coupon\CouponMovementArray;
|
||||
|
||||
covers(CouponMovementArray::class);
|
||||
|
||||
describe('coupon movement array', function (): void {
|
||||
$couponMovement = new CouponMovement(100);
|
||||
|
||||
it('creates an array with valid coupon movements', function () use ($couponMovement): void {
|
||||
// GIVEN
|
||||
$couponMovements = [$couponMovement, $couponMovement];
|
||||
|
||||
// WHEN
|
||||
$array = new CouponMovementArray($couponMovements);
|
||||
|
||||
// THEN
|
||||
expect($array->couponMovements)->toBe($couponMovements);
|
||||
});
|
||||
|
||||
it('rejects an empty array', function (): void {
|
||||
// GIVEN / WHEN
|
||||
$action = fn (): CouponMovementArray => new CouponMovementArray([]);
|
||||
|
||||
// THEN
|
||||
expect($action)->toThrow(
|
||||
\DomainException::class,
|
||||
'CouponMovementArray requires at least one CouponMovement.',
|
||||
);
|
||||
});
|
||||
|
||||
it('rejects a non coupon movement element', function (): void {
|
||||
// GIVEN / WHEN
|
||||
$action = fn (): CouponMovementArray => new CouponMovementArray(['movement']);
|
||||
|
||||
// THEN
|
||||
expect($action)->toThrow(
|
||||
\DomainException::class,
|
||||
'Value of CouponMovementArray must be CouponMovement instances.',
|
||||
);
|
||||
});
|
||||
|
||||
it('rejects a non coupon movement element mixed with valid ones', function () use ($couponMovement): void {
|
||||
// GIVEN
|
||||
$couponMovements = [$couponMovement, 'movement'];
|
||||
|
||||
// WHEN
|
||||
$action = fn (): CouponMovementArray => new CouponMovementArray($couponMovements);
|
||||
|
||||
// THEN
|
||||
expect($action)->toThrow(
|
||||
\DomainException::class,
|
||||
'Value of CouponMovementArray must be CouponMovement instances.',
|
||||
);
|
||||
});
|
||||
});
|
||||
|
|
@ -0,0 +1,47 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Tests\Unit\Domain\Models\ValueObjects\Coupon;
|
||||
|
||||
use Domain\Models\ValueObjects\Coupon\CouponMovement;
|
||||
|
||||
covers(CouponMovement::class);
|
||||
|
||||
describe('coupon movement', function (): void {
|
||||
it('keeps the given quantity and creation date', function (): void {
|
||||
// GIVEN
|
||||
$quantity = 10;
|
||||
$createdAt = new \DateTimeImmutable('2026-01-01 12:00:00');
|
||||
|
||||
// WHEN
|
||||
$movement = new CouponMovement($quantity, $createdAt);
|
||||
|
||||
// THEN
|
||||
expect($movement->quantity)->toBe($quantity)
|
||||
->and($movement->createdAt)->toBe($createdAt);
|
||||
});
|
||||
|
||||
it('defaults the creation date to now', function (): void {
|
||||
// GIVEN
|
||||
$before = new \DateTimeImmutable();
|
||||
|
||||
// WHEN
|
||||
$movement = new CouponMovement(5);
|
||||
|
||||
// THEN
|
||||
$after = new \DateTimeImmutable();
|
||||
|
||||
expect($movement->createdAt)->toBeInstanceOf(\DateTimeImmutable::class)
|
||||
->and($movement->createdAt >= $before)->toBeTrue()
|
||||
->and($movement->createdAt <= $after)->toBeTrue();
|
||||
});
|
||||
|
||||
it('accepts a negative quantity', function (): void {
|
||||
// GIVEN / WHEN
|
||||
$movement = new CouponMovement(-3);
|
||||
|
||||
// THEN
|
||||
expect($movement->quantity)->toBe(-3);
|
||||
});
|
||||
});
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Tests\Unit\Domain\Models\ValueObjects;
|
||||
|
||||
use Domain\Models\ValueObjects\Coupon\CouponName;
|
||||
|
||||
covers(CouponName::class);
|
||||
|
||||
describe('coupon name', function (): void {
|
||||
$value = 'Name';
|
||||
$emptyValue = '';
|
||||
|
||||
it('creates a valid coupon name', function () use ($value): void {
|
||||
// GIVEN / WHEN
|
||||
$name = new CouponName($value);
|
||||
|
||||
// THEN
|
||||
expect($name->value)->toBe($value);
|
||||
});
|
||||
|
||||
it('rejects invalid coupon name', function () use ($emptyValue): void {
|
||||
// GIVEN / WHEN / THEN
|
||||
expect(fn (): CouponName => new CouponName($emptyValue))
|
||||
->toThrow(\DomainException::class);
|
||||
});
|
||||
});
|
||||
|
|
@ -0,0 +1,45 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Tests\Unit\Domain\Models\ValueObjects;
|
||||
|
||||
use Domain\Models\ValueObjects\Coupon\CouponProcessingCode;
|
||||
use Shared\Enums\Country;
|
||||
|
||||
covers(CouponProcessingCode::class);
|
||||
|
||||
describe('processing code', function (): void {
|
||||
$value = 'ABC1234567890';
|
||||
$emptyValue = '';
|
||||
|
||||
it('creates a valid processing code FRANCE', function () use ($value): void {
|
||||
// GIVEN / WHEN
|
||||
$processingCode = new CouponProcessingCode(
|
||||
$value,
|
||||
Country::FRANCE,
|
||||
);
|
||||
|
||||
// THEN
|
||||
expect($processingCode->value)->toBe($value);
|
||||
});
|
||||
|
||||
it('creates a valid processing code BENELUX', function () use ($value): void {
|
||||
// GIVEN / WHEN
|
||||
$processingCode = new CouponProcessingCode(
|
||||
$value,
|
||||
Country::BENELUX,
|
||||
);
|
||||
|
||||
// THEN
|
||||
expect($processingCode->value)->toBe($value);
|
||||
});
|
||||
|
||||
it('rejects invalid processing code', function () use ($emptyValue): void {
|
||||
// GIVEN / WHEN / THEN
|
||||
expect(fn (): CouponProcessingCode => new CouponProcessingCode(
|
||||
$emptyValue,
|
||||
Country::FRANCE,
|
||||
))->toThrow(\DomainException::class);
|
||||
});
|
||||
});
|
||||
|
|
@ -0,0 +1,88 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Tests\Unit\Domain\Models\ValueObjects\Coupon;
|
||||
|
||||
use Domain\Models\ValueObjects\Coupon\CouponProcessingCode;
|
||||
use Domain\Models\ValueObjects\Coupon\CouponProcessingCodeArray;
|
||||
use Shared\Enums\Country;
|
||||
|
||||
covers(CouponProcessingCodeArray::class);
|
||||
|
||||
describe('coupon processing code array', function (): void {
|
||||
$franceCode = new CouponProcessingCode('ABC1234567890', Country::FRANCE);
|
||||
$beneluxCode = new CouponProcessingCode('XYZ0987654321', Country::BENELUX);
|
||||
|
||||
it('creates an array containing a France processing code', function () use ($franceCode): void {
|
||||
// GIVEN
|
||||
$processingCodes = [$franceCode];
|
||||
|
||||
// WHEN
|
||||
$array = new CouponProcessingCodeArray($processingCodes);
|
||||
|
||||
// THEN
|
||||
expect($array->value)->toBe($processingCodes);
|
||||
});
|
||||
|
||||
it('accepts additional countries next to France', function () use ($franceCode, $beneluxCode): void {
|
||||
// GIVEN
|
||||
$processingCodes = [$beneluxCode, $franceCode];
|
||||
|
||||
// WHEN
|
||||
$array = new CouponProcessingCodeArray($processingCodes);
|
||||
|
||||
// THEN
|
||||
expect($array->value)->toBe($processingCodes);
|
||||
});
|
||||
|
||||
it('rejects an empty array', function (): void {
|
||||
// GIVEN / WHEN
|
||||
$action = fn (): CouponProcessingCodeArray => new CouponProcessingCodeArray([]);
|
||||
|
||||
// THEN
|
||||
expect($action)->toThrow(
|
||||
\DomainException::class,
|
||||
'ProcessingCodes requires at least one CouponProcessingCode.',
|
||||
);
|
||||
});
|
||||
|
||||
it('rejects a non processing code element', function (): void {
|
||||
// GIVEN / WHEN
|
||||
$action = fn (): CouponProcessingCodeArray => new CouponProcessingCodeArray(['ABC1234567890']);
|
||||
|
||||
// THEN
|
||||
expect($action)->toThrow(
|
||||
\DomainException::class,
|
||||
'Value of CouponProcessingCodeArray must be CouponProcessingCode instances.',
|
||||
);
|
||||
});
|
||||
|
||||
it('rejects a non processing code element mixed with valid ones', function () use ($franceCode): void {
|
||||
// GIVEN
|
||||
$processingCodes = [$franceCode, 'ABC1234567890'];
|
||||
|
||||
// WHEN
|
||||
$action = fn (): CouponProcessingCodeArray => new CouponProcessingCodeArray($processingCodes);
|
||||
|
||||
// THEN
|
||||
expect($action)->toThrow(
|
||||
\DomainException::class,
|
||||
'Value of CouponProcessingCodeArray must be CouponProcessingCode instances.',
|
||||
);
|
||||
});
|
||||
|
||||
it('rejects an array without France processing code', function () use ($beneluxCode): void {
|
||||
// GIVEN
|
||||
$processingCodes = [$beneluxCode];
|
||||
|
||||
// WHEN
|
||||
$action = fn (): CouponProcessingCodeArray => new CouponProcessingCodeArray($processingCodes);
|
||||
|
||||
// THEN
|
||||
expect($action)->toThrow(
|
||||
\DomainException::class,
|
||||
'CouponProcessingCodes requires a CouponProcessingCode for France.',
|
||||
);
|
||||
});
|
||||
});
|
||||
|
|
@ -0,0 +1,93 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Tests\Unit\Domain\Models\ValueObjects\Coupon;
|
||||
|
||||
use Domain\Models\ValueObjects\Coupon\CouponProcessingCode;
|
||||
use Shared\Enums\Country;
|
||||
|
||||
covers(CouponProcessingCode::class);
|
||||
|
||||
describe('coupon processing code', function (): void {
|
||||
$value = 'ABC1234567890';
|
||||
|
||||
it('creates a valid processing code', function () use ($value): void {
|
||||
// GIVEN / WHEN
|
||||
$code = new CouponProcessingCode($value, Country::FRANCE);
|
||||
|
||||
// THEN
|
||||
expect($code->value)->toBe($value)
|
||||
->and($code->availableIn)->toBe(Country::FRANCE);
|
||||
});
|
||||
|
||||
it('accepts lowercase and uppercase letters and digits', function (): void {
|
||||
// GIVEN / WHEN
|
||||
$code = new CouponProcessingCode('aBc1234567xYz', Country::FRANCE);
|
||||
|
||||
// THEN
|
||||
expect($code->value)->toBe('aBc1234567xYz');
|
||||
});
|
||||
|
||||
it('rejects an invalid value', function (string $invalidValue): void {
|
||||
// GIVEN / WHEN
|
||||
$action = fn (): CouponProcessingCode => new CouponProcessingCode($invalidValue, Country::FRANCE);
|
||||
|
||||
// THEN
|
||||
expect($action)->toThrow(
|
||||
\DomainException::class,
|
||||
'Processing Code must be exactly 13 alphanumeric characters, e.g. ABC1234567890.',
|
||||
);
|
||||
})->with([
|
||||
'empty' => '',
|
||||
'too short' => 'ABC123456789',
|
||||
'too long' => 'ABC12345678901',
|
||||
'special char' => 'ABC123456789!',
|
||||
'with space' => 'ABC 123456789',
|
||||
'trailing break' => "ABC1234567890\n",
|
||||
]);
|
||||
|
||||
it('is equal to another processing code with the same value', function () use ($value): void {
|
||||
// GIVEN
|
||||
$code = new CouponProcessingCode($value, Country::FRANCE);
|
||||
$other = new CouponProcessingCode($value, Country::FRANCE);
|
||||
|
||||
// WHEN / THEN
|
||||
expect($code->equals($other))->toBeTrue();
|
||||
});
|
||||
|
||||
it('ignores the country when comparing', function () use ($value): void {
|
||||
// GIVEN
|
||||
$france = new CouponProcessingCode($value, Country::FRANCE);
|
||||
$benelux = new CouponProcessingCode($value, Country::BENELUX);
|
||||
|
||||
// WHEN / THEN
|
||||
expect($france->equals($benelux))->toBeTrue();
|
||||
});
|
||||
|
||||
it('is not equal to a processing code with a different value', function () use ($value): void {
|
||||
// GIVEN
|
||||
$code = new CouponProcessingCode($value, Country::FRANCE);
|
||||
$other = new CouponProcessingCode('XYZ0987654321', Country::FRANCE);
|
||||
|
||||
// WHEN / THEN
|
||||
expect($code->equals($other))->toBeFalse();
|
||||
});
|
||||
|
||||
it('is not equal to a value that is not a processing code', function () use ($value): void {
|
||||
// GIVEN
|
||||
$code = new CouponProcessingCode($value, Country::FRANCE);
|
||||
|
||||
// WHEN / THEN
|
||||
expect($code->equals($value))->toBeFalse()
|
||||
->and($code->equals(null))->toBeFalse();
|
||||
});
|
||||
|
||||
it('is converted to its value as a string', function () use ($value): void {
|
||||
// GIVEN
|
||||
$code = new CouponProcessingCode($value, Country::FRANCE);
|
||||
|
||||
// WHEN / THEN
|
||||
expect((string) $code)->toBe($value);
|
||||
});
|
||||
});
|
||||
|
|
@ -0,0 +1,67 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Tests\Unit\Domain\Models\ValueObjects\Coupon;
|
||||
|
||||
use Domain\Models\ValueObjects\Coupon\CouponIncoCode;
|
||||
use Domain\Models\ValueObjects\Coupon\CouponProductArray;
|
||||
|
||||
covers(CouponProductArray::class);
|
||||
|
||||
describe('coupon product array', function (): void {
|
||||
$firstProduct = new CouponIncoCode(35784);
|
||||
$secondProduct = new CouponIncoCode(15522);
|
||||
|
||||
it('is empty by default', function (): void {
|
||||
// GIVEN / WHEN
|
||||
$array = new CouponProductArray();
|
||||
|
||||
// THEN
|
||||
expect($array->value)->toBe([]);
|
||||
});
|
||||
|
||||
it('accepts an empty array explicitly', function (): void {
|
||||
// GIVEN / WHEN
|
||||
$array = new CouponProductArray([]);
|
||||
|
||||
// THEN
|
||||
expect($array->value)->toBe([]);
|
||||
});
|
||||
|
||||
it('creates an array with valid products', function () use ($firstProduct, $secondProduct): void {
|
||||
// GIVEN
|
||||
$products = [$firstProduct, $secondProduct];
|
||||
|
||||
// WHEN
|
||||
$array = new CouponProductArray($products);
|
||||
|
||||
// THEN
|
||||
expect($array->value)->toBe($products);
|
||||
});
|
||||
|
||||
it('rejects a non product element', function (): void {
|
||||
// GIVEN / WHEN
|
||||
$action = fn (): CouponProductArray => new CouponProductArray([35784]);
|
||||
|
||||
// THEN
|
||||
expect($action)->toThrow(
|
||||
\DomainException::class,
|
||||
'Value of CouponProductArray must be CouponIncoCode instances.',
|
||||
);
|
||||
});
|
||||
|
||||
it('rejects a non product element mixed with valid ones', function () use ($firstProduct): void {
|
||||
// GIVEN
|
||||
$products = [$firstProduct, 35784];
|
||||
|
||||
// WHEN
|
||||
$action = fn (): CouponProductArray => new CouponProductArray($products);
|
||||
|
||||
// THEN
|
||||
expect($action)->toThrow(
|
||||
\DomainException::class,
|
||||
'Value of CouponProductArray must be CouponIncoCode instances.',
|
||||
);
|
||||
});
|
||||
});
|
||||
|
|
@ -9,38 +9,30 @@ use Domain\Models\ValueObjects\Coupon\CouponQuantity;
|
|||
covers(CouponQuantity::class);
|
||||
|
||||
describe('coupon quantity', function (): void {
|
||||
beforeEach(function (): void {
|
||||
$this->quantity = 10;
|
||||
$this->zeroQuantity = 0;
|
||||
$this->negativeQuantity = -1;
|
||||
});
|
||||
$quantity = 10;
|
||||
$zeroQuantity = 0;
|
||||
$negativeQuantity = -1;
|
||||
|
||||
it('creates a valid coupon quantity', function (): void {
|
||||
it('creates a valid coupon quantity', function () use ($quantity): void {
|
||||
// GIVEN / WHEN
|
||||
$couponQuantity = new CouponQuantity(
|
||||
$this->quantity
|
||||
);
|
||||
$couponQuantity = new CouponQuantity($quantity);
|
||||
|
||||
// THEN
|
||||
expect($couponQuantity)->toBeInstanceOf(CouponQuantity::class)
|
||||
->and($couponQuantity->quantity)->toBe($this->quantity);
|
||||
->and($couponQuantity->value)->toBe($quantity);
|
||||
});
|
||||
|
||||
it('rejects a quantity of zero', function (): void {
|
||||
it('rejects a quantity of zero', function () use ($zeroQuantity): void {
|
||||
// WHEN
|
||||
$action = fn (): CouponQuantity => new CouponQuantity(
|
||||
$this->zeroQuantity
|
||||
);
|
||||
$action = fn (): CouponQuantity => new CouponQuantity($zeroQuantity);
|
||||
|
||||
// THEN
|
||||
expect($action)->toThrow(\DomainException::class, 'CouponQuantity quantity must be positive.');
|
||||
});
|
||||
|
||||
it('rejects a negative quantity', function (): void {
|
||||
it('rejects a negative quantity', function () use ($negativeQuantity): void {
|
||||
// WHEN
|
||||
$action = fn (): CouponQuantity => new CouponQuantity(
|
||||
$this->negativeQuantity
|
||||
);
|
||||
$action = fn (): CouponQuantity => new CouponQuantity($negativeQuantity);
|
||||
|
||||
// THEN
|
||||
expect($action)->toThrow(\DomainException::class, 'CouponQuantity quantity must be positive.');
|
||||
|
|
|
|||
|
|
@ -0,0 +1,88 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Tests\Unit\Domain\Models\ValueObjects\Coupon;
|
||||
|
||||
use Domain\Models\ValueObjects\Coupon\CouponValidityInformation;
|
||||
use Domain\Models\ValueObjects\Coupon\CouponValidityInformationArray;
|
||||
use Shared\Enums\Country;
|
||||
|
||||
covers(CouponValidityInformationArray::class);
|
||||
|
||||
describe('coupon validity information array', function (): void {
|
||||
$franceInformation = new CouponValidityInformation('Valable en France.', Country::FRANCE);
|
||||
$beneluxInformation = new CouponValidityInformation('Valid in Benelux.', Country::BENELUX);
|
||||
|
||||
it('creates an array containing a France validity information', function () use ($franceInformation): void {
|
||||
// GIVEN
|
||||
$informations = [$franceInformation];
|
||||
|
||||
// WHEN
|
||||
$array = new CouponValidityInformationArray($informations);
|
||||
|
||||
// THEN
|
||||
expect($array->value)->toBe($informations);
|
||||
});
|
||||
|
||||
it('accepts additional countries next to France', function () use ($franceInformation, $beneluxInformation): void {
|
||||
// GIVEN
|
||||
$informations = [$beneluxInformation, $franceInformation];
|
||||
|
||||
// WHEN
|
||||
$array = new CouponValidityInformationArray($informations);
|
||||
|
||||
// THEN
|
||||
expect($array->value)->toBe($informations);
|
||||
});
|
||||
|
||||
it('rejects an empty array', function (): void {
|
||||
// GIVEN / WHEN
|
||||
$action = fn (): CouponValidityInformationArray => new CouponValidityInformationArray([]);
|
||||
|
||||
// THEN
|
||||
expect($action)->toThrow(
|
||||
\DomainException::class,
|
||||
'CouponValidityInformations requires at least one CouponValidityInformation.',
|
||||
);
|
||||
});
|
||||
|
||||
it('rejects a non validity information element', function (): void {
|
||||
// GIVEN / WHEN
|
||||
$action = fn (): CouponValidityInformationArray => new CouponValidityInformationArray(['validity']);
|
||||
|
||||
// THEN
|
||||
expect($action)->toThrow(
|
||||
\DomainException::class,
|
||||
'Value of CouponValidityInformationArray must be CouponValidityInformation instances.',
|
||||
);
|
||||
});
|
||||
|
||||
it('rejects a non validity information element mixed with valid ones', function () use ($franceInformation): void {
|
||||
// GIVEN
|
||||
$informations = [$franceInformation, 'validity'];
|
||||
|
||||
// WHEN
|
||||
$action = fn (): CouponValidityInformationArray => new CouponValidityInformationArray($informations);
|
||||
|
||||
// THEN
|
||||
expect($action)->toThrow(
|
||||
\DomainException::class,
|
||||
'Value of CouponValidityInformationArray must be CouponValidityInformation instances.',
|
||||
);
|
||||
});
|
||||
|
||||
it('rejects an array without France validity information', function () use ($beneluxInformation): void {
|
||||
// GIVEN
|
||||
$informations = [$beneluxInformation];
|
||||
|
||||
// WHEN
|
||||
$action = fn (): CouponValidityInformationArray => new CouponValidityInformationArray($informations);
|
||||
|
||||
// THEN
|
||||
expect($action)->toThrow(
|
||||
\DomainException::class,
|
||||
'CouponValidityInformations requires a CouponValidityInformation for France.',
|
||||
);
|
||||
});
|
||||
});
|
||||
|
|
@ -10,29 +10,27 @@ use Shared\Enums\Country;
|
|||
covers(CouponValidityInformation::class);
|
||||
|
||||
describe('coupon validity information', function (): void {
|
||||
beforeEach(function (): void {
|
||||
$this->validityText = 'Lorem ipsum dolor sit amet consectetur adipiscing elit.';
|
||||
$this->emptyValidityText = '';
|
||||
$this->forLocale = Country::FRANCE;
|
||||
});
|
||||
$validityText = 'Lorem ipsum dolor sit amet consectetur adipiscing elit.';
|
||||
$emptyValidityText = '';
|
||||
$forLocale = Country::FRANCE;
|
||||
|
||||
it('creates a valid coupon validity information', function (): void {
|
||||
it('creates a valid coupon validity information', function () use ($validityText, $forLocale): void {
|
||||
// GIVEN / WHEN
|
||||
$couponValidityInformation = new CouponValidityInformation(
|
||||
$this->validityText,
|
||||
$this->forLocale
|
||||
$validityText,
|
||||
$forLocale,
|
||||
);
|
||||
|
||||
// THEN
|
||||
expect($couponValidityInformation->validityText)->toBe($this->validityText)
|
||||
->and($couponValidityInformation->forLocale)->toBe($this->forLocale);
|
||||
expect($couponValidityInformation->validityText)->toBe($validityText)
|
||||
->and($couponValidityInformation->forLocale)->toBe($forLocale);
|
||||
});
|
||||
|
||||
it('rejects invalid coupon validity information', function (): void {
|
||||
it('rejects invalid coupon validity information', function () use ($emptyValidityText, $forLocale): void {
|
||||
// GIVEN / WHEN / THEN
|
||||
expect(fn (): CouponValidityInformation => new CouponValidityInformation(
|
||||
$this->emptyValidityText,
|
||||
$this->forLocale
|
||||
$emptyValidityText,
|
||||
$forLocale,
|
||||
))->toThrow(\DomainException::class);
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,38 +0,0 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Tests\Unit\Domain\Models\ValueObjects;
|
||||
|
||||
use Domain\Models\ValueObjects\Coupon\CouponValidity;
|
||||
use DateTime;
|
||||
|
||||
covers(CouponValidity::class);
|
||||
|
||||
describe('coupon validity', function (): void {
|
||||
beforeEach(function (): void {
|
||||
$this->days = 30;
|
||||
$this->zeroDays = 0;
|
||||
$this->until = new DateTime('2026-11-30');
|
||||
});
|
||||
|
||||
it('creates a valid coupon validity', function (): void {
|
||||
// GIVEN / WHEN
|
||||
$couponValidity = new CouponValidity(
|
||||
$this->days,
|
||||
$this->until
|
||||
);
|
||||
|
||||
// THEN
|
||||
expect($couponValidity->days)->toBe($this->days)
|
||||
->and($couponValidity->until)->toBe($this->until);
|
||||
});
|
||||
|
||||
it('rejects invalid coupon validity', function (): void {
|
||||
// GIVEN / WHEN / THEN
|
||||
expect(fn (): CouponValidity => new CouponValidity(
|
||||
$this->zeroDays,
|
||||
$this->until
|
||||
))->toThrow(\DomainException::class);
|
||||
});
|
||||
});
|
||||
|
|
@ -1,33 +0,0 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Tests\Unit\Domain\Models\ValueObjects;
|
||||
|
||||
use Domain\Models\ValueObjects\CouponName;
|
||||
|
||||
covers(CouponName::class);
|
||||
|
||||
describe('coupon name', function (): void {
|
||||
beforeEach(function (): void {
|
||||
$this->value = 'Name';
|
||||
$this->emptyValue = '';
|
||||
});
|
||||
|
||||
it('creates a valid coupon name', function (): void {
|
||||
// GIVEN / WHEN
|
||||
$name = new CouponName(
|
||||
$this->value
|
||||
);
|
||||
|
||||
// THEN
|
||||
expect($name->value)->toBe($this->value);
|
||||
});
|
||||
|
||||
it('rejects invalid coupon name', function (): void {
|
||||
// GIVEN / WHEN / THEN
|
||||
expect(fn (): CouponName => new CouponName(
|
||||
$this->emptyValue
|
||||
))->toThrow(\DomainException::class);
|
||||
});
|
||||
});
|
||||
|
|
@ -1,38 +0,0 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Tests\Unit\Domain\Models\ValueObjects;
|
||||
|
||||
use Domain\Enums\BarcodeFormat;
|
||||
use Domain\Models\ValueObjects\GS1;
|
||||
|
||||
covers(GS1::class);
|
||||
|
||||
describe('gs1', function (): void {
|
||||
beforeEach(function (): void {
|
||||
$this->value = '1010100101';
|
||||
$this->emptyValue = '';
|
||||
$this->format = BarcodeFormat::EAN13;
|
||||
});
|
||||
|
||||
it('creates a valid gs1', function (): void {
|
||||
// WHEN
|
||||
$GS1 = new GS1(
|
||||
$this->value,
|
||||
$this->format
|
||||
);
|
||||
|
||||
// THEN
|
||||
expect($GS1->value)->toBe($this->value)
|
||||
->and($GS1->format)->toBe($this->format);
|
||||
});
|
||||
|
||||
it('rejects invalid gs1', function (): void {
|
||||
// GIVEN / WHEN / THEN
|
||||
expect(fn (): GS1 => new GS1(
|
||||
$this->emptyValue,
|
||||
$this->format
|
||||
))->toThrow(\DomainException::class);
|
||||
});
|
||||
});
|
||||
|
|
@ -1,33 +0,0 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Tests\Unit\Domain\Models\ValueObjects;
|
||||
|
||||
use Domain\Models\ValueObjects\IncoCode;
|
||||
|
||||
covers(IncoCode::class);
|
||||
|
||||
describe('inco code', function (): void {
|
||||
beforeEach(function (): void {
|
||||
$this->value = 1010100101;
|
||||
$this->zeroValue = 0;
|
||||
});
|
||||
|
||||
it('creates a valid inco code', function (): void {
|
||||
// GIVEN / WHEN
|
||||
$incoCode = new IncoCode(
|
||||
$this->value
|
||||
);
|
||||
|
||||
// THEN
|
||||
expect($incoCode->value)->toBe($this->value);
|
||||
});
|
||||
|
||||
it('rejects invalid inco code', function (): void {
|
||||
// GIVEN / WHEN / THEN
|
||||
expect(fn (): IncoCode => new IncoCode(
|
||||
$this->zeroValue
|
||||
))->toThrow(\DomainException::class);
|
||||
});
|
||||
});
|
||||
|
|
@ -11,36 +11,26 @@ use Shared\ValueObjects\Money;
|
|||
covers(MoneyAmount::class);
|
||||
|
||||
describe('money amount', function (): void {
|
||||
beforeEach(function (): void {
|
||||
$this->money = new Money(Currency::EUR, 300);
|
||||
$this->secondMoney = new Money(Currency::EUR, 200);
|
||||
$this->minimumMoney = new Money(Currency::EUR, 1);
|
||||
$this->zeroMoney = new Money(Currency::EUR, 0);
|
||||
$this->aboveLimitMoney = new Money(Currency::EUR, 301);
|
||||
});
|
||||
$money = new Money(Currency::EUR, 300);
|
||||
$secondMoney = new Money(Currency::EUR, 200);
|
||||
$minimumMoney = new Money(Currency::EUR, 1);
|
||||
$zeroMoney = new Money(Currency::EUR, 0);
|
||||
$aboveLimitMoney = new Money(Currency::EUR, 301);
|
||||
|
||||
it('wraps a Money value', function (): void {
|
||||
it('wraps a Money value', function () use ($money): void {
|
||||
// GIVEN / WHEN
|
||||
$amount = new MoneyAmount(
|
||||
$this->money
|
||||
);
|
||||
$amount = new MoneyAmount($money);
|
||||
|
||||
// THEN
|
||||
expect($amount)->toBeInstanceOf(MoneyAmount::class)
|
||||
->and($amount->value)->toBe($this->money);
|
||||
->and($amount->value)->toBe($money);
|
||||
});
|
||||
|
||||
it('implements equals by delegating to the wrapped Money', function (): void {
|
||||
it('implements equals by delegating to the wrapped Money', function () use ($money, $secondMoney): void {
|
||||
// GIVEN / WHEN
|
||||
$amount1 = new MoneyAmount(
|
||||
$this->money
|
||||
);
|
||||
$amount2 = new MoneyAmount(
|
||||
$this->money
|
||||
);
|
||||
$amount3 = new MoneyAmount(
|
||||
$this->secondMoney
|
||||
);
|
||||
$amount1 = new MoneyAmount($money);
|
||||
$amount2 = new MoneyAmount($money);
|
||||
$amount3 = new MoneyAmount($secondMoney);
|
||||
|
||||
// THEN
|
||||
expect($amount1->equals($amount2))->toBeTrue()
|
||||
|
|
@ -48,41 +38,39 @@ describe('money amount', function (): void {
|
|||
->and($amount1->equals(null))->toBeFalse();
|
||||
});
|
||||
|
||||
it('converts to string by delegating to the wrapped Money', function (): void {
|
||||
it('converts to string by delegating to the wrapped Money', function () use ($money): void {
|
||||
// GIVEN / WHEN
|
||||
$amount = new MoneyAmount(
|
||||
$this->money
|
||||
);
|
||||
$amount = new MoneyAmount($money);
|
||||
|
||||
// THEN
|
||||
expect((string) $amount)->toBe((string) $amount->value);
|
||||
});
|
||||
|
||||
it('accepts the minimum amount of 0.01€', function (): void {
|
||||
it('accepts the minimum amount of 0.01€', function () use ($minimumMoney): void {
|
||||
// GIVEN / WHEN
|
||||
$amount = new MoneyAmount($this->minimumMoney);
|
||||
$amount = new MoneyAmount($minimumMoney);
|
||||
|
||||
// THEN
|
||||
expect($amount->value)->toBe($this->minimumMoney);
|
||||
expect($amount->value)->toBe($minimumMoney);
|
||||
});
|
||||
|
||||
it('accepts the maximum amount of 3.00€', function (): void {
|
||||
it('accepts the maximum amount of 3.00€', function () use ($money): void {
|
||||
// GIVEN / WHEN
|
||||
$amount = new MoneyAmount($this->money);
|
||||
$amount = new MoneyAmount($money);
|
||||
|
||||
// THEN
|
||||
expect($amount->value)->toBe($this->money);
|
||||
expect($amount->value)->toBe($money);
|
||||
});
|
||||
|
||||
it('throws when the amount is zero', function (): void {
|
||||
it('throws when the amount is zero', function () use ($zeroMoney): void {
|
||||
// GIVEN / WHEN / THEN
|
||||
expect(fn () => new MoneyAmount($this->zeroMoney))
|
||||
expect(fn (): MoneyAmount => new MoneyAmount($zeroMoney))
|
||||
->toThrow(\DomainException::class, 'Money amount must be between 0.01€ and 3.00€');
|
||||
});
|
||||
|
||||
it('throws when the amount is above 3.00€', function (): void {
|
||||
it('throws when the amount is above 3.00€', function () use ($aboveLimitMoney): void {
|
||||
// GIVEN / WHEN / THEN
|
||||
expect(fn () => new MoneyAmount($this->aboveLimitMoney))
|
||||
expect(fn (): MoneyAmount => new MoneyAmount($aboveLimitMoney))
|
||||
->toThrow(\DomainException::class, 'Money amount must be between 0.01€ and 3.00€');
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -9,48 +9,46 @@ use Domain\Models\ValueObjects\PrintRules;
|
|||
covers(PrintRules::class);
|
||||
|
||||
describe('print rules', function (): void {
|
||||
beforeEach(function (): void {
|
||||
$this->maxPerCustomer = 3;
|
||||
$this->minMaxPerCustomer = 1;
|
||||
$this->zeroMaxPerCustomer = 0;
|
||||
$this->cooldownDays = 30;
|
||||
$this->minCooldownDays = 1;
|
||||
$this->zeroCooldownDays = 0;
|
||||
});
|
||||
$maxPerCustomer = 3;
|
||||
$minMaxPerCustomer = 1;
|
||||
$zeroMaxPerCustomer = 0;
|
||||
$cooldownDays = 30;
|
||||
$minCooldownDays = 1;
|
||||
$zeroCooldownDays = 0;
|
||||
|
||||
it('creates print rules with both fields set', function (): void {
|
||||
it('creates print rules with both fields set', function () use ($maxPerCustomer, $cooldownDays): void {
|
||||
// GIVEN / WHEN
|
||||
$printRules = new PrintRules(
|
||||
maxPerCustomer: $this->maxPerCustomer,
|
||||
cooldownDays: $this->cooldownDays
|
||||
maxPerCustomer: $maxPerCustomer,
|
||||
cooldownDays: $cooldownDays
|
||||
);
|
||||
|
||||
// THEN
|
||||
expect($printRules)->toBeInstanceOf(PrintRules::class)
|
||||
->and($printRules->maxPerCustomer)->toBe($this->maxPerCustomer)
|
||||
->and($printRules->cooldownDays)->toBe($this->cooldownDays);
|
||||
->and($printRules->maxPerCustomer)->toBe($maxPerCustomer)
|
||||
->and($printRules->cooldownDays)->toBe($cooldownDays);
|
||||
});
|
||||
|
||||
it('creates print rules with only maxPerCustomer set', function (): void {
|
||||
it('creates print rules with only maxPerCustomer set', function () use ($maxPerCustomer): void {
|
||||
// GIVEN / WHEN
|
||||
$printRules = new PrintRules(
|
||||
maxPerCustomer: $this->maxPerCustomer
|
||||
maxPerCustomer: $maxPerCustomer
|
||||
);
|
||||
|
||||
// THEN
|
||||
expect($printRules->maxPerCustomer)->toBe($this->maxPerCustomer)
|
||||
expect($printRules->maxPerCustomer)->toBe($maxPerCustomer)
|
||||
->and($printRules->cooldownDays)->toBeNull();
|
||||
});
|
||||
|
||||
it('creates print rules with only cooldownDays set', function (): void {
|
||||
it('creates print rules with only cooldownDays set', function () use ($cooldownDays): void {
|
||||
// GIVEN / WHEN
|
||||
$printRules = new PrintRules(
|
||||
cooldownDays: $this->cooldownDays
|
||||
cooldownDays: $cooldownDays
|
||||
);
|
||||
|
||||
// THEN
|
||||
expect($printRules->maxPerCustomer)->toBeNull()
|
||||
->and($printRules->cooldownDays)->toBe($this->cooldownDays);
|
||||
->and($printRules->cooldownDays)->toBe($cooldownDays);
|
||||
});
|
||||
|
||||
it('rejects print rules without any field set', function (): void {
|
||||
|
|
@ -59,29 +57,29 @@ describe('print rules', function (): void {
|
|||
->toThrow(\InvalidArgumentException::class, 'PrintRules require at least a max per customer or a cooldown days.');
|
||||
});
|
||||
|
||||
it('accepts the minimum value of 1 for both fields', function (): void {
|
||||
it('accepts the minimum value of 1 for both fields', function () use ($minMaxPerCustomer, $minCooldownDays): void {
|
||||
// GIVEN / WHEN
|
||||
$printRules = new PrintRules(
|
||||
maxPerCustomer: $this->minMaxPerCustomer,
|
||||
cooldownDays: $this->minCooldownDays
|
||||
maxPerCustomer: $minMaxPerCustomer,
|
||||
cooldownDays: $minCooldownDays
|
||||
);
|
||||
|
||||
// THEN
|
||||
expect($printRules->maxPerCustomer)->toBe($this->minMaxPerCustomer)
|
||||
->and($printRules->cooldownDays)->toBe($this->minCooldownDays);
|
||||
expect($printRules->maxPerCustomer)->toBe($minMaxPerCustomer)
|
||||
->and($printRules->cooldownDays)->toBe($minCooldownDays);
|
||||
});
|
||||
|
||||
it('rejects a maxPerCustomer equal to zero', function (): void {
|
||||
it('rejects a maxPerCustomer equal to zero', function () use ($zeroMaxPerCustomer): void {
|
||||
// GIVEN / WHEN / THEN
|
||||
expect(fn (): PrintRules => new PrintRules(
|
||||
maxPerCustomer: $this->zeroMaxPerCustomer
|
||||
maxPerCustomer: $zeroMaxPerCustomer
|
||||
))->toThrow(\InvalidArgumentException::class, 'Max per customer must be greater than 0.');
|
||||
});
|
||||
|
||||
it('rejects a cooldownDays equal to zero', function (): void {
|
||||
it('rejects a cooldownDays equal to zero', function () use ($zeroCooldownDays): void {
|
||||
// GIVEN / WHEN / THEN
|
||||
expect(fn (): PrintRules => new PrintRules(
|
||||
cooldownDays: $this->zeroCooldownDays
|
||||
cooldownDays: $zeroCooldownDays
|
||||
))->toThrow(\InvalidArgumentException::class, 'Cooldown days must be greater than 0.');
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,33 +0,0 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Tests\Unit\Domain\Models\ValueObjects;
|
||||
|
||||
use Domain\Models\ValueObjects\ProcessingCode;
|
||||
|
||||
covers(ProcessingCode::class);
|
||||
|
||||
describe('processing code', function (): void {
|
||||
beforeEach(function (): void {
|
||||
$this->value = '1010100101';
|
||||
$this->emptyValue = '';
|
||||
});
|
||||
|
||||
it('creates a valid processing code', function (): void {
|
||||
// GIVEN / WHEN
|
||||
$processingCode = new ProcessingCode(
|
||||
$this->value
|
||||
);
|
||||
|
||||
// THEN
|
||||
expect($processingCode->value)->toBe($this->value);
|
||||
});
|
||||
|
||||
it('rejects invalid processing code', function (): void {
|
||||
// GIVEN / WHEN / THEN
|
||||
expect(fn (): ProcessingCode => new ProcessingCode(
|
||||
$this->emptyValue
|
||||
))->toThrow(\DomainException::class);
|
||||
});
|
||||
});
|
||||
|
|
@ -61,7 +61,7 @@ describe('raw picture', function (): void {
|
|||
|
||||
it('measures size in raw bytes rather than characters', function (): void {
|
||||
// GIVEN
|
||||
$halfLimit = (int) (RawPicturePath::MAX_SIZE_IN_BYTES / 2) + 1;
|
||||
$halfLimit = RawPicturePath::MAX_SIZE_IN_BYTES / 2 + 1;
|
||||
$content = str_repeat('é', $halfLimit);
|
||||
|
||||
// WHEN
|
||||
|
|
|
|||
|
|
@ -10,22 +10,17 @@ use DateTime;
|
|||
covers(Period::class);
|
||||
|
||||
describe('period', function (): void {
|
||||
beforeEach(function (): void {
|
||||
$this->start = new DateTime('2026-01-01');
|
||||
$this->end = new DateTime('2026-01-31');
|
||||
});
|
||||
$start = new DateTime('2026-01-01');
|
||||
$end = new DateTime('2026-01-31');
|
||||
|
||||
it('creates a valid period', function (): void {
|
||||
it('creates a valid period', function () use ($start, $end): void {
|
||||
// GIVEN / WHEN
|
||||
$period = new Period(
|
||||
$this->start,
|
||||
$this->end
|
||||
);
|
||||
$period = new Period($start, $end);
|
||||
|
||||
// THEN
|
||||
expect($period)->toBeInstanceOf(Period::class)
|
||||
->and($period->start)->toBe($this->start)
|
||||
->and($period->end)->toBe($this->end);
|
||||
->and($period->start)->toBe($start)
|
||||
->and($period->end)->toBe($end);
|
||||
});
|
||||
|
||||
it('accepts a period whose end equals its start', function (): void {
|
||||
|
|
@ -43,7 +38,7 @@ describe('period', function (): void {
|
|||
|
||||
it('throws when the end is before the start', function (): void {
|
||||
// GIVEN / WHEN / THEN
|
||||
expect(fn () => new Period(new DateTime('2026-02-01'), new DateTime('2026-01-01')))
|
||||
expect(fn (): Period => new Period(new DateTime('2026-02-01'), new DateTime('2026-01-01')))
|
||||
->toThrow(\DomainException::class, 'Period end date cannot be before its start date.');
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -9,38 +9,30 @@ use Domain\Models\ValueObjects\RequestedCoupon\RequestedCouponQuantity;
|
|||
covers(RequestedCouponQuantity::class);
|
||||
|
||||
describe('quantity', function (): void {
|
||||
beforeEach(function (): void {
|
||||
$this->value = 10;
|
||||
$this->zeroValue = 0;
|
||||
$this->negativeValue = -1;
|
||||
});
|
||||
$value = 10;
|
||||
$zeroValue = 0;
|
||||
$negativeValue = -1;
|
||||
|
||||
it('creates a valid quantity', function (): void {
|
||||
it('creates a valid quantity', function () use ($value): void {
|
||||
// GIVEN / WHEN
|
||||
$quantity = new RequestedCouponQuantity(
|
||||
$this->value
|
||||
);
|
||||
$quantity = new RequestedCouponQuantity($value);
|
||||
|
||||
// THEN
|
||||
expect($quantity)->toBeInstanceOf(RequestedCouponQuantity::class)
|
||||
->and($quantity->value)->toBe($this->value);
|
||||
->and($quantity->value)->toBe($value);
|
||||
});
|
||||
|
||||
it('rejects a quantity of zero', function (): void {
|
||||
it('rejects a quantity of zero', function () use ($zeroValue): void {
|
||||
// GIVEN / WHEN
|
||||
$action = fn (): RequestedCouponQuantity => new RequestedCouponQuantity(
|
||||
$this->zeroValue
|
||||
);
|
||||
$action = fn (): RequestedCouponQuantity => new RequestedCouponQuantity($zeroValue);
|
||||
|
||||
// THEN
|
||||
expect($action)->toThrow(\DomainException::class, 'Quantity should be more than 0.');
|
||||
});
|
||||
|
||||
it('rejects a negative quantity', function (): void {
|
||||
it('rejects a negative quantity', function () use ($negativeValue): void {
|
||||
// GIVEN / WHEN
|
||||
$action = fn (): RequestedCouponQuantity => new RequestedCouponQuantity(
|
||||
$this->negativeValue
|
||||
);
|
||||
$action = fn (): RequestedCouponQuantity => new RequestedCouponQuantity($negativeValue);
|
||||
|
||||
// THEN
|
||||
expect($action)->toThrow(\DomainException::class, 'Quantity should be more than 0.');
|
||||
|
|
|
|||
|
|
@ -4,18 +4,21 @@ declare(strict_types=1);
|
|||
|
||||
namespace Tests\Unit\Domain\Models\ValueObjects\RequestedCoupon;
|
||||
|
||||
use Carbon\CarbonImmutable;
|
||||
use DateTime;
|
||||
use Domain\Enums\BarcodeFormat;
|
||||
use Domain\Models\ValueObjects\Coupon\CouponValidity;
|
||||
use Domain\Models\ValueObjects\Coupon\CouponIncoCode;
|
||||
use Domain\Models\ValueObjects\Coupon\CouponLegalInformation;
|
||||
use Domain\Models\ValueObjects\Coupon\CouponLegalInformationArray;
|
||||
use Domain\Models\ValueObjects\Coupon\CouponName;
|
||||
use Domain\Models\ValueObjects\Coupon\CouponPicture;
|
||||
use Domain\Models\ValueObjects\Coupon\CouponProcessingCode;
|
||||
use Domain\Models\ValueObjects\Coupon\CouponProcessingCodeArray;
|
||||
use Domain\Models\ValueObjects\Coupon\CouponProductArray;
|
||||
use Domain\Models\ValueObjects\Coupon\CouponValidityInformation;
|
||||
use Domain\Models\ValueObjects\CouponName;
|
||||
use Domain\Models\ValueObjects\GS1;
|
||||
use Domain\Models\ValueObjects\IncoCode;
|
||||
use Domain\Models\ValueObjects\Coupon\CouponValidityInformationArray;
|
||||
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;
|
||||
use Domain\Models\ValueObjects\RequestedCoupon\RequestedCouponQuantity;
|
||||
use Shared\Enums\Country;
|
||||
|
|
@ -25,210 +28,265 @@ use Shared\ValueObjects\Money;
|
|||
covers(RequestedCoupon::class);
|
||||
|
||||
describe('requested coupon', function (): void {
|
||||
beforeEach(function (): void {
|
||||
$this->name = new CouponName('Coupon A');
|
||||
$this->quantity = new RequestedCouponQuantity(100);
|
||||
$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->couponValidity = new CouponValidity(30, new DateTime('2026-02-01'));
|
||||
$this->franceValidityInformation = new CouponValidityInformation(
|
||||
'Lorem ipsum dolor sit amet consectetur adipiscing elit.',
|
||||
Country::FRANCE
|
||||
);
|
||||
$this->beneluxValidityInformation = new CouponValidityInformation(
|
||||
'Lorem ipsum dolor sit amet consectetur adipiscing elit.',
|
||||
Country::BENELUX
|
||||
);
|
||||
$this->couponValidityInformation = [
|
||||
$this->franceValidityInformation,
|
||||
$this->beneluxValidityInformation,
|
||||
];
|
||||
$this->products = [new IncoCode(35784), new IncoCode(15522)];
|
||||
$this->printRules = new PrintRules(maxPerCustomer: 3);
|
||||
$this->gs1 = new GS1('01234567890128', BarcodeFormat::EAN13);
|
||||
});
|
||||
$couponName = new CouponName('Coupon A');
|
||||
$quantity = new RequestedCouponQuantity(100);
|
||||
$diffusion = new Period(new DateTime('2026-01-01'), new DateTime('2026-02-01'));
|
||||
$moneyAmount = new MoneyAmount(new Money(Currency::EUR, 300));
|
||||
$couponPicture = new CouponPicture(
|
||||
new PicturePath('files/product.jpg'),
|
||||
new PicturePath('files/thumbnail.jpg'),
|
||||
new PicturePath('files/mobileThumbnail.jpg')
|
||||
);
|
||||
|
||||
afterEach(function (): void {
|
||||
CarbonImmutable::setTestNow();
|
||||
});
|
||||
$franceProcessingCode = new CouponProcessingCode('ABC1234567890', Country::FRANCE);
|
||||
$beneluxProcessingCode = new CouponProcessingCode('XYZ9876543210', Country::BENELUX);
|
||||
$couponProcessingCodes = new CouponProcessingCodeArray([
|
||||
$franceProcessingCode,
|
||||
$beneluxProcessingCode,
|
||||
]);
|
||||
|
||||
it('hydrates a requested coupon with all its fields', function (): void {
|
||||
$franceValidityInformation = new CouponValidityInformation(
|
||||
'Lorem ipsum dolor sit amet consectetur adipiscing elit.',
|
||||
Country::FRANCE
|
||||
);
|
||||
$beneluxValidityInformation = new CouponValidityInformation(
|
||||
'Lorem ipsum dolor sit amet consectetur adipiscing elit.',
|
||||
Country::BENELUX
|
||||
);
|
||||
$couponValidityInformations = new CouponValidityInformationArray([
|
||||
$franceValidityInformation,
|
||||
$beneluxValidityInformation,
|
||||
]);
|
||||
|
||||
$franceLegalInformation = new CouponLegalInformation(
|
||||
'Lorem ipsum dolor sit amet consectetur adipiscing elit.',
|
||||
Country::FRANCE
|
||||
);
|
||||
$beneluxLegalInformation = new CouponLegalInformation(
|
||||
'Lorem ipsum dolor sit amet consectetur adipiscing elit.',
|
||||
Country::BENELUX
|
||||
);
|
||||
$couponLegalInformations = new CouponLegalInformationArray([
|
||||
$franceLegalInformation,
|
||||
$beneluxLegalInformation,
|
||||
]);
|
||||
|
||||
$couponProducts = new CouponProductArray([
|
||||
new CouponIncoCode(35784),
|
||||
new CouponIncoCode(15522),
|
||||
]);
|
||||
$printRules = new PrintRules(maxPerCustomer: 3);
|
||||
|
||||
it('hydrates a requested coupon with all its fields', function () use (
|
||||
$couponName,
|
||||
$quantity,
|
||||
$diffusion,
|
||||
$moneyAmount,
|
||||
$couponPicture,
|
||||
$couponProcessingCodes,
|
||||
$couponValidityInformations,
|
||||
$couponLegalInformations,
|
||||
$couponProducts,
|
||||
$printRules,
|
||||
): void {
|
||||
// GIVEN / WHEN
|
||||
$coupon = new RequestedCoupon(
|
||||
$this->name,
|
||||
$this->quantity,
|
||||
$this->diffusion,
|
||||
$this->moneyAmount,
|
||||
$this->processingCode,
|
||||
$this->couponValidity,
|
||||
$this->couponValidityInformation,
|
||||
$this->products,
|
||||
$this->printRules,
|
||||
$this->gs1,
|
||||
couponName: $couponName,
|
||||
quantity: $quantity,
|
||||
diffusion: $diffusion,
|
||||
moneyAmount: $moneyAmount,
|
||||
couponPicture: $couponPicture,
|
||||
couponProcessingCodes: $couponProcessingCodes,
|
||||
couponValidityInformations: $couponValidityInformations,
|
||||
couponLegalInformations: $couponLegalInformations,
|
||||
couponProducts: $couponProducts,
|
||||
printRules: $printRules,
|
||||
);
|
||||
|
||||
// THEN
|
||||
expect($coupon->name)->toBe($this->name)
|
||||
->and($coupon->quantity)->toBe($this->quantity)
|
||||
->and($coupon->diffusion)->toBe($this->diffusion)
|
||||
->and($coupon->moneyAmount)->toBe($this->moneyAmount)
|
||||
->and($coupon->processingCode)->toBe($this->processingCode)
|
||||
->and($coupon->couponValidity)->toBe($this->couponValidity)
|
||||
->and($coupon->couponValidityInformation)->toBe($this->couponValidityInformation)
|
||||
->and($coupon->products)->toBe($this->products)
|
||||
->and($coupon->printRules)->toBe($this->printRules)
|
||||
->and($coupon->gs1)->toBe($this->gs1);
|
||||
expect($coupon->couponName)->toBe($couponName)
|
||||
->and($coupon->quantity)->toBe($quantity)
|
||||
->and($coupon->diffusion)->toBe($diffusion)
|
||||
->and($coupon->moneyAmount)->toBe($moneyAmount)
|
||||
->and($coupon->couponPicture)->toBe($couponPicture)
|
||||
->and($coupon->couponProcessingCodes)->toBe($couponProcessingCodes)
|
||||
->and($coupon->couponValidityInformations)->toBe($couponValidityInformations)
|
||||
->and($coupon->couponLegalInformations)->toBe($couponLegalInformations)
|
||||
->and($coupon->couponProducts)->toBe($couponProducts)
|
||||
->and($coupon->printRules)->toBe($printRules);
|
||||
});
|
||||
|
||||
it('hydrates a requested coupon without products', function (): void {
|
||||
it('hydrates a requested coupon without products', function () use (
|
||||
$couponName,
|
||||
$quantity,
|
||||
$diffusion,
|
||||
$moneyAmount,
|
||||
$couponPicture,
|
||||
$couponProcessingCodes,
|
||||
$couponValidityInformations,
|
||||
$couponLegalInformations,
|
||||
$printRules,
|
||||
): void {
|
||||
// GIVEN / WHEN
|
||||
$coupon = new RequestedCoupon(
|
||||
name: $this->name,
|
||||
quantity: $this->quantity,
|
||||
diffusion: $this->diffusion,
|
||||
moneyAmount: $this->moneyAmount,
|
||||
processingCode: $this->processingCode,
|
||||
couponValidity: $this->couponValidity,
|
||||
couponValidityInformation: $this->couponValidityInformation,
|
||||
printRules: $this->printRules,
|
||||
gs1: $this->gs1
|
||||
couponName: $couponName,
|
||||
quantity: $quantity,
|
||||
diffusion: $diffusion,
|
||||
moneyAmount: $moneyAmount,
|
||||
couponPicture: $couponPicture,
|
||||
couponProcessingCodes: $couponProcessingCodes,
|
||||
couponValidityInformations: $couponValidityInformations,
|
||||
couponLegalInformations: $couponLegalInformations,
|
||||
couponProducts: new CouponProductArray(),
|
||||
printRules: $printRules,
|
||||
);
|
||||
|
||||
// THEN
|
||||
expect($coupon->products)->toBe([])
|
||||
->and($coupon->printRules)->toBe($this->printRules)
|
||||
->and($coupon->gs1)->toBe($this->gs1);
|
||||
expect($coupon->couponProducts->value)->toBe([])
|
||||
->and($coupon->printRules)->toBe($printRules);
|
||||
});
|
||||
|
||||
it('hydrates a requested coupon without print rules', function (): void {
|
||||
it('hydrates a requested coupon without print rules', function () use (
|
||||
$couponName,
|
||||
$quantity,
|
||||
$diffusion,
|
||||
$moneyAmount,
|
||||
$couponPicture,
|
||||
$couponProcessingCodes,
|
||||
$couponValidityInformations,
|
||||
$couponLegalInformations,
|
||||
$couponProducts,
|
||||
): void {
|
||||
// GIVEN / WHEN
|
||||
$coupon = new RequestedCoupon(
|
||||
name: $this->name,
|
||||
quantity: $this->quantity,
|
||||
diffusion: $this->diffusion,
|
||||
moneyAmount: $this->moneyAmount,
|
||||
processingCode: $this->processingCode,
|
||||
couponValidity: $this->couponValidity,
|
||||
couponValidityInformation: $this->couponValidityInformation,
|
||||
products: $this->products,
|
||||
gs1: $this->gs1
|
||||
couponName: $couponName,
|
||||
quantity: $quantity,
|
||||
diffusion: $diffusion,
|
||||
moneyAmount: $moneyAmount,
|
||||
couponPicture: $couponPicture,
|
||||
couponProcessingCodes: $couponProcessingCodes,
|
||||
couponValidityInformations: $couponValidityInformations,
|
||||
couponLegalInformations: $couponLegalInformations,
|
||||
couponProducts: $couponProducts,
|
||||
);
|
||||
|
||||
// THEN
|
||||
expect($coupon->printRules)->toBeNull()
|
||||
->and($coupon->products)->toBe($this->products)
|
||||
->and($coupon->gs1)->toBe($this->gs1);
|
||||
->and($coupon->couponProducts)->toBe($couponProducts);
|
||||
});
|
||||
|
||||
it('hydrates a requested coupon without gs1', function (): void {
|
||||
it('accepts a france only coupon', function () use (
|
||||
$couponName,
|
||||
$quantity,
|
||||
$diffusion,
|
||||
$moneyAmount,
|
||||
$couponPicture,
|
||||
$franceProcessingCode,
|
||||
$franceValidityInformation,
|
||||
$franceLegalInformation,
|
||||
$couponProducts,
|
||||
): void {
|
||||
// GIVEN / WHEN
|
||||
$coupon = new RequestedCoupon(
|
||||
name: $this->name,
|
||||
quantity: $this->quantity,
|
||||
diffusion: $this->diffusion,
|
||||
moneyAmount: $this->moneyAmount,
|
||||
processingCode: $this->processingCode,
|
||||
couponValidity: $this->couponValidity,
|
||||
couponValidityInformation: $this->couponValidityInformation,
|
||||
products: $this->products,
|
||||
printRules: $this->printRules
|
||||
couponName: $couponName,
|
||||
quantity: $quantity,
|
||||
diffusion: $diffusion,
|
||||
moneyAmount: $moneyAmount,
|
||||
couponPicture: $couponPicture,
|
||||
couponProcessingCodes: new CouponProcessingCodeArray([
|
||||
$franceProcessingCode,
|
||||
]),
|
||||
couponValidityInformations: new CouponValidityInformationArray([
|
||||
$franceValidityInformation,
|
||||
]),
|
||||
couponLegalInformations: new CouponLegalInformationArray([
|
||||
$franceLegalInformation,
|
||||
]),
|
||||
couponProducts: $couponProducts,
|
||||
);
|
||||
|
||||
// THEN
|
||||
expect($coupon->gs1)->toBeNull()
|
||||
->and($coupon->products)->toBe($this->products)
|
||||
->and($coupon->printRules)->toBe($this->printRules);
|
||||
expect($coupon)->toBeInstanceOf(RequestedCoupon::class);
|
||||
});
|
||||
|
||||
it('hydrates a requested coupon with only required fields', function (): void {
|
||||
// GIVEN / WHEN
|
||||
$coupon = new RequestedCoupon(
|
||||
name: $this->name,
|
||||
quantity: $this->quantity,
|
||||
diffusion: $this->diffusion,
|
||||
moneyAmount: $this->moneyAmount,
|
||||
processingCode: $this->processingCode,
|
||||
couponValidity: $this->couponValidity,
|
||||
couponValidityInformation: $this->couponValidityInformation,
|
||||
);
|
||||
|
||||
// THEN
|
||||
expect($coupon->products)->toBe([])
|
||||
->and($coupon->printRules)->toBeNull()
|
||||
->and($coupon->gs1)->toBeNull();
|
||||
});
|
||||
|
||||
it('throws when there is no validity information for france', function (): void {
|
||||
it('throws when there is no processing code for france', function () use (
|
||||
$couponName,
|
||||
$quantity,
|
||||
$diffusion,
|
||||
$moneyAmount,
|
||||
$couponPicture,
|
||||
$beneluxProcessingCode,
|
||||
$couponValidityInformations,
|
||||
$couponLegalInformations,
|
||||
$couponProducts,
|
||||
): void {
|
||||
// GIVEN / WHEN / THEN
|
||||
expect(fn () => new RequestedCoupon(
|
||||
name: $this->name,
|
||||
quantity: $this->quantity,
|
||||
diffusion: $this->diffusion,
|
||||
moneyAmount: $this->moneyAmount,
|
||||
processingCode: $this->processingCode,
|
||||
couponValidity: $this->couponValidity,
|
||||
couponValidityInformation: [],
|
||||
))->toThrow(\DomainException::class, 'A coupon requires validity information for France.');
|
||||
expect(fn (): RequestedCoupon => new RequestedCoupon(
|
||||
couponName: $couponName,
|
||||
quantity: $quantity,
|
||||
diffusion: $diffusion,
|
||||
moneyAmount: $moneyAmount,
|
||||
couponPicture: $couponPicture,
|
||||
couponProcessingCodes: new CouponProcessingCodeArray([
|
||||
$beneluxProcessingCode,
|
||||
]),
|
||||
couponValidityInformations: $couponValidityInformations,
|
||||
couponLegalInformations: $couponLegalInformations,
|
||||
couponProducts: $couponProducts,
|
||||
))->toThrow(\DomainException::class, 'CouponProcessingCodes requires a CouponProcessingCode for France.');
|
||||
});
|
||||
|
||||
it('throws when validity information contains an invalid item', function (): void {
|
||||
it('throws when a benelux processing code has no benelux validity information', function () use (
|
||||
$couponName,
|
||||
$quantity,
|
||||
$diffusion,
|
||||
$moneyAmount,
|
||||
$couponPicture,
|
||||
$couponProcessingCodes,
|
||||
$franceValidityInformation,
|
||||
$couponLegalInformations,
|
||||
$couponProducts,
|
||||
): void {
|
||||
// GIVEN / WHEN / THEN
|
||||
expect(fn () => new RequestedCoupon(
|
||||
$this->name,
|
||||
$this->quantity,
|
||||
$this->diffusion,
|
||||
$this->moneyAmount,
|
||||
$this->processingCode,
|
||||
$this->couponValidity,
|
||||
['Not a CouponValidityInformation'],
|
||||
$this->products,
|
||||
$this->printRules,
|
||||
$this->gs1
|
||||
))->toThrow(\DomainException::class, 'Coupon validity information must be CouponValidityInformation instances.');
|
||||
expect(fn (): RequestedCoupon => new RequestedCoupon(
|
||||
couponName: $couponName,
|
||||
quantity: $quantity,
|
||||
diffusion: $diffusion,
|
||||
moneyAmount: $moneyAmount,
|
||||
couponPicture: $couponPicture,
|
||||
couponProcessingCodes: $couponProcessingCodes,
|
||||
couponValidityInformations: new CouponValidityInformationArray([
|
||||
$franceValidityInformation,
|
||||
]),
|
||||
couponLegalInformations: $couponLegalInformations,
|
||||
couponProducts: $couponProducts,
|
||||
))->toThrow(\DomainException::class, 'A coupon requires validity information for BENELUX.');
|
||||
});
|
||||
|
||||
it('throws when a gs1 coupon has no benelux validity information', function (): void {
|
||||
it('throws when a benelux processing code has no benelux legal information', function () use (
|
||||
$couponName,
|
||||
$quantity,
|
||||
$diffusion,
|
||||
$moneyAmount,
|
||||
$couponPicture,
|
||||
$couponProcessingCodes,
|
||||
$couponValidityInformations,
|
||||
$franceLegalInformation,
|
||||
$couponProducts,
|
||||
): void {
|
||||
// GIVEN / WHEN / THEN
|
||||
expect(fn () => new RequestedCoupon(
|
||||
name: $this->name,
|
||||
quantity: $this->quantity,
|
||||
diffusion: $this->diffusion,
|
||||
moneyAmount: $this->moneyAmount,
|
||||
processingCode: $this->processingCode,
|
||||
couponValidity: $this->couponValidity,
|
||||
couponValidityInformation: [$this->franceValidityInformation],
|
||||
gs1: $this->gs1,
|
||||
))->toThrow(\DomainException::class, 'A GS1 coupon requires validity information for Benelux.');
|
||||
});
|
||||
|
||||
it('throws when a gs1 coupon has only benelux validity information', function (): void {
|
||||
// GIVEN / WHEN / THEN
|
||||
expect(fn () => new RequestedCoupon(
|
||||
name: $this->name,
|
||||
quantity: $this->quantity,
|
||||
diffusion: $this->diffusion,
|
||||
moneyAmount: $this->moneyAmount,
|
||||
processingCode: $this->processingCode,
|
||||
couponValidity: $this->couponValidity,
|
||||
couponValidityInformation: [$this->beneluxValidityInformation],
|
||||
gs1: $this->gs1,
|
||||
))->toThrow(\DomainException::class, 'A coupon requires validity information for France.');
|
||||
});
|
||||
|
||||
it('accepts a coupon without gs1 and without benelux validity information', function (): void {
|
||||
// GIVEN / WHEN
|
||||
$coupon = new RequestedCoupon(
|
||||
name: $this->name,
|
||||
quantity: $this->quantity,
|
||||
diffusion: $this->diffusion,
|
||||
moneyAmount: $this->moneyAmount,
|
||||
processingCode: $this->processingCode,
|
||||
couponValidity: $this->couponValidity,
|
||||
couponValidityInformation: [$this->franceValidityInformation],
|
||||
);
|
||||
|
||||
// THEN
|
||||
expect($coupon->gs1)->toBeNull();
|
||||
expect(fn (): RequestedCoupon => new RequestedCoupon(
|
||||
couponName: $couponName,
|
||||
quantity: $quantity,
|
||||
diffusion: $diffusion,
|
||||
moneyAmount: $moneyAmount,
|
||||
couponPicture: $couponPicture,
|
||||
couponProcessingCodes: $couponProcessingCodes,
|
||||
couponValidityInformations: $couponValidityInformations,
|
||||
couponLegalInformations: new CouponLegalInformationArray([
|
||||
$franceLegalInformation,
|
||||
]),
|
||||
couponProducts: $couponProducts,
|
||||
))->toThrow(\DomainException::class, 'A coupon requires legal information for BENELUX.');
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -10,73 +10,71 @@ use Domain\Models\ValueObjects\Stock\StockAdjustment;
|
|||
covers(StockAdjustment::class);
|
||||
|
||||
describe('stock adjustment', function (): void {
|
||||
beforeEach(function (): void {
|
||||
$this->quantity = 10;
|
||||
$this->zeroQuantity = 0;
|
||||
$this->negativeQuantity = -5;
|
||||
$this->reason = 'Inventory correction';
|
||||
});
|
||||
$quantity = 10;
|
||||
$zeroQuantity = 0;
|
||||
$negativeQuantity = -5;
|
||||
$reason = 'Inventory correction';
|
||||
|
||||
it('creates a valid stock adjustment', function (): void {
|
||||
it('creates a valid stock adjustment', function () use ($quantity, $reason): void {
|
||||
// GIVEN
|
||||
$actorId = ActorId::generate();
|
||||
|
||||
// WHEN
|
||||
$adjustment = new StockAdjustment(
|
||||
$this->quantity,
|
||||
$this->reason,
|
||||
$actorId
|
||||
$quantity,
|
||||
$reason,
|
||||
$actorId,
|
||||
);
|
||||
|
||||
// THEN
|
||||
expect($adjustment)->toBeInstanceOf(StockAdjustment::class)
|
||||
->and($adjustment->quantity)->toBe($this->quantity)
|
||||
->and($adjustment->reason)->toBe($this->reason)
|
||||
->and($adjustment->quantity)->toBe($quantity)
|
||||
->and($adjustment->reason)->toBe($reason)
|
||||
->and($adjustment->actorId)->toBe($actorId)
|
||||
->and($adjustment->createdAt)->toBeNull();
|
||||
});
|
||||
|
||||
it('creates a stock adjustment with an explicit createdAt date', function (): void {
|
||||
it('creates a stock adjustment with an explicit createdAt date', function () use ($quantity, $reason): void {
|
||||
// GIVEN
|
||||
$actorId = ActorId::generate();
|
||||
$createdAt = new \DateTimeImmutable('2026-06-15 12:00:00', new \DateTimeZone('UTC'));
|
||||
|
||||
// WHEN
|
||||
$adjustment = new StockAdjustment(
|
||||
$this->quantity,
|
||||
$this->reason,
|
||||
$quantity,
|
||||
$reason,
|
||||
$actorId,
|
||||
$createdAt
|
||||
$createdAt,
|
||||
);
|
||||
|
||||
// THEN
|
||||
expect($adjustment->createdAt)->toBe($createdAt);
|
||||
});
|
||||
|
||||
it('rejects a quantity of zero', function (): void {
|
||||
it('rejects a quantity of zero', function () use ($zeroQuantity, $reason): void {
|
||||
// GIVEN
|
||||
$actorId = ActorId::generate();
|
||||
|
||||
// WHEN
|
||||
$action = fn (): StockAdjustment => new StockAdjustment(
|
||||
$this->zeroQuantity,
|
||||
$this->reason,
|
||||
$actorId
|
||||
$zeroQuantity,
|
||||
$reason,
|
||||
$actorId,
|
||||
);
|
||||
|
||||
// THEN
|
||||
expect($action)->toThrow(\DomainException::class, 'Stock Amount should be more than 0.');
|
||||
});
|
||||
|
||||
it('rejects a negative quantity', function (): void {
|
||||
it('rejects a negative quantity', function () use ($negativeQuantity, $reason): void {
|
||||
// GIVEN
|
||||
$actorId = ActorId::generate();
|
||||
|
||||
// WHEN
|
||||
$action = fn (): StockAdjustment => new StockAdjustment(
|
||||
$this->negativeQuantity,
|
||||
$this->reason,
|
||||
$actorId
|
||||
$negativeQuantity,
|
||||
$reason,
|
||||
$actorId,
|
||||
);
|
||||
|
||||
// THEN
|
||||
|
|
|
|||
|
|
@ -9,38 +9,30 @@ use Domain\Models\ValueObjects\Stock\StockAmount;
|
|||
covers(StockAmount::class);
|
||||
|
||||
describe('stock amount', function (): void {
|
||||
beforeEach(function (): void {
|
||||
$this->value = 10;
|
||||
$this->zeroValue = 0;
|
||||
$this->negativeValue = -1;
|
||||
});
|
||||
$value = 10;
|
||||
$zeroValue = 0;
|
||||
$negativeValue = -1;
|
||||
|
||||
it('creates a valid stock amount', function (): void {
|
||||
it('creates a valid stock amount', function () use ($value): void {
|
||||
// GIVEN / WHEN
|
||||
$amount = new StockAmount(
|
||||
$this->value
|
||||
);
|
||||
$amount = new StockAmount($value);
|
||||
|
||||
// THEN
|
||||
expect($amount)->toBeInstanceOf(StockAmount::class)
|
||||
->and($amount->value)->toBe($this->value);
|
||||
->and($amount->value)->toBe($value);
|
||||
});
|
||||
|
||||
it('accepts a zero value', function (): void {
|
||||
it('accepts a zero value', function () use ($zeroValue): void {
|
||||
// GIVEN / WHEN
|
||||
$amount = new StockAmount(
|
||||
$this->zeroValue
|
||||
);
|
||||
$amount = new StockAmount($zeroValue);
|
||||
|
||||
// THEN
|
||||
expect($amount->value)->toBe($this->zeroValue);
|
||||
expect($amount->value)->toBe($zeroValue);
|
||||
});
|
||||
|
||||
it('rejects a negative value', function (): void {
|
||||
it('rejects a negative value', function () use ($negativeValue): void {
|
||||
// GIVEN / WHEN
|
||||
$action = fn (): StockAmount => new StockAmount(
|
||||
$this->negativeValue
|
||||
);
|
||||
$action = fn (): StockAmount => new StockAmount($negativeValue);
|
||||
|
||||
// THEN
|
||||
expect($action)->toThrow(\DomainException::class, 'Stock Amount should be positive.');
|
||||
|
|
|
|||
|
|
@ -4,9 +4,10 @@ declare(strict_types=1);
|
|||
|
||||
namespace Tests\Unit\Shared\Enums;
|
||||
|
||||
use Shared\DDD\Exceptions\UnknownCountryIsoCodeException;
|
||||
use Shared\Enums\Country;
|
||||
|
||||
covers(Country::class);
|
||||
covers(Country::class, UnknownCountryIsoCodeException::class);
|
||||
|
||||
describe('country', function (): void {
|
||||
it('has the expected cases with their backing values', function (): void {
|
||||
|
|
@ -19,4 +20,12 @@ describe('country', function (): void {
|
|||
// THEN
|
||||
expect(Country::FRANCE->name)->toBe('FRANCE');
|
||||
});
|
||||
|
||||
it('is a domain exception', function (): void {
|
||||
// GIVEN / WHEN
|
||||
$exception = UnknownCountryIsoCodeException::fromIsoCode('XX');
|
||||
|
||||
// THEN
|
||||
expect($exception)->toBeInstanceOf(\DomainException::class);
|
||||
});
|
||||
});
|
||||
|
|
@ -250,7 +250,7 @@ describe('dates helper', function (): void {
|
|||
$invalidInput = 'not-a-valid-date';
|
||||
|
||||
// WHEN / THEN
|
||||
expect(fn () => DatesHelper::parseDateTime($invalidInput))
|
||||
expect(fn (): \DateTimeInterface => DatesHelper::parseDateTime($invalidInput))
|
||||
->toThrow(InvalidDateFormatException::class);
|
||||
});
|
||||
|
||||
|
|
@ -259,7 +259,7 @@ describe('dates helper', function (): void {
|
|||
$emptyInput = ' ';
|
||||
|
||||
// WHEN / THEN
|
||||
expect(fn () => DatesHelper::parseDateTime($emptyInput))
|
||||
expect(fn (): \DateTimeInterface => DatesHelper::parseDateTime($emptyInput))
|
||||
->toThrow(InvalidDateFormatException::class);
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ use Ramsey\Uuid\Uuid;
|
|||
use Shared\Helpers\Exceptions\InvalidUuidException;
|
||||
use Shared\Helpers\UuidHelper;
|
||||
|
||||
covers(UuidHelper::class);
|
||||
covers(UuidHelper::class, InvalidUuidException::class);
|
||||
|
||||
describe('Uuid Helper Unit Tests', function (): void {
|
||||
it('prevents direct instantiation but covers constructor', function (): void {
|
||||
|
|
@ -23,7 +23,7 @@ describe('Uuid Helper Unit Tests', function (): void {
|
|||
$constructor->invoke($reflection->newInstanceWithoutConstructor());
|
||||
|
||||
// THEN
|
||||
expect(fn () => $reflection->newInstance())
|
||||
expect(fn (): UuidHelper => $reflection->newInstance())
|
||||
->toThrow(\ReflectionException::class);
|
||||
});
|
||||
|
||||
|
|
@ -83,6 +83,7 @@ describe('Uuid Helper Unit Tests', function (): void {
|
|||
|
||||
public function unserialize(string $data): void
|
||||
{
|
||||
// Keep empty.
|
||||
}
|
||||
|
||||
public function __serialize(): array
|
||||
|
|
@ -92,6 +93,7 @@ describe('Uuid Helper Unit Tests', function (): void {
|
|||
|
||||
public function __unserialize(array $data): void
|
||||
{
|
||||
// Keep empty.
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -127,7 +129,15 @@ describe('Uuid Helper Unit Tests', function (): void {
|
|||
$uuidV4 = Uuid::uuid4();
|
||||
|
||||
// WHEN & THEN
|
||||
expect(fn () => UuidHelper::toDateTime($uuidV4))
|
||||
expect(fn (): \DateTimeImmutable => UuidHelper::toDateTime($uuidV4))
|
||||
->toThrow(InvalidUuidException::class, 'Cannot extract datetime from non-V7 UUID');
|
||||
});
|
||||
|
||||
it('is an invalid argument exception', function (): void {
|
||||
// GIVEN / WHEN
|
||||
$exception = InvalidUuidException::forValue('foo');
|
||||
|
||||
// THEN
|
||||
expect($exception)->toBeInstanceOf(\InvalidArgumentException::class);
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -46,7 +46,7 @@ describe('PageNumber Value Object Unit Tests', function (): void {
|
|||
|
||||
it('rejects page number less than or equal to zero', function (int $invalidValue): void {
|
||||
// WHEN / THEN
|
||||
expect(fn () => new PageNumber($invalidValue))
|
||||
expect(fn (): PageNumber => new PageNumber($invalidValue))
|
||||
->toThrow(\InvalidArgumentException::class, 'Page number must be greater than 0');
|
||||
})->with([
|
||||
'zero' => [0],
|
||||
|
|
|
|||
|
|
@ -54,7 +54,7 @@ describe('PageSize Value Object Unit Tests', function (): void {
|
|||
|
||||
it('rejects page size less than or equal to zero', function (int $invalidValue): void {
|
||||
// WHEN / THEN
|
||||
expect(fn () => new PageSize($invalidValue))
|
||||
expect(fn (): PageSize => new PageSize($invalidValue))
|
||||
->toThrow(\InvalidArgumentException::class, 'Page size must be greater than 0');
|
||||
})->with([
|
||||
'zero' => [0],
|
||||
|
|
@ -64,7 +64,7 @@ describe('PageSize Value Object Unit Tests', function (): void {
|
|||
|
||||
it('rejects page size exceeding maximum page size', function (): void {
|
||||
// WHEN / THEN
|
||||
expect(fn () => new PageSize(PageSize::MAX_PAGE_SIZE + 1))
|
||||
expect(fn (): PageSize => new PageSize(PageSize::MAX_PAGE_SIZE + 1))
|
||||
->toThrow(\InvalidArgumentException::class, 'Page size must be less than or equal to 10000');
|
||||
});
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue