feat: correct handling of vouchers

This commit is contained in:
Björn Fromme
2025-11-24 10:20:21 +01:00
parent ce1b9ece09
commit f33e55f201
7 changed files with 151 additions and 24 deletions
+3 -3
View File
@@ -204,7 +204,7 @@ class ApiClient
'user' => $this->config['bpn_username'],
'key' => $this->createKey($this->config['bpn_username'], $this->config['bpn_password'], static::TYPE_BOOKING_UPDATE),
'satz' => ['@typ' => static::TYPE_BOOKING_UPDATE],
'buchungsart' => 'Buchung',
'buchungsart' => Constants::BOOKING_TYPE_BOOKING,
...$payload,
];
@@ -228,7 +228,7 @@ class ApiClient
{
// Forcibly override booking status to generate inquiry payload
$bookingDto->bookingStatus = 'A';
$payload = $this->bookingDataProcessor->createBookingRequestPayload($bookingDto, 'Anfrage');
$payload = $this->bookingDataProcessor->createBookingRequestPayload($bookingDto, Constants::BOOKING_TYPE_INQUIRY);
$data = [
'user' => $this->config['bpn_username'],
@@ -255,7 +255,7 @@ class ApiClient
*/
public function createBooking(BookingDto $bookingDto, bool $debug = false): Notification|BookingResponse
{
$payload = $this->bookingDataProcessor->createBookingRequestPayload($bookingDto, 'Buchung');
$payload = $this->bookingDataProcessor->createBookingRequestPayload($bookingDto, Constants::BOOKING_TYPE_BOOKING);
$data = [
'user' => $this->config['bpn_username'],
+4
View File
@@ -48,6 +48,10 @@ final class Constants
public const STATUS_BLOCKED = 'Buchungsstop';
public const STATUS_ON_REQUEST = 'Anfrage';
// Booking types for API requests
public const BOOKING_TYPE_INQUIRY = 'Anfrage';
public const BOOKING_TYPE_BOOKING = 'Buchung';
// Payment methods
public const PAYMENT_METHOD_TRANSFER = 'transfer';
public const PAYMENT_METHOD_DEBIT = 'debit';
@@ -688,11 +688,16 @@ class BookingDataProcessor
}
}
// Add promo voucher or goodwill voucher as aktionscode
// Goodwill vouchers (Kulanz) take precedence over promo vouchers
$aktionscode = $this->getPromoVoucherCodeForParticipant($dto);
if (null !== $aktionscode) {
$participantPayload['aktionscode'] = $aktionscode;
// Add promotional voucher as promotionalCode
$promotionalCode = $this->getPromoVoucherCodeForParticipant($dto);
if (null !== $promotionalCode) {
$participantPayload['aktionscode'] = $promotionalCode;
}
// Add goodwill voucher as participant-level einloesecode
$goodwillCode = $this->getGoodwillVoucherCodeForParticipant($dto);
if (null !== $goodwillCode) {
$participantPayload['einloesecode'] = $goodwillCode;
}
}
@@ -835,6 +840,9 @@ class BookingDataProcessor
}
}
// Determine if this is an inquiry booking for voucher handling
$isInquiryBooking = 'A' === $bookingDto->bookingStatus;
// Add participants
$payload['teilnehmerliste']['teilnehmer'] = [];
foreach ($bookingDto->participants as $index => $participant) {
@@ -885,11 +893,19 @@ class BookingDataProcessor
}
}
// Add promo voucher or goodwill voucher as aktionscode
// Goodwill vouchers (Kulanz) take precedence over promo vouchers
$aktionscode = $this->getPromoVoucherCodeForParticipant($participant);
if (null !== $aktionscode) {
$participantData['aktionscode'] = $aktionscode;
// Add promotional voucher as aktionscode (allowed for inquiry bookings)
$promotionalCode = $this->getPromoVoucherCodeForParticipant($participant);
if (null !== $promotionalCode) {
$participantData['aktionscode'] = $promotionalCode;
}
// Add goodwill voucher as participant-level einloesecode
// Goodwill vouchers are excluded from inquiry bookings and only allowed in final booking requests
if (false === $isInquiryBooking && Constants::BOOKING_TYPE_BOOKING === $bookingType) {
$goodwillCode = $this->getGoodwillVoucherCodeForParticipant($participant);
if (null !== $goodwillCode) {
$participantData['einloesecode'] = $goodwillCode;
}
}
$payload['teilnehmerliste']['teilnehmer'][] = $participantData;
@@ -909,7 +925,9 @@ class BookingDataProcessor
$this->addServicesFromMap($payload, 'zustiege', 'zustieg', '@idzustieg', $pickupMap);
$this->addServicesFromMap($payload, 'versicherungen', 'versicherung', '@idversicherung', $insuranceMap);
// Add purchase vouchers if any exist
// Add purchase vouchers (regular purchase vouchers, excluding goodwill vouchers)
// Purchase vouchers are allowed for both inquiry and final bookings
// Goodwill vouchers are handled separately and excluded from inquiry bookings
$purchaseVouchers = $this->collectPurchaseVouchers($bookingDto);
if (false === empty($purchaseVouchers)) {
$payload['gutscheine']['gutschein'] = [];
@@ -1196,22 +1214,16 @@ class BookingDataProcessor
}
/**
* Gets the aktionscode for a participant.
* Gets the aktionscode (promotional voucher code) for a participant.
*
* Checks if the participant has a goodwill (Kulanz) purchase voucher first.
* If yes, returns that code (goodwill vouchers override promo vouchers).
* Otherwise, returns the promo voucher code if present.
* Returns the promotional voucher code if present.
* Goodwill vouchers are handled separately via getGoodwillVoucherCodeForParticipant().
*
* @return string|null The aktionscode to use, or null if none
*/
private function getPromoVoucherCodeForParticipant(ParticipantDto $participant): ?string
{
// Check for goodwill voucher first (takes precedence)
if (true === $participant->hasGoodwillVoucher && null !== $participant->purchaseVoucherCode && '' !== trim($participant->purchaseVoucherCode)) {
return trim($participant->purchaseVoucherCode);
}
// Fall back to promo voucher if present
// Only return promotional voucher code (goodwill vouchers are handled separately)
if (null !== $participant->promoVoucherCode && '' !== trim($participant->promoVoucherCode)) {
return trim($participant->promoVoucherCode);
}
@@ -1219,6 +1231,21 @@ class BookingDataProcessor
return null;
}
/**
* Extracts goodwill voucher code for a participant.
*
* Goodwill vouchers are sent as <einloesecode> per participant (not in aggregate),
* allowing them to coexist with promotional codes.
*/
private function getGoodwillVoucherCodeForParticipant(ParticipantDto $participant): ?string
{
if (true === $participant->hasGoodwillVoucher && null !== $participant->purchaseVoucherCode && '' !== trim($participant->purchaseVoucherCode)) {
return trim($participant->purchaseVoucherCode);
}
return null;
}
/**
* Applies bulk insurance assignment if the applicant has enabled it.
*