($maxPerCustomer || $cooldownDays) ? new PrintRules( maxPerCustomer: $maxPerCustomer, cooldownDays: $cooldownDays, ) : null; $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( id: CampaignId::generate(), code: $campaignCode, name: new CampaignName('Campaign name'), publication: $published, printAllAtOnce: true, coupons: new CampaignCouponArray([ $campaignCoupon($maxPerCustomer, $cooldownDays), ]), brandCode: $brandCode, actorId: ActorId::generate(), ); $printedCoupon = new PrintedCoupon( id: PrintedCouponId::generate(), marketingCode: new MarketingDirectCode('0000000000001'), printableCode: PrintableCouponCode::generate(), couponCode: $couponCode, campaignCode: $campaignCode, customer: $crmCustomerHashcode, printedAt: DatesHelper::now(), ); $makeInput = fn (Campaign $campaign): Input => new Input( campaignCode: $campaign->code, couponCode: $couponCode, crmCustomerHashcode: $crmCustomerHashcode, ); it('creates a printable coupon', function () use ($makeInput, $crmCustomerHashcode, $makeCampaign, $makeCoupon, $campaignCoupon): void { // GIVEN $campaign = $makeCampaign(); $input = $makeInput($campaign); $coupon = $makeCoupon(); $campaignRepository = \Mockery::mock(CampaignRepository::class); $campaignRepository->shouldReceive('findByCode')->once()->with($campaign->code)->andReturn($campaign); $campaignRepository->shouldReceive('findCampaignCoupon')->once()->with($campaign->code, $coupon->code) ->andReturn($campaignCoupon()); $couponRepository = \Mockery::mock(CouponRepository::class); $couponRepository->shouldReceive('findByCode')->once()->with($coupon->code)->andReturn($coupon); $printableCouponRepository = \Mockery::mock(PrintableCouponRepository::class); $printableCouponRepository->shouldReceive('save')->once()->with(\Mockery::type(PrintableCoupon::class)); $printEligibilityChecker = new PrintEligibilityChecker($printableCouponRepository); $useCase = new CreatePrintableCoupon( $printableCouponRepository, $couponRepository, $campaignRepository, $printEligibilityChecker, ); // WHEN $result = $useCase->execute($input); // THEN expect($result)->toBeInstanceOf(PrintableCouponCreated::class) ->and($result->campaignCode)->toEqual($campaign->code) ->and($result->couponCode)->toEqual($coupon->code) ->and($result->crmCustomerHashcode)->toEqual($crmCustomerHashcode) ->and($result->distributableUntil)->toEqual($coupon->diffusion->period->end); }); it('rejects a printable coupon when campaign not found', function () use ($makeInput, $makeCampaign): void { // GIVEN $campaign = $makeCampaign(); $input = $makeInput($campaign); $campaignRepository = \Mockery::mock(CampaignRepository::class); $campaignRepository->shouldReceive('findByCode')->once()->with($campaign->code)->andReturn(null); $couponRepository = \Mockery::mock(CouponRepository::class); $printableCouponRepository = \Mockery::mock(PrintableCouponRepository::class); $printEligibilityChecker = new PrintEligibilityChecker($printableCouponRepository); $useCase = new CreatePrintableCoupon( $printableCouponRepository, $couponRepository, $campaignRepository, $printEligibilityChecker, ); // WHEN $result = $useCase->execute($input); // THEN expect($result)->toBeInstanceOf(CampaignNotFound::class); }); it('rejects a printable coupon when campaign is not published', function () use ($makeInput, $makeCampaign): void { // GIVEN $campaign = $makeCampaign(published: false); $input = $makeInput($campaign); $campaignRepository = \Mockery::mock(CampaignRepository::class); $campaignRepository->shouldReceive('findByCode')->once()->with($campaign->code)->andReturn($campaign); $couponRepository = \Mockery::mock(CouponRepository::class); $printableCouponRepository = \Mockery::mock(PrintableCouponRepository::class); $printEligibilityChecker = new PrintEligibilityChecker($printableCouponRepository); $useCase = new CreatePrintableCoupon( $printableCouponRepository, $couponRepository, $campaignRepository, $printEligibilityChecker, ); // WHEN // WHEN $result = $useCase->execute($input); // THEN expect($result)->toBeInstanceOf(CampaignNotPublished::class); }); it('rejects a printable coupon when coupon is not found', function () use ($makeInput, $makeCampaign, $makeCoupon): void { // GIVEN $campaign = $makeCampaign(); $input = $makeInput($campaign); $coupon = $makeCoupon(); $campaignRepository = \Mockery::mock(CampaignRepository::class); $campaignRepository->shouldReceive('findByCode')->once()->with($campaign->code)->andReturn($campaign); $couponRepository = \Mockery::mock(CouponRepository::class); $couponRepository->shouldReceive('findByCode')->once()->with($coupon->code)->andReturn(null); $printableCouponRepository = \Mockery::mock(PrintableCouponRepository::class); $printEligibilityChecker = new PrintEligibilityChecker($printableCouponRepository); $useCase = new CreatePrintableCoupon( $printableCouponRepository, $couponRepository, $campaignRepository, $printEligibilityChecker, ); // WHEN // WHEN $result = $useCase->execute($input); // THEN expect($result)->toBeInstanceOf(CouponNotFound::class); }); it('rejects a printable coupon when campaign coupon is not found', function () use ($makeInput, $makeCampaign, $makeCoupon): void { // GIVEN $campaign = $makeCampaign(); $input = $makeInput($campaign); $coupon = $makeCoupon(); $campaignRepository = \Mockery::mock(CampaignRepository::class); $campaignRepository->shouldReceive('findByCode')->once()->with($campaign->code)->andReturn($campaign); $campaignRepository->shouldReceive('findCampaignCoupon')->once()->with($campaign->code, $coupon->code) ->andReturn(null); $couponRepository = \Mockery::mock(CouponRepository::class); $couponRepository->shouldReceive('findByCode')->once()->with($coupon->code)->andReturn($coupon); $printableCouponRepository = \Mockery::mock(PrintableCouponRepository::class); $printEligibilityChecker = new PrintEligibilityChecker($printableCouponRepository); $useCase = new CreatePrintableCoupon( $printableCouponRepository, $couponRepository, $campaignRepository, $printEligibilityChecker, ); // WHEN // WHEN $result = $useCase->execute($input); // THEN expect($result)->toBeInstanceOf(CouponNotAssociated::class); }); it('rejects a printable coupon when outside of diffusion start', function () use ($makeInput, $makeCampaign, $makeCoupon, $campaignCoupon): void { // GIVEN $campaign = $makeCampaign(); $input = $makeInput($campaign); $coupon = $makeCoupon(['diffusionStart' => new DateTime()->modify('+1 day')]); $campaignRepository = \Mockery::mock(CampaignRepository::class); $campaignRepository->shouldReceive('findByCode')->once()->with($campaign->code)->andReturn($campaign); $campaignRepository->shouldReceive('findCampaignCoupon')->once()->with($campaign->code, $coupon->code) ->andReturn($campaignCoupon()); $couponRepository = \Mockery::mock(CouponRepository::class); $couponRepository->shouldReceive('findByCode')->once()->with($coupon->code)->andReturn($coupon); $printableCouponRepository = \Mockery::mock(PrintableCouponRepository::class); $printEligibilityChecker = new PrintEligibilityChecker($printableCouponRepository); $useCase = new CreatePrintableCoupon( $printableCouponRepository, $couponRepository, $campaignRepository, $printEligibilityChecker, ); // WHEN $action = fn () => $useCase->execute($input); // THEN expect($action)->toThrow(\DomainException::class, 'The printing period has not yet begun.'); }); it('rejects a printable coupon when outside of diffusion end', function () use ($makeInput, $makeCampaign, $makeCoupon, $campaignCoupon): void { // GIVEN $campaign = $makeCampaign(); $input = $makeInput($campaign); $coupon = $makeCoupon(['diffusionEnd' => new DateTime()->modify('-1 day')]); $campaignRepository = \Mockery::mock(CampaignRepository::class); $campaignRepository->shouldReceive('findByCode')->once()->with($campaign->code)->andReturn($campaign); $campaignRepository->shouldReceive('findCampaignCoupon')->once()->with($campaign->code, $coupon->code) ->andReturn($campaignCoupon()); $couponRepository = \Mockery::mock(CouponRepository::class); $couponRepository->shouldReceive('findByCode')->once()->with($coupon->code)->andReturn($coupon); $printableCouponRepository = \Mockery::mock(PrintableCouponRepository::class); $printEligibilityChecker = new PrintEligibilityChecker($printableCouponRepository); $useCase = new CreatePrintableCoupon( $printableCouponRepository, $couponRepository, $campaignRepository, $printEligibilityChecker, ); // WHEN $action = fn () => $useCase->execute($input); // THEN expect($action)->toThrow(\DomainException::class, 'The printing period has expired.'); }); it('creates a printable coupon when calendar period is inside diffusion period', function () use ( $makeInput, $crmCustomerHashcode, $makeCampaign, $makeCoupon, $campaignCoupon, ): void { // GIVEN $calendarStart = new DateTime()->modify('-1 day'); $calendarEnd = new DateTime()->modify('+1 day'); $campaign = $makeCampaign(); $input = $makeInput($campaign); $coupon = $makeCoupon([ 'availabilityCalendar' => new CouponAvailabilityCalendar([ new Period( start: $calendarStart, end: $calendarEnd, ), ]), ]); $campaignRepository = \Mockery::mock(CampaignRepository::class); $campaignRepository->shouldReceive('findByCode')->once()->with($campaign->code)->andReturn($campaign); $campaignRepository->shouldReceive('findCampaignCoupon')->once()->with($campaign->code, $coupon->code) ->andReturn($campaignCoupon()); $couponRepository = \Mockery::mock(CouponRepository::class); $couponRepository->shouldReceive('findByCode')->once()->with($coupon->code)->andReturn($coupon); $printableCouponRepository = \Mockery::mock(PrintableCouponRepository::class); $printableCouponRepository->shouldReceive('save')->once()->with(\Mockery::type(PrintableCoupon::class)); $printEligibilityChecker = new PrintEligibilityChecker($printableCouponRepository); $useCase = new CreatePrintableCoupon( $printableCouponRepository, $couponRepository, $campaignRepository, $printEligibilityChecker, ); // WHEN $result = $useCase->execute($input); // THEN expect($result)->toBeInstanceOf(PrintableCouponCreated::class) ->and($result->campaignCode)->toEqual($campaign->code) ->and($result->crmCustomerHashcode)->toEqual($crmCustomerHashcode) ->and($result->distributableUntil)->toEqual($calendarEnd); }); it('rejects a printable coupon when maximum number of prints reached', function () use ( $makeInput, $crmCustomerHashcode, $makeCampaign, $makeCoupon, $campaignCoupon, ): void { // GIVEN $campaign = $makeCampaign(maxPerCustomer: 1); $input = $makeInput($campaign); $coupon = $makeCoupon(); $campaignRepository = \Mockery::mock(CampaignRepository::class); $campaignRepository->shouldReceive('findByCode')->once()->with($campaign->code)->andReturn($campaign); $campaignRepository->shouldReceive('findCampaignCoupon')->once()->with($campaign->code, $coupon->code) ->andReturn($campaignCoupon(maxPerCustomer: 1)); $couponRepository = \Mockery::mock(CouponRepository::class); $couponRepository->shouldReceive('findByCode')->once()->with($coupon->code)->andReturn($coupon); $printableCouponRepository = \Mockery::mock(PrintableCouponRepository::class); $printableCouponRepository->shouldReceive('countPrintedCouponForCustomer')->once()->with( $campaign->code, $coupon->code, $crmCustomerHashcode, )->andReturn(5); $printEligibilityChecker = new PrintEligibilityChecker($printableCouponRepository); $useCase = new CreatePrintableCoupon( $printableCouponRepository, $couponRepository, $campaignRepository, $printEligibilityChecker, ); // WHEN $action = fn () => $useCase->execute($input); // THEN expect($action)->toThrow(\DomainException::class, 'Maximum number of prints reached.'); }); it('rejects a printable coupon when reprint period has expired', function () use ( $makeInput, $crmCustomerHashcode, $makeCampaign, $makeCoupon, $campaignCoupon, $printedCoupon, ): void { // GIVEN $campaign = $makeCampaign(cooldownDays: 30); $input = $makeInput($campaign); $coupon = $makeCoupon(); $campaignRepository = \Mockery::mock(CampaignRepository::class); $campaignRepository->shouldReceive('findByCode')->once()->with($campaign->code)->andReturn($campaign); $campaignRepository->shouldReceive('findCampaignCoupon')->once()->with($campaign->code, $coupon->code) ->andReturn($campaignCoupon(cooldownDays: 30)); $couponRepository = \Mockery::mock(CouponRepository::class); $couponRepository->shouldReceive('findByCode')->once()->with($coupon->code)->andReturn($coupon); $printableCouponRepository = \Mockery::mock(PrintableCouponRepository::class); $printableCouponRepository->shouldReceive('countPrintedCouponForCustomer')->once()->with( $campaign->code, $coupon->code, $crmCustomerHashcode, )->andReturn(5); $printableCouponRepository->shouldReceive('findLastPrintedCouponForCustomer')->once()->with( $campaign->code, $coupon->code, $crmCustomerHashcode, )->andReturn($printedCoupon); $printEligibilityChecker = new PrintEligibilityChecker($printableCouponRepository); $useCase = new CreatePrintableCoupon( $printableCouponRepository, $couponRepository, $campaignRepository, $printEligibilityChecker, ); // WHEN $action = fn () => $useCase->execute($input); // THEN expect($action)->toThrow(\DomainException::class, 'Reprint period has not expired.'); }); });