238 lines
10 KiB
PHP
238 lines
10 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace App\Tests\Form\Service;
|
|
|
|
use App\BusProNet\Model\PromoVoucher;
|
|
use App\BusProNet\Model\PromoVoucherValidationResult;
|
|
use App\BusProNet\Model\PurchaseVoucher;
|
|
use App\BusProNet\Model\PurchaseVoucherValidationResult;
|
|
use App\BusProNet\Model\Travel;
|
|
use App\Form\Model\BookingDto;
|
|
use App\Form\Model\ParticipantDto;
|
|
use App\Form\Service\ParticipantVoucherFieldHandler;
|
|
use App\Service\BookingPriceCalculator;
|
|
use App\Service\VoucherCodeClassifier;
|
|
use App\Service\VoucherValidator;
|
|
use PHPUnit\Framework\MockObject\Stub;
|
|
use PHPUnit\Framework\TestCase;
|
|
|
|
class ParticipantVoucherFieldHandlerTest extends TestCase
|
|
{
|
|
private VoucherValidator&Stub $voucherValidator;
|
|
private BookingDto $bookingDto;
|
|
private ParticipantDto $participant;
|
|
|
|
protected function setUp(): void
|
|
{
|
|
$this->voucherValidator = $this->createStub(VoucherValidator::class);
|
|
|
|
$travel = new Travel();
|
|
$travel->id = 12500;
|
|
|
|
$this->participant = new ParticipantDto();
|
|
$this->participant->index = 0;
|
|
|
|
$this->bookingDto = new BookingDto($travel, 1);
|
|
$this->bookingDto->participants = [$this->participant];
|
|
}
|
|
|
|
private function handler(?VoucherValidator $voucherValidator = null): ParticipantVoucherFieldHandler
|
|
{
|
|
$priceCalculator = $this->createStub(BookingPriceCalculator::class);
|
|
$priceCalculator->method('calculateIndividualParticipantPrice')->willReturn(500.0);
|
|
|
|
return new ParticipantVoucherFieldHandler(
|
|
$voucherValidator ?? $this->voucherValidator,
|
|
$priceCalculator,
|
|
new VoucherCodeClassifier(['LW0705' => '2099-12-31']),
|
|
);
|
|
}
|
|
|
|
private static function promoVoucher(string $code): PromoVoucher
|
|
{
|
|
return new PromoVoucher($code, 'Aktion', PromoVoucher::APPLICABILITY_PER_PERSON, 50.0, 0.0, 0.0);
|
|
}
|
|
|
|
private static function purchaseVoucher(string $code, string $type = PurchaseVoucher::TYPE_PURCHASE): PurchaseVoucher
|
|
{
|
|
return new PurchaseVoucher('80190', $code, 1, 100.0, $type);
|
|
}
|
|
|
|
public function testRunsOnlyInCreateMode(): void
|
|
{
|
|
self::assertTrue($this->handler()->shouldProcess([], BookingDto::MODE_CREATE, 0));
|
|
self::assertFalse($this->handler()->shouldProcess([], BookingDto::MODE_EDIT, 0));
|
|
}
|
|
|
|
public function testAppliesPrefixedPromoCodeAndClearsTheField(): void
|
|
{
|
|
$voucher = self::promoVoucher('R-SOMMER26');
|
|
$this->voucherValidator->method('validatePromoVoucher')
|
|
->willReturn(new PromoVoucherValidationResult(isValid: true, voucher: $voucher));
|
|
|
|
$this->handler()->processField(['voucherCode' => ' r-sommer26 '], $this->bookingDto, 0);
|
|
|
|
self::assertSame('R-SOMMER26', $this->participant->promoVoucherCode);
|
|
self::assertSame($voucher, $this->participant->validatedPromoVoucher);
|
|
self::assertNull($this->participant->voucherCode);
|
|
self::assertNull($this->participant->voucherCodeError);
|
|
self::assertNull($this->participant->purchaseVoucherCode);
|
|
}
|
|
|
|
public function testAppliesLegacyPromoCodeAsPromo(): void
|
|
{
|
|
$voucherValidator = $this->createMock(VoucherValidator::class);
|
|
$voucherValidator->expects(self::once())->method('validatePromoVoucher')
|
|
->with('LW0705', 12500, 500.0)
|
|
->willReturn(new PromoVoucherValidationResult(isValid: true, voucher: self::promoVoucher('LW0705')));
|
|
$voucherValidator->expects(self::never())->method('validatePurchaseVoucher');
|
|
|
|
$this->handler($voucherValidator)->processField(['voucherCode' => 'lw0705'], $this->bookingDto, 0);
|
|
|
|
self::assertSame('LW0705', $this->participant->promoVoucherCode);
|
|
}
|
|
|
|
public function testAppliesPurchaseCode(): void
|
|
{
|
|
$voucher = self::purchaseVoucher('1F7V6PADRZ');
|
|
$this->voucherValidator->method('validatePurchaseVoucher')
|
|
->willReturn(new PurchaseVoucherValidationResult(isValid: true, voucher: $voucher));
|
|
|
|
$this->handler()->processField(['voucherCode' => '1f7v6padrz'], $this->bookingDto, 0);
|
|
|
|
self::assertSame('1F7V6PADRZ', $this->participant->purchaseVoucherCode);
|
|
self::assertSame($voucher, $this->participant->validatedPurchaseVoucher);
|
|
self::assertNull($this->participant->voucherCode);
|
|
self::assertFalse($this->participant->hasGoodwillVoucher());
|
|
}
|
|
|
|
public function testAppliesGoodwillCodeAsPurchaseCode(): void
|
|
{
|
|
$this->voucherValidator->method('validatePurchaseVoucher')
|
|
->willReturn(new PurchaseVoucherValidationResult(isValid: true, voucher: self::purchaseVoucher('KULANZ', PurchaseVoucher::TYPE_GOODWILL)));
|
|
|
|
$this->handler()->processField(['voucherCode' => 'KULANZ'], $this->bookingDto, 0);
|
|
|
|
self::assertSame('KULANZ', $this->participant->purchaseVoucherCode);
|
|
self::assertTrue($this->participant->hasGoodwillVoucher());
|
|
}
|
|
|
|
public function testRejectedCodeStaysInTheFieldWithBusProsReason(): void
|
|
{
|
|
$this->voucherValidator->method('validatePurchaseVoucher')
|
|
->willReturn(new PurchaseVoucherValidationResult(isValid: false, errorMessage: 'Gutschein nicht gefunden'));
|
|
|
|
$this->handler()->processField(['voucherCode' => 'abcdef'], $this->bookingDto, 0);
|
|
|
|
self::assertSame('abcdef', $this->participant->voucherCode);
|
|
self::assertSame('Gutschein ungültig: Gutschein nicht gefunden', $this->participant->voucherCodeError);
|
|
self::assertNull($this->participant->purchaseVoucherCode);
|
|
}
|
|
|
|
public function testMalformedCodeIsRejectedWithoutAskingBusPro(): void
|
|
{
|
|
$voucherValidator = $this->createMock(VoucherValidator::class);
|
|
$voucherValidator->expects(self::never())->method('validatePurchaseVoucher');
|
|
$voucherValidator->expects(self::never())->method('validatePromoVoucher');
|
|
|
|
$this->handler($voucherValidator)->processField(['voucherCode' => 'X-123'], $this->bookingDto, 0);
|
|
|
|
self::assertSame('X-123', $this->participant->voucherCode);
|
|
self::assertNotNull($this->participant->voucherCodeError);
|
|
}
|
|
|
|
public function testCodeAlreadyAppliedIsRejected(): void
|
|
{
|
|
$this->participant->purchaseVoucherCode = '1F7V6PADRZ';
|
|
|
|
$voucherValidator = $this->createMock(VoucherValidator::class);
|
|
$voucherValidator->expects(self::never())->method('validatePurchaseVoucher');
|
|
|
|
$this->handler($voucherValidator)->processField(['voucherCode' => '1f7v6padrz'], $this->bookingDto, 0);
|
|
|
|
self::assertSame('Dieser Code ist bereits eingelöst.', $this->participant->voucherCodeError);
|
|
}
|
|
|
|
public function testSecondPurchaseCodeIsRejectedAndTheFirstKept(): void
|
|
{
|
|
$this->participant->purchaseVoucherCode = '1F7V6PADRZ';
|
|
|
|
$voucherValidator = $this->createMock(VoucherValidator::class);
|
|
$voucherValidator->expects(self::never())->method('validatePurchaseVoucher');
|
|
|
|
$this->handler($voucherValidator)->processField(['voucherCode' => '1VDHQWPZHK'], $this->bookingDto, 0);
|
|
|
|
self::assertSame('1F7V6PADRZ', $this->participant->purchaseVoucherCode);
|
|
self::assertSame('1VDHQWPZHK', $this->participant->voucherCode);
|
|
self::assertStringContainsString('1F7V6PADRZ', (string) $this->participant->voucherCodeError);
|
|
}
|
|
|
|
public function testSecondPromoCodeIsRejectedAndTheFirstKept(): void
|
|
{
|
|
$applied = self::promoVoucher('R-SOMMER26');
|
|
$this->participant->promoVoucherCode = 'R-SOMMER26';
|
|
$this->participant->validatedPromoVoucher = $applied;
|
|
$this->voucherValidator->method('validatePromoVoucher')
|
|
->willReturn(new PromoVoucherValidationResult(isValid: true, voucher: $applied));
|
|
|
|
$this->handler()->processField(['voucherCode' => 'R-WINTER26'], $this->bookingDto, 0);
|
|
|
|
self::assertSame('R-SOMMER26', $this->participant->promoVoucherCode);
|
|
self::assertSame($applied, $this->participant->validatedPromoVoucher);
|
|
self::assertStringContainsString('R-SOMMER26', (string) $this->participant->voucherCodeError);
|
|
}
|
|
|
|
public function testPromoAndPurchaseCodeCanBeCombined(): void
|
|
{
|
|
$this->participant->purchaseVoucherCode = '1F7V6PADRZ';
|
|
$this->voucherValidator->method('validatePromoVoucher')
|
|
->willReturn(new PromoVoucherValidationResult(isValid: true, voucher: self::promoVoucher('R-SOMMER26')));
|
|
|
|
$this->handler()->processField(['voucherCode' => 'R-SOMMER26'], $this->bookingDto, 0);
|
|
|
|
self::assertSame('1F7V6PADRZ', $this->participant->purchaseVoucherCode);
|
|
self::assertSame('R-SOMMER26', $this->participant->promoVoucherCode);
|
|
self::assertNull($this->participant->voucherCodeError);
|
|
}
|
|
|
|
public function testRemovesAnAppliedCode(): void
|
|
{
|
|
$this->participant->purchaseVoucherCode = '1F7V6PADRZ';
|
|
$this->participant->validatedPurchaseVoucher = self::purchaseVoucher('1F7V6PADRZ');
|
|
$this->participant->removeVoucherCode = '1F7V6PADRZ';
|
|
|
|
$this->handler()->processField(['voucherCode' => '', 'removeVoucherCode' => '1f7v6padrz'], $this->bookingDto, 0);
|
|
|
|
self::assertNull($this->participant->purchaseVoucherCode);
|
|
self::assertNull($this->participant->validatedPurchaseVoucher);
|
|
self::assertNull($this->participant->removeVoucherCode);
|
|
}
|
|
|
|
public function testAppliedPromoCodeRejectedOnRecheckKeepsTheCodeWithItsReason(): void
|
|
{
|
|
$this->participant->promoVoucherCode = 'R-SOMMER26';
|
|
$this->participant->validatedPromoVoucher = self::promoVoucher('R-SOMMER26');
|
|
$this->voucherValidator->method('validatePromoVoucher')
|
|
->willReturn(new PromoVoucherValidationResult(isValid: false, errorMessage: 'Mindestpreis nicht erreicht'));
|
|
|
|
$this->handler()->processField([], $this->bookingDto, 0);
|
|
|
|
self::assertSame('R-SOMMER26', $this->participant->promoVoucherCode);
|
|
self::assertNull($this->participant->validatedPromoVoucher);
|
|
self::assertSame('Aktionscode ungültig: Mindestpreis nicht erreicht', $this->participant->promoVoucherError);
|
|
}
|
|
|
|
public function testCodeLeftFromAnEarlierRequestIsDroppedWhenTheFieldIsNotSubmitted(): void
|
|
{
|
|
$this->participant->voucherCode = 'ABCDEF';
|
|
$this->participant->voucherCodeError = 'Gutschein ungültig: Gutschein nicht gefunden';
|
|
|
|
$this->handler()->processField([], $this->bookingDto, 0);
|
|
|
|
self::assertNull($this->participant->voucherCode);
|
|
self::assertNull($this->participant->voucherCodeError);
|
|
}
|
|
}
|