requestedCoupon = new RequestedCoupon( new CouponName('Coupon A'), new RequestedCouponQuantity(100), new Period(new DateTime('2026-01-01'), new DateTime('2026-02-01')), new MoneyAmount(new Money(Currency::EUR, 300)), new ProcessingCode('PC1'), new CouponValidity(30, new DateTime('2026-02-01')), [ new CouponValidityInformation('Lorem ipsum dolor sit amet consectetur adipiscing elit.', Country::FRANCE), new CouponValidityInformation('Lorem ipsum dolor sit amet consectetur adipiscing elit.', Country::BENELUX) ], [new IncoCode(35784), new IncoCode(15522)], new PrintRules(maxPerCustomer: 3), new GS1('01234567890128', BarcodeFormat::EAN13), new WarningThresholdQuantity(10) ); $this->code = new BrandCode('AAA01'); $this->name = new CampaignName('Campaign A'); $this->applicant = new Applicant('John', 'Doe', new Email('john.doe@example.com')); $this->campaignType = CampaignRequestType::CLUB; $this->requestedCoupon = $this->requestedCoupon; $this->status = CampaignRequestStatus::CREATED; $this->transformedStatus = CampaignRequestStatus::TRANSFORMED; $this->rejectedStatus = CampaignRequestStatus::REJECTED; $this->rejectionReason = new RejectionReason('Missing legal documents.'); }); afterEach(function (): void { CarbonImmutable::setTestNow(); }); it('hydrates a campaign request with all its fields', function (): void { // GIVEN $id = CampaignRequestId::generate(); // WHEN $campaignRequest = CampaignRequest::hydrate( $id, $this->code, $this->name, $this->applicant, $this->campaignType, $this->requestedCoupon, $this->status, ); // THEN expect($campaignRequest->id())->toBe($id) ->and($campaignRequest->brandCode)->toBe($this->code) ->and($campaignRequest->name)->toBe($this->name) ->and($campaignRequest->applicant)->toBe($this->applicant) ->and($campaignRequest->campaignType)->toBe($this->campaignType) ->and($campaignRequest->requestedCoupon)->toBe($this->requestedCoupon) ->and($campaignRequest->status)->toBe($this->status) ->and($campaignRequest->updatedAt)->toBeNull() ->and($campaignRequest->updatedAt())->toBeNull(); }); it('hydrates a campaign request with an explicit updatedAt date', function (): void { // GIVEN $updatedAt = new \DateTimeImmutable('2026-06-15 12:00:00', new \DateTimeZone('UTC')); // WHEN $campaignRequest = CampaignRequest::hydrate( CampaignRequestId::generate(), $this->code, $this->name, $this->applicant, $this->campaignType, $this->requestedCoupon, $this->status, null, $updatedAt, ); // THEN expect($campaignRequest->updatedAt)->toBe($updatedAt) ->and($campaignRequest->updatedAt())->toBe($updatedAt); }); it('hydrates a rejected campaign request with a rejection reason', function (): void { // GIVEN / WHEN $campaignRequest = CampaignRequest::hydrate( CampaignRequestId::generate(), $this->code, $this->name, $this->applicant, $this->campaignType, $this->requestedCoupon, $this->rejectedStatus, $this->rejectionReason, ); // THEN expect($campaignRequest->status)->toBe($this->rejectedStatus) ->and($campaignRequest->rejectionReason)->toBe($this->rejectionReason); }); it('rejects a rejected campaign request without a rejection reason', function (): void { // GIVEN / WHEN $action = fn (): CampaignRequest => CampaignRequest::hydrate( CampaignRequestId::generate(), $this->code, $this->name, $this->applicant, $this->campaignType, $this->requestedCoupon, $this->rejectedStatus, ); // THEN expect($action)->toThrow( \DomainException::class, 'A rejection reason is required when the campaign request is rejected.' ); }); it('rejects a non-rejected campaign request with a rejection reason', function (): void { // WHEN $action = fn (): CampaignRequest => CampaignRequest::hydrate( CampaignRequestId::generate(), $this->code, $this->name, $this->applicant, $this->campaignType, $this->requestedCoupon, $this->status, $this->rejectionReason, ); // THEN expect($action)->toThrow( \DomainException::class, 'A rejection reason can only be set when the campaign request is rejected.' ); }); it('rejects a campaign request and sets the rejection reason and updatedAt', function (): void { // GIVEN CarbonImmutable::setTestNow('2026-06-15 12:00:00'); $campaignRequest = CampaignRequest::hydrate( CampaignRequestId::generate(), $this->code, $this->name, $this->applicant, $this->campaignType, $this->requestedCoupon, $this->status, ); // WHEN $rejected = $campaignRequest->reject($this->rejectionReason); // THEN expect($rejected->status)->toBe(CampaignRequestStatus::REJECTED) ->and($rejected->rejectionReason)->toBe($this->rejectionReason) ->and($rejected->id())->toBe($campaignRequest->id()) ->and($rejected->brandCode)->toBe($campaignRequest->brandCode) ->and($rejected->name)->toBe($campaignRequest->name) ->and($rejected->applicant)->toBe($campaignRequest->applicant) ->and($rejected->campaignType)->toBe($campaignRequest->campaignType) ->and($rejected->requestedCoupon)->toBe($campaignRequest->requestedCoupon) ->and($rejected->updatedAt)->not->toBeNull() ->and($rejected->updatedAt()?->format('Y-m-d H:i:s'))->toBe('2026-06-15 12:00:00'); }); it('rejects rejecting a transformed campaign request', function (): void { // GIVEN $campaignRequest = CampaignRequest::hydrate( CampaignRequestId::generate(), $this->code, $this->name, $this->applicant, $this->campaignType, $this->requestedCoupon, $this->transformedStatus, ); // WHEN $action = fn (): CampaignRequest => $campaignRequest->reject($this->rejectionReason); // THEN expect($action)->toThrow(\DomainException::class, 'Only a created campaign request can be rejected.'); }); it('rejects rejecting an already rejected campaign request', function (): void { // GIVEN $campaignRequest = CampaignRequest::hydrate( CampaignRequestId::generate(), $this->code, $this->name, $this->applicant, $this->campaignType, $this->requestedCoupon, $this->rejectedStatus, new RejectionReason('First reason.'), ); // WHEN $action = fn (): CampaignRequest => $campaignRequest->reject(new RejectionReason('Second reason.')); // THEN expect($action)->toThrow(\DomainException::class, 'Only a created campaign request can be rejected.'); }); it('returns the creation date extracted from the id', function (): void { // GIVEN $expected = new \DateTimeImmutable('2024-06-15 12:34:56.789000', new \DateTimeZone('UTC')); $id = new CampaignRequestId(Uuid::uuid7($expected)); $campaignRequest = CampaignRequest::hydrate( $id, $this->code, $this->name, $this->applicant, $this->campaignType, $this->requestedCoupon, $this->status, ); // WHEN $result = $campaignRequest->createdAt(); // THEN expect($result->format('Y-m-d H:i:s.v'))->toBe($expected->format('Y-m-d H:i:s.v')); }); });