refactor: split buspro ApiClient into domain clients
This commit is contained in:
1 parent
0a55544ca8
commit
b755a6f43e
52 files changed
+805
-695
No files matched your search
@@ -1,399 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\BusProNet;
|
||||
|
||||
use App\BusProNet\DataProcessor\BookingDataProcessor;
|
||||
use App\BusProNet\DataProcessor\VoucherSalePayloadBuilder;
|
||||
use App\BusProNet\Exception\ApiClientException;
|
||||
use App\BusProNet\Model\Agency;
|
||||
use App\BusProNet\Model\BaseData;
|
||||
use App\BusProNet\Model\Booking;
|
||||
use App\BusProNet\Model\BookingResponse;
|
||||
use App\BusProNet\Model\BookingUpdate;
|
||||
use App\BusProNet\Model\CrmAttributes;
|
||||
use App\BusProNet\Model\ExtendedServiceAvailabilityResponse;
|
||||
use App\BusProNet\Model\Notification;
|
||||
use App\BusProNet\Model\PersonalData;
|
||||
use App\BusProNet\Model\PersonalDataUpdateResponse;
|
||||
use App\BusProNet\Model\PromoVoucher;
|
||||
use App\BusProNet\Model\PurchaseVoucher;
|
||||
use App\BusProNet\Model\RegistrationResponse;
|
||||
use App\BusProNet\Model\ServiceAvailabilityResponse;
|
||||
use App\BusProNet\Model\Travel;
|
||||
use App\BusProNet\Model\VoucherPaymentMethod;
|
||||
use App\BusProNet\Model\VoucherPreview;
|
||||
use App\BusProNet\Model\VoucherSaleResponse;
|
||||
use App\BusProNet\Model\VoucherTemplates;
|
||||
use App\BusProNet\Transport\XmlChannel;
|
||||
use App\Form\Model\BookingDto;
|
||||
use App\Form\Model\RegistrationDto;
|
||||
use App\Form\Model\VoucherPurchaseDto;
|
||||
|
||||
class ApiClient
|
||||
{
|
||||
public const TYPE_NOTIFICATION = 'HINWEIS';
|
||||
public const TYPE_CUSTOMER_DATA = 'KUNDENKONTO';
|
||||
public const TYPE_BASE_DATA_COUNTRIES = 'STAMMLAENDER';
|
||||
public const TYPE_MUTABLE_DATA = 'MOEGLICHEAENDERUNGEN';
|
||||
public const TYPE_AVAILABILITY = 'VERFUEGBARKEIT';
|
||||
public const TYPE_AVAILABILITY_EXTENDED = 'VERFUEGBARKEIT2';
|
||||
public const TYPE_AVAILABILITY_HOTEL = 'VERFUEGBARKEITHOTEL';
|
||||
public const TYPE_BOOKING_UPDATE = 'BUCHUNGAENDERUNG';
|
||||
public const TYPE_BOOKING = 'BUCHUNG';
|
||||
public const TYPE_PRODUCTS = 'PRODUKTE';
|
||||
public const TYPE_PRODUCT_DATA = 'PRODUKTDATEN';
|
||||
public const TYPE_AGENCIES = 'AGENTUREN';
|
||||
public const TYPE_PURCHASE_VOUCHER = 'GUTSCHEINPRUEFUNGEINLOESUNG';
|
||||
public const TYPE_PROMO_VOUCHER = 'AKTIONSGUTSCHEIN';
|
||||
// Selling Kaufgutscheine. Not to be confused with TYPE_PURCHASE_VOUCHER, which redeems one in a booking.
|
||||
public const TYPE_VOUCHER_TEMPLATES = 'GUTSCHEINVORLAGEN';
|
||||
public const TYPE_VOUCHER_PAYMENT_METHODS = 'GUTSCHEINZAHLUNGSARTEN';
|
||||
public const TYPE_VOUCHER_PREVIEW = 'GUTSCHEINVORSCHAU';
|
||||
public const TYPE_VOUCHER_SALE = 'GUTSCHEINBUCHUNG';
|
||||
|
||||
public function __construct(
|
||||
private readonly XmlChannel $channel,
|
||||
private readonly BookingDataProcessor $bookingDataProcessor,
|
||||
private readonly VoucherSalePayloadBuilder $voucherSalePayloadBuilder,
|
||||
) {
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws ApiClientException
|
||||
*/
|
||||
public function getPersonalData(string $email, string $password): Notification|PersonalData
|
||||
{
|
||||
return $this->customerRequest('Adressdaten', ['email' => $email, 'passwort' => $password]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws ApiClientException
|
||||
*/
|
||||
public function register(RegistrationDto $registrationData): Notification|RegistrationResponse
|
||||
{
|
||||
return $this->customerRequest('Adresse_Neu', ['adressdaten' => $registrationData->toPayload()]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws ApiClientException
|
||||
*/
|
||||
public function resetPassword(string $email): Notification
|
||||
{
|
||||
return $this->customerRequest('Passwort_Anfrage', ['email' => $email]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws ApiClientException
|
||||
*/
|
||||
public function updatePersonalData(
|
||||
string $email,
|
||||
string $password,
|
||||
PersonalData $personalData,
|
||||
bool $debug = false,
|
||||
): Notification|PersonalDataUpdateResponse {
|
||||
return $this->customerRequest('Adressdaten_Ändern', [
|
||||
'email' => $email,
|
||||
'passwort' => $password,
|
||||
'idadresse' => $personalData->addressId,
|
||||
'adressdaten' => $personalData->toPayload(),
|
||||
], $debug);
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws ApiClientException
|
||||
*/
|
||||
public function createAddress(
|
||||
PersonalData $personalData,
|
||||
bool $debug = false,
|
||||
): RegistrationResponse|Notification {
|
||||
return $this->customerRequest('Adresse_Neu', [
|
||||
'adressdaten' => $personalData->toPayload(false),
|
||||
'ohnemailversand' => 'True',
|
||||
], $debug);
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws ApiClientException
|
||||
*/
|
||||
public function updateNewsletterRegistration(string $email, string $password, PersonalData $personalData): Notification|PersonalData
|
||||
{
|
||||
return $this->customerRequest('Newsletter', [
|
||||
'email' => $email,
|
||||
'passwort' => $password,
|
||||
'idadresse' => $personalData->addressId,
|
||||
'newsletter' => [
|
||||
'email' => $email,
|
||||
'anmeldung' => $personalData->communication->newsletter ? 'True' : 'False',
|
||||
],
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws ApiClientException
|
||||
*/
|
||||
public function getBookings(string $email, string $password): Notification|BaseData
|
||||
{
|
||||
return $this->customerRequest('Vorgänge', ['email' => $email, 'passwort' => $password]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws ApiClientException
|
||||
*/
|
||||
public function getBooking(string $email, string $password, int $id): Notification|Booking
|
||||
{
|
||||
return $this->customerRequest('Vorgang_Details', ['email' => $email, 'passwort' => $password, 'idbuchung' => $id]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws ApiClientException
|
||||
*/
|
||||
public function updateBooking(BookingDto $formData, bool $debug = false): Notification|BookingUpdate
|
||||
{
|
||||
return $this->channel->request(static::TYPE_BOOKING_UPDATE, [
|
||||
'buchungsart' => Constants::BOOKING_TYPE_BOOKING,
|
||||
...$this->bookingDataProcessor->createUpdateRequestPayload($formData),
|
||||
], [], $debug);
|
||||
}
|
||||
|
||||
/**
|
||||
* First phase of the two-phase booking process: validates the booking and returns the
|
||||
* prices without creating it.
|
||||
*
|
||||
* @throws ApiClientException
|
||||
*/
|
||||
public function createBookingInquiry(BookingDto $bookingDto, bool $debug = false): Notification|BookingResponse
|
||||
{
|
||||
return $this->sendBooking($bookingDto, Constants::BOOKING_TYPE_INQUIRY, $debug);
|
||||
}
|
||||
|
||||
/**
|
||||
* Second phase of the two-phase booking process: creates the booking after a successful
|
||||
* inquiry.
|
||||
*
|
||||
* @throws ApiClientException
|
||||
*/
|
||||
public function createBooking(BookingDto $bookingDto, bool $debug = false): Notification|BookingResponse
|
||||
{
|
||||
return $this->sendBooking($bookingDto, Constants::BOOKING_TYPE_BOOKING, $debug);
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws ApiClientException
|
||||
*/
|
||||
public function getMutableData(int $dateId): Notification|BaseData
|
||||
{
|
||||
return $this->channel->request(static::TYPE_MUTABLE_DATA, ['idreise' => $dateId]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws ApiClientException
|
||||
*/
|
||||
public function getAvailabilities(int $dateId): Notification|ServiceAvailabilityResponse
|
||||
{
|
||||
return $this->channel->request(static::TYPE_AVAILABILITY, ['idreise' => $dateId]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws ApiClientException
|
||||
*/
|
||||
public function getAvailabilitiesExtended(int $dateId): Notification|ExtendedServiceAvailabilityResponse
|
||||
{
|
||||
return $this->channel->request(static::TYPE_AVAILABILITY_EXTENDED, ['idreise' => $dateId]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws ApiClientException
|
||||
*/
|
||||
public function getHotelAvailability(int $dateId, int $hotelId, \DateTimeInterface $dateTo): Notification|BaseData
|
||||
{
|
||||
return $this->channel->request(static::TYPE_AVAILABILITY_HOTEL, [
|
||||
'idreise' => $dateId,
|
||||
'idpartner' => $hotelId,
|
||||
'terminbis' => $dateTo->format('d.m.Y'),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws ApiClientException
|
||||
*/
|
||||
public function getCrmAttributes(string $email, string $password): Notification|CrmAttributes
|
||||
{
|
||||
return $this->customerRequest('SelektionCRM', ['email' => $email, 'passwort' => $password]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws ApiClientException
|
||||
*/
|
||||
public function getBaseData(string $type): Notification|BaseData
|
||||
{
|
||||
return $this->channel->request($type);
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws ApiClientException
|
||||
*/
|
||||
public function getDocuments(string $email, string $password, int $bookingId, string $type): mixed
|
||||
{
|
||||
return $this->customerRequest($type, ['email' => $email, 'passwort' => $password, 'idbuchung' => $bookingId]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws ApiClientException
|
||||
*/
|
||||
public function getTravelData(int $travelId, ?int $hotelId = null): Notification|Travel
|
||||
{
|
||||
return $this->channel->request(static::TYPE_PRODUCT_DATA, ['idprodukt' => $travelId], ['hotelId' => $hotelId]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the unparsed response, which has the structure of BusPro's XML export and is
|
||||
* stored in the export directory as is.
|
||||
*
|
||||
* @throws ApiClientException
|
||||
*/
|
||||
public function getTravelDataXml(int $travelId): string
|
||||
{
|
||||
return $this->channel->requestRaw(static::TYPE_PRODUCT_DATA, ['idprodukt' => $travelId]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws ApiClientException
|
||||
*/
|
||||
public function getProducts(): Notification|BaseData
|
||||
{
|
||||
return $this->channel->request(static::TYPE_PRODUCTS);
|
||||
}
|
||||
|
||||
/**
|
||||
* Changes rarely, so callers cache it for long periods.
|
||||
*
|
||||
* @return Agency[]|Notification
|
||||
*
|
||||
* @throws ApiClientException
|
||||
*/
|
||||
public function getAgencies(): array|Notification
|
||||
{
|
||||
return $this->channel->request(static::TYPE_AGENCIES);
|
||||
}
|
||||
|
||||
/**
|
||||
* Looks up a purchase voucher (Gutschein) by its redemption code. Purchase vouchers, regular
|
||||
* or goodwill (Kulanz), carry a balance that each redemption reduces.
|
||||
*
|
||||
* @throws ApiClientException
|
||||
*/
|
||||
public function validatePurchaseVoucher(string $redemptionCode): Notification|PurchaseVoucher
|
||||
{
|
||||
return $this->channel->request(static::TYPE_PURCHASE_VOUCHER, ['einloesecode' => $redemptionCode]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates a promo voucher (Aktionsgutschein) for a travel and participant price. Promo
|
||||
* vouchers are absolute discounts, per person ("P") or per booking ("B") as pro_buchung_person
|
||||
* says.
|
||||
*
|
||||
* @throws ApiClientException
|
||||
*/
|
||||
public function validatePromoVoucher(string $promoCode, int $travelId, float $participantPrice): Notification|PromoVoucher
|
||||
{
|
||||
return $this->channel->request(static::TYPE_PROMO_VOUCHER, [
|
||||
'aktionsgutschein' => $promoCode,
|
||||
'idreise' => $travelId,
|
||||
'preis' => number_format($participantPrice, 2, ',', ''),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches the voucher designs on sale and the amount bounds.
|
||||
*
|
||||
* @throws ApiClientException
|
||||
*/
|
||||
public function getVoucherTemplates(): Notification|VoucherTemplates
|
||||
{
|
||||
return $this->channel->request(static::TYPE_VOUCHER_TEMPLATES);
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches the payment methods offered for voucher purchases.
|
||||
*
|
||||
* @return list<VoucherPaymentMethod>|Notification
|
||||
*
|
||||
* @throws ApiClientException
|
||||
*/
|
||||
public function getVoucherPaymentMethods(): array|Notification
|
||||
{
|
||||
return $this->channel->request(static::TYPE_VOUCHER_PAYMENT_METHODS);
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders the PDF preview of a voucher design with the entered data.
|
||||
*
|
||||
* @throws ApiClientException
|
||||
*/
|
||||
public function getVoucherPreview(VoucherPurchaseDto $voucherPurchaseDto): Notification|VoucherPreview
|
||||
{
|
||||
return $this->channel->request(static::TYPE_VOUCHER_PREVIEW, $this->voucherSalePayloadBuilder->buildPreviewPayload($voucherPurchaseDto));
|
||||
}
|
||||
|
||||
/**
|
||||
* Dry run of a voucher purchase: full validation, nothing is issued.
|
||||
*
|
||||
* Every HINWEIS is a rejection on this path, including 650 (missing address data), so the
|
||||
* result must not be judged by Notification::isError().
|
||||
*
|
||||
* @throws ApiClientException
|
||||
*/
|
||||
public function createVoucherSaleInquiry(VoucherPurchaseDto $voucherPurchaseDto): Notification|VoucherSaleResponse
|
||||
{
|
||||
return $this->sendVoucherSale($voucherPurchaseDto, Constants::BOOKING_TYPE_INQUIRY);
|
||||
}
|
||||
|
||||
/**
|
||||
* Buys the voucher. BusPro mails it to the buyer once the payment has arrived.
|
||||
*
|
||||
* Every HINWEIS is a rejection on this path, including 650.
|
||||
*
|
||||
* @throws ApiClientException
|
||||
*/
|
||||
public function createVoucherSale(VoucherPurchaseDto $voucherPurchaseDto): Notification|VoucherSaleResponse
|
||||
{
|
||||
return $this->sendVoucherSale($voucherPurchaseDto, Constants::BOOKING_TYPE_BOOKING);
|
||||
}
|
||||
|
||||
/**
|
||||
* Replays a request as is, except for the key, which is regenerated for the current date.
|
||||
* Returns the unparsed response.
|
||||
*
|
||||
* @throws ApiClientException
|
||||
*/
|
||||
public function sendRawXml(string $xml, bool $debug = false): string
|
||||
{
|
||||
return $this->channel->replay($xml, $debug);
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws ApiClientException
|
||||
*/
|
||||
private function sendBooking(BookingDto $bookingDto, string $bookingType, bool $debug): Notification|BookingResponse
|
||||
{
|
||||
return $this->channel->request(static::TYPE_BOOKING, $this->bookingDataProcessor->createBookingRequestPayload($bookingDto, $bookingType), [], $debug);
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws ApiClientException
|
||||
*/
|
||||
private function sendVoucherSale(VoucherPurchaseDto $voucherPurchaseDto, string $saleType): Notification|VoucherSaleResponse
|
||||
{
|
||||
return $this->channel->request(static::TYPE_VOUCHER_SALE, $this->voucherSalePayloadBuilder->buildSalePayload($voucherPurchaseDto, $saleType));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, mixed> $fields
|
||||
*
|
||||
* @throws ApiClientException
|
||||
*/
|
||||
private function customerRequest(string $art, array $fields, bool $debug = false): mixed
|
||||
{
|
||||
return $this->channel->request(static::TYPE_CUSTOMER_DATA, ['art' => $art, ...$fields], [], $debug);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,119 @@
|
||||
<?php
|
||||
|
||||
namespace App\BusProNet\Client;
|
||||
|
||||
use App\BusProNet\Exception\ApiClientException;
|
||||
use App\BusProNet\MessageType;
|
||||
use App\BusProNet\Model\CrmAttributes;
|
||||
use App\BusProNet\Model\Notification;
|
||||
use App\BusProNet\Model\PersonalData;
|
||||
use App\BusProNet\Model\PersonalDataUpdateResponse;
|
||||
use App\BusProNet\Model\RegistrationResponse;
|
||||
use App\BusProNet\Transport\XmlChannel;
|
||||
use App\Form\Model\RegistrationDto;
|
||||
|
||||
/**
|
||||
* A customer's BusPro account: login, address data, newsletter, CRM selections.
|
||||
*/
|
||||
class AccountClient
|
||||
{
|
||||
public function __construct(
|
||||
private readonly XmlChannel $channel,
|
||||
) {
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws ApiClientException
|
||||
*/
|
||||
public function getPersonalData(string $email, string $password): Notification|PersonalData
|
||||
{
|
||||
return $this->channel->request(MessageType::CustomerData, [
|
||||
'art' => 'Adressdaten',
|
||||
'email' => $email,
|
||||
'passwort' => $password,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws ApiClientException
|
||||
*/
|
||||
public function register(RegistrationDto $registrationData): Notification|RegistrationResponse
|
||||
{
|
||||
return $this->channel->request(MessageType::CustomerData, [
|
||||
'art' => 'Adresse_Neu',
|
||||
'adressdaten' => $registrationData->toPayload(),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws ApiClientException
|
||||
*/
|
||||
public function resetPassword(string $email): Notification
|
||||
{
|
||||
return $this->channel->request(MessageType::CustomerData, [
|
||||
'art' => 'Passwort_Anfrage',
|
||||
'email' => $email,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws ApiClientException
|
||||
*/
|
||||
public function updatePersonalData(
|
||||
string $email,
|
||||
string $password,
|
||||
PersonalData $personalData,
|
||||
bool $debug = false,
|
||||
): Notification|PersonalDataUpdateResponse {
|
||||
return $this->channel->request(MessageType::CustomerData, [
|
||||
'art' => 'Adressdaten_Ändern',
|
||||
'email' => $email,
|
||||
'passwort' => $password,
|
||||
'idadresse' => $personalData->addressId,
|
||||
'adressdaten' => $personalData->toPayload(),
|
||||
], [], $debug);
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws ApiClientException
|
||||
*/
|
||||
public function createAddress(
|
||||
PersonalData $personalData,
|
||||
bool $debug = false,
|
||||
): RegistrationResponse|Notification {
|
||||
return $this->channel->request(MessageType::CustomerData, [
|
||||
'art' => 'Adresse_Neu',
|
||||
'adressdaten' => $personalData->toPayload(false),
|
||||
'ohnemailversand' => 'True',
|
||||
], [], $debug);
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws ApiClientException
|
||||
*/
|
||||
public function updateNewsletterRegistration(string $email, string $password, PersonalData $personalData): Notification|PersonalData
|
||||
{
|
||||
return $this->channel->request(MessageType::CustomerData, [
|
||||
'art' => 'Newsletter',
|
||||
'email' => $email,
|
||||
'passwort' => $password,
|
||||
'idadresse' => $personalData->addressId,
|
||||
'newsletter' => [
|
||||
'email' => $email,
|
||||
'anmeldung' => $personalData->communication->newsletter ? 'True' : 'False',
|
||||
],
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws ApiClientException
|
||||
*/
|
||||
public function getCrmAttributes(string $email, string $password): Notification|CrmAttributes
|
||||
{
|
||||
return $this->channel->request(MessageType::CustomerData, [
|
||||
'art' => 'SelektionCRM',
|
||||
'email' => $email,
|
||||
'passwort' => $password,
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,106 @@
|
||||
<?php
|
||||
|
||||
namespace App\BusProNet\Client;
|
||||
|
||||
use App\BusProNet\Constants;
|
||||
use App\BusProNet\DataProcessor\BookingDataProcessor;
|
||||
use App\BusProNet\Exception\ApiClientException;
|
||||
use App\BusProNet\MessageType;
|
||||
use App\BusProNet\Model\BaseData;
|
||||
use App\BusProNet\Model\Booking;
|
||||
use App\BusProNet\Model\BookingResponse;
|
||||
use App\BusProNet\Model\BookingUpdate;
|
||||
use App\BusProNet\Model\Notification;
|
||||
use App\BusProNet\Transport\XmlChannel;
|
||||
use App\Form\Model\BookingDto;
|
||||
|
||||
/**
|
||||
* A customer's bookings: listing, details and documents, creating and changing them.
|
||||
*/
|
||||
class BookingClient
|
||||
{
|
||||
public function __construct(
|
||||
private readonly XmlChannel $channel,
|
||||
private readonly BookingDataProcessor $bookingDataProcessor,
|
||||
) {
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws ApiClientException
|
||||
*/
|
||||
public function getBookings(string $email, string $password): Notification|BaseData
|
||||
{
|
||||
return $this->channel->request(MessageType::CustomerData, [
|
||||
'art' => 'Vorgänge',
|
||||
'email' => $email,
|
||||
'passwort' => $password,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws ApiClientException
|
||||
*/
|
||||
public function getBooking(string $email, string $password, int $id): Notification|Booking
|
||||
{
|
||||
return $this->channel->request(MessageType::CustomerData, [
|
||||
'art' => 'Vorgang_Details',
|
||||
'email' => $email,
|
||||
'passwort' => $password,
|
||||
'idbuchung' => $id,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws ApiClientException
|
||||
*/
|
||||
public function getDocuments(string $email, string $password, int $bookingId, string $type): mixed
|
||||
{
|
||||
return $this->channel->request(MessageType::CustomerData, [
|
||||
'art' => $type,
|
||||
'email' => $email,
|
||||
'passwort' => $password,
|
||||
'idbuchung' => $bookingId,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws ApiClientException
|
||||
*/
|
||||
public function updateBooking(BookingDto $formData, bool $debug = false): Notification|BookingUpdate
|
||||
{
|
||||
return $this->channel->request(MessageType::BookingUpdate, [
|
||||
'buchungsart' => Constants::BOOKING_TYPE_BOOKING,
|
||||
...$this->bookingDataProcessor->createUpdateRequestPayload($formData),
|
||||
], [], $debug);
|
||||
}
|
||||
|
||||
/**
|
||||
* First phase of the two-phase booking process: validates the booking and returns the
|
||||
* prices without creating it.
|
||||
*
|
||||
* @throws ApiClientException
|
||||
*/
|
||||
public function createBookingInquiry(BookingDto $bookingDto, bool $debug = false): Notification|BookingResponse
|
||||
{
|
||||
return $this->sendBooking($bookingDto, Constants::BOOKING_TYPE_INQUIRY, $debug);
|
||||
}
|
||||
|
||||
/**
|
||||
* Second phase of the two-phase booking process: creates the booking after a successful
|
||||
* inquiry.
|
||||
*
|
||||
* @throws ApiClientException
|
||||
*/
|
||||
public function createBooking(BookingDto $bookingDto, bool $debug = false): Notification|BookingResponse
|
||||
{
|
||||
return $this->sendBooking($bookingDto, Constants::BOOKING_TYPE_BOOKING, $debug);
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws ApiClientException
|
||||
*/
|
||||
private function sendBooking(BookingDto $bookingDto, string $bookingType, bool $debug): Notification|BookingResponse
|
||||
{
|
||||
return $this->channel->request(MessageType::Booking, $this->bookingDataProcessor->createBookingRequestPayload($bookingDto, $bookingType), [], $debug);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
<?php
|
||||
|
||||
namespace App\BusProNet\Client;
|
||||
|
||||
use App\BusProNet\Exception\ApiClientException;
|
||||
use App\BusProNet\MessageType;
|
||||
use App\BusProNet\Model\Agency;
|
||||
use App\BusProNet\Model\BaseData;
|
||||
use App\BusProNet\Model\Notification;
|
||||
use App\BusProNet\Transport\XmlChannel;
|
||||
|
||||
/**
|
||||
* Lists that change rarely and that callers cache for long periods.
|
||||
*/
|
||||
class ReferenceDataClient
|
||||
{
|
||||
public function __construct(
|
||||
private readonly XmlChannel $channel,
|
||||
) {
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Agency[]|Notification
|
||||
*
|
||||
* @throws ApiClientException
|
||||
*/
|
||||
public function getAgencies(): array|Notification
|
||||
{
|
||||
return $this->channel->request(MessageType::Agencies);
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws ApiClientException
|
||||
*/
|
||||
public function getBaseData(MessageType $type): Notification|BaseData
|
||||
{
|
||||
return $this->channel->request($type);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,87 @@
|
||||
<?php
|
||||
|
||||
namespace App\BusProNet\Client;
|
||||
|
||||
use App\BusProNet\Exception\ApiClientException;
|
||||
use App\BusProNet\MessageType;
|
||||
use App\BusProNet\Model\BaseData;
|
||||
use App\BusProNet\Model\ExtendedServiceAvailabilityResponse;
|
||||
use App\BusProNet\Model\Notification;
|
||||
use App\BusProNet\Model\ServiceAvailabilityResponse;
|
||||
use App\BusProNet\Model\Travel;
|
||||
use App\BusProNet\Transport\XmlChannel;
|
||||
|
||||
/**
|
||||
* Travels from the live API. Most reads belong in TravelDataProvider, which arbitrates
|
||||
* between this, the XML export and the snapshots.
|
||||
*/
|
||||
class TravelClient
|
||||
{
|
||||
public function __construct(
|
||||
private readonly XmlChannel $channel,
|
||||
) {
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws ApiClientException
|
||||
*/
|
||||
public function getTravelData(int $travelId, ?int $hotelId = null): Notification|Travel
|
||||
{
|
||||
return $this->channel->request(MessageType::ProductData, ['idprodukt' => $travelId], ['hotelId' => $hotelId]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the unparsed response, which has the structure of BusPro's XML export and is
|
||||
* stored in the export directory as is.
|
||||
*
|
||||
* @throws ApiClientException
|
||||
*/
|
||||
public function getTravelDataXml(int $travelId): string
|
||||
{
|
||||
return $this->channel->requestRaw(MessageType::ProductData, ['idprodukt' => $travelId]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws ApiClientException
|
||||
*/
|
||||
public function getProducts(): Notification|BaseData
|
||||
{
|
||||
return $this->channel->request(MessageType::Products);
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws ApiClientException
|
||||
*/
|
||||
public function getMutableData(int $dateId): Notification|BaseData
|
||||
{
|
||||
return $this->channel->request(MessageType::MutableData, ['idreise' => $dateId]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws ApiClientException
|
||||
*/
|
||||
public function getAvailabilities(int $dateId): Notification|ServiceAvailabilityResponse
|
||||
{
|
||||
return $this->channel->request(MessageType::Availability, ['idreise' => $dateId]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws ApiClientException
|
||||
*/
|
||||
public function getAvailabilitiesExtended(int $dateId): Notification|ExtendedServiceAvailabilityResponse
|
||||
{
|
||||
return $this->channel->request(MessageType::AvailabilityExtended, ['idreise' => $dateId]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws ApiClientException
|
||||
*/
|
||||
public function getHotelAvailability(int $dateId, int $hotelId, \DateTimeInterface $dateTo): Notification|BaseData
|
||||
{
|
||||
return $this->channel->request(MessageType::AvailabilityHotel, [
|
||||
'idreise' => $dateId,
|
||||
'idpartner' => $hotelId,
|
||||
'terminbis' => $dateTo->format('d.m.Y'),
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,121 @@
|
||||
<?php
|
||||
|
||||
namespace App\BusProNet\Client;
|
||||
|
||||
use App\BusProNet\Constants;
|
||||
use App\BusProNet\DataProcessor\VoucherSalePayloadBuilder;
|
||||
use App\BusProNet\Exception\ApiClientException;
|
||||
use App\BusProNet\MessageType;
|
||||
use App\BusProNet\Model\Notification;
|
||||
use App\BusProNet\Model\PromoVoucher;
|
||||
use App\BusProNet\Model\PurchaseVoucher;
|
||||
use App\BusProNet\Model\VoucherPaymentMethod;
|
||||
use App\BusProNet\Model\VoucherPreview;
|
||||
use App\BusProNet\Model\VoucherSaleResponse;
|
||||
use App\BusProNet\Model\VoucherTemplates;
|
||||
use App\BusProNet\Transport\XmlChannel;
|
||||
use App\Form\Model\VoucherPurchaseDto;
|
||||
|
||||
/**
|
||||
* Redeeming vouchers in a booking, and selling purchase vouchers (Kaufgutscheine).
|
||||
*/
|
||||
class VoucherClient
|
||||
{
|
||||
public function __construct(
|
||||
private readonly XmlChannel $channel,
|
||||
private readonly VoucherSalePayloadBuilder $voucherSalePayloadBuilder,
|
||||
) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Looks up a purchase voucher (Gutschein) by its redemption code. Purchase vouchers, regular
|
||||
* or goodwill (Kulanz), carry a balance that each redemption reduces.
|
||||
*
|
||||
* @throws ApiClientException
|
||||
*/
|
||||
public function validatePurchaseVoucher(string $redemptionCode): Notification|PurchaseVoucher
|
||||
{
|
||||
return $this->channel->request(MessageType::PurchaseVoucher, ['einloesecode' => $redemptionCode]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates a promo voucher (Aktionsgutschein) for a travel and participant price. Promo
|
||||
* vouchers are absolute discounts, per person ("P") or per booking ("B") as pro_buchung_person
|
||||
* says.
|
||||
*
|
||||
* @throws ApiClientException
|
||||
*/
|
||||
public function validatePromoVoucher(string $promoCode, int $travelId, float $participantPrice): Notification|PromoVoucher
|
||||
{
|
||||
return $this->channel->request(MessageType::PromoVoucher, [
|
||||
'aktionsgutschein' => $promoCode,
|
||||
'idreise' => $travelId,
|
||||
'preis' => number_format($participantPrice, 2, ',', ''),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches the voucher designs on sale and the amount bounds.
|
||||
*
|
||||
* @throws ApiClientException
|
||||
*/
|
||||
public function getVoucherTemplates(): Notification|VoucherTemplates
|
||||
{
|
||||
return $this->channel->request(MessageType::VoucherTemplates);
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches the payment methods offered for voucher purchases.
|
||||
*
|
||||
* @return list<VoucherPaymentMethod>|Notification
|
||||
*
|
||||
* @throws ApiClientException
|
||||
*/
|
||||
public function getVoucherPaymentMethods(): array|Notification
|
||||
{
|
||||
return $this->channel->request(MessageType::VoucherPaymentMethods);
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders the PDF preview of a voucher design with the entered data.
|
||||
*
|
||||
* @throws ApiClientException
|
||||
*/
|
||||
public function getVoucherPreview(VoucherPurchaseDto $voucherPurchaseDto): Notification|VoucherPreview
|
||||
{
|
||||
return $this->channel->request(MessageType::VoucherPreview, $this->voucherSalePayloadBuilder->buildPreviewPayload($voucherPurchaseDto));
|
||||
}
|
||||
|
||||
/**
|
||||
* Dry run of a voucher purchase: full validation, nothing is issued.
|
||||
*
|
||||
* Every HINWEIS is a rejection on this path, including 650 (missing address data), so the
|
||||
* result must not be judged by Notification::isError().
|
||||
*
|
||||
* @throws ApiClientException
|
||||
*/
|
||||
public function createVoucherSaleInquiry(VoucherPurchaseDto $voucherPurchaseDto): Notification|VoucherSaleResponse
|
||||
{
|
||||
return $this->sendVoucherSale($voucherPurchaseDto, Constants::BOOKING_TYPE_INQUIRY);
|
||||
}
|
||||
|
||||
/**
|
||||
* Buys the voucher. BusPro mails it to the buyer once the payment has arrived.
|
||||
*
|
||||
* Every HINWEIS is a rejection on this path, including 650.
|
||||
*
|
||||
* @throws ApiClientException
|
||||
*/
|
||||
public function createVoucherSale(VoucherPurchaseDto $voucherPurchaseDto): Notification|VoucherSaleResponse
|
||||
{
|
||||
return $this->sendVoucherSale($voucherPurchaseDto, Constants::BOOKING_TYPE_BOOKING);
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws ApiClientException
|
||||
*/
|
||||
private function sendVoucherSale(VoucherPurchaseDto $voucherPurchaseDto, string $saleType): Notification|VoucherSaleResponse
|
||||
{
|
||||
return $this->channel->request(MessageType::VoucherSale, $this->voucherSalePayloadBuilder->buildSalePayload($voucherPurchaseDto, $saleType));
|
||||
}
|
||||
}
|
||||
@@ -2,7 +2,8 @@
|
||||
|
||||
namespace App\BusProNet\DataProvider;
|
||||
|
||||
use App\BusProNet\ApiClient;
|
||||
use App\BusProNet\Client\ReferenceDataClient;
|
||||
use App\BusProNet\MessageType;
|
||||
use App\BusProNet\Model\Country;
|
||||
use Psr\Cache\InvalidArgumentException;
|
||||
use Symfony\Contracts\Cache\CacheInterface;
|
||||
@@ -10,7 +11,7 @@ use Symfony\Contracts\Cache\ItemInterface;
|
||||
|
||||
class CountryDataProvider
|
||||
{
|
||||
public function __construct(private readonly ApiClient $apiClient, private readonly CacheInterface $cache)
|
||||
public function __construct(private readonly ReferenceDataClient $referenceDataClient, private readonly CacheInterface $cache)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -22,8 +23,8 @@ class CountryDataProvider
|
||||
$item->expiresAfter(6 * 60 * 60);
|
||||
|
||||
return $this
|
||||
->apiClient
|
||||
->getBaseData(ApiClient::TYPE_BASE_DATA_COUNTRIES)
|
||||
->referenceDataClient
|
||||
->getBaseData(MessageType::Countries)
|
||||
->getItems()
|
||||
;
|
||||
});
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
<?php
|
||||
|
||||
namespace App\BusProNet;
|
||||
|
||||
/**
|
||||
* The `typ` of BusPro's `<satz>`: the command on a request, the kind of answer on a response.
|
||||
*/
|
||||
enum MessageType: string
|
||||
{
|
||||
// Only ever a response: BusPro's refusal or remark, whatever was asked.
|
||||
case Notification = 'HINWEIS';
|
||||
case CustomerData = 'KUNDENKONTO';
|
||||
case Countries = 'STAMMLAENDER';
|
||||
case MutableData = 'MOEGLICHEAENDERUNGEN';
|
||||
case Availability = 'VERFUEGBARKEIT';
|
||||
case AvailabilityExtended = 'VERFUEGBARKEIT2';
|
||||
case AvailabilityHotel = 'VERFUEGBARKEITHOTEL';
|
||||
case BookingUpdate = 'BUCHUNGAENDERUNG';
|
||||
case Booking = 'BUCHUNG';
|
||||
case Products = 'PRODUKTE';
|
||||
case ProductData = 'PRODUKTDATEN';
|
||||
case Agencies = 'AGENTUREN';
|
||||
case PurchaseVoucher = 'GUTSCHEINPRUEFUNGEINLOESUNG';
|
||||
case PromoVoucher = 'AKTIONSGUTSCHEIN';
|
||||
// Selling Kaufgutscheine. Not to be confused with PurchaseVoucher, which redeems one in a booking.
|
||||
case VoucherTemplates = 'GUTSCHEINVORLAGEN';
|
||||
case VoucherPaymentMethods = 'GUTSCHEINZAHLUNGSARTEN';
|
||||
case VoucherPreview = 'GUTSCHEINVORSCHAU';
|
||||
case VoucherSale = 'GUTSCHEINBUCHUNG';
|
||||
}
|
||||
@@ -5,6 +5,7 @@ namespace App\BusProNet\Transport;
|
||||
use App\BusProNet\Exception\ApiClientException;
|
||||
use App\BusProNet\Exception\ImmediateConnectionCloseException;
|
||||
use App\BusProNet\Exception\ResponseParserException;
|
||||
use App\BusProNet\MessageType;
|
||||
use App\BusProNet\XmlParser\ApiResponseParser;
|
||||
use App\Service\XmlDumpWriter;
|
||||
use Psr\Log\LoggerInterface;
|
||||
@@ -42,7 +43,7 @@ class XmlChannel
|
||||
*
|
||||
* @throws ApiClientException
|
||||
*/
|
||||
public function request(string $type, array $fields = [], array $parserArgs = [], bool $debug = false): mixed
|
||||
public function request(MessageType $type, array $fields = [], array $parserArgs = [], bool $debug = false): mixed
|
||||
{
|
||||
$data = $this->envelope($type, $fields);
|
||||
|
||||
@@ -50,10 +51,10 @@ class XmlChannel
|
||||
$requestId = $this->requestIds->next();
|
||||
$dump = $debug || true === $this->config['debug'];
|
||||
|
||||
$xml = $this->exchange($requestId, $this->serializeXml($data), $type, 'Sending request to BPN API', $dump);
|
||||
$xml = $this->exchange($requestId, $this->serializeXml($data), $type->value, 'Sending request to BPN API', $dump);
|
||||
|
||||
return $this->parseResponse($type, $xml, $parserArgs, $requestId);
|
||||
}, $type);
|
||||
}, $type->value);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -63,7 +64,7 @@ class XmlChannel
|
||||
*
|
||||
* @throws ApiClientException
|
||||
*/
|
||||
public function requestRaw(string $type, array $fields = []): string
|
||||
public function requestRaw(MessageType $type, array $fields = []): string
|
||||
{
|
||||
$data = $this->envelope($type, $fields);
|
||||
|
||||
@@ -71,7 +72,7 @@ class XmlChannel
|
||||
$requestId = $this->requestIds->next();
|
||||
$body = $this->serializeXml($data);
|
||||
|
||||
return $this->exchange($requestId, $body, $type, 'Sending raw request to BPN API', true === $this->config['debug']);
|
||||
return $this->exchange($requestId, $body, $type->value, 'Sending raw request to BPN API', true === $this->config['debug']);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -93,12 +94,12 @@ class XmlChannel
|
||||
*
|
||||
* @return array<string, mixed>
|
||||
*/
|
||||
private function envelope(string $type, array $fields): array
|
||||
private function envelope(MessageType $type, array $fields): array
|
||||
{
|
||||
return [
|
||||
'user' => $this->config['bpn_username'],
|
||||
'key' => $this->createKey($type),
|
||||
'satz' => ['@typ' => $type],
|
||||
'key' => $this->createKey($type->value),
|
||||
'satz' => ['@typ' => $type->value],
|
||||
...$fields,
|
||||
];
|
||||
}
|
||||
@@ -205,7 +206,7 @@ class XmlChannel
|
||||
*
|
||||
* @throws ApiClientException
|
||||
*/
|
||||
private function parseResponse(string $type, string $xml, array $parserArgs, string $requestId, bool $dumpOnFailure = true): mixed
|
||||
private function parseResponse(MessageType $type, string $xml, array $parserArgs, string $requestId, bool $dumpOnFailure = true): mixed
|
||||
{
|
||||
try {
|
||||
return $this->responseParser->parseXmlString($type, $xml, $parserArgs);
|
||||
@@ -218,7 +219,7 @@ class XmlChannel
|
||||
|
||||
$this->logger->error('Unable to parse response received from API', [
|
||||
'request_id' => $requestId,
|
||||
'type' => $type,
|
||||
'type' => $type->value,
|
||||
'response_length' => strlen($xml),
|
||||
'error_message' => $e->getMessage(),
|
||||
]);
|
||||
|
||||
@@ -4,7 +4,7 @@ declare(strict_types=1);
|
||||
|
||||
namespace App\BusProNet\XmlLoader;
|
||||
|
||||
use App\BusProNet\ApiClient;
|
||||
use App\BusProNet\Client\ReferenceDataClient;
|
||||
use App\BusProNet\Model\Agency;
|
||||
use App\BusProNet\Model\Notification;
|
||||
use Psr\Cache\InvalidArgumentException;
|
||||
@@ -19,7 +19,7 @@ class AgencyLoader
|
||||
|
||||
public function __construct(
|
||||
private readonly CacheInterface $cache,
|
||||
private readonly ApiClient $apiClient,
|
||||
private readonly ReferenceDataClient $referenceDataClient,
|
||||
private readonly LoggerInterface $logger,
|
||||
) {
|
||||
}
|
||||
@@ -34,7 +34,7 @@ class AgencyLoader
|
||||
// Cache for 24 hours (agencies change infrequently)
|
||||
$item->expiresAfter(24 * 60 * 60);
|
||||
|
||||
$result = $this->apiClient->getAgencies();
|
||||
$result = $this->referenceDataClient->getAgencies();
|
||||
|
||||
if ($result instanceof Notification) {
|
||||
$this->logger->error('Failed to fetch agencies from BPN API', [
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
|
||||
namespace App\BusProNet\XmlParser;
|
||||
|
||||
use App\BusProNet\ApiClient;
|
||||
use App\BusProNet\Exception\ResponseParserException;
|
||||
use App\BusProNet\MessageType;
|
||||
use App\BusProNet\XmlCrawlerFactory;
|
||||
|
||||
class ApiResponseParser extends AbstractParser
|
||||
@@ -14,10 +14,11 @@ class ApiResponseParser extends AbstractParser
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, mixed> $additionalArgs
|
||||
*
|
||||
* @throws ResponseParserException
|
||||
*/
|
||||
/** @param array<string, mixed> $additionalArgs */
|
||||
public function parseXmlString(string $type, string $xml, array $additionalArgs = []): mixed
|
||||
public function parseXmlString(MessageType $type, string $xml, array $additionalArgs = []): mixed
|
||||
{
|
||||
$crawler = XmlCrawlerFactory::create($xml);
|
||||
|
||||
@@ -25,17 +26,20 @@ class ApiResponseParser extends AbstractParser
|
||||
throw new ResponseParserException('Unable to parse XML response: '.XmlCrawlerFactory::diagnose($xml));
|
||||
}
|
||||
|
||||
// Override type unless present in XML to catch error responses
|
||||
$responseType = $this
|
||||
->getStringOrNullValue($crawler->filterXPath('//ergebnis/satz/@typ')) ?? $type;
|
||||
// The type in the XML wins, to catch error responses. BusPro may send one we don't know.
|
||||
$typeAttribute = $this->getStringOrNullValue($crawler->filterXPath('//ergebnis/satz/@typ'));
|
||||
$responseType = null === $typeAttribute ? $type : MessageType::tryFrom($typeAttribute);
|
||||
if (null === $responseType) {
|
||||
throw new ResponseParserException(sprintf('Unrecognised BusProNet response type "%s"', $typeAttribute));
|
||||
}
|
||||
|
||||
$resultNode = $crawler->filterXPath('//ergebnis');
|
||||
|
||||
try {
|
||||
switch ($responseType) {
|
||||
case ApiClient::TYPE_NOTIFICATION:
|
||||
case MessageType::Notification:
|
||||
return (new NotificationParser())->parse($crawler);
|
||||
case ApiClient::TYPE_CUSTOMER_DATA:
|
||||
case MessageType::CustomerData:
|
||||
$subType = $this->getStringOrNullValue($resultNode->filterXPath('//art'));
|
||||
if (null === $subType || '' === $subType) {
|
||||
throw new ResponseParserException('Unable to determine customer data subtype from XML response');
|
||||
@@ -63,23 +67,23 @@ class ApiResponseParser extends AbstractParser
|
||||
}
|
||||
|
||||
throw new ResponseParserException(sprintf('Unrecognised customer data subtype "%s"', $subType));
|
||||
case ApiClient::TYPE_BASE_DATA_COUNTRIES:
|
||||
case MessageType::Countries:
|
||||
return (new CountriesParser())->parse($resultNode);
|
||||
case ApiClient::TYPE_MUTABLE_DATA:
|
||||
case MessageType::MutableData:
|
||||
return (new MutableDataParser())->parse($resultNode);
|
||||
case ApiClient::TYPE_AVAILABILITY:
|
||||
case MessageType::Availability:
|
||||
return (new AvailabilitiesParser())->parseServices($resultNode);
|
||||
case ApiClient::TYPE_AVAILABILITY_EXTENDED:
|
||||
case MessageType::AvailabilityExtended:
|
||||
return (new ExtendedAvailabilitiesParser())->parseServices($resultNode);
|
||||
case ApiClient::TYPE_AVAILABILITY_HOTEL:
|
||||
case MessageType::AvailabilityHotel:
|
||||
return (new AvailabilitiesParser())->parseRooms($resultNode);
|
||||
case ApiClient::TYPE_BOOKING_UPDATE:
|
||||
case MessageType::BookingUpdate:
|
||||
return (new BookingUpdateParser())->parse($resultNode);
|
||||
case ApiClient::TYPE_BOOKING:
|
||||
case MessageType::Booking:
|
||||
return (new BookingResponseParser())->parse($resultNode);
|
||||
case ApiClient::TYPE_PRODUCTS:
|
||||
case MessageType::Products:
|
||||
return (new ProductsParser())->parse($resultNode);
|
||||
case ApiClient::TYPE_PRODUCT_DATA:
|
||||
case MessageType::ProductData:
|
||||
$travelNode = $crawler->filterXPath('//reise/termin');
|
||||
|
||||
if (0 === $travelNode->count()) {
|
||||
@@ -87,25 +91,23 @@ class ApiResponseParser extends AbstractParser
|
||||
}
|
||||
|
||||
return $this->travelParser->parse($travelNode->first(), ...$additionalArgs);
|
||||
case ApiClient::TYPE_AGENCIES:
|
||||
case MessageType::Agencies:
|
||||
return (new AgencyParser())->parse($resultNode);
|
||||
case ApiClient::TYPE_PURCHASE_VOUCHER:
|
||||
case MessageType::PurchaseVoucher:
|
||||
return (new PurchaseVoucherParser())->parse($resultNode);
|
||||
case ApiClient::TYPE_PROMO_VOUCHER:
|
||||
case MessageType::PromoVoucher:
|
||||
return (new PromoVoucherParser())->parse($resultNode);
|
||||
case ApiClient::TYPE_VOUCHER_TEMPLATES:
|
||||
case MessageType::VoucherTemplates:
|
||||
return (new VoucherTemplatesParser())->parse($resultNode);
|
||||
case ApiClient::TYPE_VOUCHER_PAYMENT_METHODS:
|
||||
case MessageType::VoucherPaymentMethods:
|
||||
return (new VoucherPaymentMethodsParser())->parse($resultNode);
|
||||
case ApiClient::TYPE_VOUCHER_PREVIEW:
|
||||
case MessageType::VoucherPreview:
|
||||
return (new VoucherPreviewParser())->parse($resultNode);
|
||||
case ApiClient::TYPE_VOUCHER_SALE:
|
||||
case MessageType::VoucherSale:
|
||||
return (new VoucherSaleResponseParser())->parse($resultNode);
|
||||
}
|
||||
} catch (\InvalidArgumentException $e) {
|
||||
throw new ResponseParserException('Invalid XML response structure: '.$e->getMessage(), 0, $e);
|
||||
}
|
||||
|
||||
throw new ResponseParserException(sprintf('Unrecognised BusProNet response type "%s"', $responseType));
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user