Merge branch 'update-coupon-info' into 'coupon'
feat: ✨ update legal and validity information of a coupon
See merge request ldc-web/projets/mesbr!64
This commit is contained in:
commit
7c8708496a
11 changed files with 116 additions and 1 deletions
|
|
@ -5,7 +5,9 @@ declare(strict_types=1);
|
|||
namespace Application\UseCases\Coupon\Update;
|
||||
|
||||
use Domain\Models\ValueObjects\Coupon\CouponCode;
|
||||
use Domain\Models\ValueObjects\Coupon\CouponLegalInformationArray;
|
||||
use Domain\Models\ValueObjects\Coupon\CouponPicture;
|
||||
use Domain\Models\ValueObjects\Coupon\CouponValidityInformationArray;
|
||||
use Shared\DDD\UseCases\Input as UseCaseInput;
|
||||
use Webmozart\Assert\Assert;
|
||||
|
||||
|
|
@ -14,9 +16,13 @@ final readonly class Input implements UseCaseInput
|
|||
public function __construct(
|
||||
public CouponCode $code,
|
||||
public ?CouponPicture $picture = null,
|
||||
public ?CouponValidityInformationArray $validityInformations = null,
|
||||
public ?CouponLegalInformationArray $legalInformations = null,
|
||||
) {
|
||||
Assert::true(
|
||||
$this->picture instanceof CouponPicture,
|
||||
$this->picture instanceof CouponPicture
|
||||
|| $this->validityInformations instanceof CouponValidityInformationArray
|
||||
|| $this->legalInformations instanceof CouponLegalInformationArray,
|
||||
'At least one field must be provided to update the coupon.',
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,7 +8,9 @@ use Application\UseCases\Coupon\Update\Output\CouponNotFound;
|
|||
use Application\UseCases\Coupon\Update\Output\CouponUpdated;
|
||||
use Application\UseCases\Coupon\Update\Output\Output;
|
||||
use Domain\Models\Entities\Coupon;
|
||||
use Domain\Models\ValueObjects\Coupon\CouponLegalInformationArray;
|
||||
use Domain\Models\ValueObjects\Coupon\CouponPicture;
|
||||
use Domain\Models\ValueObjects\Coupon\CouponValidityInformationArray;
|
||||
use Domain\Ports\Repositories\CouponRepository;
|
||||
use Shared\DDD\UseCases\Input as BaseInput;
|
||||
use Shared\DDD\UseCases\Transactional;
|
||||
|
|
@ -38,6 +40,16 @@ final readonly class UpdateCoupon implements UseCase, Transactional
|
|||
$coupon = $coupon->changePicture($input->picture);
|
||||
}
|
||||
|
||||
if (
|
||||
$input->validityInformations instanceof CouponValidityInformationArray
|
||||
|| $input->legalInformations instanceof CouponLegalInformationArray
|
||||
) {
|
||||
$coupon = $coupon->changeInformations(
|
||||
$input->validityInformations ?? $coupon->validityInformations,
|
||||
$input->legalInformations ?? $coupon->legalInformations,
|
||||
);
|
||||
}
|
||||
|
||||
$this->repository->save($coupon);
|
||||
|
||||
return new CouponUpdated(
|
||||
|
|
|
|||
|
|
@ -165,4 +165,26 @@ final readonly class Coupon implements AggregateRoot, HasTimestampIdentifier
|
|||
updatedAt: DatesHelper::now(),
|
||||
);
|
||||
}
|
||||
|
||||
public function changeInformations(CouponValidityInformationArray $validityInformations, CouponLegalInformationArray $legalInformations): self
|
||||
{
|
||||
return new self(
|
||||
id: $this->id,
|
||||
code: $this->code,
|
||||
name: $this->name,
|
||||
amount: $this->amount,
|
||||
picture: $this->picture,
|
||||
diffusion: $this->diffusion,
|
||||
validityInformations: $validityInformations,
|
||||
legalInformations: $legalInformations,
|
||||
processingCode: $this->processingCode,
|
||||
brandCode: $this->brandCode,
|
||||
createdBy: $this->createdBy,
|
||||
products: $this->products,
|
||||
movements: $this->movements,
|
||||
quantity: $this->quantity,
|
||||
availabilityCalendar: $this->availabilityCalendar,
|
||||
updatedAt: DatesHelper::now(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -29,6 +29,9 @@ final readonly class CouponCountryCoverage
|
|||
throw new \DomainException(sprintf('A coupon requires legal information for %s.', $country->name));
|
||||
}
|
||||
}
|
||||
|
||||
self::countDiffusionCountries($validityInformations, $processingCodes);
|
||||
self::countDiffusionCountries($legalInformations, $processingCodes);
|
||||
}
|
||||
|
||||
private static function hasInformationFor(
|
||||
|
|
@ -40,4 +43,13 @@ final readonly class CouponCountryCoverage
|
|||
fn (CouponValidityInformation | CouponLegalInformation $information): bool => $information->forLocale === $country,
|
||||
);
|
||||
}
|
||||
|
||||
private static function countDiffusionCountries(
|
||||
CouponValidityInformationArray | CouponLegalInformationArray $informations,
|
||||
ProcessingCodeArray $processingCodes,
|
||||
): void {
|
||||
if (count($informations->value) !== count($processingCodes->value)) {
|
||||
throw new \DomainException('A coupon requires exactly one information per diffusion country.');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -57,6 +57,7 @@ describe('create campaign request use case', function (): void {
|
|||
),
|
||||
couponProcessingCodes: new ProcessingCodeArray([
|
||||
new ProcessingCode('5425003944130', Country::FRANCE),
|
||||
new ProcessingCode('4006381333931', Country::BENELUX),
|
||||
]),
|
||||
couponValidityInformations: new CouponValidityInformationArray([
|
||||
new CouponValidityInformation('Lorem ipsum dolor sit amet consectetur adipiscing elit.', Country::FRANCE),
|
||||
|
|
|
|||
|
|
@ -61,6 +61,7 @@ describe('find campaign request use case', function (): void {
|
|||
),
|
||||
couponProcessingCodes: new ProcessingCodeArray([
|
||||
new ProcessingCode('5425003944130', Country::FRANCE),
|
||||
new ProcessingCode('4006381333931', Country::BENELUX),
|
||||
]),
|
||||
couponValidityInformations: new CouponValidityInformationArray([
|
||||
new CouponValidityInformation('Lorem ipsum dolor sit amet consectetur adipiscing elit.', Country::FRANCE),
|
||||
|
|
|
|||
|
|
@ -55,6 +55,7 @@ describe('list campaigns request use case', function (): void {
|
|||
),
|
||||
couponProcessingCodes: new ProcessingCodeArray([
|
||||
new ProcessingCode('5425003944130', Country::FRANCE),
|
||||
new ProcessingCode('4006381333931', Country::BENELUX),
|
||||
]),
|
||||
couponValidityInformations: new CouponValidityInformationArray([
|
||||
new CouponValidityInformation('Lorem ipsum dolor sit amet consectetur adipiscing elit.', Country::FRANCE),
|
||||
|
|
@ -80,6 +81,7 @@ describe('list campaigns request use case', function (): void {
|
|||
),
|
||||
couponProcessingCodes: new ProcessingCodeArray([
|
||||
new ProcessingCode('5425003944130', Country::FRANCE),
|
||||
new ProcessingCode('4006381333931', Country::BENELUX),
|
||||
]),
|
||||
couponValidityInformations: new CouponValidityInformationArray([
|
||||
new CouponValidityInformation('Lorem ipsum dolor sit amet consectetur adipiscing elit.', Country::FRANCE),
|
||||
|
|
|
|||
|
|
@ -56,6 +56,7 @@ describe('reject campaign request use case', function (): void {
|
|||
),
|
||||
couponProcessingCodes: new ProcessingCodeArray([
|
||||
new ProcessingCode('5425003944130', Country::FRANCE),
|
||||
new ProcessingCode('4006381333931', Country::BENELUX),
|
||||
]),
|
||||
couponValidityInformations: new CouponValidityInformationArray([
|
||||
new CouponValidityInformation('Lorem ipsum dolor sit amet consectetur adipiscing elit.', Country::FRANCE),
|
||||
|
|
|
|||
|
|
@ -142,6 +142,46 @@ describe('update coupon use case', function (): void {
|
|||
expect($result)->toBeInstanceOf(CouponNotFound::class);
|
||||
});
|
||||
|
||||
it('updates the legal and validity information and keeps the other fields', function () use ($makeCoupon): void {
|
||||
// GIVEN
|
||||
$coupon = $makeCoupon();
|
||||
$newValidityInformations = new CouponValidityInformationArray([
|
||||
new CouponValidityInformation('New validity information.', Country::FRANCE),
|
||||
]);
|
||||
$newLegalInformations = new CouponLegalInformationArray([
|
||||
new CouponLegalInformation('New legal information.', Country::FRANCE),
|
||||
]);
|
||||
$input = new Input(
|
||||
code: $coupon->code,
|
||||
validityInformations: $newValidityInformations,
|
||||
legalInformations: $newLegalInformations,
|
||||
);
|
||||
|
||||
$repository = \Mockery::mock(CouponRepository::class);
|
||||
$repository->shouldReceive('findByCode')->once()->with($coupon->code)->andReturn($coupon);
|
||||
$repository->shouldReceive('save')->once()->with(\Mockery::on(
|
||||
fn (Coupon $saved): bool => $saved->validityInformations === $newValidityInformations
|
||||
&& $saved->legalInformations === $newLegalInformations
|
||||
&& $saved->id === $coupon->id
|
||||
&& $saved->name === $coupon->name
|
||||
&& $saved->amount === $coupon->amount
|
||||
&& $saved->picture === $coupon->picture
|
||||
&& $saved->diffusion === $coupon->diffusion
|
||||
&& $saved->movements === $coupon->movements
|
||||
&& $saved->updatedAt instanceof \DateTimeInterface,
|
||||
));
|
||||
|
||||
$useCase = new UpdateCoupon($repository);
|
||||
|
||||
// WHEN
|
||||
$result = $useCase->execute($input);
|
||||
|
||||
// THEN
|
||||
expect($result)->toBeInstanceOf(CouponUpdated::class)
|
||||
->and($result->validityInformations)->toBe($newValidityInformations)
|
||||
->and($result->legalInformations)->toBe($newLegalInformations);
|
||||
});
|
||||
|
||||
it('rejects an input with nothing to update', function (): void {
|
||||
// GIVEN
|
||||
$code = new CouponCode('COU01');
|
||||
|
|
|
|||
|
|
@ -51,6 +51,7 @@ describe('campaign request', function (): void {
|
|||
),
|
||||
couponProcessingCodes: new ProcessingCodeArray([
|
||||
new ProcessingCode('5425003944130', Country::FRANCE),
|
||||
new ProcessingCode('4006381333931', Country::BENELUX),
|
||||
]),
|
||||
couponValidityInformations: new CouponValidityInformationArray([
|
||||
new CouponValidityInformation('Lorem ipsum dolor sit amet consectetur adipiscing elit.', Country::FRANCE),
|
||||
|
|
|
|||
|
|
@ -90,6 +90,23 @@ describe('coupon country coverage', function (): void {
|
|||
expect($action)->toThrow(\DomainException::class, 'A coupon requires legal information for BENELUX.');
|
||||
});
|
||||
|
||||
it('rejects information for a country where the coupon is not diffused', function () use (
|
||||
$franceCode,
|
||||
$franceValidity,
|
||||
$beneluxValidity,
|
||||
$franceLegal,
|
||||
): void {
|
||||
// GIVEN / WHEN
|
||||
$action = fn () => CouponCountryCoverage::assert(
|
||||
new ProcessingCodeArray([$franceCode]),
|
||||
new CouponValidityInformationArray([$franceValidity, $beneluxValidity]),
|
||||
new CouponLegalInformationArray([$franceLegal]),
|
||||
);
|
||||
|
||||
// THEN
|
||||
expect($action)->toThrow(\DomainException::class, 'A coupon requires exactly one information per diffusion country.');
|
||||
});
|
||||
|
||||
it('cannot be instantiated from the outside', function (): void {
|
||||
// GIVEN
|
||||
$reflection = new \ReflectionClass(CouponCountryCoverage::class);
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue