Merge branch 'printed' into 'coupon'
feat: ✨ add use case create printable coupon + tests
See merge request ldc-web/projets/mesbr!66
This commit is contained in:
commit
56d3a35d0e
20 changed files with 719 additions and 41 deletions
|
|
@ -0,0 +1,100 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Application\UseCases\PrintableCoupon\Create;
|
||||
|
||||
use Domain\Models\Entities\Campaign;
|
||||
use Domain\Models\Entities\Coupon;
|
||||
use Domain\Models\Entities\PrintableCoupon;
|
||||
use Domain\Models\ValueObjects\Campaign\CampaignCoupon;
|
||||
use Domain\Models\ValueObjects\CrmHashcode;
|
||||
use Domain\Models\ValueObjects\PrintRules;
|
||||
use Domain\Ports\Repositories\CampaignRepository;
|
||||
use Domain\Ports\Repositories\CouponRepository;
|
||||
use Domain\Ports\Repositories\PrintableCouponRepository;
|
||||
use Shared\DDD\UseCases\Input as BaseInput;
|
||||
use Shared\DDD\UseCases\UseCase;
|
||||
use Shared\DDD\UseCases\Transactional;
|
||||
use Webmozart\Assert\Assert;
|
||||
|
||||
/** @implements UseCase<\Application\UseCases\PrintableCoupon\Create\Input, \Application\UseCases\PrintableCoupon\Create\Output> */
|
||||
final readonly class CreatePrintableCoupon implements UseCase, Transactional
|
||||
{
|
||||
public function __construct(
|
||||
private PrintableCouponRepository $printableCouponRepository,
|
||||
private CouponRepository $couponRepository,
|
||||
private CampaignRepository $campaignRepository,
|
||||
) {
|
||||
}
|
||||
|
||||
#[\Override]
|
||||
public function execute(BaseInput $input): Output
|
||||
{
|
||||
Assert::isInstanceOf($input, Input::class);
|
||||
|
||||
$campaign = $this->campaignRepository->findByCode($input->campaignCode);
|
||||
if (! $campaign instanceof Campaign) {
|
||||
throw new \DomainException(sprintf('Campaign from code "%s" not found.', $input->campaignCode->value));
|
||||
}
|
||||
if (! $campaign->publication) {
|
||||
throw new \DomainException('Campaign must be published.');
|
||||
}
|
||||
|
||||
$coupon = $this->couponRepository->findByCode($input->couponCode);
|
||||
if (! $coupon instanceof Coupon) {
|
||||
throw new \DomainException(sprintf('Coupon code "%s" not found.', $input->couponCode->value));
|
||||
}
|
||||
|
||||
$campaignCoupon = $this->campaignRepository->findCampaignCoupon($campaign->code, $coupon->code);
|
||||
if (! $campaignCoupon instanceof CampaignCoupon) {
|
||||
throw new \DomainException('Coupon must be associated to the associated campaign coupon.');
|
||||
}
|
||||
|
||||
$period = $coupon->getActivePeriod();
|
||||
|
||||
$this->checkPrintRulesFromCampaignCoupon($campaign, $campaignCoupon, $coupon, $input->crmCustomerHashcode);
|
||||
|
||||
$printableCoupon = PrintableCoupon::create(
|
||||
campaignCode: $campaign->code,
|
||||
couponCode: $coupon->code,
|
||||
couponName: $coupon->name,
|
||||
crmCustomerHashcode: $input->crmCustomerHashcode,
|
||||
distributableUntil: $period->end,
|
||||
);
|
||||
|
||||
$this->printableCouponRepository->save($printableCoupon);
|
||||
|
||||
return new Output(
|
||||
campaignCode: $printableCoupon->campaignCode,
|
||||
couponCode: $printableCoupon->couponCode,
|
||||
couponName: $printableCoupon->couponName,
|
||||
crmCustomerHashcode: $printableCoupon->crmCustomerHashcode,
|
||||
distributableUntil: $printableCoupon->distributableUntil,
|
||||
);
|
||||
}
|
||||
|
||||
public function checkPrintRulesFromCampaignCoupon(
|
||||
Campaign $campaign,
|
||||
CampaignCoupon $campaignCoupon,
|
||||
Coupon $coupon,
|
||||
CrmHashcode $crmCustomerHashcode,
|
||||
): void {
|
||||
if ($campaignCoupon->printRules instanceof PrintRules) {
|
||||
$countPrintedCoupon = $this->printableCouponRepository->countPrintedCouponForCustomer(
|
||||
$campaign->code,
|
||||
$coupon->code,
|
||||
$crmCustomerHashcode,
|
||||
);
|
||||
$campaignCoupon->printRules->hasPrintLimitNotReached($countPrintedCoupon);
|
||||
|
||||
$lastPrintedCoupon = $this->printableCouponRepository->findLastPrintedCouponForCustomer(
|
||||
$campaign->code,
|
||||
$coupon->code,
|
||||
$crmCustomerHashcode,
|
||||
);
|
||||
$diff = $lastPrintedCoupon->printedAt()->diff(new \DateTime());
|
||||
$campaignCoupon->printRules->hasReprintPeriodExpired($diff->days);
|
||||
}
|
||||
}
|
||||
}
|
||||
20
src/Application/UseCases/PrintableCoupon/Create/Input.php
Normal file
20
src/Application/UseCases/PrintableCoupon/Create/Input.php
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Application\UseCases\PrintableCoupon\Create;
|
||||
|
||||
use Domain\Models\ValueObjects\Campaign\CampaignCode;
|
||||
use Domain\Models\ValueObjects\Coupon\CouponCode;
|
||||
use Domain\Models\ValueObjects\CrmHashcode;
|
||||
use Shared\DDD\UseCases\Input as UseCaseInput;
|
||||
|
||||
final readonly class Input implements UseCaseInput
|
||||
{
|
||||
public function __construct(
|
||||
public CampaignCode $campaignCode,
|
||||
public CouponCode $couponCode,
|
||||
public CrmHashcode $crmCustomerHashcode,
|
||||
) {
|
||||
}
|
||||
}
|
||||
23
src/Application/UseCases/PrintableCoupon/Create/Output.php
Normal file
23
src/Application/UseCases/PrintableCoupon/Create/Output.php
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Application\UseCases\PrintableCoupon\Create;
|
||||
|
||||
use Domain\Models\ValueObjects\Campaign\CampaignCode;
|
||||
use Domain\Models\ValueObjects\Coupon\CouponCode;
|
||||
use Domain\Models\ValueObjects\Coupon\CouponName;
|
||||
use Domain\Models\ValueObjects\CrmHashcode;
|
||||
use Shared\DDD\UseCases\Output as UseCaseOutput;
|
||||
|
||||
final readonly class Output implements UseCaseOutput
|
||||
{
|
||||
public function __construct(
|
||||
public CampaignCode $campaignCode,
|
||||
public CouponCode $couponCode,
|
||||
public CouponName $couponName,
|
||||
public CrmHashcode $crmCustomerHashcode,
|
||||
public \DateTimeInterface $distributableUntil,
|
||||
) {
|
||||
}
|
||||
}
|
||||
|
|
@ -4,6 +4,7 @@ declare(strict_types=1);
|
|||
|
||||
namespace Application\UseCases\PrintableCoupon\List;
|
||||
|
||||
use Domain\Models\Entities\Coupon;
|
||||
use Domain\Models\Entities\PrintableCoupon;
|
||||
use Domain\Models\ValueObjects\Coupon\CouponPicture;
|
||||
use Domain\Ports\Repositories\CouponRepository;
|
||||
|
|
@ -46,8 +47,10 @@ final readonly class ListPrintableCoupons implements UseCase
|
|||
continue;
|
||||
}
|
||||
|
||||
$coupon = $this->couponRepository->findByCode($couponCode)
|
||||
?? throw new \LogicException(sprintf('Coupon "%s" referenced by a printable coupon does not exist.', $couponCode->value));
|
||||
$coupon = $this->couponRepository->findByCode($couponCode);
|
||||
if (!$coupon instanceof Coupon) {
|
||||
throw new \LogicException(sprintf('Coupon "%s" referenced by a printable coupon does not exist.', $couponCode->value));
|
||||
}
|
||||
|
||||
$picturesByCouponCode[$couponCode->value] = $coupon->picture;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -59,7 +59,6 @@ final readonly class Brand implements AggregateRoot, HasTimestampIdentifier
|
|||
logo: $logo,
|
||||
rcs: $rcs,
|
||||
contact: $contact,
|
||||
updatedAt: null,
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -65,7 +65,6 @@ final readonly class Campaign implements AggregateRoot, HasTimestampIdentifier
|
|||
coupons: $coupons,
|
||||
brandCode: $brandCode,
|
||||
actorId: $actorId,
|
||||
updatedAt: null,
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -71,7 +71,6 @@ final readonly class CampaignRequest implements AggregateRoot, HasTimestampIdent
|
|||
campaignType: $campaignType,
|
||||
requestedCoupon: $requestedCoupon,
|
||||
status: CampaignRequestStatus::CREATED,
|
||||
updatedAt: null,
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ use Domain\Models\ValueObjects\Coupon\CouponPicture;
|
|||
use Domain\Models\ValueObjects\Coupon\CouponProductArray;
|
||||
use Domain\Models\ValueObjects\Coupon\CouponValidityInformationArray;
|
||||
use Domain\Models\ValueObjects\MoneyAmount;
|
||||
use Domain\Models\ValueObjects\Period;
|
||||
use Domain\Models\ValueObjects\ProcessingCodeArray;
|
||||
use Shared\DDD\Models\AggregateRoot;
|
||||
use Shared\DDD\Models\HasTimestampIdentifier;
|
||||
|
|
@ -50,6 +51,7 @@ final readonly class Coupon implements AggregateRoot, HasTimestampIdentifier
|
|||
$this->validityInformations,
|
||||
$this->legalInformations,
|
||||
);
|
||||
$this->validateCalendarPeriodsWithinDiffusionPeriod();
|
||||
}
|
||||
|
||||
public function id(): CouponId
|
||||
|
|
@ -102,7 +104,6 @@ final readonly class Coupon implements AggregateRoot, HasTimestampIdentifier
|
|||
products: $products,
|
||||
movements: $movements,
|
||||
availabilityCalendar: $availabilityCalendar,
|
||||
updatedAt: null,
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -182,4 +183,36 @@ final readonly class Coupon implements AggregateRoot, HasTimestampIdentifier
|
|||
updatedAt: DatesHelper::now(),
|
||||
);
|
||||
}
|
||||
|
||||
public function getActivePeriod(): Period
|
||||
{
|
||||
$currentDate = new \DateTime();
|
||||
$diffusionPeriod = $this->diffusion->period;
|
||||
$period = $this->availabilityCalendar?->isActiveAt($currentDate)
|
||||
? $this->availabilityCalendar->getCurrentPeriod($currentDate)
|
||||
?? $diffusionPeriod
|
||||
: $diffusionPeriod;
|
||||
|
||||
if (! $period->hasStarted()) {
|
||||
throw new \DomainException('The printing period has not yet begun.');
|
||||
}
|
||||
|
||||
if (! $period->hasEnded()) {
|
||||
throw new \DomainException('The printing period has expired.');
|
||||
}
|
||||
|
||||
return $period;
|
||||
}
|
||||
|
||||
public function validateCalendarPeriodsWithinDiffusionPeriod(): void
|
||||
{
|
||||
if ($this->availabilityCalendar instanceof CouponAvailabilityCalendar) {
|
||||
$diffusionPeriod = $this->diffusion->period;
|
||||
foreach ($this->availabilityCalendar->periods as $calendarPeriod) {
|
||||
if (! $diffusionPeriod->inRange($calendarPeriod->start) || ! $diffusionPeriod->inRange($calendarPeriod->end)) {
|
||||
throw new \DomainException('Calendar period must be in diffusion period.');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -58,7 +58,6 @@ final readonly class PrintableCoupon implements AggregateRoot, HasTimestampIdent
|
|||
couponName: $couponName,
|
||||
crmCustomerHashcode: $crmCustomerHashcode,
|
||||
distributableUntil: $distributableUntil,
|
||||
updatedAt: null,
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -7,9 +7,9 @@ namespace Domain\Models\ValueObjects\Campaign;
|
|||
final readonly class CampaignCode
|
||||
{
|
||||
public function __construct(
|
||||
public string $code,
|
||||
public string $value,
|
||||
) {
|
||||
if (mb_trim($this->code) === '') {
|
||||
if (mb_trim($this->value) === '') {
|
||||
throw new \DomainException('Campaign code cannot be empty.');
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,8 +10,10 @@ use DateTime;
|
|||
|
||||
final readonly class CouponAvailabilityCalendar implements Equatable
|
||||
{
|
||||
/**
|
||||
* @param array<Period> $periods
|
||||
*/
|
||||
public function __construct(
|
||||
/** @var Period[] */
|
||||
public array $periods,
|
||||
) {
|
||||
if ($this->periods === []) {
|
||||
|
|
@ -27,7 +29,7 @@ final readonly class CouponAvailabilityCalendar implements Equatable
|
|||
|
||||
public function isActiveAt(DateTime $in): bool
|
||||
{
|
||||
return array_any($this->periods, fn ($period): bool => $in >= $period->start && $in <= $period->end);
|
||||
return array_any($this->periods, fn ($period): bool => $period->inRange($in));
|
||||
}
|
||||
|
||||
public function beginsAt(): DateTime
|
||||
|
|
@ -40,6 +42,11 @@ final readonly class CouponAvailabilityCalendar implements Equatable
|
|||
return max(array_map(fn (Period $period): DateTime => $period->end, $this->periods));
|
||||
}
|
||||
|
||||
public function getCurrentPeriod(DateTime $in): ?Period
|
||||
{
|
||||
return array_first(array_filter($this->periods, fn ($period): bool => $period->inRange($in)));
|
||||
}
|
||||
|
||||
#[\Override]
|
||||
public function equals(mixed $other): bool
|
||||
{
|
||||
|
|
|
|||
|
|
@ -4,16 +4,31 @@ declare(strict_types=1);
|
|||
|
||||
namespace Domain\Models\ValueObjects;
|
||||
|
||||
use DateTime;
|
||||
use Shared\Helpers\DatesHelper;
|
||||
|
||||
final readonly class Period
|
||||
{
|
||||
public function __construct(
|
||||
public DateTime $start,
|
||||
public DateTime $end,
|
||||
public \DateTime $start,
|
||||
public \DateTime $end,
|
||||
) {
|
||||
if ($this->end < $this->start) {
|
||||
throw new \DomainException('Period end date cannot be before its start date.');
|
||||
}
|
||||
}
|
||||
|
||||
public function hasStarted(): bool
|
||||
{
|
||||
return $this->start <= DatesHelper::now();
|
||||
}
|
||||
|
||||
public function hasEnded(): bool
|
||||
{
|
||||
return $this->end >= DatesHelper::now();
|
||||
}
|
||||
|
||||
public function inRange(\DateTime $date): bool
|
||||
{
|
||||
return $date >= $this->start && $date <= $this->end;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,15 +11,33 @@ final readonly class PrintRules
|
|||
public ?int $cooldownDays = null,
|
||||
) {
|
||||
if (null === $this->maxPerCustomer && null === $this->cooldownDays) {
|
||||
throw new \InvalidArgumentException('PrintRules require at least a max per customer or a cooldown days.');
|
||||
throw new \DomainException('PrintRules require at least a max per customer or a cooldown days.');
|
||||
}
|
||||
|
||||
if (null !== $this->maxPerCustomer && $this->maxPerCustomer <= 0) {
|
||||
throw new \InvalidArgumentException('Max per customer must be greater than 0.');
|
||||
throw new \DomainException('Max per customer must be greater than 0.');
|
||||
}
|
||||
|
||||
if (null !== $this->cooldownDays && $this->cooldownDays <= 0) {
|
||||
throw new \InvalidArgumentException('Cooldown days must be greater than 0.');
|
||||
if (null !== $this->cooldownDays && $this->cooldownDays < 30) {
|
||||
throw new \DomainException('Cooldown days must be greater than 30.');
|
||||
}
|
||||
|
||||
if ($this->maxPerCustomer && $this->cooldownDays) {
|
||||
throw new \DomainException('No more than one print rule.');
|
||||
}
|
||||
}
|
||||
|
||||
public function hasPrintLimitNotReached(int $countPrintedCoupon): void
|
||||
{
|
||||
if ($this->maxPerCustomer && $this->maxPerCustomer < $countPrintedCoupon) {
|
||||
throw new \DomainException('Maximum number of prints reached.');
|
||||
}
|
||||
}
|
||||
|
||||
public function hasReprintPeriodExpired(int $diffDays): void
|
||||
{
|
||||
if ($this->cooldownDays && $diffDays < $this->cooldownDays) {
|
||||
throw new \DomainException('Reprint period has not expired.');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,6 +5,8 @@ declare(strict_types=1);
|
|||
namespace Domain\Ports\Repositories;
|
||||
|
||||
use Domain\Models\Entities\Campaign;
|
||||
use Domain\Models\ValueObjects\Campaign\CampaignCode;
|
||||
use Domain\Models\ValueObjects\Campaign\CampaignCoupon;
|
||||
use Domain\Models\ValueObjects\Coupon\CouponCode;
|
||||
use Shared\DDD\Ports\Repository;
|
||||
|
||||
|
|
@ -19,4 +21,8 @@ interface CampaignRepository extends Repository
|
|||
* @return array<Campaign>
|
||||
*/
|
||||
public function findByCouponCode(CouponCode $couponCode): array;
|
||||
|
||||
public function findByCode(CampaignCode $code): ?Campaign;
|
||||
|
||||
public function findCampaignCoupon(CampaignCode $campaignCode, CouponCode $couponCode): ?CampaignCoupon;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,8 +6,10 @@ namespace Domain\Ports\Repositories;
|
|||
|
||||
use Domain\Models\Entities\PrintableCoupon;
|
||||
use Domain\Models\ValueObjects\Campaign\CampaignCode;
|
||||
use Domain\Models\ValueObjects\Coupon\CouponCode;
|
||||
use Domain\Models\ValueObjects\CrmHashcode;
|
||||
use Domain\Models\ValueObjects\PrintableCoupon\PrintableCouponSortCriteria;
|
||||
use Domain\Models\ValueObjects\PrintableCoupon\PrintedCoupon;
|
||||
use Shared\DDD\Ports\Repository;
|
||||
use Shared\ValueObjects\Pagination\Paginated;
|
||||
use Shared\ValueObjects\Pagination\Pagination;
|
||||
|
|
@ -27,5 +29,17 @@ interface PrintableCouponRepository extends Repository
|
|||
?PrintableCouponSortCriteria $sortCriteria = null,
|
||||
): Paginated;
|
||||
|
||||
public function countPrintedCouponForCustomer(
|
||||
CampaignCode $campaignCode,
|
||||
CouponCode $couponCode,
|
||||
CrmHashcode $crmCustomerHashcode,
|
||||
): int;
|
||||
|
||||
public function findLastPrintedCouponForCustomer(
|
||||
CampaignCode $campaignCode,
|
||||
CouponCode $couponCode,
|
||||
CrmHashcode $crmCustomerHashcode,
|
||||
): PrintedCoupon;
|
||||
|
||||
public function save(PrintableCoupon $printableCoupon): void;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ use Application\UseCases\Coupon\Find\FindCoupon;
|
|||
use Application\UseCases\Coupon\Find\Input;
|
||||
use Application\UseCases\Coupon\Find\Output\CouponFound;
|
||||
use Application\UseCases\Coupon\Find\Output\CouponNotFound;
|
||||
use Application\UseCases\Coupon\Find\Output\Output;
|
||||
use DateTime;
|
||||
use Domain\Models\Entities\Brand;
|
||||
use Domain\Models\Entities\Campaign;
|
||||
|
|
@ -180,7 +181,7 @@ describe('find coupon use case', function (): void {
|
|||
$useCase = new FindCoupon($couponRepository, $brandRepository, $campaignRepository);
|
||||
|
||||
// WHEN / THEN
|
||||
expect(fn () => $useCase->execute(new Input(code: $coupon->code)))
|
||||
expect(fn (): Output => $useCase->execute(new Input(code: $coupon->code)))
|
||||
->toThrow(\DomainException::class);
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,429 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Tests\Unit\Application\UseCases\PrintableCoupon\Create;
|
||||
|
||||
use Application\UseCases\PrintableCoupon\Create\Input;
|
||||
use Application\UseCases\PrintableCoupon\Create\Output;
|
||||
use Application\UseCases\PrintableCoupon\Create\CreatePrintableCoupon;
|
||||
use DateTime;
|
||||
use Domain\Models\Entities\Campaign;
|
||||
use Domain\Models\Entities\Coupon;
|
||||
use Domain\Models\Entities\PrintableCoupon;
|
||||
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\CampaignName;
|
||||
use Domain\Models\ValueObjects\Coupon\CouponAvailabilityCalendar;
|
||||
use Domain\Models\ValueObjects\Coupon\CouponCode;
|
||||
use Domain\Models\ValueObjects\Coupon\CouponDiffusion;
|
||||
use Domain\Models\ValueObjects\Coupon\CouponLegalInformation;
|
||||
use Domain\Models\ValueObjects\Coupon\CouponLegalInformationArray;
|
||||
use Domain\Models\ValueObjects\Coupon\CouponMovement;
|
||||
use Domain\Models\ValueObjects\Coupon\CouponMovementArray;
|
||||
use Domain\Models\ValueObjects\Coupon\CouponName;
|
||||
use Domain\Models\ValueObjects\Coupon\CouponPicture;
|
||||
use Domain\Models\ValueObjects\Coupon\CouponProductArray;
|
||||
use Domain\Models\ValueObjects\Coupon\CouponValidityInformation;
|
||||
use Domain\Models\ValueObjects\Coupon\CouponValidityInformationArray;
|
||||
use Domain\Models\ValueObjects\CrmHashcode;
|
||||
use Domain\Models\ValueObjects\IncoCode;
|
||||
use Domain\Models\ValueObjects\MoneyAmount;
|
||||
use Domain\Models\ValueObjects\Period;
|
||||
use Domain\Models\ValueObjects\PicturePath;
|
||||
use Domain\Models\ValueObjects\PrintableCoupon\MarketingDirectCode;
|
||||
use Domain\Models\ValueObjects\PrintableCoupon\PrintableCouponCode;
|
||||
use Domain\Models\ValueObjects\PrintableCoupon\PrintedCoupon;
|
||||
use Domain\Models\ValueObjects\PrintableCoupon\PrintedCouponId;
|
||||
use Domain\Models\ValueObjects\PrintRules;
|
||||
use Domain\Models\ValueObjects\ProcessingCode;
|
||||
use Domain\Models\ValueObjects\ProcessingCodeArray;
|
||||
use Domain\Ports\Repositories\CampaignRepository;
|
||||
use Domain\Ports\Repositories\CouponRepository;
|
||||
use Domain\Ports\Repositories\PrintableCouponRepository;
|
||||
use Ramsey\Uuid\Uuid;
|
||||
use Shared\Enums\Country;
|
||||
use Shared\Enums\Currency;
|
||||
use Shared\Helpers\DatesHelper;
|
||||
use Shared\ValueObjects\Money;
|
||||
|
||||
covers(CreatePrintableCoupon::class, Input::class, Output::class);
|
||||
|
||||
describe('create coupon use case', function (): void {
|
||||
$crmCustomerHashcode = new CrmHashcode(Uuid::uuid4());
|
||||
$brandCode = new BrandCode('AAA01');
|
||||
$campaignCode = new CampaignCode('CMP01');
|
||||
$couponCode = new CouponCode('COU01');
|
||||
$couponName = new CouponName('Coupon name');
|
||||
$couponDiffusionStart = new DateTime()->modify('-1 month');
|
||||
$couponDiffusionEnd = new DateTime()->modify('+1 month');
|
||||
$makeCoupon = fn (array $overrides = []): Coupon => Coupon::create(
|
||||
code: $couponCode,
|
||||
name: $couponName,
|
||||
amount: new MoneyAmount(new Money(Currency::EUR, 100)),
|
||||
picture: new CouponPicture(
|
||||
new PicturePath('files/product.jpg'),
|
||||
new PicturePath('files/thumbnail.jpg'),
|
||||
new PicturePath('files/mobile_thumbnail.jpg'),
|
||||
),
|
||||
diffusion: new CouponDiffusion(
|
||||
new Period(
|
||||
$overrides['diffusionStart'] ?? $couponDiffusionStart,
|
||||
$overrides['diffusionEnd'] ?? $couponDiffusionEnd,
|
||||
),
|
||||
),
|
||||
validityInformations: new CouponValidityInformationArray([
|
||||
new CouponValidityInformation(
|
||||
'Lorem ipsum dolor sit amet consectetur adipiscing elit.',
|
||||
Country::FRANCE,
|
||||
),
|
||||
]),
|
||||
legalInformations: new CouponLegalInformationArray([
|
||||
new CouponLegalInformation(
|
||||
'Lorem ipsum dolor sit amet consectetur adipiscing elit.',
|
||||
Country::FRANCE,
|
||||
),
|
||||
]),
|
||||
processingCode: new ProcessingCodeArray([
|
||||
new ProcessingCode('5425003944130', Country::FRANCE),
|
||||
]),
|
||||
brandCode: $brandCode,
|
||||
createdBy: ActorId::generate(),
|
||||
products: new CouponProductArray([
|
||||
new IncoCode(35784) ,
|
||||
new IncoCode(15522),
|
||||
]),
|
||||
movements: new CouponMovementArray([
|
||||
new CouponMovement(1000)
|
||||
]),
|
||||
availabilityCalendar: $overrides['availabilityCalendar'] ?? null,
|
||||
);
|
||||
$printRules = fn (?int $maxPerCustomer = null, ?int $cooldownDays = null): ?PrintRules => ($maxPerCustomer || $cooldownDays) ? new PrintRules(
|
||||
maxPerCustomer: $maxPerCustomer,
|
||||
cooldownDays: $cooldownDays,
|
||||
) : null;
|
||||
$campaignCoupon = fn (?int $maxPerCustomer = null, ?int $cooldownDays = null): CampaignCoupon => new CampaignCoupon(
|
||||
$couponCode,
|
||||
$printRules($maxPerCustomer, $cooldownDays),
|
||||
);
|
||||
$makeCampaign = fn (?int $maxPerCustomer = null, ?int $cooldownDays = null, bool $published = true): Campaign => Campaign::create(
|
||||
code: $campaignCode,
|
||||
name: new CampaignName('Campaign name'),
|
||||
publication: $published,
|
||||
printAllAtOnce: true,
|
||||
coupons: new CampaignCouponArray([
|
||||
$campaignCoupon($maxPerCustomer, $cooldownDays),
|
||||
]),
|
||||
brandCode: $brandCode,
|
||||
actorId: ActorId::generate(),
|
||||
);
|
||||
$printedCoupon = new PrintedCoupon(
|
||||
id: PrintedCouponId::generate(),
|
||||
marketingCode: new MarketingDirectCode('0000000000001'),
|
||||
printableCode: PrintableCouponCode::generate(),
|
||||
couponCode: $couponCode,
|
||||
campaignCode: $campaignCode,
|
||||
customer: $crmCustomerHashcode,
|
||||
printedAt: DatesHelper::now(),
|
||||
);
|
||||
$makeInput = fn (): Input => new Input(
|
||||
campaignCode: $campaignCode,
|
||||
couponCode: $couponCode,
|
||||
crmCustomerHashcode: $crmCustomerHashcode,
|
||||
);
|
||||
|
||||
it('creates a printable coupon', function () use ($makeInput, $crmCustomerHashcode, $makeCampaign, $makeCoupon, $campaignCoupon): void {
|
||||
// GIVEN
|
||||
$input = $makeInput();
|
||||
$campaign = $makeCampaign();
|
||||
$coupon = $makeCoupon();
|
||||
|
||||
$campaignRepository = \Mockery::mock(CampaignRepository::class);
|
||||
$campaignRepository->shouldReceive('findByCode')->once()->with($campaign->code)->andReturn($campaign);
|
||||
$campaignRepository->shouldReceive('findCampaignCoupon')->once()->with($campaign->code, $coupon->code)
|
||||
->andReturn($campaignCoupon());
|
||||
|
||||
$couponRepository = \Mockery::mock(CouponRepository::class);
|
||||
$couponRepository->shouldReceive('findByCode')->once()->with($coupon->code)->andReturn($coupon);
|
||||
|
||||
$printableCouponRepository = \Mockery::mock(PrintableCouponRepository::class);
|
||||
$printableCouponRepository->shouldReceive('save')->once()->with(\Mockery::type(PrintableCoupon::class));
|
||||
|
||||
$useCase = new CreatePrintableCoupon($printableCouponRepository, $couponRepository, $campaignRepository);
|
||||
|
||||
// WHEN
|
||||
$result = $useCase->execute($input);
|
||||
|
||||
// THEN
|
||||
expect($result)->toBeInstanceOf(Output::class)
|
||||
->and($result->campaignCode)->toEqual($campaign->code)
|
||||
->and($result->couponCode)->toEqual($coupon->code)
|
||||
->and($result->crmCustomerHashcode)->toEqual($crmCustomerHashcode)
|
||||
->and($result->distributableUntil)->toEqual($coupon->diffusion->period->end);
|
||||
});
|
||||
|
||||
it('rejects a printable coupon when campaign not found', function () use ($makeInput, $makeCampaign): void {
|
||||
// GIVEN
|
||||
$input = $makeInput();
|
||||
$campaign = $makeCampaign();
|
||||
|
||||
$campaignRepository = \Mockery::mock(CampaignRepository::class);
|
||||
$campaignRepository->shouldReceive('findByCode')->once()->with($campaign->code)->andReturn(null);
|
||||
|
||||
$couponRepository = \Mockery::mock(CouponRepository::class);
|
||||
|
||||
$printableCouponRepository = \Mockery::mock(PrintableCouponRepository::class);
|
||||
|
||||
$useCase = new CreatePrintableCoupon($printableCouponRepository, $couponRepository, $campaignRepository);
|
||||
|
||||
// WHEN
|
||||
$action = fn (): Output => $useCase->execute($input);
|
||||
|
||||
// THEN
|
||||
expect($action)->toThrow(\DomainException::class, sprintf('Campaign from code "%s" not found.', $input->campaignCode->value));
|
||||
});
|
||||
|
||||
it('rejects a printable coupon when campaign is not published', function () use ($makeInput, $makeCampaign): void {
|
||||
// GIVEN
|
||||
$input = $makeInput();
|
||||
$campaign = $makeCampaign(published: false);
|
||||
|
||||
$campaignRepository = \Mockery::mock(CampaignRepository::class);
|
||||
$campaignRepository->shouldReceive('findByCode')->once()->with($campaign->code)->andReturn($campaign);
|
||||
|
||||
$couponRepository = \Mockery::mock(CouponRepository::class);
|
||||
|
||||
$printableCouponRepository = \Mockery::mock(PrintableCouponRepository::class);
|
||||
|
||||
$useCase = new CreatePrintableCoupon($printableCouponRepository, $couponRepository, $campaignRepository);
|
||||
|
||||
// WHEN
|
||||
$action = fn (): Output => $useCase->execute($input);
|
||||
|
||||
// THEN
|
||||
expect($action)->toThrow(\DomainException::class, 'Campaign must be published.');
|
||||
});
|
||||
|
||||
it('rejects a printable coupon when coupon is not found', function () use ($makeInput, $makeCampaign, $makeCoupon): void {
|
||||
// GIVEN
|
||||
$input = $makeInput();
|
||||
$campaign = $makeCampaign();
|
||||
$coupon = $makeCoupon();
|
||||
|
||||
$campaignRepository = \Mockery::mock(CampaignRepository::class);
|
||||
$campaignRepository->shouldReceive('findByCode')->once()->with($campaign->code)->andReturn($campaign);
|
||||
|
||||
$couponRepository = \Mockery::mock(CouponRepository::class);
|
||||
$couponRepository->shouldReceive('findByCode')->once()->with($coupon->code)->andReturn(null);
|
||||
|
||||
$printableCouponRepository = \Mockery::mock(PrintableCouponRepository::class);
|
||||
|
||||
$useCase = new CreatePrintableCoupon($printableCouponRepository, $couponRepository, $campaignRepository);
|
||||
|
||||
// WHEN
|
||||
$action = fn (): Output => $useCase->execute($input);
|
||||
|
||||
// THEN
|
||||
expect($action)->toThrow(\DomainException::class, sprintf('Coupon code "%s" not found.', $input->couponCode->value));
|
||||
});
|
||||
|
||||
it('rejects a printable coupon when campaign coupon is not found', function () use ($makeInput, $makeCampaign, $makeCoupon): void {
|
||||
// GIVEN
|
||||
$input = $makeInput();
|
||||
$campaign = $makeCampaign();
|
||||
$coupon = $makeCoupon();
|
||||
|
||||
$campaignRepository = \Mockery::mock(CampaignRepository::class);
|
||||
$campaignRepository->shouldReceive('findByCode')->once()->with($campaign->code)->andReturn($campaign);
|
||||
$campaignRepository->shouldReceive('findCampaignCoupon')->once()->with($campaign->code, $coupon->code)
|
||||
->andReturn(null);
|
||||
|
||||
$couponRepository = \Mockery::mock(CouponRepository::class);
|
||||
$couponRepository->shouldReceive('findByCode')->once()->with($coupon->code)->andReturn($coupon);
|
||||
|
||||
$printableCouponRepository = \Mockery::mock(PrintableCouponRepository::class);
|
||||
|
||||
$useCase = new CreatePrintableCoupon($printableCouponRepository, $couponRepository, $campaignRepository);
|
||||
|
||||
// WHEN
|
||||
$action = fn (): Output => $useCase->execute($input);
|
||||
|
||||
// THEN
|
||||
expect($action)->toThrow(\DomainException::class, 'Coupon must be associated to the associated campaign coupon.');
|
||||
});
|
||||
|
||||
it('rejects a printable coupon when outside of diffusion start', function () use ($makeInput, $makeCampaign, $makeCoupon, $campaignCoupon): void {
|
||||
// GIVEN
|
||||
$input = $makeInput();
|
||||
$campaign = $makeCampaign();
|
||||
$coupon = $makeCoupon(['diffusionStart' => new DateTime()->modify('+1 day')]);
|
||||
|
||||
$campaignRepository = \Mockery::mock(CampaignRepository::class);
|
||||
$campaignRepository->shouldReceive('findByCode')->once()->with($campaign->code)->andReturn($campaign);
|
||||
$campaignRepository->shouldReceive('findCampaignCoupon')->once()->with($campaign->code, $coupon->code)
|
||||
->andReturn($campaignCoupon());
|
||||
|
||||
$couponRepository = \Mockery::mock(CouponRepository::class);
|
||||
$couponRepository->shouldReceive('findByCode')->once()->with($coupon->code)->andReturn($coupon);
|
||||
|
||||
$printableCouponRepository = \Mockery::mock(PrintableCouponRepository::class);
|
||||
|
||||
$useCase = new CreatePrintableCoupon($printableCouponRepository, $couponRepository, $campaignRepository);
|
||||
|
||||
// WHEN
|
||||
$action = fn (): Output => $useCase->execute($input);
|
||||
|
||||
// THEN
|
||||
expect($action)->toThrow(\DomainException::class, 'The printing period has not yet begun.');
|
||||
});
|
||||
|
||||
it('rejects a printable coupon when outside of diffusion end', function () use ($makeInput, $makeCampaign, $makeCoupon, $campaignCoupon): void {
|
||||
// GIVEN
|
||||
$input = $makeInput();
|
||||
$campaign = $makeCampaign();
|
||||
$coupon = $makeCoupon(['diffusionEnd' => new DateTime()->modify('-1 day')]);
|
||||
|
||||
$campaignRepository = \Mockery::mock(CampaignRepository::class);
|
||||
$campaignRepository->shouldReceive('findByCode')->once()->with($campaign->code)->andReturn($campaign);
|
||||
$campaignRepository->shouldReceive('findCampaignCoupon')->once()->with($campaign->code, $coupon->code)
|
||||
->andReturn($campaignCoupon());
|
||||
|
||||
$couponRepository = \Mockery::mock(CouponRepository::class);
|
||||
$couponRepository->shouldReceive('findByCode')->once()->with($coupon->code)->andReturn($coupon);
|
||||
|
||||
$printableCouponRepository = \Mockery::mock(PrintableCouponRepository::class);
|
||||
|
||||
$useCase = new CreatePrintableCoupon($printableCouponRepository, $couponRepository, $campaignRepository);
|
||||
|
||||
// WHEN
|
||||
$action = fn (): Output => $useCase->execute($input);
|
||||
|
||||
// THEN
|
||||
expect($action)->toThrow(\DomainException::class, 'The printing period has expired.');
|
||||
});
|
||||
|
||||
it('creates a printable coupon when calendar period is inside diffusion period', function () use (
|
||||
$makeInput,
|
||||
$crmCustomerHashcode,
|
||||
$makeCampaign,
|
||||
$makeCoupon,
|
||||
$campaignCoupon,
|
||||
): void {
|
||||
// GIVEN
|
||||
$calendarStart = new DateTime()->modify('-1 day');
|
||||
$calendarEnd = new DateTime()->modify('+1 day');
|
||||
$input = $makeInput();
|
||||
$campaign = $makeCampaign();
|
||||
$coupon = $makeCoupon([
|
||||
'availabilityCalendar' => new CouponAvailabilityCalendar([
|
||||
new Period(
|
||||
start: $calendarStart,
|
||||
end: $calendarEnd,
|
||||
),
|
||||
]),
|
||||
]);
|
||||
|
||||
$campaignRepository = \Mockery::mock(CampaignRepository::class);
|
||||
$campaignRepository->shouldReceive('findByCode')->once()->with($campaign->code)->andReturn($campaign);
|
||||
$campaignRepository->shouldReceive('findCampaignCoupon')->once()->with($campaign->code, $coupon->code)
|
||||
->andReturn($campaignCoupon());
|
||||
|
||||
$couponRepository = \Mockery::mock(CouponRepository::class);
|
||||
$couponRepository->shouldReceive('findByCode')->once()->with($coupon->code)->andReturn($coupon);
|
||||
|
||||
$printableCouponRepository = \Mockery::mock(PrintableCouponRepository::class);
|
||||
$printableCouponRepository->shouldReceive('save')->once()->with(\Mockery::type(PrintableCoupon::class));
|
||||
|
||||
$useCase = new CreatePrintableCoupon($printableCouponRepository, $couponRepository, $campaignRepository);
|
||||
|
||||
// WHEN
|
||||
$result = $useCase->execute($input);
|
||||
|
||||
// THEN
|
||||
expect($result)->toBeInstanceOf(Output::class)
|
||||
->and($result->campaignCode)->toEqual($campaign->code)
|
||||
->and($result->crmCustomerHashcode)->toEqual($crmCustomerHashcode)
|
||||
->and($result->distributableUntil)->toEqual($calendarEnd);
|
||||
});
|
||||
|
||||
it('rejects a printable coupon when maximum number of prints reached', function () use (
|
||||
$makeInput,
|
||||
$crmCustomerHashcode,
|
||||
$makeCampaign,
|
||||
$makeCoupon,
|
||||
$campaignCoupon,
|
||||
): void {
|
||||
// GIVEN
|
||||
$input = $makeInput();
|
||||
$campaign = $makeCampaign(maxPerCustomer: 1);
|
||||
$coupon = $makeCoupon();
|
||||
|
||||
$campaignRepository = \Mockery::mock(CampaignRepository::class);
|
||||
$campaignRepository->shouldReceive('findByCode')->once()->with($campaign->code)->andReturn($campaign);
|
||||
$campaignRepository->shouldReceive('findCampaignCoupon')->once()->with($campaign->code, $coupon->code)
|
||||
->andReturn($campaignCoupon(maxPerCustomer: 1));
|
||||
|
||||
$couponRepository = \Mockery::mock(CouponRepository::class);
|
||||
$couponRepository->shouldReceive('findByCode')->once()->with($coupon->code)->andReturn($coupon);
|
||||
|
||||
$printableCouponRepository = \Mockery::mock(PrintableCouponRepository::class);
|
||||
$printableCouponRepository->shouldReceive('countPrintedCouponForCustomer')->once()->with(
|
||||
$campaign->code,
|
||||
$coupon->code,
|
||||
$crmCustomerHashcode,
|
||||
)->andReturn(5);
|
||||
|
||||
$useCase = new CreatePrintableCoupon($printableCouponRepository, $couponRepository, $campaignRepository);
|
||||
|
||||
// WHEN
|
||||
$action = fn (): Output => $useCase->execute($input);
|
||||
|
||||
// THEN
|
||||
expect($action)->toThrow(\DomainException::class, 'Maximum number of prints reached.');
|
||||
});
|
||||
|
||||
it('rejects a printable coupon when reprint period has expired', function () use (
|
||||
$makeInput,
|
||||
$crmCustomerHashcode,
|
||||
$makeCampaign,
|
||||
$makeCoupon,
|
||||
$campaignCoupon,
|
||||
$printedCoupon,
|
||||
): void {
|
||||
// GIVEN
|
||||
$input = $makeInput();
|
||||
$campaign = $makeCampaign(cooldownDays: 30);
|
||||
$coupon = $makeCoupon();
|
||||
|
||||
$campaignRepository = \Mockery::mock(CampaignRepository::class);
|
||||
$campaignRepository->shouldReceive('findByCode')->once()->with($campaign->code)->andReturn($campaign);
|
||||
$campaignRepository->shouldReceive('findCampaignCoupon')->once()->with($campaign->code, $coupon->code)
|
||||
->andReturn($campaignCoupon(cooldownDays: 30));
|
||||
|
||||
$couponRepository = \Mockery::mock(CouponRepository::class);
|
||||
$couponRepository->shouldReceive('findByCode')->once()->with($coupon->code)->andReturn($coupon);
|
||||
|
||||
$printableCouponRepository = \Mockery::mock(PrintableCouponRepository::class);
|
||||
$printableCouponRepository->shouldReceive('countPrintedCouponForCustomer')->once()->with(
|
||||
$campaign->code,
|
||||
$coupon->code,
|
||||
$crmCustomerHashcode,
|
||||
)->andReturn(5);
|
||||
$printableCouponRepository->shouldReceive('findLastPrintedCouponForCustomer')->once()->with(
|
||||
$campaign->code,
|
||||
$coupon->code,
|
||||
$crmCustomerHashcode,
|
||||
)->andReturn($printedCoupon);
|
||||
|
||||
$useCase = new CreatePrintableCoupon($printableCouponRepository, $couponRepository, $campaignRepository);
|
||||
|
||||
// WHEN
|
||||
$action = fn (): Output => $useCase->execute($input);
|
||||
|
||||
// THEN
|
||||
expect($action)->toThrow(\DomainException::class, 'Reprint period has not expired.');
|
||||
});
|
||||
});
|
||||
|
|
@ -45,7 +45,7 @@ describe('coupon', function (): void {
|
|||
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')));
|
||||
$diffusion = new CouponDiffusion(new Period(new DateTime('2026-01-01'), new DateTime('2026-12-31')));
|
||||
$validityInformations = new CouponValidityInformationArray([
|
||||
new CouponValidityInformation(
|
||||
'Lorem ipsum dolor sit amet consectetur adipiscing elit.',
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ describe('campaign code', function (): void {
|
|||
$name = new CampaignCode($code);
|
||||
|
||||
// THEN
|
||||
expect($name->code)->toBe($code);
|
||||
expect($name->value)->toBe($code);
|
||||
});
|
||||
|
||||
it('rejects invalid campaign code', function () use ($emptyCode): void {
|
||||
|
|
|
|||
|
|
@ -16,17 +16,16 @@ describe('print rules', function (): void {
|
|||
$minCooldownDays = 1;
|
||||
$zeroCooldownDays = 0;
|
||||
|
||||
it('creates print rules with both fields set', function () use ($maxPerCustomer, $cooldownDays): void {
|
||||
it('rejects print rules with both fields set', function () use ($maxPerCustomer, $cooldownDays): void {
|
||||
// GIVEN / WHEN
|
||||
$printRules = new PrintRules(
|
||||
$printRules = fn (): PrintRules => new PrintRules(
|
||||
maxPerCustomer: $maxPerCustomer,
|
||||
cooldownDays: $cooldownDays
|
||||
);
|
||||
|
||||
// THEN
|
||||
expect($printRules)->toBeInstanceOf(PrintRules::class)
|
||||
->and($printRules->maxPerCustomer)->toBe($maxPerCustomer)
|
||||
->and($printRules->cooldownDays)->toBe($cooldownDays);
|
||||
expect($printRules)
|
||||
->toThrow(\DomainException::class, 'No more than one print rule.');
|
||||
});
|
||||
|
||||
it('creates print rules with only maxPerCustomer set', function () use ($maxPerCustomer): void {
|
||||
|
|
@ -54,32 +53,46 @@ describe('print rules', function (): void {
|
|||
it('rejects print rules without any field set', function (): void {
|
||||
// WHEN / THEN
|
||||
expect(fn (): PrintRules => new PrintRules())
|
||||
->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 () use ($minMaxPerCustomer, $minCooldownDays): void {
|
||||
// GIVEN / WHEN
|
||||
$printRules = new PrintRules(
|
||||
maxPerCustomer: $minMaxPerCustomer,
|
||||
cooldownDays: $minCooldownDays
|
||||
);
|
||||
|
||||
// THEN
|
||||
expect($printRules->maxPerCustomer)->toBe($minMaxPerCustomer)
|
||||
->and($printRules->cooldownDays)->toBe($minCooldownDays);
|
||||
->toThrow(\DomainException::class, 'PrintRules require at least a max per customer or a cooldown days.');
|
||||
});
|
||||
|
||||
it('rejects a maxPerCustomer equal to zero', function () use ($zeroMaxPerCustomer): void {
|
||||
// GIVEN / WHEN / THEN
|
||||
expect(fn (): PrintRules => new PrintRules(
|
||||
maxPerCustomer: $zeroMaxPerCustomer
|
||||
))->toThrow(\InvalidArgumentException::class, 'Max per customer must be greater than 0.');
|
||||
))->toThrow(\DomainException::class, 'Max per customer must be greater than 0.');
|
||||
});
|
||||
|
||||
it('rejects a cooldownDays equal to zero', function () use ($zeroCooldownDays): void {
|
||||
// GIVEN / WHEN / THEN
|
||||
expect(fn (): PrintRules => new PrintRules(
|
||||
cooldownDays: $zeroCooldownDays
|
||||
))->toThrow(\InvalidArgumentException::class, 'Cooldown days must be greater than 0.');
|
||||
))->toThrow(\DomainException::class, 'Cooldown days must be greater than 30.');
|
||||
});
|
||||
|
||||
it('rejects print rule when max per customer limit has reached', function () use ($maxPerCustomer, $minMaxPerCustomer): void {
|
||||
// GIVEN
|
||||
$printRules = new PrintRules(
|
||||
maxPerCustomer: $minMaxPerCustomer
|
||||
);
|
||||
|
||||
// WHEN
|
||||
$action = fn () => $printRules->hasPrintLimitNotReached($maxPerCustomer);
|
||||
|
||||
// THEN
|
||||
expect($action)->toThrow(\DomainException::class, 'Maximum number of prints reached.');
|
||||
});
|
||||
|
||||
it('rejects print rule when cooldown days period has expired', function () use ($cooldownDays, $minCooldownDays): void {
|
||||
// GIVEN
|
||||
$printRules = new PrintRules(
|
||||
cooldownDays: $cooldownDays
|
||||
);
|
||||
|
||||
// WHEN
|
||||
$action = fn () => $printRules->hasReprintPeriodExpired($minCooldownDays);
|
||||
|
||||
// THEN
|
||||
expect($action)->toThrow(\DomainException::class, 'Reprint period has not expired.');
|
||||
});
|
||||
});
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue