feat: fold purchase and promo voucher fields into one code field

This commit is contained in:
fromme committed 2026-10-06 10:41:30 +02:00
1 parent 93512b8345
commit 21d756a2e3
21 files changed
+801 -432

No files matched your search

@@ -15,12 +15,8 @@ use App\Form\Model\BookingDto;
use App\Form\Model\ParticipantDto;
use App\Form\Service\ServiceAgeEvaluator;
use App\Service\BookingEditPreFlightChecker;
use App\Service\BookingPriceCalculator;
use App\Service\ParticipantEligibilityChecker;
use App\Service\VoucherValidator;
use App\Validator\Constraints\MandatoryAdditionalServicesSelectedValidator;
use App\Validator\Constraints\PromoVoucherValidator;
use App\Validator\Constraints\PurchaseVoucherValidator;
use App\Validator\Constraints\SkiPassSelectionValidator;
use Carbon\CarbonImmutable;
use PHPUnit\Framework\TestCase;
@@ -248,17 +244,13 @@ class BookingEditPreFlightCheckerTest extends TestCase
private function createValidator(): ValidatorInterface
{
$voucherValidator = $this->createStub(VoucherValidator::class);
$bookingPriceCalculator = $this->createStub(BookingPriceCalculator::class);
$participantEligibilityChecker = $this->createStub(ParticipantEligibilityChecker::class);
$participantEligibilityChecker
->method('isParticipantEligible')
->willReturn(false);
$validatorFactory = new class($voucherValidator, $bookingPriceCalculator, $participantEligibilityChecker, new ServiceAgeEvaluator()) implements ConstraintValidatorFactoryInterface {
$validatorFactory = new class($participantEligibilityChecker, new ServiceAgeEvaluator()) implements ConstraintValidatorFactoryInterface {
public function __construct(
private readonly VoucherValidator $voucherValidator,
private readonly BookingPriceCalculator $bookingPriceCalculator,
private readonly ParticipantEligibilityChecker $participantEligibilityChecker,
private readonly ServiceAgeEvaluator $serviceAgeEvaluator,
) {
@@ -272,14 +264,6 @@ class BookingEditPreFlightCheckerTest extends TestCase
return new EmailValidator(Email::VALIDATION_MODE_HTML5);
}
if (PurchaseVoucherValidator::class === $className) {
return new PurchaseVoucherValidator($this->voucherValidator);
}
if (PromoVoucherValidator::class === $className) {
return new PromoVoucherValidator($this->voucherValidator, $this->bookingPriceCalculator);
}
if (MandatoryAdditionalServicesSelectedValidator::class === $className) {
return new MandatoryAdditionalServicesSelectedValidator(
$this->participantEligibilityChecker,
@@ -0,0 +1,58 @@
<?php
declare(strict_types=1);
namespace App\Tests\Service;
use App\Enum\VoucherCodeKind;
use App\Service\VoucherCodeClassifier;
use PHPUnit\Framework\Attributes\DataProvider;
use PHPUnit\Framework\TestCase;
class VoucherCodeClassifierTest extends TestCase
{
private VoucherCodeClassifier $classifier;
protected function setUp(): void
{
$this->classifier = new VoucherCodeClassifier(['lw0705' => '2027-04-30']);
}
/**
* @return iterable<string, array{string, VoucherCodeKind}>
*/
public static function codes(): iterable
{
yield 'prefixed promo' => ['R-SOMMER26', VoucherCodeKind::Promo];
yield 'prefixed promo in lowercase' => ['r-sommer26', VoucherCodeKind::Promo];
yield 'legacy promo, matched case-insensitively' => ['Lw0705', VoucherCodeKind::Promo];
yield 'purchase code' => ['1F7V6PADRZ', VoucherCodeKind::Purchase];
yield 'purchase code in lowercase' => ['1f7v6padrz', VoucherCodeKind::Purchase];
yield 'surrounding whitespace' => [' 1F7V6PADRZ ', VoucherCodeKind::Purchase];
yield 'hyphen without the promo prefix' => ['X-1F7V6PADRZ', VoucherCodeKind::Malformed];
yield 'characters outside the code alphabet' => ['1F7V 6PADRZ', VoucherCodeKind::Malformed];
yield 'empty' => [' ', VoucherCodeKind::Malformed];
yield 'too long' => [str_repeat('A', 51), VoucherCodeKind::Malformed];
}
#[DataProvider('codes')]
public function testClassify(string $code, VoucherCodeKind $expected): void
{
self::assertSame($expected, $this->classifier->classify($code, new \DateTimeImmutable('2026-10-06')));
}
public function testLegacyCodeIsRecognisedOnItsLastDay(): void
{
self::assertSame(VoucherCodeKind::Promo, $this->classifier->classify('LW0705', new \DateTimeImmutable('2027-04-30')));
}
public function testLegacyCodeIsAPurchaseCodeOnceExpired(): void
{
self::assertSame(VoucherCodeKind::Purchase, $this->classifier->classify('LW0705', new \DateTimeImmutable('2027-05-01')));
}
public function testNormalizeTrimsAndUppercases(): void
{
self::assertSame('R-SOMMER26', $this->classifier->normalize(' r-Sommer26 '));
}
}