feat: ✨ Transform CampaignRequest into Campaign + Coupon - #38 - US0.3
This commit is contained in:
parent
6faeb77d02
commit
491e349959
38 changed files with 787 additions and 341 deletions
16
src/Application/UseCases/CampaignRequest/Transform/Input.php
Normal file
16
src/Application/UseCases/CampaignRequest/Transform/Input.php
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Application\UseCases\CampaignRequest\Transform;
|
||||
|
||||
use Domain\Models\ValueObjects\CampaignRequest\CampaignRequestId;
|
||||
use Shared\DDD\UseCases\Input as UseCaseInput;
|
||||
|
||||
final readonly class Input implements UseCaseInput
|
||||
{
|
||||
public function __construct(
|
||||
public CampaignRequestId $id
|
||||
) {
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Application\UseCases\CampaignRequest\Transform\Outputs;
|
||||
|
||||
use Shared\DDD\UseCases\Output;
|
||||
|
||||
final readonly class CampaignRequestAlreadyTranformed implements Output
|
||||
{
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Application\UseCases\CampaignRequest\Transform\Outputs;
|
||||
|
||||
use Shared\DDD\UseCases\Output;
|
||||
|
||||
final readonly class CampaignRequestNotFound implements Output
|
||||
{
|
||||
}
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Application\UseCases\CampaignRequest\Transform\Outputs;
|
||||
|
||||
use Domain\Models\Entities\Campaign;
|
||||
use Domain\Models\Entities\Coupon;
|
||||
use Domain\Models\ValueObjects\CampaignRequest\CampaignRequestId;
|
||||
use Domain\Models\ValueObjects\CampaignRequest\CampaignRequestStatus;
|
||||
use Shared\DDD\UseCases\Output;
|
||||
|
||||
final readonly class CampaignRequestTransformed implements Output
|
||||
{
|
||||
public function __construct(
|
||||
public CampaignRequestId $id,
|
||||
public CampaignRequestStatus $status,
|
||||
public Campaign $campaign,
|
||||
public Coupon $coupon,
|
||||
) {
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Application\UseCases\CampaignRequest\Transform\Outputs;
|
||||
|
||||
use Shared\DDD\UseCases\Output;
|
||||
|
||||
final readonly class CouponAlreadyExists implements Output
|
||||
{
|
||||
}
|
||||
|
|
@ -0,0 +1,122 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Application\UseCases\CampaignRequest\Transform;
|
||||
|
||||
use Application\UseCases\CampaignRequest\Transform\Outputs\CampaignRequestAlreadyTranformed;
|
||||
use Application\UseCases\CampaignRequest\Transform\Outputs\CampaignRequestNotFound;
|
||||
use Application\UseCases\CampaignRequest\Transform\Outputs\CampaignRequestTransformed;
|
||||
use Application\UseCases\CampaignRequest\Transform\Outputs\CouponAlreadyExists;
|
||||
use Domain\Models\Entities\Campaign;
|
||||
use Domain\Models\Entities\CampaignRequest;
|
||||
use Domain\Models\Entities\Coupon;
|
||||
use Domain\Models\ValueObjects\Actor\ActorId;
|
||||
use Domain\Models\ValueObjects\Campaign\CampaignCoupon;
|
||||
use Domain\Models\ValueObjects\Campaign\CampaignCouponArray;
|
||||
use Domain\Models\ValueObjects\CampaignRequest\CampaignRequestStatus;
|
||||
use Domain\Models\ValueObjects\CampaignRequest\CampaignRequestType;
|
||||
use Domain\Models\ValueObjects\Coupon\CouponCode;
|
||||
use Domain\Models\ValueObjects\Coupon\CouponDiffusion;
|
||||
use Domain\Models\ValueObjects\Coupon\CouponMovement;
|
||||
use Domain\Models\ValueObjects\Coupon\CouponMovementArray;
|
||||
use Domain\Ports\Repositories\CampaignRepository;
|
||||
use Domain\Ports\Repositories\CampaignRequestRepository;
|
||||
use Domain\Ports\Repositories\CouponRepository;
|
||||
use Shared\DDD\UseCases\Input as BaseInput;
|
||||
use Shared\DDD\UseCases\Output;
|
||||
use Shared\DDD\UseCases\Transactional;
|
||||
use Shared\DDD\UseCases\UseCase;
|
||||
use Webmozart\Assert\Assert;
|
||||
|
||||
/** @implements UseCase<\Application\UseCases\CampaignRequest\Transform\Input, \Shared\DDD\UseCases\Output> */
|
||||
final readonly class TransformCampaignRequest implements UseCase, Transactional
|
||||
{
|
||||
public function __construct(
|
||||
private CampaignRequestRepository $repository,
|
||||
private CampaignRepository $campaignRepository,
|
||||
private CouponRepository $couponRepository,
|
||||
) {
|
||||
}
|
||||
|
||||
#[\Override]
|
||||
public function execute(BaseInput $input): Output
|
||||
{
|
||||
Assert::isInstanceOf($input, Input::class);
|
||||
|
||||
$campaignRequest = $this->repository->findById($input->id);
|
||||
|
||||
if (! $campaignRequest instanceof CampaignRequest) {
|
||||
return new CampaignRequestNotFound();
|
||||
}
|
||||
|
||||
if ($campaignRequest->status !== CampaignRequestStatus::CREATED) {
|
||||
return new CampaignRequestAlreadyTranformed();
|
||||
}
|
||||
|
||||
// TODO: get the real ActorID
|
||||
$actorId = ActorId::generate();
|
||||
|
||||
$createdCoupon = self::createCouponFromRequest($campaignRequest, $actorId);
|
||||
|
||||
|
||||
$campaignCoupon = new CampaignCoupon($createdCoupon->code, $campaignRequest->requestedCoupon->printRules);
|
||||
|
||||
$campaignCreated = self::createCampaignFromRequest($campaignRequest, $campaignCoupon, $actorId);
|
||||
|
||||
$campaignRequest = $campaignRequest->updateStatusWhenTransformed();
|
||||
$this->repository->save($campaignRequest);
|
||||
|
||||
return new CampaignRequestTransformed(
|
||||
id: $campaignRequest->id(),
|
||||
status: $campaignRequest->status,
|
||||
campaign: $campaignCreated,
|
||||
coupon: $createdCoupon,
|
||||
);
|
||||
}
|
||||
|
||||
private function createCouponFromRequest(CampaignRequest $campaignRequest, ActorId $actorId): Coupon | CouponAlreadyExists
|
||||
{
|
||||
$requestedCoupon = $campaignRequest->requestedCoupon;
|
||||
|
||||
foreach ($requestedCoupon->couponProcessingCodes->toArray() as $processingCode) {
|
||||
if ($this->couponRepository->existsByProcessingCode($processingCode)) {
|
||||
return new CouponAlreadyExists();
|
||||
}
|
||||
}
|
||||
|
||||
$coupon = Coupon::create(
|
||||
name: $requestedCoupon->couponName,
|
||||
amount: $requestedCoupon->moneyAmount,
|
||||
picture: $requestedCoupon->couponPicture,
|
||||
diffusion: new CouponDiffusion($requestedCoupon->diffusion),
|
||||
validityInformations: $requestedCoupon->couponValidityInformations,
|
||||
legalInformations: $requestedCoupon->couponLegalInformations,
|
||||
processingCode: $requestedCoupon->couponProcessingCodes,
|
||||
brandCode: $campaignRequest->brandCode,
|
||||
createdBy: $actorId,
|
||||
products: $requestedCoupon->couponProducts,
|
||||
movements: new CouponMovementArray([
|
||||
new CouponMovement($requestedCoupon->quantity->value)
|
||||
]),
|
||||
);
|
||||
$this->couponRepository->save($coupon);
|
||||
|
||||
return $coupon;
|
||||
}
|
||||
|
||||
private function createCampaignFromRequest(CampaignRequest $campaignRequest, CampaignCoupon $campaignCoupon, ActorId $actorId): Campaign
|
||||
{
|
||||
$isGame = $campaignRequest->campaignType === CampaignRequestType::GAME;
|
||||
$campaign = Campaign::create(
|
||||
name: $campaignRequest->name,
|
||||
printAllAtOnce: $isGame,
|
||||
coupons: new CampaignCouponArray([$campaignCoupon]),
|
||||
brandCode: $campaignRequest->brandCode,
|
||||
actorId: $actorId
|
||||
);
|
||||
$this->campaignRepository->save($campaign);
|
||||
|
||||
return $campaign;
|
||||
}
|
||||
}
|
||||
|
|
@ -34,12 +34,13 @@ final readonly class CreateCoupon implements UseCase, Transactional
|
|||
return new BrandNotFound();
|
||||
}
|
||||
|
||||
if ($this->couponRepository->existsByCode($input->code)) {
|
||||
return new CouponCodeAlreadyExists();
|
||||
foreach ($input->processingCode->toArray() as $processingCode) {
|
||||
if ($this->couponRepository->existsByProcessingCode($processingCode)) {
|
||||
return new CouponCodeAlreadyExists();
|
||||
}
|
||||
}
|
||||
|
||||
$coupon = Coupon::create(
|
||||
code: $input->code,
|
||||
name: $input->name,
|
||||
amount: $input->amount,
|
||||
picture: $input->picture,
|
||||
|
|
|
|||
|
|
@ -7,7 +7,6 @@ namespace Application\UseCases\Coupon\Create;
|
|||
use Domain\Models\ValueObjects\Actor\ActorId;
|
||||
use Domain\Models\ValueObjects\Brand\BrandCode;
|
||||
use Domain\Models\ValueObjects\Coupon\CouponAvailabilityCalendar;
|
||||
use Domain\Models\ValueObjects\Coupon\CouponCode;
|
||||
use Domain\Models\ValueObjects\Coupon\CouponDiffusion;
|
||||
use Domain\Models\ValueObjects\Coupon\CouponLegalInformationArray;
|
||||
use Domain\Models\ValueObjects\Coupon\CouponMovementArray;
|
||||
|
|
@ -22,7 +21,6 @@ use Shared\DDD\UseCases\Input as UseCaseInput;
|
|||
final readonly class Input implements UseCaseInput
|
||||
{
|
||||
public function __construct(
|
||||
public CouponCode $code,
|
||||
public CouponName $name,
|
||||
public MoneyAmount $amount,
|
||||
public CouponPicture $picture,
|
||||
|
|
|
|||
|
|
@ -124,4 +124,19 @@ final readonly class CampaignRequest implements AggregateRoot, HasTimestampIdent
|
|||
|
||||
return $this->rejectionReason;
|
||||
}
|
||||
|
||||
public function updateStatusWhenTransformed(): self
|
||||
{
|
||||
return new self(
|
||||
id: $this->id,
|
||||
brandCode: $this->brandCode,
|
||||
applicant: $this->applicant,
|
||||
campaignType: $this->campaignType,
|
||||
name: $this->name,
|
||||
requestedCoupon: $this->requestedCoupon,
|
||||
status: CampaignRequestStatus::TRANSFORMED,
|
||||
rejectionReason: null,
|
||||
updatedAt: DatesHelper::now(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -75,7 +75,6 @@ final readonly class Coupon implements AggregateRoot, HasTimestampIdentifier
|
|||
}
|
||||
|
||||
public static function create(
|
||||
CouponCode $code,
|
||||
CouponName $name,
|
||||
MoneyAmount $amount,
|
||||
CouponPicture $picture,
|
||||
|
|
@ -91,7 +90,7 @@ final readonly class Coupon implements AggregateRoot, HasTimestampIdentifier
|
|||
): Coupon {
|
||||
return new self(
|
||||
id: CouponId::generate(),
|
||||
code: $code,
|
||||
code: CouponCode::generate(),
|
||||
name: $name,
|
||||
amount: $amount,
|
||||
picture: $picture,
|
||||
|
|
|
|||
|
|
@ -4,23 +4,13 @@ declare(strict_types=1);
|
|||
|
||||
namespace Domain\Models\ValueObjects\Coupon;
|
||||
|
||||
final readonly class CouponCode
|
||||
use Ramsey\Uuid\Uuid;
|
||||
use Shared\DDD\Models\Uuidv7EntityId;
|
||||
|
||||
final readonly class CouponCode extends Uuidv7EntityId
|
||||
{
|
||||
private const string REGEX = '/^[A-Z]{3}\d{2}$/';
|
||||
|
||||
public function __construct(
|
||||
public string $value,
|
||||
) {
|
||||
if (! preg_match(self::REGEX, $value)) {
|
||||
throw new \DomainException(
|
||||
"Invalid code '{$value}' does not match pattern " . self::REGEX,
|
||||
);
|
||||
}
|
||||
|
||||
if ($value[3] === $value[4]) {
|
||||
throw new \DomainException(
|
||||
"Invalid code '{$value}' has the same digit repeated",
|
||||
);
|
||||
}
|
||||
public static function generate(): self
|
||||
{
|
||||
return new self(Uuid::uuid7());
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ use Domain\Models\Entities\Coupon;
|
|||
use Domain\Models\ValueObjects\Brand\BrandCode;
|
||||
use Domain\Models\ValueObjects\Coupon\CouponCode;
|
||||
use Domain\Models\ValueObjects\Coupon\CouponSortCriteria;
|
||||
use Domain\Models\ValueObjects\ProcessingCode;
|
||||
use Shared\DDD\Ports\Repository;
|
||||
use Shared\ValueObjects\Pagination\Paginated;
|
||||
use Shared\ValueObjects\Pagination\Pagination;
|
||||
|
|
@ -21,6 +22,10 @@ interface CouponRepository extends Repository
|
|||
|
||||
public function findByCode(CouponCode $code): ?Coupon;
|
||||
|
||||
public function existsByProcessingCode(ProcessingCode $code): bool;
|
||||
|
||||
public function findByProcessingCode(ProcessingCode $code): bool;
|
||||
|
||||
/**
|
||||
* @param array<CouponCode> $code
|
||||
*
|
||||
|
|
@ -37,5 +42,5 @@ interface CouponRepository extends Repository
|
|||
?BrandCode $brandCode = null,
|
||||
): Paginated;
|
||||
|
||||
public function save(Coupon $brand): void;
|
||||
public function save(Coupon $coupon): void;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -94,10 +94,10 @@ final class CampaignFactory
|
|||
|
||||
return new CampaignCouponArray(array_map(
|
||||
static fn (string | CouponCode $code): CampaignCoupon => new CampaignCoupon(
|
||||
$code instanceof CouponCode ? $code : new CouponCode($code),
|
||||
$code instanceof CouponCode ? $code : CouponCode::generate(),
|
||||
$printRules,
|
||||
),
|
||||
$couponCodes ?? ['COU01'],
|
||||
$couponCodes ?? [CouponCode::generate()],
|
||||
));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
135
tests/Fixtures/CampaignRequest/CampaignRequestFactory.php
Normal file
135
tests/Fixtures/CampaignRequest/CampaignRequestFactory.php
Normal file
|
|
@ -0,0 +1,135 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Tests\Fixtures\CampaignRequest;
|
||||
|
||||
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\CampaignRequestId;
|
||||
use Domain\Models\ValueObjects\CampaignRequest\CampaignRequestStatus;
|
||||
use Domain\Models\ValueObjects\CampaignRequest\CampaignRequestType;
|
||||
use Domain\Models\ValueObjects\CampaignRequest\RejectionReason;
|
||||
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\CouponProductArray;
|
||||
use Domain\Models\ValueObjects\Coupon\CouponValidityInformation;
|
||||
use Domain\Models\ValueObjects\Coupon\CouponValidityInformationArray;
|
||||
use Domain\Models\ValueObjects\IncoCode;
|
||||
use Domain\Models\ValueObjects\MoneyAmount;
|
||||
use Domain\Models\ValueObjects\Period;
|
||||
use Domain\Models\ValueObjects\PicturePath;
|
||||
use Domain\Models\ValueObjects\PrintRules;
|
||||
use Domain\Models\ValueObjects\ProcessingCode;
|
||||
use Domain\Models\ValueObjects\ProcessingCodeArray;
|
||||
use Domain\Models\ValueObjects\RequestedCoupon\RequestedCoupon;
|
||||
use Domain\Models\ValueObjects\RequestedCoupon\RequestedCouponQuantity;
|
||||
use Shared\Enums\Country;
|
||||
use Shared\Enums\Currency;
|
||||
use Shared\ValueObjects\Email;
|
||||
use Shared\ValueObjects\Money;
|
||||
|
||||
final class CampaignRequestFactory
|
||||
{
|
||||
/** Demande neuve : id généré, statut CREATED, updatedAt = null. */
|
||||
public static function make(
|
||||
string $brandCode = 'AAA01',
|
||||
string $name = 'Campaign request',
|
||||
?Applicant $applicant = null,
|
||||
CampaignRequestType $campaignType = CampaignRequestType::CLUB,
|
||||
?RequestedCoupon $requestedCoupon = null,
|
||||
): CampaignRequest {
|
||||
return CampaignRequest::create(
|
||||
brandCode: new BrandCode($brandCode),
|
||||
name: new CampaignName($name),
|
||||
applicant: $applicant ?? self::applicant(),
|
||||
campaignType: $campaignType,
|
||||
requestedCoupon: $requestedCoupon ?? self::requestedCoupon(),
|
||||
);
|
||||
}
|
||||
|
||||
/** Demande reconstruite comme depuis la base (id et statut contrôlables). */
|
||||
public static function hydrated(
|
||||
?CampaignRequestId $id = null,
|
||||
CampaignRequestStatus $status = CampaignRequestStatus::CREATED,
|
||||
?RejectionReason $rejectionReason = null,
|
||||
string $brandCode = 'AAA01',
|
||||
string $name = 'Campaign request',
|
||||
?Applicant $applicant = null,
|
||||
CampaignRequestType $campaignType = CampaignRequestType::CLUB,
|
||||
?RequestedCoupon $requestedCoupon = null,
|
||||
): CampaignRequest {
|
||||
if ($status === CampaignRequestStatus::REJECTED) {
|
||||
$rejectionReason ??= self::rejectionReason();
|
||||
}
|
||||
|
||||
return CampaignRequest::hydrate(
|
||||
id: $id ?? CampaignRequestId::generate(),
|
||||
brandCode: new BrandCode($brandCode),
|
||||
name: new CampaignName($name),
|
||||
applicant: $applicant ?? self::applicant(),
|
||||
campaignType: $campaignType,
|
||||
requestedCoupon: $requestedCoupon ?? self::requestedCoupon(),
|
||||
status: $status,
|
||||
rejectionReason: $rejectionReason,
|
||||
);
|
||||
}
|
||||
|
||||
/** Demande rejetée, obtenue par la vraie transition métier. */
|
||||
public static function rejected(?RejectionReason $reason = null): CampaignRequest
|
||||
{
|
||||
return self::make()->reject($reason ?? self::rejectionReason());
|
||||
}
|
||||
|
||||
/** Demande transformée en campagne, obtenue par la vraie transition métier. */
|
||||
public static function transformed(): CampaignRequest
|
||||
{
|
||||
return self::make()->updateStatusWhenTransformed();
|
||||
}
|
||||
|
||||
public static function applicant(
|
||||
string $firstname = 'Jane',
|
||||
string $lastname = 'Doe',
|
||||
string $email = 'jane.doe@example.com',
|
||||
): Applicant {
|
||||
return new Applicant($firstname, $lastname, new Email($email)); // Email : À VÉRIFIER
|
||||
}
|
||||
|
||||
public static function rejectionReason(string $reason = 'Not eligible'): RejectionReason
|
||||
{
|
||||
return new RejectionReason($reason);
|
||||
}
|
||||
|
||||
public static function requestedCoupon(
|
||||
string $couponName = 'Coupon name',
|
||||
int $quantity = 1000,
|
||||
?PrintRules $printRules = null,
|
||||
): RequestedCoupon {
|
||||
return new RequestedCoupon(
|
||||
couponName: new CouponName($couponName),
|
||||
quantity: new RequestedCouponQuantity($quantity), // À VÉRIFIER
|
||||
diffusion: new Period(new \DateTime()->modify('+1 month'), new \DateTime()->modify('+2 months')),
|
||||
moneyAmount: new MoneyAmount(new Money(Currency::EUR, 100)),
|
||||
couponPicture: new CouponPicture(
|
||||
new PicturePath('files/product.jpg'),
|
||||
new PicturePath('files/thumbnail.jpg'),
|
||||
new PicturePath('files/mobile_thumbnail.jpg'),
|
||||
),
|
||||
couponProcessingCodes: new ProcessingCodeArray([
|
||||
new ProcessingCode('5425003944130', Country::FRANCE),
|
||||
]),
|
||||
couponValidityInformations: new CouponValidityInformationArray([
|
||||
new CouponValidityInformation('Lorem ipsum dolor sit amet consectetur.', Country::FRANCE),
|
||||
]),
|
||||
couponLegalInformations: new CouponLegalInformationArray([
|
||||
new CouponLegalInformation('Lorem ipsum dolor sit amet consectetur.', Country::FRANCE),
|
||||
]),
|
||||
couponProducts: new CouponProductArray([new IncoCode(35784)]),
|
||||
printRules: $printRules,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -10,6 +10,7 @@ use Domain\Models\ValueObjects\Brand\BrandCode;
|
|||
use Domain\Models\ValueObjects\Coupon\CouponAvailabilityCalendar;
|
||||
use Domain\Models\ValueObjects\Coupon\CouponCode;
|
||||
use Domain\Models\ValueObjects\Coupon\CouponDiffusion;
|
||||
use Domain\Models\ValueObjects\Coupon\CouponId;
|
||||
use Domain\Models\ValueObjects\Coupon\CouponLegalInformation;
|
||||
use Domain\Models\ValueObjects\Coupon\CouponLegalInformationArray;
|
||||
use Domain\Models\ValueObjects\Coupon\CouponMovement;
|
||||
|
|
@ -32,65 +33,74 @@ use Shared\ValueObjects\Money;
|
|||
final class CouponFactory
|
||||
{
|
||||
public static function make(
|
||||
string | CouponCode $code = 'COU01',
|
||||
?int $amount = 100,
|
||||
?\DateTime $diffusionStart = null,
|
||||
?\DateTime $diffusionEnd = null,
|
||||
?CouponAvailabilityCalendar $availabilityCalendar = null,
|
||||
string $brandCode = 'AAA01',
|
||||
?CouponCode $code = null,
|
||||
): Coupon {
|
||||
return Coupon::create(
|
||||
code: $code instanceof CouponCode ? $code : new CouponCode($code),
|
||||
name: new CouponName('Coupon name'),
|
||||
amount: new MoneyAmount(new Money(Currency::EUR, $amount)),
|
||||
picture: new CouponPicture(
|
||||
$arguments = [
|
||||
'name' => new CouponName('Coupon name'),
|
||||
'amount' => new MoneyAmount(new Money(Currency::EUR, $amount)),
|
||||
'picture' => new CouponPicture(
|
||||
new PicturePath('files/product.jpg'),
|
||||
new PicturePath('files/thumbnail.jpg'),
|
||||
new PicturePath('files/mobile_thumbnail.jpg'),
|
||||
),
|
||||
diffusion: new CouponDiffusion(
|
||||
'diffusion' => new CouponDiffusion(
|
||||
new Period(
|
||||
start: $diffusionStart ?? new \DateTime()->modify('-1 month'),
|
||||
end: $diffusionEnd ?? new \DateTime()->modify('+1 month'),
|
||||
),
|
||||
),
|
||||
validityInformations: new CouponValidityInformationArray([
|
||||
'validityInformations' => 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)
|
||||
]),
|
||||
legalInformations: new CouponLegalInformationArray([
|
||||
'legalInformations' => 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)
|
||||
]),
|
||||
processingCode: new ProcessingCodeArray([
|
||||
'processingCode' => new ProcessingCodeArray([
|
||||
new ProcessingCode('5425003944130', Country::FRANCE),
|
||||
new ProcessingCode('4006381333931', Country::BENELUX),
|
||||
]),
|
||||
brandCode: new BrandCode($brandCode),
|
||||
createdBy: ActorId::generate(),
|
||||
products: new CouponProductArray([new IncoCode(35784), new IncoCode(15522)]),
|
||||
movements: new CouponMovementArray([new CouponMovement(1000)]),
|
||||
availabilityCalendar: $availabilityCalendar,
|
||||
);
|
||||
'brandCode' => new BrandCode($brandCode),
|
||||
'createdBy' => ActorId::generate(),
|
||||
'products' => new CouponProductArray([new IncoCode(35784), new IncoCode(15522)]),
|
||||
'movements' => new CouponMovementArray([new CouponMovement(1000)]),
|
||||
'availabilityCalendar' => $availabilityCalendar,
|
||||
];
|
||||
|
||||
if ($code instanceof CouponCode) {
|
||||
return Coupon::hydrate(...[
|
||||
'id' => CouponId::generate(),
|
||||
'code' => $code,
|
||||
...$arguments,
|
||||
]);
|
||||
}
|
||||
|
||||
return Coupon::create(...$arguments);
|
||||
}
|
||||
|
||||
/** Coupon dont la diffusion est terminée. */
|
||||
public static function expired(string | CouponCode $code = 'COU01'): Coupon
|
||||
public static function expired(?CouponCode $code = null): Coupon
|
||||
{
|
||||
return self::make(
|
||||
code: $code,
|
||||
diffusionStart: new \DateTime()->modify('-2 months'),
|
||||
diffusionEnd: new \DateTime()->modify('-1 day'),
|
||||
code: $code,
|
||||
);
|
||||
}
|
||||
|
||||
/** Coupon dont la diffusion n'a pas commencé. */
|
||||
public static function upcoming(string | CouponCode $code = 'COU01'): Coupon
|
||||
public static function upcoming(?CouponCode $code = null): Coupon
|
||||
{
|
||||
return self::make(
|
||||
code: $code,
|
||||
diffusionStart: new \DateTime()->modify('+1 day'),
|
||||
diffusionEnd: new \DateTime()->modify('+2 months'),
|
||||
code: $code,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -27,8 +27,8 @@ describe('create campaign use case', function (): void {
|
|||
'brandCode' => new BrandCode('AAA01'),
|
||||
'printAllAtOnce' => false,
|
||||
'coupons' => new CampaignCouponArray([
|
||||
new CampaignCoupon(new CouponCode('COU01'), new PrintRules(maxPerCustomer: 1)),
|
||||
new CampaignCoupon(new CouponCode('COU02'), new PrintRules(cooldownDays: 30)),
|
||||
new CampaignCoupon(CouponCode::generate(), new PrintRules(maxPerCustomer: 1)),
|
||||
new CampaignCoupon(CouponCode::generate(), new PrintRules(cooldownDays: 30)),
|
||||
]),
|
||||
'createdBy' => ActorId::generate(),
|
||||
], $overrides));
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ use Application\UseCases\Campaign\Find\Outputs\CampaignFound;
|
|||
use Application\UseCases\Campaign\Outputs\CampaignNotFound;
|
||||
use Domain\Models\Entities\Campaign;
|
||||
use Domain\Models\ValueObjects\Campaign\CampaignCode;
|
||||
use Domain\Models\ValueObjects\Coupon\CouponCode;
|
||||
use Domain\Ports\Repositories\CampaignRepository;
|
||||
use Domain\Models\ValueObjects\PrintRules;
|
||||
use Tests\Fixtures\Campaign\CampaignFactory;
|
||||
|
|
@ -17,15 +18,16 @@ use Tests\Fixtures\Campaign\CampaignFactory;
|
|||
covers(FindCampaign::class, Input::class, CampaignFound::class, CampaignNotFound::class);
|
||||
|
||||
describe('find campaign use case', function (): void {
|
||||
$makeCampaign = static fn (array $couponCodes = ['COU01']): Campaign => CampaignFactory::hydrated(
|
||||
$couponCode = CouponCode::generate();
|
||||
$makeCampaign = static fn (?array $couponCodes = null): Campaign => CampaignFactory::hydrated(
|
||||
published: true,
|
||||
name: 'Campaign A',
|
||||
printAllAtOnce: false,
|
||||
couponCodes: $couponCodes,
|
||||
couponCodes: $couponCodes ?? [$couponCode],
|
||||
printRules: new PrintRules(maxPerCustomer: 1),
|
||||
);
|
||||
|
||||
it('finds a campaign by its code with paginated coupons', function () use ($makeCampaign): void {
|
||||
it('finds a campaign by its code with coupons array', function () use ($makeCampaign, $couponCode): void {
|
||||
// GIVEN
|
||||
$campaign = $makeCampaign();
|
||||
$repository = \Mockery::mock(CampaignRepository::class);
|
||||
|
|
@ -44,14 +46,14 @@ describe('find campaign use case', function (): void {
|
|||
->and($result->publication)->toBe($campaign->publication)
|
||||
->and($result->printAllAtOnce)->toBe($campaign->printAllAtOnce)
|
||||
->and($result->coupons)->toBe($campaign->coupons)
|
||||
->and($result->coupons->toArray()[0]->couponCode->value)->toBe('COU01')
|
||||
->and($result->coupons->toArray()[0]->couponCode->value)->toBe($couponCode->value)
|
||||
->and($result->createdAt)->toEqual($campaign->createdAt())
|
||||
->and($result->updatedAt)->toEqual($campaign->updatedAt());
|
||||
});
|
||||
|
||||
it('returns CampaignNotFound when the code is not found', function (): void {
|
||||
// GIVEN
|
||||
$code = CampaignCode::generate();
|
||||
$code = CampaignCode::generate();
|
||||
|
||||
$repository = \Mockery::mock(CampaignRepository::class);
|
||||
$repository->shouldReceive('findByCode')->once()->with($code)->andReturn(null);
|
||||
|
|
|
|||
|
|
@ -11,7 +11,6 @@ use Application\UseCases\Campaign\Update\Outputs\CampaignUpdated;
|
|||
use Application\UseCases\Campaign\Update\Outputs\CouponAlreadyInCampaign;
|
||||
use Application\UseCases\Campaign\Update\Outputs\CouponNotActive;
|
||||
use Application\UseCases\Campaign\Update\Outputs\CouponNotFound;
|
||||
use DateTime;
|
||||
use Domain\Models\Entities\Campaign;
|
||||
use Domain\Models\ValueObjects\Actor\ActorId;
|
||||
use Domain\Models\ValueObjects\Brand\BrandCode;
|
||||
|
|
@ -24,6 +23,7 @@ use Domain\Models\ValueObjects\Coupon\CouponCode;
|
|||
use Domain\Models\ValueObjects\PrintRules;
|
||||
use Domain\Ports\Repositories\CampaignRepository;
|
||||
use Domain\Ports\Repositories\CouponRepository;
|
||||
use Shared\Helpers\DatesHelper;
|
||||
use Tests\Fixtures\Campaign\CampaignFactory;
|
||||
use Tests\Fixtures\Coupon\CouponFactory;
|
||||
|
||||
|
|
@ -38,9 +38,9 @@ covers(
|
|||
);
|
||||
|
||||
describe('add coupons to campaign use case', function (): void {
|
||||
$coupon1 = CouponFactory::make(code: 'COU01');
|
||||
$coupon2 = CouponFactory::make(code: 'COU02');
|
||||
$coupon3 = CouponFactory::make(code: 'COU03');
|
||||
$coupon1 = CouponFactory::make();
|
||||
$coupon2 = CouponFactory::make();
|
||||
$coupon3 = CouponFactory::make();
|
||||
$campaignCoupon1 = new CampaignCoupon($coupon1->code, new PrintRules(maxPerCustomer: 1));
|
||||
$campaignCoupon2 = new CampaignCoupon($coupon2->code, new PrintRules(maxPerCustomer: 1));
|
||||
$existingCampaign = static fn (CampaignCode $code, bool $basePublicationStatus): Campaign => Campaign::hydrate(
|
||||
|
|
@ -114,11 +114,11 @@ describe('add coupons to campaign use case', function (): void {
|
|||
|
||||
it('returns a specific error when the coupon is not printable', function (): void {
|
||||
// WHEN
|
||||
$campaign = CampaignFactory::hydrated(couponCodes: ['COU01']);
|
||||
$coupon = CouponFactory::make(
|
||||
code: 'COU02',
|
||||
diffusionStart: new DateTime('2026-01-01'),
|
||||
diffusionEnd: new DateTime('2026-01-31')
|
||||
$baseCoupon = CouponFactory::make();
|
||||
$campaign = CampaignFactory::hydrated(couponCodes: [$baseCoupon->code]);
|
||||
$couponToAdd = CouponFactory::make(
|
||||
diffusionStart: DatesHelper::now()->subYear()->subMonth()->toDateTime(),
|
||||
diffusionEnd: DatesHelper::now()->subYear()->toDateTime()
|
||||
);
|
||||
|
||||
$repository = \Mockery::mock(CampaignRepository::class);
|
||||
|
|
@ -126,9 +126,9 @@ describe('add coupons to campaign use case', function (): void {
|
|||
$repository->shouldNotReceive('save');
|
||||
|
||||
$couponRepository = \Mockery::mock(CouponRepository::class);
|
||||
$couponRepository->shouldReceive('findByCode')->once()->andReturn($coupon);
|
||||
$couponRepository->shouldReceive('findByCode')->once()->andReturn($couponToAdd);
|
||||
|
||||
$input = new AddCouponToCampaignInput(code: $campaign->code, couponCode: $coupon->code, printRules: null);
|
||||
$input = new AddCouponToCampaignInput(code: $campaign->code, couponCode: $couponToAdd->code, printRules: null);
|
||||
|
||||
$useCase = new AddCouponToCampaign($repository, $couponRepository);
|
||||
|
||||
|
|
@ -160,16 +160,17 @@ describe('add coupons to campaign use case', function (): void {
|
|||
|
||||
it('returns a specific error when the coupon is not found', function (): void {
|
||||
// GIVEN
|
||||
$campaign = CampaignFactory::hydrated();
|
||||
$campaign = CampaignFactory::hydrated();
|
||||
$couponCode = CouponCode::generate();
|
||||
|
||||
$repository = \Mockery::mock(CampaignRepository::class);
|
||||
$repository->shouldReceive('findByCode')->once()->andReturn($campaign);
|
||||
$repository->shouldNotReceive('save');
|
||||
|
||||
$couponRepository = \Mockery::mock(CouponRepository::class);
|
||||
$couponRepository->shouldReceive('findByCode')->once()->andReturn(null);
|
||||
$couponRepository->shouldReceive('findByCode')->once()->with($couponCode)->andReturn(null);
|
||||
|
||||
$input = new AddCouponToCampaignInput(code: $campaign->code, couponCode: new CouponCode('ZZZ01'), printRules: null);
|
||||
$input = new AddCouponToCampaignInput(code: $campaign->code, couponCode: $couponCode, printRules: null);
|
||||
|
||||
$useCase = new AddCouponToCampaign($repository, $couponRepository);
|
||||
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ use Application\UseCases\Campaign\Update\Outputs\CampaignStatusUpdated;
|
|||
use Application\UseCases\Campaign\Update\Outputs\CampaignUnpublicationSkipped;
|
||||
use Domain\Models\Entities\Campaign;
|
||||
use Domain\Models\ValueObjects\Campaign\CampaignCode;
|
||||
use Domain\Models\ValueObjects\Coupon\CouponCode;
|
||||
use Domain\Ports\Repositories\CampaignRepository;
|
||||
use Domain\Ports\Repositories\CouponRepository;
|
||||
use Domain\Services\Campaign\CampaignAvailabilityChecker;
|
||||
|
|
@ -68,14 +69,15 @@ describe('auto unpublish campaign use case', function (): void {
|
|||
|
||||
it('skips a published campaign that still has an active coupon', function (): void {
|
||||
// GIVEN
|
||||
$campaign = CampaignFactory::hydrated(published: true, couponCodes: ['COU01']);
|
||||
$couponCode = CouponCode::generate();
|
||||
$campaign = CampaignFactory::hydrated(published: true, couponCodes: [$couponCode]);
|
||||
|
||||
$repository = \Mockery::mock(CampaignRepository::class);
|
||||
$repository->shouldReceive('findByCode')->once()->with($campaign->code)->andReturn($campaign);
|
||||
$repository->shouldNotReceive('save');
|
||||
|
||||
$couponRepository = \Mockery::mock(CouponRepository::class);
|
||||
$couponRepository->shouldReceive('findByCodes')->once()->andReturn([CouponFactory::make('COU01')]);
|
||||
$couponRepository->shouldReceive('findByCodes')->once()->andReturn([CouponFactory::make()]);
|
||||
|
||||
$useCase = new AutoUnpublishCampaign($repository, new CampaignAvailabilityChecker($couponRepository));
|
||||
|
||||
|
|
@ -88,7 +90,7 @@ describe('auto unpublish campaign use case', function (): void {
|
|||
|
||||
it('skips a published campaign with one active and one expired coupon', function (): void {
|
||||
// GIVEN
|
||||
$campaign = CampaignFactory::hydrated(published: true, couponCodes: ['COU01', 'COU02']);
|
||||
$campaign = CampaignFactory::hydrated(published: true, couponCodes: [CouponCode::generate(), CouponCode::generate()]);
|
||||
|
||||
$repository = \Mockery::mock(CampaignRepository::class);
|
||||
$repository->shouldReceive('findByCode')->once()->with($campaign->code)->andReturn($campaign);
|
||||
|
|
@ -96,8 +98,8 @@ describe('auto unpublish campaign use case', function (): void {
|
|||
|
||||
$couponRepository = \Mockery::mock(CouponRepository::class);
|
||||
$couponRepository->shouldReceive('findByCodes')->once()->andReturn([
|
||||
CouponFactory::expired('COU01'),
|
||||
CouponFactory::make('COU02'),
|
||||
CouponFactory::expired(),
|
||||
CouponFactory::make(),
|
||||
]);
|
||||
|
||||
$useCase = new AutoUnpublishCampaign($repository, new CampaignAvailabilityChecker($couponRepository));
|
||||
|
|
@ -111,7 +113,9 @@ describe('auto unpublish campaign use case', function (): void {
|
|||
|
||||
it('unpublishes a published campaign when every coupon is not available', function (): void {
|
||||
// GIVEN
|
||||
$campaign = CampaignFactory::hydrated(published: true, couponCodes: ['COU01', 'COU02']);
|
||||
$couponCode1 = CouponCode::generate();
|
||||
$couponCode2 = CouponCode::generate();
|
||||
$campaign = CampaignFactory::hydrated(published: true, couponCodes: [$couponCode1->value, $couponCode2->value]);
|
||||
|
||||
$repository = \Mockery::mock(CampaignRepository::class);
|
||||
$repository->shouldReceive('findByCode')->once()->with($campaign->code)->andReturn($campaign);
|
||||
|
|
@ -123,8 +127,8 @@ describe('auto unpublish campaign use case', function (): void {
|
|||
|
||||
$couponRepository = \Mockery::mock(CouponRepository::class);
|
||||
$couponRepository->shouldReceive('findByCodes')->once()->andReturn([
|
||||
CouponFactory::expired('COU01'),
|
||||
CouponFactory::upcoming('COU02'),
|
||||
CouponFactory::expired(),
|
||||
CouponFactory::upcoming(),
|
||||
]);
|
||||
|
||||
$useCase = new AutoUnpublishCampaign($repository, new CampaignAvailabilityChecker($couponRepository));
|
||||
|
|
@ -143,7 +147,8 @@ describe('auto unpublish campaign use case', function (): void {
|
|||
|
||||
it('unpublishes a published campaign when no coupon is found', function (): void {
|
||||
// GIVEN
|
||||
$campaign = CampaignFactory::hydrated(published: true, couponCodes: ['COU01']);
|
||||
$couponCode = CouponCode::generate();
|
||||
$campaign = CampaignFactory::hydrated(published: true, couponCodes: [$couponCode]);
|
||||
|
||||
$repository = \Mockery::mock(CampaignRepository::class);
|
||||
$repository->shouldReceive('findByCode')->once()->with($campaign->code)->andReturn($campaign);
|
||||
|
|
|
|||
|
|
@ -27,8 +27,8 @@ use Tests\Fixtures\Coupon\CouponFactory;
|
|||
covers(PublishCampaign::class, PublishCampaignInput::class, CampaignStatusUpdated::class, CampaignNotFound::class);
|
||||
|
||||
describe('update campaign publication use case', function (): void {
|
||||
$campaignCoupon1 = new CampaignCoupon(new CouponCode('COU01'), new PrintRules(maxPerCustomer: 1));
|
||||
$campaignCoupon2 = new CampaignCoupon(new CouponCode('COU02'), new PrintRules(maxPerCustomer: 1));
|
||||
$campaignCoupon1 = new CampaignCoupon(CouponCode::generate(), new PrintRules(maxPerCustomer: 1));
|
||||
$campaignCoupon2 = new CampaignCoupon(CouponCode::generate(), new PrintRules(maxPerCustomer: 1));
|
||||
$existingCampaign = static fn (CampaignCode $code, bool $basePublicationStatus): Campaign => Campaign::hydrate(
|
||||
CampaignId::generate(),
|
||||
$code,
|
||||
|
|
@ -77,9 +77,9 @@ describe('update campaign publication use case', function (): void {
|
|||
$publication = true;
|
||||
$input = new PublishCampaignInput(code: $campaign->code, publication: $publication);
|
||||
$expectedCoupons = [
|
||||
CouponFactory::make('COU01'),
|
||||
CouponFactory::make('COU02'),
|
||||
CouponFactory::expired('COU03'),
|
||||
CouponFactory::make(),
|
||||
CouponFactory::make(),
|
||||
CouponFactory::expired(),
|
||||
];
|
||||
|
||||
$repository = \Mockery::mock(CampaignRepository::class);
|
||||
|
|
@ -130,8 +130,8 @@ describe('update campaign publication use case', function (): void {
|
|||
$publication = true;
|
||||
$input = new PublishCampaignInput(code: $campaign->code, publication: $publication);
|
||||
$expectedCoupons = [
|
||||
CouponFactory::expired('COU01'),
|
||||
CouponFactory::upcoming('COU02'),
|
||||
CouponFactory::expired(),
|
||||
CouponFactory::upcoming(),
|
||||
];
|
||||
|
||||
$repository = \Mockery::mock(CampaignRepository::class);
|
||||
|
|
|
|||
|
|
@ -37,9 +37,9 @@ covers(
|
|||
);
|
||||
|
||||
describe('remove coupons to campaign use case', function (): void {
|
||||
$coupon1 = CouponFactory::make(code: 'COU01');
|
||||
$coupon2 = CouponFactory::make(code: 'COU02');
|
||||
$coupon3 = CouponFactory::make(code: 'COU03');
|
||||
$coupon1 = CouponFactory::make();
|
||||
$coupon2 = CouponFactory::make();
|
||||
$coupon3 = CouponFactory::make();
|
||||
$campaignCoupon1 = new CampaignCoupon($coupon1->code, new PrintRules(maxPerCustomer: 1));
|
||||
$campaignCoupon2 = new CampaignCoupon($coupon2->code, new PrintRules(maxPerCustomer: 1));
|
||||
$campaignCoupon3 = new CampaignCoupon($coupon3->code, new PrintRules(maxPerCustomer: 1));
|
||||
|
|
@ -92,7 +92,7 @@ describe('remove coupons to campaign use case', function (): void {
|
|||
it('returns a specific output when the coupon is not in the campaign', function () use ($existingCampaign): void {
|
||||
// GIVEN
|
||||
$campaign = $existingCampaign(CampaignCode::generate(), true);
|
||||
$coupon = CouponFactory::make(code: 'COU04');
|
||||
$coupon = CouponFactory::make();
|
||||
|
||||
$repository = \Mockery::mock(CampaignRepository::class);
|
||||
$repository->shouldReceive('findByCode')->once()->andReturn($campaign);
|
||||
|
|
@ -164,7 +164,7 @@ describe('remove coupons to campaign use case', function (): void {
|
|||
$couponRepository = \Mockery::mock(CouponRepository::class);
|
||||
$couponRepository->shouldReceive('findByCode')->once()->andReturn(null);
|
||||
|
||||
$input = new RemoveCouponToCampaignInput(code: $campaign->code, couponCode: new CouponCode('ZZZ01'));
|
||||
$input = new RemoveCouponToCampaignInput(code: $campaign->code, couponCode: CouponCode::generate());
|
||||
$useCase = new RemoveCouponToCampaign($repository, $couponRepository);
|
||||
|
||||
// WHEN
|
||||
|
|
|
|||
|
|
@ -0,0 +1,150 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Tests\Unit\Application\UseCases\CampaignRequest\Transform;
|
||||
|
||||
use Application\UseCases\CampaignRequest\Transform\TransformCampaignRequest;
|
||||
use Application\UseCases\CampaignRequest\Transform\Input;
|
||||
use Application\UseCases\CampaignRequest\Transform\Outputs\CampaignRequestTransformed;
|
||||
use Application\UseCases\CampaignRequest\Transform\Outputs\CampaignRequestAlreadyTranformed;
|
||||
use Application\UseCases\CampaignRequest\Transform\Outputs\CampaignRequestNotFound;
|
||||
use DateTime;
|
||||
use Domain\Models\Entities\Campaign;
|
||||
use Domain\Models\Entities\CampaignRequest;
|
||||
use Domain\Models\Entities\Coupon;
|
||||
use Domain\Models\ValueObjects\CampaignRequest\Applicant;
|
||||
use Domain\Models\ValueObjects\CampaignRequest\CampaignRequestStatus;
|
||||
use Domain\Models\ValueObjects\CampaignRequest\CampaignRequestType;
|
||||
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\CouponProductArray;
|
||||
use Domain\Models\ValueObjects\Coupon\CouponValidityInformation;
|
||||
use Domain\Models\ValueObjects\Coupon\CouponValidityInformationArray;
|
||||
use Domain\Models\ValueObjects\IncoCode;
|
||||
use Domain\Models\ValueObjects\MoneyAmount;
|
||||
use Domain\Models\ValueObjects\Period;
|
||||
use Domain\Models\ValueObjects\PicturePath;
|
||||
use Domain\Models\ValueObjects\PrintRules;
|
||||
use Domain\Models\ValueObjects\ProcessingCode;
|
||||
use Domain\Models\ValueObjects\ProcessingCodeArray;
|
||||
use Domain\Models\ValueObjects\RequestedCoupon\RequestedCoupon;
|
||||
use Domain\Models\ValueObjects\RequestedCoupon\RequestedCouponQuantity;
|
||||
use Domain\Ports\Repositories\CampaignRepository;
|
||||
use Domain\Ports\Repositories\CampaignRequestRepository;
|
||||
use Domain\Ports\Repositories\CouponRepository;
|
||||
use Shared\Enums\Country;
|
||||
use Shared\Enums\Currency;
|
||||
use Shared\ValueObjects\Email;
|
||||
use Shared\ValueObjects\Money;
|
||||
use Tests\Fixtures\CampaignRequest\CampaignRequestFactory;
|
||||
|
||||
covers(TransformCampaignRequest::class, Input::class, CampaignRequestTransformed::class);
|
||||
|
||||
describe('transform campaign request use case', function (): void {
|
||||
$brandCode = 'AAA01';
|
||||
$campaignName = 'Name';
|
||||
$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 ProcessingCodeArray([
|
||||
new ProcessingCode('5425003944130', Country::FRANCE),
|
||||
new ProcessingCode('4006381333931', Country::BENELUX),
|
||||
]),
|
||||
couponValidityInformations: new CouponValidityInformationArray([
|
||||
new CouponValidityInformation('FR - validity information.', Country::FRANCE),
|
||||
new CouponValidityInformation('BE - validity information.', Country::BENELUX)
|
||||
]),
|
||||
couponLegalInformations: new CouponLegalInformationArray([
|
||||
new CouponLegalInformation('FR - legal information.', Country::FRANCE),
|
||||
new CouponLegalInformation('BE - legal information.', Country::BENELUX)
|
||||
]),
|
||||
couponProducts: new CouponProductArray([new IncoCode(35784), new IncoCode(15522)]),
|
||||
printRules: new PrintRules(maxPerCustomer: 3)
|
||||
);
|
||||
$existingCampaignRequest = fn (array $overrides = []): CampaignRequest => CampaignRequestFactory::hydrated(
|
||||
status: $overrides['status'] ?? CampaignRequestStatus::CREATED,
|
||||
brandCode: $brandCode,
|
||||
name: $campaignName,
|
||||
applicant: new Applicant('John', 'Doe', new Email('john.doe@example.com')),
|
||||
campaignType: $overrides['campaignType'] ?? CampaignRequestType::CLUB,
|
||||
requestedCoupon: $overrides['coupon'] ?? $requestedCoupon,
|
||||
);
|
||||
|
||||
it('transforms a campaign request to a campaign and a coupon', function () use ($existingCampaignRequest, $campaignName): void {
|
||||
// GIVEN
|
||||
$campaignRequest = $existingCampaignRequest();
|
||||
|
||||
$campaignRequestRepository = \Mockery::mock(CampaignRequestRepository::class);
|
||||
$campaignRequestRepository->shouldReceive('findById')->once()->with($campaignRequest->id)->andReturn($campaignRequest);
|
||||
$campaignRequestRepository->shouldReceive('save')->once()->with(\Mockery::type(CampaignRequest::class));
|
||||
$campaignRepository = \Mockery::mock(CampaignRepository::class);
|
||||
$campaignRepository->shouldReceive('save')->once()->with(\Mockery::type(Campaign::class));
|
||||
$couponRepository = \Mockery::mock(CouponRepository::class);
|
||||
$couponRepository->shouldReceive('save')->once()->with(\Mockery::type(Coupon::class));
|
||||
|
||||
$input = new Input($campaignRequest->id);
|
||||
$useCase = new TransformCampaignRequest($campaignRequestRepository, $campaignRepository, $couponRepository);
|
||||
|
||||
// WHEN
|
||||
$result = $useCase->execute($input);
|
||||
|
||||
// THEN
|
||||
expect($result)->toBeInstanceOf(CampaignRequestTransformed::class)
|
||||
->and($result->campaign->name->value)->toBe($campaignName)
|
||||
->and($result->status)->toBe(CampaignRequestStatus::TRANSFORMED);
|
||||
});
|
||||
|
||||
it('can not tranform a campaign request which has already been transformed', function () use ($existingCampaignRequest): void {
|
||||
// GIVEN
|
||||
$campaignRequest = $existingCampaignRequest(['status' => CampaignRequestStatus::TRANSFORMED]);
|
||||
|
||||
$campaignRequestRepository = \Mockery::mock(CampaignRequestRepository::class);
|
||||
$campaignRequestRepository->shouldReceive('findById')->once()->with($campaignRequest->id)->andReturn($campaignRequest);
|
||||
$campaignRequestRepository->shouldNotReceive('save');
|
||||
$campaignRepository = \Mockery::mock(CampaignRepository::class);
|
||||
$campaignRepository->shouldNotReceive('save');
|
||||
$couponRepository = \Mockery::mock(CouponRepository::class);
|
||||
$couponRepository->shouldNotReceive('save');
|
||||
|
||||
$input = new Input($campaignRequest->id);
|
||||
$useCase = new TransformCampaignRequest($campaignRequestRepository, $campaignRepository, $couponRepository);
|
||||
|
||||
// WHEN
|
||||
$result = $useCase->execute($input);
|
||||
|
||||
// THEN
|
||||
expect($result)->toBeInstanceOf(CampaignRequestAlreadyTranformed::class);
|
||||
});
|
||||
|
||||
it('returns CampaignRequestNotFound when the code is not found', function () use ($existingCampaignRequest): void {
|
||||
// GIVEN
|
||||
$campaignRequest = $existingCampaignRequest(['status' => CampaignRequestStatus::CREATED]);
|
||||
|
||||
$campaignRequestRepository = \Mockery::mock(CampaignRequestRepository::class);
|
||||
$campaignRequestRepository->shouldReceive('findById')->once()->with($campaignRequest->id)->andReturn(null);
|
||||
$campaignRequestRepository->shouldNotReceive('save');
|
||||
$campaignRepository = \Mockery::mock(CampaignRepository::class);
|
||||
$campaignRepository->shouldNotReceive('save');
|
||||
$couponRepository = \Mockery::mock(CouponRepository::class);
|
||||
$couponRepository->shouldNotReceive('save');
|
||||
|
||||
$input = new Input($campaignRequest->id);
|
||||
$useCase = new TransformCampaignRequest($campaignRequestRepository, $campaignRepository, $couponRepository);
|
||||
|
||||
// WHEN
|
||||
$result = $useCase->execute($input);
|
||||
|
||||
// THEN
|
||||
expect($result)->toBeInstanceOf(CampaignRequestNotFound::class);
|
||||
});
|
||||
});
|
||||
|
|
@ -42,7 +42,6 @@ covers(CreateCoupon::class, Input::class, CouponCreated::class, CouponCodeAlread
|
|||
|
||||
describe('create coupon use case', function (): void {
|
||||
$makeInput = fn (array $overrides = []): Input => new Input(...array_merge([
|
||||
'code' => new CouponCode('COU01'),
|
||||
'name' => new CouponName('Coupon name'),
|
||||
'amount' => new MoneyAmount(new Money(Currency::EUR, 100)),
|
||||
'picture' => new CouponPicture(
|
||||
|
|
@ -79,7 +78,7 @@ describe('create coupon use case', function (): void {
|
|||
$brandRepository->shouldReceive('existsByCode')->once()->with($input->brandCode)->andReturn(true);
|
||||
|
||||
$couponRepository = \Mockery::mock(CouponRepository::class);
|
||||
$couponRepository->shouldReceive('existsByCode')->once()->with($input->code)->andReturn(false);
|
||||
$couponRepository->shouldReceive('existsByProcessingCode')->once()->with($input->processingCode->toArray()[0])->andReturn(false);
|
||||
$couponRepository->shouldReceive('save')->once()->with(\Mockery::type(Coupon::class));
|
||||
|
||||
$useCase = new CreateCoupon($couponRepository, $brandRepository);
|
||||
|
|
@ -90,7 +89,7 @@ describe('create coupon use case', function (): void {
|
|||
// THEN
|
||||
expect($result)->toBeInstanceOf(CouponCreated::class)
|
||||
->and($result->id)->toBeInstanceOf(CouponId::class)
|
||||
->and($result->code)->toEqual($input->code)
|
||||
->and($result->code)->toBeInstanceOf(CouponCode::class)
|
||||
->and($result->name)->toEqual($input->name)
|
||||
->and($result->amount)->toEqual($input->amount)
|
||||
->and($result->picture)->toEqual($input->picture)
|
||||
|
|
@ -113,7 +112,7 @@ describe('create coupon use case', function (): void {
|
|||
$brandRepository->shouldReceive('existsByCode')->once()->with($input->brandCode)->andReturn(false);
|
||||
|
||||
$couponRepository = \Mockery::mock(CouponRepository::class);
|
||||
$couponRepository->shouldNotReceive('existsByCode');
|
||||
$couponRepository->shouldNotReceive('existsByProcessingCode');
|
||||
$couponRepository->shouldNotReceive('save');
|
||||
|
||||
$useCase = new CreateCoupon($couponRepository, $brandRepository);
|
||||
|
|
@ -133,7 +132,7 @@ describe('create coupon use case', function (): void {
|
|||
$brandRepository->shouldReceive('existsByCode')->once()->with($input->brandCode)->andReturn(true);
|
||||
|
||||
$couponRepository = \Mockery::mock(CouponRepository::class);
|
||||
$couponRepository->shouldReceive('existsByCode')->once()->with($input->code)->andReturn(true);
|
||||
$couponRepository->shouldReceive('existsByProcessingCode')->once()->with($input->processingCode->toArray()[0])->andReturn(true);
|
||||
$couponRepository->shouldNotReceive('save');
|
||||
|
||||
$useCase = new CreateCoupon($couponRepository, $brandRepository);
|
||||
|
|
@ -157,7 +156,7 @@ describe('create coupon use case', function (): void {
|
|||
$brandRepository->shouldReceive('existsByCode')->once()->andReturn(true);
|
||||
|
||||
$couponRepository = \Mockery::mock(CouponRepository::class);
|
||||
$couponRepository->shouldReceive('existsByCode')->once()->andReturn(false);
|
||||
$couponRepository->shouldReceive('existsByProcessingCode')->once()->andReturn(false);
|
||||
$couponRepository->shouldReceive('save')->once()->with(\Mockery::on(
|
||||
fn (Coupon $saved): bool => $saved->availabilityCalendar === $calendar,
|
||||
));
|
||||
|
|
@ -195,7 +194,7 @@ describe('create coupon use case', function (): void {
|
|||
$brandRepository->shouldReceive('existsByCode')->once()->andReturn(true);
|
||||
|
||||
$couponRepository = \Mockery::mock(CouponRepository::class);
|
||||
$couponRepository->shouldReceive('existsByCode')->once()->andReturn(false);
|
||||
$couponRepository->shouldReceive('existsByProcessingCode')->andReturn(false);
|
||||
$couponRepository->shouldReceive('save')->once()->with(\Mockery::type(Coupon::class));
|
||||
|
||||
$useCase = new CreateCoupon($couponRepository, $brandRepository);
|
||||
|
|
@ -244,7 +243,7 @@ describe('create coupon use case', function (): void {
|
|||
$brandRepository->shouldReceive('existsByCode')->andReturn(true);
|
||||
|
||||
$couponRepository = \Mockery::mock(CouponRepository::class);
|
||||
$couponRepository->shouldReceive('existsByCode')->andReturn(false);
|
||||
$couponRepository->shouldReceive('existsByProcessingCode')->andReturn(false);
|
||||
$couponRepository->shouldNotReceive('save');
|
||||
|
||||
$useCase = new CreateCoupon($couponRepository, $brandRepository);
|
||||
|
|
@ -273,7 +272,7 @@ describe('create coupon use case', function (): void {
|
|||
$brandRepository->shouldReceive('existsByCode')->andReturn(true);
|
||||
|
||||
$couponRepository = \Mockery::mock(CouponRepository::class);
|
||||
$couponRepository->shouldReceive('existsByCode')->andReturn(false);
|
||||
$couponRepository->shouldReceive('existsByProcessingCode')->andReturn(false);
|
||||
$couponRepository->shouldNotReceive('save');
|
||||
|
||||
$useCase = new CreateCoupon($couponRepository, $brandRepository);
|
||||
|
|
@ -285,6 +284,43 @@ describe('create coupon use case', function (): void {
|
|||
expect($action)->toThrow(\DomainException::class, 'A coupon requires validity information for BENELUX.');
|
||||
});
|
||||
|
||||
it('rejects a coupon with an already used processingCode (with 2 locales)', function () use ($makeInput): void {
|
||||
// GIVEN
|
||||
$processingCode = new ProcessingCodeArray([
|
||||
new ProcessingCode('5425003944130', Country::FRANCE),
|
||||
new ProcessingCode('5425003944147', Country::BENELUX),
|
||||
]);
|
||||
$validityInformations = 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),
|
||||
]);
|
||||
$legalInformations = 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),
|
||||
]);
|
||||
$input = $makeInput([
|
||||
'processingCode' => $processingCode,
|
||||
'validityInformations' => $validityInformations,
|
||||
'legalInformations' => $legalInformations,
|
||||
]);
|
||||
|
||||
$brandRepository = \Mockery::mock(BrandRepository::class);
|
||||
$brandRepository->shouldReceive('existsByCode')->once()->with($input->brandCode)->andReturn(true);
|
||||
|
||||
$couponRepository = \Mockery::mock(CouponRepository::class);
|
||||
$couponRepository->shouldReceive('existsByProcessingCode')->with($input->processingCode->toArray()[0])->andReturn(false);
|
||||
$couponRepository->shouldReceive('existsByProcessingCode')->with($input->processingCode->toArray()[1])->andReturn(true);
|
||||
$couponRepository->shouldNotReceive('save');
|
||||
|
||||
$useCase = new CreateCoupon($couponRepository, $brandRepository);
|
||||
|
||||
// WHEN
|
||||
$result = $useCase->execute($input);
|
||||
|
||||
// THEN
|
||||
expect($result)->toBeInstanceOf(CouponCodeAlreadyExists::class);
|
||||
});
|
||||
|
||||
it('rejects two processing codes for the same country', function () use ($makeInput): void {
|
||||
// GIVEN / WHEN
|
||||
$action = fn (): Input => $makeInput([
|
||||
|
|
|
|||
|
|
@ -56,7 +56,6 @@ describe('find coupon use case', function (): void {
|
|||
contact: new Email('contact@example.com'),
|
||||
);
|
||||
$coupon = Coupon::create(
|
||||
code: new CouponCode('COU01'),
|
||||
name: new CouponName('Coupon name'),
|
||||
amount: new MoneyAmount(new Money(Currency::EUR, 100)),
|
||||
picture: new CouponPicture(
|
||||
|
|
@ -144,7 +143,7 @@ describe('find coupon use case', function (): void {
|
|||
|
||||
it('returns CouponNotFound when the code is not found', function (): void {
|
||||
// GIVEN
|
||||
$code = new CouponCode('COU02');
|
||||
$code = CouponCode::generate();
|
||||
|
||||
$couponRepository = \Mockery::mock(CouponRepository::class);
|
||||
$couponRepository->shouldReceive('findByCode')->once()->with($code)->andReturn(null);
|
||||
|
|
|
|||
|
|
@ -46,7 +46,7 @@ covers(ListCoupons::class, Input::class, Output::class, CouponListItem::class);
|
|||
describe('list coupons use case', function (): void {
|
||||
$coupon1 = Coupon::hydrate(
|
||||
id: CouponId::generate(),
|
||||
code: new CouponCode('AAA01'),
|
||||
code: CouponCode::generate(),
|
||||
name: new CouponName('Coupon 1'),
|
||||
amount: new MoneyAmount(new Money(Currency::EUR, 300)),
|
||||
picture: new CouponPicture(
|
||||
|
|
@ -77,7 +77,7 @@ describe('list coupons use case', function (): void {
|
|||
);
|
||||
$coupon2 = Coupon::hydrate(
|
||||
id: CouponId::generate(),
|
||||
code: new CouponCode('BBB02'),
|
||||
code: CouponCode::generate(),
|
||||
name: new CouponName('Coupon 2'),
|
||||
amount: new MoneyAmount(new Money(Currency::EUR, 300)),
|
||||
picture: new CouponPicture(
|
||||
|
|
|
|||
|
|
@ -40,7 +40,7 @@ covers(UpdateCoupon::class, Input::class, CouponUpdated::class, CouponNotFound::
|
|||
describe('update coupon use case', function (): void {
|
||||
$makeCoupon = static fn (): Coupon => Coupon::hydrate(
|
||||
id: CouponId::generate(),
|
||||
code: new CouponCode('COU01'),
|
||||
code: CouponCode::generate(),
|
||||
name: new CouponName('Coupon name'),
|
||||
amount: new MoneyAmount(new Money(Currency::EUR, 100)),
|
||||
picture: new CouponPicture(
|
||||
|
|
@ -115,7 +115,7 @@ describe('update coupon use case', function (): void {
|
|||
|
||||
it('returns CouponNotFound when the coupon does not exist', function (): void {
|
||||
// GIVEN
|
||||
$code = new CouponCode('COU01');
|
||||
$code = CouponCode::generate();
|
||||
$input = new Input(
|
||||
code: $code,
|
||||
picture: new CouponPicture(
|
||||
|
|
@ -180,7 +180,7 @@ describe('update coupon use case', function (): void {
|
|||
|
||||
it('rejects an input with nothing to update', function (): void {
|
||||
// GIVEN
|
||||
$code = new CouponCode('COU01');
|
||||
$code = CouponCode::generate();
|
||||
|
||||
// WHEN
|
||||
$action = fn (): Input => new Input(code: $code);
|
||||
|
|
|
|||
|
|
@ -24,37 +24,21 @@ use Domain\Models\ValueObjects\Campaign\CampaignId;
|
|||
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 Domain\Services\PrintableCoupon\PrintEligibilityChecker;
|
||||
use Ramsey\Uuid\Uuid;
|
||||
use Shared\Enums\Country;
|
||||
use Shared\Enums\Currency;
|
||||
use Shared\Helpers\DatesHelper;
|
||||
use Shared\ValueObjects\Money;
|
||||
use Tests\Fixtures\Coupon\CouponFactory;
|
||||
|
||||
covers(CreatePrintableCoupon::class, Input::class, PrintableCouponCreated::class);
|
||||
|
||||
|
|
@ -62,60 +46,24 @@ describe('create coupon use case', function (): void {
|
|||
$crmCustomerHashcode = new CrmHashcode(Uuid::uuid4());
|
||||
$brandCode = new BrandCode('AAA01');
|
||||
$campaignCode = CampaignCode::generate();
|
||||
$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,
|
||||
);
|
||||
$couponCode = CouponCode::generate();
|
||||
$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(
|
||||
|
||||
$makeCoupon = fn (array $overrides = []): Coupon => CouponFactory::make(
|
||||
diffusionStart: $overrides['diffusionStart'] ?? null,
|
||||
diffusionEnd: $overrides['diffusionEnd'] ?? null,
|
||||
availabilityCalendar: $overrides['availabilityCalendar'] ?? null,
|
||||
brandCode: $brandCode->value,
|
||||
code: $couponCode,
|
||||
);
|
||||
$campaignCoupon = fn (?int $maxPerCustomer = null, ?int $cooldownDays = null): CampaignCoupon => new CampaignCoupon(
|
||||
$couponCode,
|
||||
$printRules($maxPerCustomer, $cooldownDays),
|
||||
);
|
||||
$makeCampaign = fn (?int $maxPerCustomer = null, ?int $cooldownDays = null, $published = true): Campaign => Campaign::hydrate(
|
||||
$makeCampaign = fn (?int $maxPerCustomer = null, ?int $cooldownDays = null, $published = true): Campaign => Campaign::hydrate(
|
||||
id: CampaignId::generate(),
|
||||
code: $campaignCode,
|
||||
name: new CampaignName('Campaign name'),
|
||||
|
|
@ -127,7 +75,7 @@ describe('create coupon use case', function (): void {
|
|||
brandCode: $brandCode,
|
||||
actorId: ActorId::generate(),
|
||||
);
|
||||
$printedCoupon = new PrintedCoupon(
|
||||
$printedCoupon = new PrintedCoupon(
|
||||
id: PrintedCouponId::generate(),
|
||||
marketingCode: new MarketingDirectCode('0000000000001'),
|
||||
printableCode: PrintableCouponCode::generate(),
|
||||
|
|
@ -136,7 +84,7 @@ describe('create coupon use case', function (): void {
|
|||
customer: $crmCustomerHashcode,
|
||||
printedAt: DatesHelper::now(),
|
||||
);
|
||||
$makeInput = fn (Campaign $campaign): Input => new Input(
|
||||
$makeInput = fn (Campaign $campaign): Input => new Input(
|
||||
campaignCode: $campaign->code,
|
||||
couponCode: $couponCode,
|
||||
crmCustomerHashcode: $crmCustomerHashcode,
|
||||
|
|
@ -159,9 +107,7 @@ describe('create coupon use case', function (): void {
|
|||
$printableCouponRepository = \Mockery::mock(PrintableCouponRepository::class);
|
||||
$printableCouponRepository->shouldReceive('save')->once()->with(\Mockery::type(PrintableCoupon::class));
|
||||
|
||||
$printEligibilityChecker = new PrintEligibilityChecker(
|
||||
$printableCouponRepository,
|
||||
);
|
||||
$printEligibilityChecker = new PrintEligibilityChecker($printableCouponRepository);
|
||||
|
||||
$useCase = new CreatePrintableCoupon(
|
||||
$printableCouponRepository,
|
||||
|
|
@ -193,9 +139,7 @@ describe('create coupon use case', function (): void {
|
|||
|
||||
$printableCouponRepository = \Mockery::mock(PrintableCouponRepository::class);
|
||||
|
||||
$printEligibilityChecker = new PrintEligibilityChecker(
|
||||
$printableCouponRepository,
|
||||
);
|
||||
$printEligibilityChecker = new PrintEligibilityChecker($printableCouponRepository);
|
||||
|
||||
$useCase = new CreatePrintableCoupon(
|
||||
$printableCouponRepository,
|
||||
|
|
@ -223,9 +167,7 @@ describe('create coupon use case', function (): void {
|
|||
|
||||
$printableCouponRepository = \Mockery::mock(PrintableCouponRepository::class);
|
||||
|
||||
$printEligibilityChecker = new PrintEligibilityChecker(
|
||||
$printableCouponRepository,
|
||||
);
|
||||
$printEligibilityChecker = new PrintEligibilityChecker($printableCouponRepository);
|
||||
|
||||
$useCase = new CreatePrintableCoupon(
|
||||
$printableCouponRepository,
|
||||
|
|
@ -256,9 +198,7 @@ describe('create coupon use case', function (): void {
|
|||
|
||||
$printableCouponRepository = \Mockery::mock(PrintableCouponRepository::class);
|
||||
|
||||
$printEligibilityChecker = new PrintEligibilityChecker(
|
||||
$printableCouponRepository,
|
||||
);
|
||||
$printEligibilityChecker = new PrintEligibilityChecker($printableCouponRepository);
|
||||
|
||||
$useCase = new CreatePrintableCoupon(
|
||||
$printableCouponRepository,
|
||||
|
|
@ -291,9 +231,7 @@ describe('create coupon use case', function (): void {
|
|||
|
||||
$printableCouponRepository = \Mockery::mock(PrintableCouponRepository::class);
|
||||
|
||||
$printEligibilityChecker = new PrintEligibilityChecker(
|
||||
$printableCouponRepository,
|
||||
);
|
||||
$printEligibilityChecker = new PrintEligibilityChecker($printableCouponRepository);
|
||||
|
||||
$useCase = new CreatePrintableCoupon(
|
||||
$printableCouponRepository,
|
||||
|
|
@ -326,9 +264,7 @@ describe('create coupon use case', function (): void {
|
|||
|
||||
$printableCouponRepository = \Mockery::mock(PrintableCouponRepository::class);
|
||||
|
||||
$printEligibilityChecker = new PrintEligibilityChecker(
|
||||
$printableCouponRepository,
|
||||
);
|
||||
$printEligibilityChecker = new PrintEligibilityChecker($printableCouponRepository);
|
||||
|
||||
$useCase = new CreatePrintableCoupon(
|
||||
$printableCouponRepository,
|
||||
|
|
@ -360,9 +296,7 @@ describe('create coupon use case', function (): void {
|
|||
|
||||
$printableCouponRepository = \Mockery::mock(PrintableCouponRepository::class);
|
||||
|
||||
$printEligibilityChecker = new PrintEligibilityChecker(
|
||||
$printableCouponRepository,
|
||||
);
|
||||
$printEligibilityChecker = new PrintEligibilityChecker($printableCouponRepository);
|
||||
|
||||
$useCase = new CreatePrintableCoupon(
|
||||
$printableCouponRepository,
|
||||
|
|
@ -410,9 +344,7 @@ describe('create coupon use case', function (): void {
|
|||
$printableCouponRepository = \Mockery::mock(PrintableCouponRepository::class);
|
||||
$printableCouponRepository->shouldReceive('save')->once()->with(\Mockery::type(PrintableCoupon::class));
|
||||
|
||||
$printEligibilityChecker = new PrintEligibilityChecker(
|
||||
$printableCouponRepository,
|
||||
);
|
||||
$printEligibilityChecker = new PrintEligibilityChecker($printableCouponRepository);
|
||||
|
||||
$useCase = new CreatePrintableCoupon(
|
||||
$printableCouponRepository,
|
||||
|
|
@ -458,9 +390,7 @@ describe('create coupon use case', function (): void {
|
|||
$crmCustomerHashcode,
|
||||
)->andReturn(5);
|
||||
|
||||
$printEligibilityChecker = new PrintEligibilityChecker(
|
||||
$printableCouponRepository,
|
||||
);
|
||||
$printEligibilityChecker = new PrintEligibilityChecker($printableCouponRepository);
|
||||
|
||||
$useCase = new CreatePrintableCoupon(
|
||||
$printableCouponRepository,
|
||||
|
|
@ -509,9 +439,7 @@ describe('create coupon use case', function (): void {
|
|||
$crmCustomerHashcode,
|
||||
)->andReturn($printedCoupon);
|
||||
|
||||
$printEligibilityChecker = new PrintEligibilityChecker(
|
||||
$printableCouponRepository,
|
||||
);
|
||||
$printEligibilityChecker = new PrintEligibilityChecker($printableCouponRepository);
|
||||
|
||||
$useCase = new CreatePrintableCoupon(
|
||||
$printableCouponRepository,
|
||||
|
|
|
|||
|
|
@ -74,7 +74,6 @@ describe('list printable coupons use case', function (): void {
|
|||
);
|
||||
|
||||
$createCoupon = fn (CouponCode $code, CouponPicture $picture): Coupon => Coupon::create(
|
||||
code: $code,
|
||||
name: new CouponName('Coupon name'),
|
||||
amount: new MoneyAmount(new Money(Currency::EUR, 100)),
|
||||
picture: $picture,
|
||||
|
|
@ -119,7 +118,7 @@ describe('list printable coupons use case', function (): void {
|
|||
// GIVEN
|
||||
$input = $createInput();
|
||||
$picture = $createPicture('picture');
|
||||
$couponCode = new CouponCode('AAA01');
|
||||
$couponCode = CouponCode::generate();
|
||||
$printable = $createPrintableCoupon($couponCode);
|
||||
$coupon = $createCoupon($couponCode, $picture);
|
||||
|
||||
|
|
@ -167,8 +166,8 @@ describe('list printable coupons use case', function (): void {
|
|||
);
|
||||
$input = $createInput($sortCriteria);
|
||||
|
||||
$code1 = new CouponCode('AAA01');
|
||||
$code2 = new CouponCode('BBB02');
|
||||
$code1 = CouponCode::generate();
|
||||
$code2 = CouponCode::generate();
|
||||
$picture1 = $createPicture('picture-1');
|
||||
$picture2 = $createPicture('picture-2');
|
||||
|
||||
|
|
@ -232,7 +231,7 @@ describe('list printable coupons use case', function (): void {
|
|||
// GIVEN
|
||||
$input = $createInput();
|
||||
$picture = $createPicture('picture');
|
||||
$couponCode = new CouponCode('AAA01');
|
||||
$couponCode = CouponCode::generate();
|
||||
$items = [$createPrintableCoupon($couponCode), $createPrintableCoupon($couponCode)];
|
||||
|
||||
$repository = \Mockery::mock(PrintableCouponRepository::class);
|
||||
|
|
@ -257,7 +256,7 @@ describe('list printable coupons use case', function (): void {
|
|||
it('throws when the coupon of a printable coupon does not exist', function () use ($createInput, $createPrintableCoupon): void {
|
||||
// GIVEN
|
||||
$input = $createInput();
|
||||
$printable = $createPrintableCoupon(new CouponCode('BBB02'));
|
||||
$printable = $createPrintableCoupon(CouponCode::generate());
|
||||
|
||||
$repository = \Mockery::mock(PrintableCouponRepository::class);
|
||||
$repository->shouldReceive('findAllAvailable')
|
||||
|
|
|
|||
|
|
@ -33,6 +33,7 @@ use Domain\Models\ValueObjects\PicturePath;
|
|||
use Domain\Models\ValueObjects\PrintRules;
|
||||
use Domain\Models\ValueObjects\ProcessingCode;
|
||||
use Domain\Models\ValueObjects\ProcessingCodeArray;
|
||||
use Ramsey\Uuid\Uuid;
|
||||
use Shared\Enums\Country;
|
||||
use Shared\Enums\Currency;
|
||||
use Shared\ValueObjects\Money;
|
||||
|
|
@ -47,19 +48,17 @@ describe('campaign', function (): void {
|
|||
$printAllAtOnce = \boolval(1);
|
||||
$coupons = new CampaignCouponArray([
|
||||
new CampaignCoupon(
|
||||
new CouponCode('AAA01'),
|
||||
CouponCode::generate(),
|
||||
new PrintRules(maxPerCustomer: 3)
|
||||
)
|
||||
]);
|
||||
$brandCode = new BrandCode('AAA01');
|
||||
$actorId = ActorId::generate();
|
||||
|
||||
$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(
|
||||
|
|
@ -109,7 +108,7 @@ describe('campaign', function (): void {
|
|||
$name = new CampaignName('Name');
|
||||
$coupons = new CampaignCouponArray([
|
||||
new CampaignCoupon(
|
||||
new CouponCode('AAA01'),
|
||||
CouponCode::generate(),
|
||||
new PrintRules(maxPerCustomer: 3)
|
||||
)
|
||||
]);
|
||||
|
|
@ -173,10 +172,13 @@ describe('campaign', function (): void {
|
|||
$actorId,
|
||||
): void {
|
||||
// GIVEN
|
||||
$expected = new \DateTimeImmutable('now', new \DateTimeZone('UTC'));
|
||||
|
||||
$campaign = Campaign::create(
|
||||
$expected = new \DateTimeImmutable('2024-06-15 12:34:56.789000', new \DateTimeZone('UTC'));
|
||||
$id = new CampaignId(Uuid::uuid7($expected));
|
||||
$campaign = Campaign::hydrate(
|
||||
$id,
|
||||
CampaignCode::generate(),
|
||||
$name,
|
||||
false,
|
||||
$printAllAtOnce,
|
||||
$coupons,
|
||||
$brandCode,
|
||||
|
|
@ -371,8 +373,10 @@ describe('campaign', function (): void {
|
|||
|
||||
it('gets the codes of the associated coupons', function (): void {
|
||||
// GIVEN
|
||||
$expectedCoupons = ['COU01', 'COU02'];
|
||||
$campaign = CampaignFactory::hydrated(couponCodes: $expectedCoupons);
|
||||
$couponCode1 = CouponCode::generate();
|
||||
$couponCode2 = CouponCode::generate();
|
||||
$expectedCoupons = [$couponCode1->value, $couponCode2->value];
|
||||
$campaign = CampaignFactory::hydrated(couponCodes: [$couponCode1, $couponCode2]);
|
||||
|
||||
// WHEN
|
||||
$coupons = array_map(static fn (CouponCode $c): string => $c->value, $campaign->couponCodes());
|
||||
|
|
@ -429,7 +433,7 @@ describe('campaign', function (): void {
|
|||
// GIVEN
|
||||
CarbonImmutable::setTestNow('2026-06-15 16:45:00 UTC');
|
||||
$id = CampaignId::generate();
|
||||
$couponCode = new CouponCode('COU09');
|
||||
$couponCode = CouponCode::generate();
|
||||
$campaign = Campaign::hydrate(
|
||||
$id,
|
||||
$code,
|
||||
|
|
|
|||
|
|
@ -37,7 +37,7 @@ use Shared\ValueObjects\Money;
|
|||
covers(Coupon::class);
|
||||
|
||||
describe('coupon', function (): void {
|
||||
$code = new CouponCode('AAA01');
|
||||
$code = CouponCode::generate();
|
||||
$name = new CouponName('Name');
|
||||
$amount = new MoneyAmount(new Money(Currency::EUR, 1));
|
||||
$picture = new CouponPicture(
|
||||
|
|
@ -288,7 +288,6 @@ describe('coupon', function (): void {
|
|||
});
|
||||
|
||||
it('creates a new coupon with a freshly generated id', function () use (
|
||||
$code,
|
||||
$name,
|
||||
$amount,
|
||||
$picture,
|
||||
|
|
@ -304,7 +303,6 @@ describe('coupon', function (): void {
|
|||
): void {
|
||||
// GIVEN / WHEN
|
||||
$coupon = Coupon::create(
|
||||
code: $code,
|
||||
name: $name,
|
||||
amount: $amount,
|
||||
picture: $picture,
|
||||
|
|
@ -321,7 +319,6 @@ describe('coupon', function (): void {
|
|||
|
||||
// THEN
|
||||
expect($coupon->id())->toBeInstanceOf(CouponId::class)
|
||||
->and($coupon->code)->toBe($code)
|
||||
->and($coupon->name)->toBe($name)
|
||||
->and($coupon->amount)->toBe($amount)
|
||||
->and($coupon->picture)->toBe($picture)
|
||||
|
|
@ -339,7 +336,6 @@ describe('coupon', function (): void {
|
|||
});
|
||||
|
||||
it('generates a different id for each created coupon', function () use (
|
||||
$code,
|
||||
$name,
|
||||
$amount,
|
||||
$picture,
|
||||
|
|
@ -355,7 +351,6 @@ describe('coupon', function (): void {
|
|||
): void {
|
||||
// GIVEN / WHEN
|
||||
$firstCoupon = Coupon::create(
|
||||
code: $code,
|
||||
name: $name,
|
||||
amount: $amount,
|
||||
picture: $picture,
|
||||
|
|
@ -370,7 +365,6 @@ describe('coupon', function (): void {
|
|||
availabilityCalendar: $availabilityCalendar,
|
||||
);
|
||||
$secondCoupon = Coupon::create(
|
||||
code: $code,
|
||||
name: $name,
|
||||
amount: $amount,
|
||||
picture: $picture,
|
||||
|
|
@ -432,7 +426,6 @@ describe('coupon', function (): void {
|
|||
});
|
||||
|
||||
it('computes the quantity from its movements', function () use (
|
||||
$code,
|
||||
$name,
|
||||
$amount,
|
||||
$picture,
|
||||
|
|
@ -446,7 +439,6 @@ describe('coupon', function (): void {
|
|||
): void {
|
||||
// GIVEN
|
||||
$coupon = Coupon::create(
|
||||
code: $code,
|
||||
name: $name,
|
||||
amount: $amount,
|
||||
picture: $picture,
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ covers(PrintableCoupon::class);
|
|||
|
||||
describe('printable coupon', function (): void {
|
||||
$campaignCode = CampaignCode::generate();
|
||||
$couponCode = new CouponCode('AAA01');
|
||||
$couponCode = CouponCode::generate();
|
||||
$couponName = new CouponName('Coupon name');
|
||||
$crmCustomerHashcode = new CrmHashcode(Uuid::uuid4());
|
||||
$distributableUntil = new \DateTimeImmutable('2027-01-01');
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ covers(Stock::class);
|
|||
describe('stock', function (): void {
|
||||
$stockAmount = new StockAmount(10);
|
||||
$campaignCode = CampaignCode::generate();
|
||||
$couponCode = new CouponCode('AAA01');
|
||||
$couponCode = CouponCode::generate();
|
||||
$stockAdjustment = [new StockAdjustment(5, 'Inventory correction', ActorId::generate())];
|
||||
|
||||
it('hydrates a stock', function () use ($stockAmount, $campaignCode, $couponCode, $stockAdjustment): void {
|
||||
|
|
|
|||
|
|
@ -13,12 +13,12 @@ covers(CampaignCouponArray::class);
|
|||
|
||||
describe('campaign coupon array', function (): void {
|
||||
$coupon = new CampaignCoupon(
|
||||
new CouponCode('AAA01'),
|
||||
CouponCode::generate(),
|
||||
new PrintRules(maxPerCustomer: 3),
|
||||
);
|
||||
|
||||
$coupon2 = new CampaignCoupon(
|
||||
new CouponCode('AAA02'),
|
||||
CouponCode::generate(),
|
||||
new PrintRules(maxPerCustomer: 3),
|
||||
);
|
||||
|
||||
|
|
@ -69,28 +69,32 @@ describe('campaign coupon array', function (): void {
|
|||
|
||||
it('rejects the same coupon twice at initialisation', function (): void {
|
||||
// GIVEN
|
||||
$coupons = [
|
||||
new CampaignCoupon(new CouponCode('AAA01')),
|
||||
new CampaignCoupon(new CouponCode('AAA01')),
|
||||
$couponCode = CouponCode::generate();
|
||||
$coupons = [
|
||||
new CampaignCoupon($couponCode),
|
||||
new CampaignCoupon($couponCode),
|
||||
];
|
||||
|
||||
// WHEN
|
||||
$action = fn (): CampaignCouponArray => new CampaignCouponArray($coupons);
|
||||
|
||||
//WHEN / THEN
|
||||
expect($action)->toThrow(\DomainException::class, '"AAA01" is present more than once.');
|
||||
expect($action)->toThrow(\DomainException::class, sprintf(
|
||||
'"%s" is present more than once.',
|
||||
$couponCode
|
||||
));
|
||||
});
|
||||
|
||||
it('adds a coupon to a campaign coupon array', function (): void {
|
||||
// GIVEN
|
||||
$coupons = [
|
||||
new CampaignCoupon(new CouponCode('AAA01')),
|
||||
new CampaignCoupon(new CouponCode('AAA02')),
|
||||
new CampaignCoupon(CouponCode::generate()),
|
||||
new CampaignCoupon(CouponCode::generate()),
|
||||
];
|
||||
$array = new CampaignCouponArray($coupons);
|
||||
|
||||
// WHEN
|
||||
$array = $array->addCoupon(new CampaignCoupon(new CouponCode('AAA03')));
|
||||
$array = $array->addCoupon(new CampaignCoupon(CouponCode::generate()));
|
||||
|
||||
// THEN
|
||||
expect($array->toArray())->toHaveCount(3);
|
||||
|
|
@ -110,17 +114,21 @@ describe('campaign coupon array', function (): void {
|
|||
|
||||
it('cant remove a coupon which is not on the campaign', function (): void {
|
||||
// GIVEN
|
||||
$coupons = [
|
||||
new CampaignCoupon(new CouponCode('AAA01')),
|
||||
new CampaignCoupon(new CouponCode('AAA02')),
|
||||
$coupons = [
|
||||
new CampaignCoupon(CouponCode::generate()),
|
||||
new CampaignCoupon(CouponCode::generate()),
|
||||
];
|
||||
$array = new CampaignCouponArray($coupons);
|
||||
$array = new CampaignCouponArray($coupons);
|
||||
$couponCodeToRemove = CouponCode::generate();
|
||||
|
||||
// WHEN
|
||||
$action = fn () => $array->removeCoupon(new CouponCode('AAA03'));
|
||||
$action = fn () => $array->removeCoupon($couponCodeToRemove);
|
||||
|
||||
// THEN
|
||||
expect($action)->toThrow(\DomainException::class, '"AAA03" is not in the set.');
|
||||
expect($action)->toThrow(\DomainException::class, sprintf(
|
||||
'"%s" is not in the set.',
|
||||
$couponCodeToRemove
|
||||
));
|
||||
});
|
||||
|
||||
it('returns all coupon codes', function () use ($coupon, $coupon2): void {
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ use Domain\Models\ValueObjects\PrintRules;
|
|||
covers(CampaignCoupon::class);
|
||||
|
||||
describe('campaign coupon', function (): void {
|
||||
$couponCode = new CouponCode('AAA01');
|
||||
$couponCode = CouponCode::generate();
|
||||
$printRules = new PrintRules(maxPerCustomer: 3);
|
||||
|
||||
it('creates a valid campaign coupon', function () use ($couponCode, $printRules): void {
|
||||
|
|
@ -45,7 +45,7 @@ describe('campaign coupon', function (): void {
|
|||
|
||||
// WHEN
|
||||
$result = $campaignCoupon->hasCouponCode(
|
||||
new CouponCode('AAA01'),
|
||||
$couponCode,
|
||||
);
|
||||
|
||||
// THEN
|
||||
|
|
@ -61,7 +61,7 @@ describe('campaign coupon', function (): void {
|
|||
|
||||
// WHEN
|
||||
$result = $campaignCoupon->hasCouponCode(
|
||||
new CouponCode('BBB02'),
|
||||
CouponCode::generate(),
|
||||
);
|
||||
|
||||
// THEN
|
||||
|
|
|
|||
|
|
@ -5,71 +5,43 @@ declare(strict_types=1);
|
|||
namespace Tests\Unit\Domain\Models\ValueObjects\Coupon;
|
||||
|
||||
use Domain\Models\ValueObjects\Coupon\CouponCode;
|
||||
use Ramsey\Uuid\Uuid;
|
||||
|
||||
covers(CouponCode::class);
|
||||
|
||||
describe('coupon code', function (): void {
|
||||
it('creates a valid coupon code', function (): void {
|
||||
// GIVEN
|
||||
$value = 'AAA01';
|
||||
|
||||
// WHEN
|
||||
$code = new CouponCode($value);
|
||||
it('generates a valid uuid v7 code', function (): void {
|
||||
// GIVEN / WHEN
|
||||
$code = CouponCode::generate();
|
||||
|
||||
// THEN
|
||||
expect($code)->toBeInstanceOf(CouponCode::class)
|
||||
->and($code->value)->toBe($value);
|
||||
expect(Uuid::isValid($code->value))->toBeTrue()
|
||||
->and(Uuid::fromString($code->value)->getVersion())->toBe(7);
|
||||
});
|
||||
|
||||
it('generates a different code each time', function (): void {
|
||||
// GIVEN / WHEN
|
||||
$first = CouponCode::generate();
|
||||
$second = CouponCode::generate();
|
||||
|
||||
// THEN
|
||||
expect($first->value)->not->toBe($second->value);
|
||||
});
|
||||
|
||||
it('wraps a given uuid v7', function (): void {
|
||||
// GIVEN
|
||||
$uuid = Uuid::uuid7();
|
||||
|
||||
// WHEN
|
||||
$code = new CouponCode($uuid);
|
||||
|
||||
// THEN
|
||||
expect($code->value)->toBe($uuid->toString());
|
||||
});
|
||||
|
||||
it('rejects a uuid that is not v7', function (): void {
|
||||
// GIVEN / WHEN / THEN
|
||||
expect(fn (): CouponCode => new CouponCode(Uuid::uuid4()))
|
||||
->toThrow(\DomainException::class);
|
||||
});
|
||||
});
|
||||
|
||||
describe('coupon code validation rules', function (): void {
|
||||
it('rejects invalid coupon codes', function (string $invalid): void {
|
||||
// WHEN / THEN
|
||||
expect(fn (): CouponCode => new CouponCode($invalid))->toThrow(\DomainException::class);
|
||||
|
||||
// GIVEN
|
||||
})->with([
|
||||
// rejects empty strings
|
||||
'',
|
||||
' ',
|
||||
"\t",
|
||||
"\n",
|
||||
// rejects numbers only
|
||||
'12345',
|
||||
'67890',
|
||||
// rejects letters only
|
||||
'ABCDE',
|
||||
'FGHIJ',
|
||||
// rejects codes with special characters
|
||||
'AB@12',
|
||||
'CD#34',
|
||||
'EF$56',
|
||||
// rejects codes that have the same digit repeated
|
||||
'ABC11',
|
||||
'DEF22',
|
||||
'GHI33',
|
||||
// rejects codes with lowercase letters
|
||||
'AbC12',
|
||||
'dEf34',
|
||||
'GhI56',
|
||||
]);
|
||||
|
||||
it('rejects codes with more/less than 3 letters or more/less than 2 digits', function (string $invalid): void {
|
||||
// WHEN / THEN
|
||||
expect(fn (): CouponCode => new CouponCode($invalid))->toThrow(\DomainException::class);
|
||||
|
||||
// GIVEN
|
||||
})->with([
|
||||
'ABCD12',
|
||||
'ABC123',
|
||||
'ABCDE123',
|
||||
'AB12',
|
||||
'A1',
|
||||
'AB1',
|
||||
'A12',
|
||||
'AB123',
|
||||
'A123',
|
||||
'ABC1',
|
||||
'AB12C',
|
||||
]);
|
||||
});
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ covers(PrintedCoupon::class);
|
|||
describe('printed coupon', function (): void {
|
||||
$printableCode = PrintableCouponCode::generate();
|
||||
$marketingCode = new MarketingDirectCode('0000000000001');
|
||||
$couponCode = new CouponCode('AAA01');
|
||||
$couponCode = CouponCode::generate();
|
||||
$campaignCode = CampaignCode::generate();
|
||||
$customer = new CrmHashcode(Uuid::uuid4());
|
||||
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ covers(UnprintedCoupon::class);
|
|||
|
||||
describe('unprinted coupon', function (): void {
|
||||
$printableCode = PrintableCouponCode::generate();
|
||||
$couponCode = new CouponCode('AAA01');
|
||||
$couponCode = CouponCode::generate();
|
||||
$campaignCode = CampaignCode::generate();
|
||||
$customer = new CrmHashcode(Uuid::uuid4());
|
||||
|
||||
|
|
|
|||
|
|
@ -12,25 +12,16 @@ use Tests\Fixtures\Coupon\CouponFactory;
|
|||
covers(CampaignAvailabilityChecker::class);
|
||||
|
||||
describe('campaign availability checker', function (): void {
|
||||
$makeRepository = static function (array $campaignCodes, array $coupons): CouponRepository {
|
||||
it('is available with an active coupon', function (): void {
|
||||
// GIVEN
|
||||
$coupon = CouponFactory::make();
|
||||
$campaign = CampaignFactory::hydrated(couponCodes: [$coupon->code]);
|
||||
|
||||
$repository = \Mockery::mock(CouponRepository::class);
|
||||
$repository->shouldReceive('findByCodes')
|
||||
->once()
|
||||
->with(\Mockery::on(
|
||||
static fn (array $codes): bool => array_map(
|
||||
static fn ($code): string => $code->value,
|
||||
$codes,
|
||||
) === $campaignCodes,
|
||||
))
|
||||
->andReturn($coupons);
|
||||
$repository->shouldReceive('findByCodes')->once()->with($campaign->couponCodes())->andReturn([
|
||||
$coupon
|
||||
]);
|
||||
|
||||
return $repository;
|
||||
};
|
||||
|
||||
it('is available with an active coupon', function () use ($makeRepository): void {
|
||||
// GIVEN
|
||||
$campaign = CampaignFactory::hydrated(couponCodes: ['COU01']);
|
||||
$repository = $makeRepository(['COU01'], [CouponFactory::make('COU01')]);
|
||||
$service = new CampaignAvailabilityChecker($repository);
|
||||
|
||||
// WHEN
|
||||
|
|
@ -40,14 +31,19 @@ describe('campaign availability checker', function (): void {
|
|||
expect($result)->toBeTrue();
|
||||
});
|
||||
|
||||
it('is available with one active and one expired coupon', function () use ($makeRepository): void {
|
||||
it('is available with one active and one expired coupon', function (): void {
|
||||
// GIVEN
|
||||
$campaign = CampaignFactory::hydrated(couponCodes: ['COU01', 'COU02']);
|
||||
$repository = $makeRepository(['COU01', 'COU02'], [
|
||||
CouponFactory::expired('COU01'),
|
||||
CouponFactory::make('COU02'),
|
||||
$expiredCoupon = CouponFactory::expired();
|
||||
$validCoupon = CouponFactory::make();
|
||||
$campaign = CampaignFactory::hydrated(couponCodes: [$expiredCoupon->code, $validCoupon->code]);
|
||||
|
||||
$repository = \Mockery::mock(CouponRepository::class);
|
||||
$repository->shouldReceive('findByCodes')->once()->with($campaign->couponCodes())->andReturn([
|
||||
$expiredCoupon,
|
||||
$validCoupon
|
||||
]);
|
||||
$service = new CampaignAvailabilityChecker($repository);
|
||||
|
||||
$service = new CampaignAvailabilityChecker($repository);
|
||||
|
||||
// WHEN
|
||||
$result = $service->hasActiveCoupon($campaign);
|
||||
|
|
@ -56,14 +52,19 @@ describe('campaign availability checker', function (): void {
|
|||
expect($result)->toBeTrue();
|
||||
});
|
||||
|
||||
it('is not available when every coupon is expired or upcoming', function () use ($makeRepository): void {
|
||||
it('is not available when every coupon is expired or upcoming', function (): void {
|
||||
// GIVEN
|
||||
$campaign = CampaignFactory::hydrated(couponCodes: ['COU01', 'COU02']);
|
||||
$repository = $makeRepository(['COU01', 'COU02'], [
|
||||
CouponFactory::expired('COU01'),
|
||||
CouponFactory::upcoming('COU02'),
|
||||
$expiredCoupon = CouponFactory::expired();
|
||||
$upcomingCoupon = CouponFactory::upcoming();
|
||||
$campaign = CampaignFactory::hydrated(couponCodes: [$expiredCoupon->code, $upcomingCoupon->code]);
|
||||
|
||||
$repository = \Mockery::mock(CouponRepository::class);
|
||||
$repository->shouldReceive('findByCodes')->once()->with($campaign->couponCodes())->andReturn([
|
||||
$expiredCoupon,
|
||||
$upcomingCoupon
|
||||
]);
|
||||
$service = new CampaignAvailabilityChecker($repository);
|
||||
|
||||
$service = new CampaignAvailabilityChecker($repository);
|
||||
|
||||
// WHEN
|
||||
$result = $service->hasActiveCoupon($campaign);
|
||||
|
|
@ -72,11 +73,14 @@ describe('campaign availability checker', function (): void {
|
|||
expect($result)->toBeFalse();
|
||||
});
|
||||
|
||||
it('is not available when no coupon is found', function () use ($makeRepository): void {
|
||||
it('is not available when no coupon is found', function (): void {
|
||||
// GIVEN
|
||||
$campaign = CampaignFactory::hydrated(couponCodes: ['COU01']);
|
||||
$repository = $makeRepository(['COU01'], []);
|
||||
$service = new CampaignAvailabilityChecker($repository);
|
||||
$campaign = CampaignFactory::hydrated();
|
||||
|
||||
$repository = \Mockery::mock(CouponRepository::class);
|
||||
$repository->shouldReceive('findByCodes')->once()->with($campaign->couponCodes())->andReturn([]);
|
||||
|
||||
$service = new CampaignAvailabilityChecker($repository);
|
||||
|
||||
// WHEN
|
||||
$result = $service->hasActiveCoupon($campaign);
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue