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

+33 -25
View File
@@ -48,8 +48,8 @@ class ParticipantDto
'licensePlate',
'bulkInsuranceBooking',
'insurance',
'purchaseVoucherCode',
'promoVoucherCode',
'voucherCode',
'removeVoucherCode',
];
public ?int $index = null;
@@ -163,47 +163,54 @@ class ParticipantDto
public bool $bulkInsuranceBooking = false;
/**
* Purchase voucher redemption code.
* Collected from all participants and aggregated into single <gutscheine> collection in booking payload.
* The voucher field as typed: a purchase or a promo code, told apart by VoucherCodeClassifier.
* ParticipantVoucherFieldHandler applies it and clears it; a rejected code stays for correction.
*/
public ?string $voucherCode = null;
/**
* Why the typed voucher code was rejected. Kept on the DTO because the htmx refresh rebuilds
* the form from the DTO, which drops form errors; the Voucher constraint turns it into a violation.
*/
public ?string $voucherCodeError = null;
/**
* Applied code the customer asked to remove. Consumed and reset by ParticipantVoucherFieldHandler.
*/
public ?string $removeVoucherCode = null;
/**
* Applied purchase voucher redemption code (Kauf or Kulanz).
* Kauf codes are aggregated into the booking's <gutscheine>, a Kulanz code is sent as the participant's <einloesecode>.
*/
#[Assert\Length(
max: 50,
maxMessage: 'Der Gutscheincode darf maximal {{ limit }} Zeichen lang sein'
)]
#[Assert\Regex(
pattern: '/^[A-Za-z0-9\-]+$/',
message: 'Der Gutscheincode darf nur Buchstaben, Zahlen und Bindestriche enthalten'
)]
public ?string $purchaseVoucherCode = null;
/**
* Validated purchase voucher from API.
* Set by ParticipantPurchaseVoucherFieldHandler during form processing.
* Set by ParticipantVoucherFieldHandler during form processing.
* Contains voucher number, remaining balance, and type (Kauf/Kulanz).
*/
public ?PurchaseVoucher $validatedPurchaseVoucher = null;
/**
* Promo voucher code.
* Applied promo voucher code.
* Applied per participant in booking payload as <aktionscode>.
*/
#[Assert\Length(
max: 50,
maxMessage: 'Der Aktionscode darf maximal {{ limit }} Zeichen lang sein'
)]
#[Assert\Regex(
pattern: '/^[A-Za-z0-9\-]+$/',
message: 'Der Aktionscode darf nur Buchstaben, Zahlen und Bindestriche enthalten'
)]
public ?string $promoVoucherCode = null;
/**
* Validated promo voucher from API.
* Set by ParticipantPromoVoucherFieldHandler during form processing.
* Set by ParticipantVoucherFieldHandler during form processing.
* Contains discount amount/percentage and applicability (per person/booking).
* Null while promoVoucherCode is set means BusPro rejected the applied code on a later check.
*/
public ?PromoVoucher $validatedPromoVoucher = null;
/**
* Why BusPro rejected the applied promo code on a later check, e.g. the price fell below its threshold.
*/
public ?string $promoVoucherError = null;
/**
* @var array<array{type: string, message: string}> Notification messages for user feedback
*/
@@ -345,8 +352,8 @@ class ParticipantDto
/**
* Checks if this participant has a goodwill (Kulanz) voucher.
*
* Goodwill vouchers are treated as promotional vouchers in BPN XML
* (sent as <aktionscode> per participant, not in <gutscheine> collection).
* Goodwill vouchers are sent as the participant's <einloesecode>,
* not in the booking's <gutscheine> collection.
*/
public function hasGoodwillVoucher(): bool
{
@@ -425,6 +432,7 @@ class ParticipantDto
$this->mobile = $this->normalizeNullableString($this->mobile);
$this->remarksRoom = $this->normalizeNullableString($this->remarksRoom);
$this->licensePlate = $this->normalizeNullableString($this->licensePlate);
$this->voucherCode = $this->normalizeNullableString($this->voucherCode);
$this->purchaseVoucherCode = $this->normalizeNullableString($this->purchaseVoucherCode);
$this->promoVoucherCode = $this->normalizeNullableString($this->promoVoucherCode);