per participant, not aggregated * in collection. Validation is performed by PurchaseVoucher constraint. * * Dependencies: None (purchase vouchers don't require price calculation) */ class ParticipantPurchaseVoucherFieldHandler extends AbstractParticipantFieldHandler { public function __construct( private readonly VoucherValidationService $voucherValidationService, ) { } public function getFieldName(): string { return 'purchaseVoucherCode'; } public function getDependencies(): array { // No dependencies - purchase vouchers don't require price calculation return []; } public function shouldProcess(array $submittedData, string $mode, int $participantIndex): bool { $voucherCode = $this->getFieldValue($submittedData, $this->getFieldName()); return null !== $voucherCode && '' !== trim($voucherCode); } public function processField(array $submittedData, BookingDto $bookingDto, int $participantIndex): void { $participant = $this->getParticipant($bookingDto, $participantIndex); if (null === $participant) { return; } $voucherCode = $this->getFieldValue($submittedData, $this->getFieldName()); if (null === $voucherCode || '' === trim($voucherCode)) { return; } // Validate voucher to check if it's goodwill type $result = $this->voucherValidationService->validatePurchaseVoucher($voucherCode); // Only process valid vouchers if (false === $result->isValid || null === $result->voucher) { return; } // Check if this is a goodwill voucher if (true === $result->voucher->isGoodwill()) { $participant->hasGoodwillVoucher = true; } } }