From b755a6f43ec9e2b6dbe92806e07cea1eed60ce0d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Fromme?= Date: Fri, 2 Oct 2026 13:53:48 +0200 Subject: [PATCH] refactor: split buspro ApiClient into domain clients --- docs/bpn-xml-api-reference.md | 14 +- .../buspronet-schema/crm-selection-queries.md | 6 +- docs/buspronet-schema/live-api-queries.md | 4 +- src/BusProNet/ApiClient.php | 399 ------------------ src/BusProNet/Client/AccountClient.php | 119 ++++++ src/BusProNet/Client/BookingClient.php | 106 +++++ src/BusProNet/Client/ReferenceDataClient.php | 39 ++ src/BusProNet/Client/TravelClient.php | 87 ++++ src/BusProNet/Client/VoucherClient.php | 121 ++++++ .../DataProvider/CountryDataProvider.php | 9 +- src/BusProNet/MessageType.php | 30 ++ src/BusProNet/Transport/XmlChannel.php | 21 +- src/BusProNet/XmlLoader/AgencyLoader.php | 6 +- src/BusProNet/XmlParser/ApiResponseParser.php | 54 +-- src/Command/BookingRepairDraftCommand.php | 10 +- src/Command/BpnFetchTravelCommand.php | 6 +- src/Command/BpnReplayCommand.php | 6 +- .../Account/PersonalDataController.php | 10 +- src/Controller/Api/ContactFormController.php | 6 +- src/Controller/Api/CrmAttributeController.php | 6 +- src/Controller/Api/ProductController.php | 6 +- src/Controller/Api/TravelController.php | 6 +- src/Controller/Api/UserinfoController.php | 6 +- .../Booking/Create/Step3Controller.php | 6 +- .../Booking/Create/Step4Controller.php | 6 +- src/Controller/Booking/DownloadController.php | 6 +- src/Controller/Booking/IndexController.php | 6 +- src/Controller/RegistrationController.php | 6 +- src/Controller/ResetPasswordController.php | 6 +- src/Controller/Voucher/Step1Controller.php | 6 +- src/Controller/Voucher/Step3Controller.php | 8 +- src/Security/BpnAuthenticator.php | 8 +- src/Service/BookingEditDataLoader.php | 6 +- src/Service/BookingEditSubmitter.php | 6 +- src/Service/ParticipantDataPrefiller.php | 6 +- src/Service/TravelDataProvider.php | 10 +- src/Service/TravelSnapshotManager.php | 6 +- src/Service/VoucherTemplateProvider.php | 8 +- src/Service/VoucherValidator.php | 8 +- .../ApiResponseParserFailureTest.php | 12 +- .../XmlParser/VoucherResponseParserTest.php | 20 +- .../Account/PersonalDataControllerTest.php | 34 +- .../Controller/Api/UserinfoControllerTest.php | 18 +- .../Edit/ParticipantControllerTest.php | 10 +- .../Voucher/Step3ControllerTest.php | 56 +-- tests/Security/BpnAuthenticatorTest.php | 10 +- .../BookingEditDataLoaderDraftRestoreTest.php | 4 +- tests/Service/BookingEditSubmitterTest.php | 41 +- .../Service/ParticipantDataPrefillerTest.php | 32 +- tests/Service/TravelDataProviderTest.php | 18 +- tests/Service/TravelSnapshotManagerTest.php | 24 +- tests/Service/VoucherTemplateProviderTest.php | 36 +- 52 files changed, 805 insertions(+), 695 deletions(-) delete mode 100644 src/BusProNet/ApiClient.php create mode 100644 src/BusProNet/Client/AccountClient.php create mode 100644 src/BusProNet/Client/BookingClient.php create mode 100644 src/BusProNet/Client/ReferenceDataClient.php create mode 100644 src/BusProNet/Client/TravelClient.php create mode 100644 src/BusProNet/Client/VoucherClient.php create mode 100644 src/BusProNet/MessageType.php diff --git a/docs/bpn-xml-api-reference.md b/docs/bpn-xml-api-reference.md index 91ad3071..10c43714 100644 --- a/docs/bpn-xml-api-reference.md +++ b/docs/bpn-xml-api-reference.md @@ -25,7 +25,7 @@ Every request is `` with ``, `` and ``. key = md5( user + password + date("YYYYMMDD") + satz-typ ) ``` -Per satz type and per day. `ApiClient::createKey()` implements it, and `sendRawXml()` regenerates +Per satz type and per day. `XmlChannel::createKey()` implements it, and `XmlChannel::replay()` regenerates the key before sending, so a hand-built payload can carry a placeholder. ## Satz types @@ -39,7 +39,7 @@ the key before sending, so a hand-built payload can carry a placeholder. `VERFUEGBARKEITHOTEL`, `ZAHLUNG`, `ZAHLUNG2`, `ZAHLUNGSARTEN`, `ZAHLUNGSARTEN2`. `SITZPLATZAUSWAHL` and `ZAHLUNG4` are named in prose without their own section. -**Used here but undocumented:** `VERFUEGBARKEIT2` (`ApiClient::TYPE_AVAILABILITY_EXTENDED`) — the +**Used here but undocumented:** `VERFUEGBARKEIT2` (`MessageType::AvailabilityExtended`) — the extended availability call returning `buchungstatusmoeglich` and per-service `pflicht`/`frei`. Its contract is observed, not specified. @@ -201,11 +201,11 @@ the same way. Ask `MOEGLICHEAENDERUNGEN` first (``), which answers: ## How this app maps onto the contract `BookingPayloadBuilder::buildCreatePayload()` builds create; `buildBasePayload()` + the -`addTo…Payload()` helpers build edit; `ApiClient::createBooking()`/`updateBooking()` wrap them. +`addTo…Payload()` helpers build edit; `BookingClient::createBooking()`/`updateBooking()` wrap them. | Documented element | Sent on create | Sent on edit | Notes | |---|---|---|---| -| `buchungsart` | yes | yes | Edit **hardcodes `Buchung`** (`ApiClient.php:233`) | +| `buchungsart` | yes | yes | Edit **hardcodes `Buchung`** (`BookingClient::updateBooking()`) | | `status` | yes | yes | Edit replays the value read back from BusPro — see the caveat below | | `idreise`, `idpartner`, `idagentur` | yes | yes | `idpartner` sent unconditionally, even with no room | | `anmelder` | yes | yes | Create builds it from participant[0]; edit uses `PersonalData::toPayload()`. BusPro accepts an Anmelder who is not a participant | @@ -253,7 +253,7 @@ booking before relying on it. ### Gap: edit never dry-runs Create is two-phase — `Anfrage` to validate and price, then `Buchung`. Edit sends -`buchungsart=Buchung` directly (`ApiClient.php:233`), even though `BUCHUNGAENDERUNG` supports +`buchungsart=Buchung` directly (`BookingClient::updateBooking()`), even though `BUCHUNGAENDERUNG` supports `Anfrage` identically. An enquiry pass would surface `913`/`924`/`962` and return the recalculated price *before* mutating a live booking. @@ -315,8 +315,8 @@ answers `` plus per-service `status` ("buchbar"), `frei`, `prei ## Selling vouchers (Kaufgutschein) Used by the `/gutschein` flow, which replaces the BusProNet-hosted shop -(`maske_gutschein.php`). `ApiClient::TYPE_VOUCHER_*`; not to be confused with -`TYPE_PURCHASE_VOUCHER` (`GUTSCHEINPRUEFUNGEINLOESUNG`), which redeems a voucher in a booking. +(`maske_gutschein.php`). `VoucherClient`, `MessageType::Voucher*`; not to be confused with +`MessageType::PurchaseVoucher` (`GUTSCHEINPRUEFUNGEINLOESUNG`), which redeems a voucher in a booking. | Satz | Request | Response | |---|---|---| diff --git a/docs/buspronet-schema/crm-selection-queries.md b/docs/buspronet-schema/crm-selection-queries.md index 4d10269f..8546158f 100644 --- a/docs/buspronet-schema/crm-selection-queries.md +++ b/docs/buspronet-schema/crm-selection-queries.md @@ -9,7 +9,7 @@ Companion to `travel-queries.md` (static catalog) and `live-api-queries.md` (liv socket endpoints). This one covers the `KUNDENKONTO` / `art=SelektionCRM` response — the document that drives the portal's entire authorization model. -Request side: `ApiClient::getCrmAttributes()` (`src/BusProNet/ApiClient.php`) sends +Request side: `AccountClient::getCrmAttributes()` (`src/BusProNet/Client/AccountClient.php`) sends `satz typ="KUNDENKONTO"` + `art=SelektionCRM` + the customer's email/password. Response side: `CrmAttributesResponseParser` (`src/BusProNet/XmlParser/CrmAttributesResponseParser.php`) turns selection ids into @@ -229,7 +229,7 @@ Three conclusions: `dbo.AgenturSelektionenKunde` is a bare two-column link table, `(IDAdresse_FS, IDSelektionsstamm_FS)` — literally *"agency's customer selections"*. The portal authenticates against BusPro as an **agency** account (`bpn_username` in -`ApiClient`), so a per-agency whitelist of which customer selections that agency may see +`XmlChannel`), so a per-agency whitelist of which customer selections that agency may see and/or edit is exactly the right shape. It is the only candidate found so far that could explain the `1478` omission **and** `aenderbar` through one mechanism. @@ -461,7 +461,7 @@ and they are long shots. Prefer the escalation path below. Escalation path, cheapest first: 1. **Re-fetch and confirm staleness.** Our side does not cache this call — the - `xml-sync` cache tag covers the XML *export* sync, and `ApiClient::getCrmAttributes()` + `xml-sync` cache tag covers the XML *export* sync, and `AccountClient::getCrmAttributes()` has no cache layer — so a fresh login hits BusPro directly. If `1478` is still absent from a response captured after the insert, the staleness is on the BusProNet host and an application-pool/service restart there is the test. diff --git a/docs/buspronet-schema/live-api-queries.md b/docs/buspronet-schema/live-api-queries.md index 6aaf13e2..ef90c772 100644 --- a/docs/buspronet-schema/live-api-queries.md +++ b/docs/buspronet-schema/live-api-queries.md @@ -5,8 +5,8 @@ > per-endpoint migration verdicts and the `frei` discovery SQL. This complements `travel-queries.md`. That doc replaced the **XML export** (static -catalog). This one covers the **live socket API** methods on -`src/BusProNet/ApiClient.php` and classifies how replicable each is by direct MSSQL +catalog). This one covers the **live socket API** methods of the clients in +`src/BusProNet/Client/` and classifies how replicable each is by direct MSSQL query in the Go proxy. **Verdict in one line:** the *structural* parts replicate cleanly; the *live "free" diff --git a/src/BusProNet/ApiClient.php b/src/BusProNet/ApiClient.php deleted file mode 100644 index 08e9bb78..00000000 --- a/src/BusProNet/ApiClient.php +++ /dev/null @@ -1,399 +0,0 @@ -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|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 $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); - } -} diff --git a/src/BusProNet/Client/AccountClient.php b/src/BusProNet/Client/AccountClient.php new file mode 100644 index 00000000..d9ee0669 --- /dev/null +++ b/src/BusProNet/Client/AccountClient.php @@ -0,0 +1,119 @@ +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, + ]); + } +} diff --git a/src/BusProNet/Client/BookingClient.php b/src/BusProNet/Client/BookingClient.php new file mode 100644 index 00000000..5c4fbebf --- /dev/null +++ b/src/BusProNet/Client/BookingClient.php @@ -0,0 +1,106 @@ +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); + } +} diff --git a/src/BusProNet/Client/ReferenceDataClient.php b/src/BusProNet/Client/ReferenceDataClient.php new file mode 100644 index 00000000..5fb4c282 --- /dev/null +++ b/src/BusProNet/Client/ReferenceDataClient.php @@ -0,0 +1,39 @@ +channel->request(MessageType::Agencies); + } + + /** + * @throws ApiClientException + */ + public function getBaseData(MessageType $type): Notification|BaseData + { + return $this->channel->request($type); + } +} diff --git a/src/BusProNet/Client/TravelClient.php b/src/BusProNet/Client/TravelClient.php new file mode 100644 index 00000000..ceae8c03 --- /dev/null +++ b/src/BusProNet/Client/TravelClient.php @@ -0,0 +1,87 @@ +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'), + ]); + } +} diff --git a/src/BusProNet/Client/VoucherClient.php b/src/BusProNet/Client/VoucherClient.php new file mode 100644 index 00000000..0b1416a5 --- /dev/null +++ b/src/BusProNet/Client/VoucherClient.php @@ -0,0 +1,121 @@ +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|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)); + } +} diff --git a/src/BusProNet/DataProvider/CountryDataProvider.php b/src/BusProNet/DataProvider/CountryDataProvider.php index df7611ed..f9493ca9 100644 --- a/src/BusProNet/DataProvider/CountryDataProvider.php +++ b/src/BusProNet/DataProvider/CountryDataProvider.php @@ -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() ; }); diff --git a/src/BusProNet/MessageType.php b/src/BusProNet/MessageType.php new file mode 100644 index 00000000..d8d430d1 --- /dev/null +++ b/src/BusProNet/MessageType.php @@ -0,0 +1,30 @@ +`: 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'; +} diff --git a/src/BusProNet/Transport/XmlChannel.php b/src/BusProNet/Transport/XmlChannel.php index d7639d2f..b33fecbf 100644 --- a/src/BusProNet/Transport/XmlChannel.php +++ b/src/BusProNet/Transport/XmlChannel.php @@ -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 */ - 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(), ]); diff --git a/src/BusProNet/XmlLoader/AgencyLoader.php b/src/BusProNet/XmlLoader/AgencyLoader.php index dd2cc5fb..185cfa9b 100644 --- a/src/BusProNet/XmlLoader/AgencyLoader.php +++ b/src/BusProNet/XmlLoader/AgencyLoader.php @@ -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', [ diff --git a/src/BusProNet/XmlParser/ApiResponseParser.php b/src/BusProNet/XmlParser/ApiResponseParser.php index 7c601c5c..4eb8686e 100644 --- a/src/BusProNet/XmlParser/ApiResponseParser.php +++ b/src/BusProNet/XmlParser/ApiResponseParser.php @@ -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 $additionalArgs + * * @throws ResponseParserException */ - /** @param array $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)); } } diff --git a/src/Command/BookingRepairDraftCommand.php b/src/Command/BookingRepairDraftCommand.php index 4fda42a6..2c8eb499 100644 --- a/src/Command/BookingRepairDraftCommand.php +++ b/src/Command/BookingRepairDraftCommand.php @@ -4,7 +4,8 @@ declare(strict_types=1); namespace App\Command; -use App\BusProNet\ApiClient; +use App\BusProNet\Client\BookingClient; +use App\BusProNet\Client\TravelClient; use App\BusProNet\Constants; use App\BusProNet\DataProcessor\BookingDataProcessor; use App\BusProNet\Model\Booking; @@ -78,7 +79,8 @@ class BookingRepairDraftCommand extends Command public function __construct( private readonly BookingEditDraftRepository $draftRepository, private readonly EntityManagerInterface $entityManager, - private readonly ApiClient $apiClient, + private readonly BookingClient $bookingClient, + private readonly TravelClient $travelClient, private readonly Crypt $crypt, private readonly TravelDataProvider $travelDataProvider, private readonly BookingDataProcessor $bookingDataProcessor, @@ -214,7 +216,7 @@ class BookingRepairDraftCommand extends Command private function fetchLiveBooking(SymfonyStyle $io, User $user, int $bookingId): ?Booking { - $result = $this->apiClient->getBooking( + $result = $this->bookingClient->getBooking( (string) $user->getEmail(), $this->crypt->decrypt((string) $user->getPassword()), $bookingId, @@ -300,7 +302,7 @@ class BookingRepairDraftCommand extends Command } } - $live = $this->apiClient->getAvailabilitiesExtended((int) $travel->id); + $live = $this->travelClient->getAvailabilitiesExtended((int) $travel->id); if ($live instanceof Notification) { $io->warning(sprintf( 'VERFUEGBARKEIT2 failed (%d %s); falling back to travel data, which may be stale.', diff --git a/src/Command/BpnFetchTravelCommand.php b/src/Command/BpnFetchTravelCommand.php index adcaeb5d..ec6e8d63 100644 --- a/src/Command/BpnFetchTravelCommand.php +++ b/src/Command/BpnFetchTravelCommand.php @@ -4,7 +4,7 @@ declare(strict_types=1); namespace App\Command; -use App\BusProNet\ApiClient; +use App\BusProNet\Client\TravelClient; use App\BusProNet\Exception\ApiClientException; use League\Flysystem\FilesystemException; use League\Flysystem\FilesystemOperator; @@ -29,7 +29,7 @@ class BpnFetchTravelCommand extends Command ]; public function __construct( - private readonly ApiClient $apiClient, + private readonly TravelClient $travelClient, private readonly FilesystemOperator $xmlExport, private readonly CacheInterface $cache, private readonly LoggerInterface $logger, @@ -56,7 +56,7 @@ class BpnFetchTravelCommand extends Command $io->text(sprintf('Fetching travel data for product ID %d...', $travelId)); try { - $xml = $this->apiClient->getTravelDataXml($travelId); + $xml = $this->travelClient->getTravelDataXml($travelId); } catch (ApiClientException $e) { $io->error(sprintf('API request failed: %s', $e->getMessage())); $this->logger->error('Failed to fetch travel data from API', [ diff --git a/src/Command/BpnReplayCommand.php b/src/Command/BpnReplayCommand.php index e14063c6..49f3e26b 100644 --- a/src/Command/BpnReplayCommand.php +++ b/src/Command/BpnReplayCommand.php @@ -4,8 +4,8 @@ declare(strict_types=1); namespace App\Command; -use App\BusProNet\ApiClient; use App\BusProNet\Exception\ApiClientException; +use App\BusProNet\Transport\XmlChannel; use Symfony\Component\Console\Attribute\AsCommand; use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Input\InputArgument; @@ -21,7 +21,7 @@ use Symfony\Component\Console\Style\SymfonyStyle; class BpnReplayCommand extends Command { public function __construct( - private readonly ApiClient $apiClient, + private readonly XmlChannel $channel, ) { parent::__construct(); } @@ -77,7 +77,7 @@ class BpnReplayCommand extends Command $io->info('Sending request to BPN API...'); try { - $response = $this->apiClient->sendRawXml($xml); + $response = $this->channel->replay($xml); } catch (ApiClientException $e) { $io->error(sprintf('API request failed: %s', $e->getMessage())); diff --git a/src/Controller/Account/PersonalDataController.php b/src/Controller/Account/PersonalDataController.php index f75708a4..4d12b6c8 100644 --- a/src/Controller/Account/PersonalDataController.php +++ b/src/Controller/Account/PersonalDataController.php @@ -4,7 +4,7 @@ declare(strict_types=1); namespace App\Controller\Account; -use App\BusProNet\ApiClient; +use App\BusProNet\Client\AccountClient; use App\BusProNet\Exception\ApiClientException; use App\BusProNet\Model\Notification; use App\BusProNet\Model\PersonalData; @@ -39,7 +39,7 @@ class PersonalDataController extends AbstractController public const SESSION_REDIRECT_KEY = '_profile_completion_redirect'; /** - * @param ApiClient $apiClient BusProNet API client for data operations + * @param AccountClient $accountClient BusProNet account client * @param Crypt $crypt Encryption service for password handling * @param BookingEditDataLoader $dataLoader Data loader for cache invalidation * @param ProfileCompletenessChecker $completenessChecker Profile validation service @@ -48,7 +48,7 @@ class PersonalDataController extends AbstractController * @param LoggerInterface $logger Logger for audit trails and debugging */ public function __construct( - private readonly ApiClient $apiClient, + private readonly AccountClient $accountClient, private readonly Crypt $crypt, private readonly BookingEditDataLoader $dataLoader, private readonly ProfileCompletenessChecker $completenessChecker, @@ -100,7 +100,7 @@ class PersonalDataController extends AbstractController if ($personalDataForm->isSubmitted() && $personalDataForm->isValid()) { try { - $updateResult = $this->apiClient->updatePersonalData($email, $password, $personalData); + $updateResult = $this->accountClient->updatePersonalData($email, $password, $personalData); if ($updateResult instanceof Notification) { $this->logger->error('Personal data update rejected by BusProNet', [ @@ -223,7 +223,7 @@ class PersonalDataController extends AbstractController try { $personalData = $this - ->apiClient + ->accountClient ->getPersonalData($email, $password); } catch (ApiClientException $e) { $this->addFlash('error', 'Deine persönlichen Daten konnten nicht abgerufen werden'); diff --git a/src/Controller/Api/ContactFormController.php b/src/Controller/Api/ContactFormController.php index 72a1e9f9..7cfb732d 100644 --- a/src/Controller/Api/ContactFormController.php +++ b/src/Controller/Api/ContactFormController.php @@ -4,7 +4,7 @@ declare(strict_types=1); namespace App\Controller\Api; -use App\BusProNet\ApiClient; +use App\BusProNet\Client\AccountClient; use App\BusProNet\Exception\ApiClientException; use App\BusProNet\Model\ContactFormSubmission; use App\BusProNet\Model\Notification; @@ -21,7 +21,7 @@ use Symfony\Component\Security\Http\Attribute\IsGranted; #[IsGranted('ROLE_OAUTH2_API')] class ContactFormController extends AbstractController { - public function __construct(private readonly ApiClient $apiClient, private readonly LoggerInterface $logger) + public function __construct(private readonly AccountClient $accountClient, private readonly LoggerInterface $logger) { } @@ -31,7 +31,7 @@ class ContactFormController extends AbstractController $personalData = PersonalData::fromContactFormSubmission($dto); try { - $result = $this->apiClient->createAddress($personalData); + $result = $this->accountClient->createAddress($personalData); if ($result instanceof Notification) { $this->logger->info('Unable to submit contact form', [ diff --git a/src/Controller/Api/CrmAttributeController.php b/src/Controller/Api/CrmAttributeController.php index 14a8f804..892317cf 100644 --- a/src/Controller/Api/CrmAttributeController.php +++ b/src/Controller/Api/CrmAttributeController.php @@ -2,7 +2,7 @@ namespace App\Controller\Api; -use App\BusProNet\ApiClient; +use App\BusProNet\Client\AccountClient; use App\BusProNet\Exception\ApiClientException; use App\BusProNet\Model\Notification; use App\Entity\User; @@ -17,7 +17,7 @@ use Symfony\Component\Security\Http\Attribute\IsGranted; #[IsGranted('ROLE_OAUTH2_PROFILE')] class CrmAttributeController extends AbstractController { - public function __construct(private readonly ApiClient $apiClient, private readonly Crypt $crypt) + public function __construct(private readonly AccountClient $accountClient, private readonly Crypt $crypt) { } @@ -30,7 +30,7 @@ class CrmAttributeController extends AbstractController $password = $this->crypt->decrypt($user->getPassword()); try { - $data = $this->apiClient->getCrmAttributes($email, $password); + $data = $this->accountClient->getCrmAttributes($email, $password); if ($data instanceof Notification) { return new JsonResponse(['message' => $data->message, 'code' => $data->code], Response::HTTP_BAD_REQUEST); diff --git a/src/Controller/Api/ProductController.php b/src/Controller/Api/ProductController.php index 086f52d8..48b5991a 100644 --- a/src/Controller/Api/ProductController.php +++ b/src/Controller/Api/ProductController.php @@ -2,7 +2,7 @@ namespace App\Controller\Api; -use App\BusProNet\ApiClient; +use App\BusProNet\Client\TravelClient; use App\BusProNet\Exception\ApiClientException; use Psr\Cache\InvalidArgumentException; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; @@ -17,7 +17,7 @@ use Symfony\Contracts\Cache\ItemInterface; class ProductController extends AbstractController { public function __construct( - private readonly ApiClient $apiClient, + private readonly TravelClient $travelClient, private readonly CacheInterface $cache, ) { } @@ -29,7 +29,7 @@ class ProductController extends AbstractController $products = $this->cache->get('api_products', function (ItemInterface $item) { $item->expiresAfter(3600); // 1 hour cache - return $this->apiClient->getProducts(); + return $this->travelClient->getProducts(); }); return $this->json($products); diff --git a/src/Controller/Api/TravelController.php b/src/Controller/Api/TravelController.php index 8b5a1128..d9ffbb93 100644 --- a/src/Controller/Api/TravelController.php +++ b/src/Controller/Api/TravelController.php @@ -2,7 +2,7 @@ namespace App\Controller\Api; -use App\BusProNet\ApiClient; +use App\BusProNet\Client\TravelClient; use App\BusProNet\Exception\ApiClientException; use App\BusProNet\Model\Travel; use App\BusProNet\Utility\DateCodeUtility; @@ -20,7 +20,7 @@ use Symfony\Component\Security\Http\Attribute\IsGranted; class TravelController extends AbstractController { public function __construct( - private readonly ApiClient $apiClient, + private readonly TravelClient $travelClient, private readonly TravelDataProvider $travelDataService, ) { } @@ -89,7 +89,7 @@ class TravelController extends AbstractController #[MapDateTime(format: 'Y-m-d')] \DateTimeImmutable $dateTo, ): JsonResponse { try { - $result = $this->apiClient->getHotelAvailability($dateId, $hotelId, $dateTo); + $result = $this->travelClient->getHotelAvailability($dateId, $hotelId, $dateTo); return $this->json($result); } catch (ApiClientException $e) { diff --git a/src/Controller/Api/UserinfoController.php b/src/Controller/Api/UserinfoController.php index 175d745a..e13139f0 100644 --- a/src/Controller/Api/UserinfoController.php +++ b/src/Controller/Api/UserinfoController.php @@ -2,7 +2,7 @@ namespace App\Controller\Api; -use App\BusProNet\ApiClient; +use App\BusProNet\Client\AccountClient; use App\BusProNet\Exception\ApiClientException; use App\BusProNet\Model\Notification; use App\BusProNet\Model\PersonalData; @@ -19,7 +19,7 @@ use Symfony\Component\Security\Http\Attribute\IsGranted; #[IsGranted('ROLE_OAUTH2_EMAIL')] class UserinfoController extends AbstractController { - public function __construct(private readonly ApiClient $apiClient, private readonly Crypt $crypt) + public function __construct(private readonly AccountClient $accountClient, private readonly Crypt $crypt) { } @@ -48,7 +48,7 @@ class UserinfoController extends AbstractController $password = $this->crypt->decrypt($user->getPassword()); try { - $data = $this->apiClient->getPersonalData($email, $password); + $data = $this->accountClient->getPersonalData($email, $password); if ($data instanceof Notification) { return new JsonResponse(['message' => $data->message, 'code' => $data->code], Response::HTTP_BAD_REQUEST); diff --git a/src/Controller/Booking/Create/Step3Controller.php b/src/Controller/Booking/Create/Step3Controller.php index 49b0e2e6..524735d9 100644 --- a/src/Controller/Booking/Create/Step3Controller.php +++ b/src/Controller/Booking/Create/Step3Controller.php @@ -4,7 +4,7 @@ declare(strict_types=1); namespace App\Controller\Booking\Create; -use App\BusProNet\ApiClient; +use App\BusProNet\Client\BookingClient; use App\BusProNet\Exception\TimeoutException; use App\BusProNet\Model\BookingResponse; use App\BusProNet\Model\Notification; @@ -40,7 +40,7 @@ class Step3Controller extends AbstractBookingCreateController private readonly BookingCreateContextFactory $createContextFactory, private readonly BookingPriceCalculator $priceCalculator, private readonly BookingPriceMismatchAnalyzer $priceMismatchDiagnostics, - private readonly ApiClient $apiClient, + private readonly BookingClient $bookingClient, private readonly ParticipantFormSupport $participantFormSupportService, private readonly LoggerInterface $logger, ) { @@ -76,7 +76,7 @@ class Step3Controller extends AbstractBookingCreateController $this->bookingService->applyCreateBookingStatusRules($bookingCreateDto); // Validate booking data with API by submitting an inquiry booking - $inquiryResponse = $this->apiClient->createBookingInquiry($bookingCreateDto); + $inquiryResponse = $this->bookingClient->createBookingInquiry($bookingCreateDto); // Surface any insurance corrections made during payload building (e.g. a // stale price tier reassigned/cleared right before submission) diff --git a/src/Controller/Booking/Create/Step4Controller.php b/src/Controller/Booking/Create/Step4Controller.php index 7b19aead..f7677517 100644 --- a/src/Controller/Booking/Create/Step4Controller.php +++ b/src/Controller/Booking/Create/Step4Controller.php @@ -4,7 +4,7 @@ declare(strict_types=1); namespace App\Controller\Booking\Create; -use App\BusProNet\ApiClient; +use App\BusProNet\Client\BookingClient; use App\BusProNet\Exception\TimeoutException; use App\BusProNet\Model\Notification; use App\Entity\User; @@ -37,7 +37,7 @@ class Step4Controller extends AbstractBookingCreateController private readonly BookingConfigurator $bookingService, private readonly BookingSessionManager $bookingSessionService, private readonly BookingCreateContextFactory $createContextFactory, - private readonly ApiClient $apiClient, + private readonly BookingClient $bookingClient, private readonly CacheInterface $cache, private readonly BookingNewsletterOptIn $bookingNewsletterOptIn, private readonly ParticipantFormSupport $participantFormSupportService, @@ -80,7 +80,7 @@ class Step4Controller extends AbstractBookingCreateController $this->bookingService->applyCreateBookingStatusRules($bookingCreateDto); // Submit final booking (already validated in Step 3) - $bookingResponse = $this->apiClient->createBooking($bookingCreateDto); + $bookingResponse = $this->bookingClient->createBooking($bookingCreateDto); // Surface any insurance corrections made during payload building (e.g. a // stale price tier reassigned/cleared right before submission) diff --git a/src/Controller/Booking/DownloadController.php b/src/Controller/Booking/DownloadController.php index 6c31253c..65c29148 100644 --- a/src/Controller/Booking/DownloadController.php +++ b/src/Controller/Booking/DownloadController.php @@ -2,7 +2,7 @@ namespace App\Controller\Booking; -use App\BusProNet\ApiClient; +use App\BusProNet\Client\BookingClient; use App\BusProNet\Exception\ApiClientException; use App\BusProNet\Model\Notification; use App\Entity\User; @@ -20,7 +20,7 @@ use function Symfony\Component\String\u; class DownloadController extends AbstractController { public function __construct( - private readonly ApiClient $apiClient, + private readonly BookingClient $bookingClient, private readonly Crypt $crypt, private readonly LoggerInterface $logger, ) { @@ -60,7 +60,7 @@ class DownloadController extends AbstractController try { $file = $this - ->apiClient + ->bookingClient ->getDocuments($email, $password, $id, $type); } catch (ApiClientException $e) { $file = null; diff --git a/src/Controller/Booking/IndexController.php b/src/Controller/Booking/IndexController.php index e51071d0..b2176f2e 100644 --- a/src/Controller/Booking/IndexController.php +++ b/src/Controller/Booking/IndexController.php @@ -2,7 +2,7 @@ namespace App\Controller\Booking; -use App\BusProNet\ApiClient; +use App\BusProNet\Client\BookingClient; use App\BusProNet\Exception\ApiClientException; use App\BusProNet\Model\BaseData; use App\BusProNet\Model\Notification; @@ -19,7 +19,7 @@ use Symfony\Component\Security\Http\Attribute\IsGranted; class IndexController extends AbstractController { public function __construct( - private readonly ApiClient $apiClient, + private readonly BookingClient $bookingClient, private readonly TravelLoader $travelDataLoader, private readonly Crypt $crypt, private readonly LoggerInterface $logger, @@ -36,7 +36,7 @@ class IndexController extends AbstractController $password = $this->crypt->decrypt($user->getPassword()); try { - $bookings = $this->apiClient->getBookings($email, $password); + $bookings = $this->bookingClient->getBookings($email, $password); } catch (ApiClientException $e) { $this->addFlash('error', 'Buchungen nicht abrufbar'); $bookings = new BaseData([]); diff --git a/src/Controller/RegistrationController.php b/src/Controller/RegistrationController.php index 093f404e..27f8959d 100644 --- a/src/Controller/RegistrationController.php +++ b/src/Controller/RegistrationController.php @@ -2,7 +2,7 @@ namespace App\Controller; -use App\BusProNet\ApiClient; +use App\BusProNet\Client\AccountClient; use App\BusProNet\Exception\ApiClientException; use App\BusProNet\Model\Notification; use App\Form\Model\RegistrationDto; @@ -17,7 +17,7 @@ use Symfony\Component\Security\Http\Attribute\IsGranted; class RegistrationController extends AbstractController { public function __construct( - private readonly ApiClient $apiClient, + private readonly AccountClient $accountClient, private readonly LoggerInterface $logger, ) { } @@ -34,7 +34,7 @@ class RegistrationController extends AbstractController if ($form->isSubmitted() && $form->isValid()) { try { - $response = $this->apiClient->register($registrationData); + $response = $this->accountClient->register($registrationData); if ($response instanceof Notification && true === $response->isError()) { $this->addFlash('error', 'Möglicherweise bist du bereits registriert. Bitte setze dein Passwort zurück.'); } else { diff --git a/src/Controller/ResetPasswordController.php b/src/Controller/ResetPasswordController.php index 56c3fc4b..5ab583be 100644 --- a/src/Controller/ResetPasswordController.php +++ b/src/Controller/ResetPasswordController.php @@ -2,7 +2,7 @@ namespace App\Controller; -use App\BusProNet\ApiClient; +use App\BusProNet\Client\AccountClient; use App\BusProNet\Exception\ApiClientException; use Psr\Log\LoggerInterface; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; @@ -16,7 +16,7 @@ use Symfony\Component\Validator\Constraints\NotBlank; class ResetPasswordController extends AbstractController { - public function __construct(private readonly ApiClient $apiClient, private readonly LoggerInterface $logger) + public function __construct(private readonly AccountClient $accountClient, private readonly LoggerInterface $logger) { } @@ -46,7 +46,7 @@ class ResetPasswordController extends AbstractController if ($form->isSubmitted() && $form->isValid()) { try { - $this->apiClient->resetPassword($form->get('email')->getData()); + $this->accountClient->resetPassword($form->get('email')->getData()); $this->addFlash('info', 'Du erhältst in Kürze eine E-Mail mit einem Link zum Zurücksetzen deines Passworts – vorausgesetzt, bei deiner Buchung wurde eine E-Mail-Adresse angegeben.'); $this->logger->info('Initiated password reset', [ 'email' => $form->get('email')->getData(), diff --git a/src/Controller/Voucher/Step1Controller.php b/src/Controller/Voucher/Step1Controller.php index 0c5cdcae..48d3506a 100644 --- a/src/Controller/Voucher/Step1Controller.php +++ b/src/Controller/Voucher/Step1Controller.php @@ -4,7 +4,7 @@ declare(strict_types=1); namespace App\Controller\Voucher; -use App\BusProNet\ApiClient; +use App\BusProNet\Client\VoucherClient; use App\BusProNet\Exception\ApiClientException; use App\BusProNet\Model\Notification; use App\Exception\VoucherSessionNotFoundException; @@ -31,7 +31,7 @@ class Step1Controller extends AbstractVoucherPurchaseController VoucherPurchaseSessionManager $sessionManager, VoucherThumbnailResolver $thumbnailResolver, private readonly VoucherTemplateProvider $templateProvider, - private readonly ApiClient $apiClient, + private readonly VoucherClient $voucherClient, private readonly ValidatorInterface $validator, private readonly LoggerInterface $logger, ) { @@ -136,7 +136,7 @@ class Step1Controller extends AbstractVoucherPurchaseController $request->getSession()->save(); try { - $preview = $this->apiClient->getVoucherPreview($dto); + $preview = $this->voucherClient->getVoucherPreview($dto); } catch (ApiClientException $e) { $this->logger->error('Voucher preview failed', ['error' => $e->getMessage()]); diff --git a/src/Controller/Voucher/Step3Controller.php b/src/Controller/Voucher/Step3Controller.php index bf91cde0..78ad16f1 100644 --- a/src/Controller/Voucher/Step3Controller.php +++ b/src/Controller/Voucher/Step3Controller.php @@ -4,7 +4,7 @@ declare(strict_types=1); namespace App\Controller\Voucher; -use App\BusProNet\ApiClient; +use App\BusProNet\Client\VoucherClient; use App\BusProNet\Exception\TimeoutException; use App\BusProNet\Model\Notification; use App\Form\Model\VoucherPurchaseDto; @@ -32,7 +32,7 @@ class Step3Controller extends AbstractVoucherPurchaseController public function __construct( VoucherPurchaseSessionManager $sessionManager, VoucherThumbnailResolver $thumbnailResolver, - private readonly ApiClient $apiClient, + private readonly VoucherClient $voucherClient, private readonly VoucherSaleRejectionMapper $rejectionMapper, private readonly LoggerInterface $logger, ) { @@ -78,7 +78,7 @@ class Step3Controller extends AbstractVoucherPurchaseController private function runDryRun(Request $request, VoucherPurchaseDto $dto, FormInterface $form): Response { try { - $response = $this->apiClient->createVoucherSaleInquiry($dto); + $response = $this->voucherClient->createVoucherSaleInquiry($dto); } catch (\Exception $e) { $this->logger->error('Voucher sale inquiry failed', ['exception' => $e->getMessage()]); $this->addFlash('error', 'Der Gutscheinkauf konnte gerade nicht geprüft werden. Bitte versuche es später noch einmal.'); @@ -106,7 +106,7 @@ class Step3Controller extends AbstractVoucherPurchaseController private function purchase(Request $request, VoucherPurchaseDto $dto, FormInterface $form): Response { try { - $response = $this->apiClient->createVoucherSale($dto); + $response = $this->voucherClient->createVoucherSale($dto); } catch (TimeoutException $e) { // The purchase may have gone through on BusPro's side, so a blind retry could buy twice $this->logger->error('Voucher sale timeout', ['exception' => $e->getMessage()]); diff --git a/src/Security/BpnAuthenticator.php b/src/Security/BpnAuthenticator.php index 61e3f641..aa8ee56d 100644 --- a/src/Security/BpnAuthenticator.php +++ b/src/Security/BpnAuthenticator.php @@ -4,7 +4,7 @@ declare(strict_types=1); namespace App\Security; -use App\BusProNet\ApiClient; +use App\BusProNet\Client\AccountClient; use App\BusProNet\Exception\ApiClientException; use App\BusProNet\Exception\ImmediateConnectionCloseException; use App\BusProNet\Exception\TimeoutException; @@ -50,7 +50,7 @@ class BpnAuthenticator extends AbstractLoginFormAuthenticator implements Authent public function __construct( private readonly UrlGeneratorInterface $urlGenerator, - private readonly ApiClient $apiClient, + private readonly AccountClient $accountClient, private readonly EntityManagerInterface $entityManager, private readonly Crypt $crypt, private readonly ProfileCompletenessChecker $completenessChecker, @@ -77,7 +77,7 @@ class BpnAuthenticator extends AbstractLoginFormAuthenticator implements Authent $password = md5($passwordPlain); try { - $response = $this->apiClient->getPersonalData($email, $password); + $response = $this->accountClient->getPersonalData($email, $password); } catch (ApiClientException $e) { $message = $this->isConnectionError($e) ? 'Der Server ist momentan nicht erreichbar. Bitte versuche es später erneut.' : $e->getMessage(); @@ -103,7 +103,7 @@ class BpnAuthenticator extends AbstractLoginFormAuthenticator implements Authent private function createOrUpdateLocalUser(string $email, string $password, PersonalData $personalData): User { try { - $crmAttributes = $this->apiClient->getCrmAttributes($email, $password); + $crmAttributes = $this->accountClient->getCrmAttributes($email, $password); } catch (ApiClientException $e) { $message = $this->isConnectionError($e) ? 'Der Server ist momentan nicht erreichbar. Bitte versuche es später erneut. :(' : $e->getMessage(); diff --git a/src/Service/BookingEditDataLoader.php b/src/Service/BookingEditDataLoader.php index 948a4c25..de03c540 100644 --- a/src/Service/BookingEditDataLoader.php +++ b/src/Service/BookingEditDataLoader.php @@ -4,7 +4,7 @@ declare(strict_types=1); namespace App\Service; -use App\BusProNet\ApiClient; +use App\BusProNet\Client\BookingClient; use App\BusProNet\DataProcessor\BookingDataProcessor; use App\BusProNet\Model\Booking; use App\BusProNet\Model\Notification; @@ -33,7 +33,7 @@ class BookingEditDataLoader private array $droppedDraftServiceLabels = []; public function __construct( - private readonly ApiClient $apiClient, + private readonly BookingClient $bookingClient, private readonly BookingDataProcessor $bookingDataProcessor, private readonly BookingSessionManager $bookingSessionService, private readonly BookingChangeTracker $fingerprintService, @@ -226,7 +226,7 @@ class BookingEditDataLoader $item->expiresAfter(300); $item->tag([$userTag]); - return $this->apiClient->getBooking($email, $password, $bookingId); + return $this->bookingClient->getBooking($email, $password, $bookingId); }); } catch (InvalidArgumentException) { return null; diff --git a/src/Service/BookingEditSubmitter.php b/src/Service/BookingEditSubmitter.php index b316e04b..1d09d443 100644 --- a/src/Service/BookingEditSubmitter.php +++ b/src/Service/BookingEditSubmitter.php @@ -4,7 +4,7 @@ declare(strict_types=1); namespace App\Service; -use App\BusProNet\ApiClient; +use App\BusProNet\Client\BookingClient; use App\BusProNet\Exception\ApiClientException; use App\BusProNet\Exception\TimeoutException; use App\BusProNet\Model\Notification; @@ -20,7 +20,7 @@ use Symfony\Component\HttpFoundation\Request; class BookingEditSubmitter { public function __construct( - private readonly ApiClient $apiClient, + private readonly BookingClient $bookingClient, private readonly BookingEditDataLoader $dataLoader, private readonly BookingEditDraftManager $draftService, private readonly TravelDataProvider $travelDataService, @@ -90,7 +90,7 @@ class BookingEditSubmitter } try { - $response = $this->apiClient->updateBooking($bookingDto, true); + $response = $this->bookingClient->updateBooking($bookingDto, true); if ($response instanceof Notification) { $this->logger->error('Booking update not successful', [ 'email' => $email, diff --git a/src/Service/ParticipantDataPrefiller.php b/src/Service/ParticipantDataPrefiller.php index fdc31df6..46d14d88 100644 --- a/src/Service/ParticipantDataPrefiller.php +++ b/src/Service/ParticipantDataPrefiller.php @@ -4,7 +4,7 @@ declare(strict_types=1); namespace App\Service; -use App\BusProNet\ApiClient; +use App\BusProNet\Client\AccountClient; use App\BusProNet\Model\Address; use App\BusProNet\Model\Notification; use App\BusProNet\Model\PersonalData; @@ -26,7 +26,7 @@ class ParticipantDataPrefiller public const TOKEN = '#KUN#'; public function __construct( - private readonly ApiClient $apiClient, + private readonly AccountClient $accountClient, private readonly Crypt $crypt, private readonly LoggerInterface $logger, ) { @@ -90,7 +90,7 @@ class ParticipantDataPrefiller $password = $this->crypt->decrypt($user->getPassword()); $email = $user->getEmail(); - $result = $this->apiClient->getPersonalData($email, $password); + $result = $this->accountClient->getPersonalData($email, $password); if ($result instanceof Notification) { $this->logger->warning('Failed to fetch personal data for prepopulation', [ diff --git a/src/Service/TravelDataProvider.php b/src/Service/TravelDataProvider.php index 342c40e6..8f20a3c1 100644 --- a/src/Service/TravelDataProvider.php +++ b/src/Service/TravelDataProvider.php @@ -4,7 +4,7 @@ declare(strict_types=1); namespace App\Service; -use App\BusProNet\ApiClient; +use App\BusProNet\Client\TravelClient; use App\BusProNet\Exception\ApiClientException; use App\BusProNet\Model\BaseData; use App\BusProNet\Model\Notification; @@ -38,7 +38,7 @@ class TravelDataProvider public function __construct( private readonly TravelLoader $travelLoader, - private readonly ApiClient $apiClient, + private readonly TravelClient $travelClient, private readonly CacheInterface $cache, private readonly LoggerInterface $logger, private readonly TravelSnapshotManager $travelSnapshotService, @@ -183,7 +183,7 @@ class TravelDataProvider return null; } - $result = $this->apiClient->getTravelData($productId, $hotelId); + $result = $this->travelClient->getTravelData($productId, $hotelId); if (!$result instanceof Travel) { $this->logger->debug('API returned non-travel result', [ @@ -522,7 +522,7 @@ class TravelDataProvider private function fetchMutabilityData(int $dateId): ?BaseData { try { - $mutableData = $this->apiClient->getMutableData($dateId); + $mutableData = $this->travelClient->getMutableData($dateId); if ($mutableData instanceof Notification) { $this->logger->warning('API returned notification for mutability data', [ @@ -552,7 +552,7 @@ class TravelDataProvider private function fetchAvailabilityData(int $dateId): ?ServiceAvailabilityResponse { try { - $availabilities = $this->apiClient->getAvailabilities($dateId); + $availabilities = $this->travelClient->getAvailabilities($dateId); if ($availabilities instanceof Notification) { $this->logger->warning('API returned notification for availability data', [ diff --git a/src/Service/TravelSnapshotManager.php b/src/Service/TravelSnapshotManager.php index e9937411..d97847ac 100644 --- a/src/Service/TravelSnapshotManager.php +++ b/src/Service/TravelSnapshotManager.php @@ -4,7 +4,7 @@ declare(strict_types=1); namespace App\Service; -use App\BusProNet\ApiClient; +use App\BusProNet\Client\TravelClient; use App\BusProNet\Exception\ApiClientException; use App\BusProNet\Model\ExtendedAvailability; use App\BusProNet\Model\ExtendedServiceAvailabilityResponse; @@ -32,7 +32,7 @@ class TravelSnapshotManager public function __construct( private readonly TravelSnapshotRepository $snapshotRepository, private readonly EntityManagerInterface $entityManager, - private readonly ApiClient $apiClient, + private readonly TravelClient $travelClient, private readonly LoggerInterface $logger, private readonly SerializerInterface $serializer, private readonly int $retentionBufferDays = 14, @@ -210,7 +210,7 @@ class TravelSnapshotManager if (false === array_key_exists($dateId, $extendedResponseByDateId)) { $response = null; try { - $response = $this->apiClient->getAvailabilitiesExtended($dateId); + $response = $this->travelClient->getAvailabilitiesExtended($dateId); } catch (ApiClientException $e) { $extendedResponseByDateId[$dateId] = null; $this->logger->warning('Failed to fetch extended availability', [ diff --git a/src/Service/VoucherTemplateProvider.php b/src/Service/VoucherTemplateProvider.php index 327223d5..615ae136 100644 --- a/src/Service/VoucherTemplateProvider.php +++ b/src/Service/VoucherTemplateProvider.php @@ -4,7 +4,7 @@ declare(strict_types=1); namespace App\Service; -use App\BusProNet\ApiClient; +use App\BusProNet\Client\VoucherClient; use App\BusProNet\Exception\ApiClientException; use App\BusProNet\Model\Notification; use App\BusProNet\Model\VoucherPaymentMethod; @@ -27,7 +27,7 @@ class VoucherTemplateProvider private const string PAYMENT_METHOD_CACHE_KEY = 'voucher_shop.payment_method'; public function __construct( - private readonly ApiClient $apiClient, + private readonly VoucherClient $voucherClient, private readonly TagAwareCacheInterface $cache, private readonly LoggerInterface $logger, ) { @@ -42,7 +42,7 @@ class VoucherTemplateProvider $item->expiresAfter(self::CACHE_TTL); $item->tag([self::CACHE_TAG]); - $result = $this->request(fn () => $this->apiClient->getVoucherTemplates(), 'templates'); + $result = $this->request(fn () => $this->voucherClient->getVoucherTemplates(), 'templates'); if ([] === $result->templates) { $this->logger->error('BusPro offers no voucher templates for sale'); @@ -65,7 +65,7 @@ class VoucherTemplateProvider $item->tag([self::CACHE_TAG]); /** @var list $paymentMethods */ - $paymentMethods = $this->request(fn () => $this->apiClient->getVoucherPaymentMethods(), 'payment methods'); + $paymentMethods = $this->request(fn () => $this->voucherClient->getVoucherPaymentMethods(), 'payment methods'); foreach ($paymentMethods as $paymentMethod) { if ($paymentMethod->isTransfer()) { return $paymentMethod; diff --git a/src/Service/VoucherValidator.php b/src/Service/VoucherValidator.php index 7f5578be..d871630c 100644 --- a/src/Service/VoucherValidator.php +++ b/src/Service/VoucherValidator.php @@ -4,7 +4,7 @@ declare(strict_types=1); namespace App\Service; -use App\BusProNet\ApiClient; +use App\BusProNet\Client\VoucherClient; use App\BusProNet\Exception\ApiClientException; use App\BusProNet\Model\Notification; use App\BusProNet\Model\PromoVoucherValidationResult; @@ -18,7 +18,7 @@ class VoucherValidator private const CACHE_TTL = 900; // 15 minutes public function __construct( - private readonly ApiClient $apiClient, + private readonly VoucherClient $voucherClient, private readonly CacheInterface $cache, private readonly LoggerInterface $logger, ) { @@ -34,7 +34,7 @@ class VoucherValidator $item->expiresAfter(self::CACHE_TTL); try { - $result = $this->apiClient->validatePurchaseVoucher($redemptionCode); + $result = $this->voucherClient->validatePurchaseVoucher($redemptionCode); if ($result instanceof Notification) { return new PurchaseVoucherValidationResult( @@ -89,7 +89,7 @@ class VoucherValidator $item->expiresAfter(self::CACHE_TTL); try { - $result = $this->apiClient->validatePromoVoucher($promoCode, $travelId, $participantPrice); + $result = $this->voucherClient->validatePromoVoucher($promoCode, $travelId, $participantPrice); if ($result instanceof Notification) { return new PromoVoucherValidationResult( diff --git a/tests/BusProNet/XmlParser/ApiResponseParserFailureTest.php b/tests/BusProNet/XmlParser/ApiResponseParserFailureTest.php index e635793f..35157414 100644 --- a/tests/BusProNet/XmlParser/ApiResponseParserFailureTest.php +++ b/tests/BusProNet/XmlParser/ApiResponseParserFailureTest.php @@ -4,8 +4,8 @@ declare(strict_types=1); namespace App\Tests\BusProNet\XmlParser; -use App\BusProNet\ApiClient; use App\BusProNet\Exception\ResponseParserException; +use App\BusProNet\MessageType; use App\BusProNet\XmlParser\ApiResponseParser; use App\BusProNet\XmlParser\TravelParser; use PHPUnit\Framework\TestCase; @@ -23,7 +23,7 @@ class ApiResponseParserFailureTest extends TestCase $this->expectException(ResponseParserException::class); $this->expectExceptionMessage('empty response (0 bytes)'); - $this->createParser()->parseXmlString(ApiClient::TYPE_NOTIFICATION, ''); + $this->createParser()->parseXmlString(MessageType::Notification, ''); } public function testTruncatedResponseNamesTheLibxmlReason(): void @@ -31,7 +31,7 @@ class ApiResponseParserFailureTest extends TestCase $xml = 'createParser()->parseXmlString(ApiClient::TYPE_NOTIFICATION, $xml); + $this->createParser()->parseXmlString(MessageType::Notification, $xml); $this->fail('Expected a ResponseParserException'); } catch (ResponseParserException $e) { self::assertStringContainsString('('.strlen($xml).' bytes)', $e->getMessage()); @@ -46,7 +46,7 @@ class ApiResponseParserFailureTest extends TestCase $this->expectException(ResponseParserException::class); $this->expectExceptionMessage('Unrecognised BusProNet response type "IRGENDWAS"'); - $this->createParser()->parseXmlString(ApiClient::TYPE_NOTIFICATION, $xml); + $this->createParser()->parseXmlString(MessageType::Notification, $xml); } public function testUnknownCustomerDataSubtype(): void @@ -56,7 +56,7 @@ class ApiResponseParserFailureTest extends TestCase $this->expectException(ResponseParserException::class); $this->expectExceptionMessage('Unrecognised customer data subtype "Irgendwas"'); - $this->createParser()->parseXmlString(ApiClient::TYPE_CUSTOMER_DATA, $xml); + $this->createParser()->parseXmlString(MessageType::CustomerData, $xml); } public function testDiagnosingDoesNotLeakLibxmlErrorState(): void @@ -65,7 +65,7 @@ class ApiResponseParserFailureTest extends TestCase try { try { - $this->createParser()->parseXmlString(ApiClient::TYPE_NOTIFICATION, 'createParser()->parseXmlString(MessageType::Notification, 'parse(ApiClient::TYPE_VOUCHER_TEMPLATES, $xml); + $result = $this->parse(MessageType::VoucherTemplates, $xml); self::assertInstanceOf(VoucherTemplates::class, $result); self::assertSame(10, $result->minAmount); @@ -45,14 +45,14 @@ class VoucherResponseParserTest extends TestCase $this->expectException(ResponseParserException::class); $this->expectExceptionMessage('amount bounds'); - $this->parse(ApiClient::TYPE_VOUCHER_TEMPLATES, $xml); + $this->parse(MessageType::VoucherTemplates, $xml); } public function testPaymentMethods(): void { $xml = ''; - $result = $this->parse(ApiClient::TYPE_VOUCHER_PAYMENT_METHODS, $xml); + $result = $this->parse(MessageType::VoucherPaymentMethods, $xml); self::assertEquals([new VoucherPaymentMethod(2, 'Überweisung', 'UEBERW')], $result); self::assertTrue($result[0]->isTransfer()); @@ -63,7 +63,7 @@ class VoucherResponseParserTest extends TestCase $pdf = "%PDF-1.4\nprobe"; $xml = 'data:application/pdf;base64,'.base64_encode($pdf).''; - $result = $this->parse(ApiClient::TYPE_VOUCHER_PREVIEW, $xml); + $result = $this->parse(MessageType::VoucherPreview, $xml); self::assertInstanceOf(VoucherPreview::class, $result); self::assertSame($pdf, $result->pdf); @@ -75,14 +75,14 @@ class VoucherResponseParserTest extends TestCase $this->expectException(ResponseParserException::class); - $this->parse(ApiClient::TYPE_VOUCHER_PREVIEW, $xml); + $this->parse(MessageType::VoucherPreview, $xml); } public function testTheDryRunAnswersPossibleAndIssuesNothing(): void { $xml = 'möglich'; - $result = $this->parse(ApiClient::TYPE_VOUCHER_SALE, $xml); + $result = $this->parse(MessageType::VoucherSale, $xml); self::assertInstanceOf(VoucherSaleResponse::class, $result); self::assertTrue($result->isInquiryValid()); @@ -95,7 +95,7 @@ class VoucherResponseParserTest extends TestCase { $xml = 'erfolgt4711K-001234ABCD1234111,00R-998877kaeufer@example.invalid'; - $result = $this->parse(ApiClient::TYPE_VOUCHER_SALE, $xml); + $result = $this->parse(MessageType::VoucherSale, $xml); self::assertInstanceOf(VoucherSaleResponse::class, $result); self::assertTrue($result->isSaleSuccessful()); @@ -115,13 +115,13 @@ class VoucherResponseParserTest extends TestCase { $xml = '650Fehlende Adress Daten. Bitte folgende Eingabefelder prüfen: Strasse'; - $result = $this->parse(ApiClient::TYPE_VOUCHER_SALE, $xml); + $result = $this->parse(MessageType::VoucherSale, $xml); self::assertInstanceOf(Notification::class, $result); self::assertSame(650, $result->code); } - private function parse(string $type, string $xml): mixed + private function parse(MessageType $type, string $xml): mixed { return (new ApiResponseParser($this->createStub(TravelParser::class)))->parseXmlString($type, $xml); } diff --git a/tests/Controller/Account/PersonalDataControllerTest.php b/tests/Controller/Account/PersonalDataControllerTest.php index 8879040c..1d4b65c6 100644 --- a/tests/Controller/Account/PersonalDataControllerTest.php +++ b/tests/Controller/Account/PersonalDataControllerTest.php @@ -4,7 +4,7 @@ declare(strict_types=1); namespace App\Tests\Controller\Account; -use App\BusProNet\ApiClient; +use App\BusProNet\Client\AccountClient; use App\BusProNet\Model\Notification; use App\BusProNet\Model\PersonalData; use App\Controller\Account\PersonalDataController; @@ -28,10 +28,10 @@ class PersonalDataControllerTest extends TestCase public function testIndexRendersNewsletterSubscribeCtaWhenNotSubscribed(): void { $controller = $this->createController( - apiClient: $this->createMock(ApiClient::class), + accountClient: $this->createMock(AccountClient::class), newsletterManager: $this->createMock(NewsletterManager::class), ); - $controller->apiClient + $controller->accountClient ->expects(self::once()) ->method('getPersonalData') ->with('customer@example.com', 'secret') @@ -59,10 +59,10 @@ class PersonalDataControllerTest extends TestCase public function testIndexStillTracksPendingNewsletterConfirmationWhenSubscribed(): void { $controller = $this->createController( - apiClient: $this->createMock(ApiClient::class), + accountClient: $this->createMock(AccountClient::class), newsletterManager: $this->createMock(NewsletterManager::class), ); - $controller->apiClient + $controller->accountClient ->expects(self::once()) ->method('getPersonalData') ->with('customer@example.com', 'secret') @@ -89,10 +89,10 @@ class PersonalDataControllerTest extends TestCase public function testNewsletterActionReturnsHtmxRedirectAndFlash(): void { $controller = $this->createController( - apiClient: $this->createMock(ApiClient::class), + accountClient: $this->createMock(AccountClient::class), newsletterManager: $this->createMock(NewsletterManager::class), ); - $controller->apiClient + $controller->accountClient ->expects(self::once()) ->method('getPersonalData') ->with('customer@example.com', 'secret') @@ -132,10 +132,10 @@ class PersonalDataControllerTest extends TestCase public function testNewsletterActionResendsPendingConfirmation(): void { $controller = $this->createController( - apiClient: $this->createMock(ApiClient::class), + accountClient: $this->createMock(AccountClient::class), newsletterManager: $this->createMock(NewsletterManager::class), ); - $controller->apiClient + $controller->accountClient ->expects(self::once()) ->method('getPersonalData') ->with('customer@example.com', 'secret') @@ -170,7 +170,7 @@ class PersonalDataControllerTest extends TestCase public function testIndexLocksTheEmailField(): void { $controller = $this->createController(); - $controller->apiClient + $controller->accountClient ->method('getPersonalData') ->willReturn($this->createPersonalData('Mia', 'Muster')); @@ -186,14 +186,14 @@ class PersonalDataControllerTest extends TestCase public function testIndexDoesNotSubmitTheFormWhenPersonalDataCouldNotBeLoaded(): void { $controller = $this->createController( - apiClient: $this->createMock(ApiClient::class), + accountClient: $this->createMock(AccountClient::class), form: $this->createMock(FormInterface::class), ); - $controller->apiClient + $controller->accountClient ->expects(self::once()) ->method('getPersonalData') ->willReturn(new Notification(500, 'no such customer')); - $controller->apiClient + $controller->accountClient ->expects(self::never()) ->method('updatePersonalData'); @@ -214,7 +214,7 @@ class PersonalDataControllerTest extends TestCase * expectations on, and reaches it again through the controller's public property. */ private function createController( - ?ApiClient $apiClient = null, + ?AccountClient $accountClient = null, ?NewsletterManager $newsletterManager = null, ?FormInterface $form = null, ): TestablePersonalDataController { @@ -236,7 +236,7 @@ class PersonalDataControllerTest extends TestCase ->willReturn(false); return new TestablePersonalDataController( - $apiClient ?? $this->createStub(ApiClient::class), + $accountClient ?? $this->createStub(AccountClient::class), $crypt, $this->createStub(BookingEditDataLoader::class), $this->createStub(ProfileCompletenessChecker::class), @@ -281,7 +281,7 @@ final class TestablePersonalDataController extends PersonalDataController public array $createFormOptions = []; public function __construct( - public readonly ApiClient $apiClient, + public readonly AccountClient $accountClient, Crypt $crypt, BookingEditDataLoader $dataLoader, ProfileCompletenessChecker $completenessChecker, @@ -292,7 +292,7 @@ final class TestablePersonalDataController extends PersonalDataController public readonly FormInterface $form, ) { parent::__construct( - $apiClient, + $accountClient, $crypt, $dataLoader, $completenessChecker, diff --git a/tests/Controller/Api/UserinfoControllerTest.php b/tests/Controller/Api/UserinfoControllerTest.php index 60d41d1a..a2013436 100644 --- a/tests/Controller/Api/UserinfoControllerTest.php +++ b/tests/Controller/Api/UserinfoControllerTest.php @@ -4,7 +4,7 @@ declare(strict_types=1); namespace App\Tests\Controller\Api; -use App\BusProNet\ApiClient; +use App\BusProNet\Client\AccountClient; use App\BusProNet\Model\PersonalData; use App\Controller\Api\UserinfoController; use App\Entity\User; @@ -104,10 +104,10 @@ class UserinfoControllerTest extends TestCase public function testUpstreamFailureIsReportedRatherThanAnswered(): void { - $apiClient = $this->createStub(ApiClient::class); - $apiClient->method('getPersonalData')->willThrowException(new \App\BusProNet\Exception\ApiClientException('nope')); + $accountClient = $this->createStub(AccountClient::class); + $accountClient->method('getPersonalData')->willThrowException(new \App\BusProNet\Exception\ApiClientException('nope')); - $response = $this->call($apiClient, []); + $response = $this->call($accountClient, []); self::assertSame(Response::HTTP_BAD_REQUEST, $response->getStatusCode()); } @@ -120,10 +120,10 @@ class UserinfoControllerTest extends TestCase */ private function claims(array $grantedScopeRoles = [], array $roles = [Role::TEAMER]): array { - $apiClient = $this->createStub(ApiClient::class); - $apiClient->method('getPersonalData')->willReturn($this->personalData()); + $accountClient = $this->createStub(AccountClient::class); + $accountClient->method('getPersonalData')->willReturn($this->personalData()); - $response = $this->call($apiClient, $grantedScopeRoles, $roles); + $response = $this->call($accountClient, $grantedScopeRoles, $roles); self::assertSame(Response::HTTP_OK, $response->getStatusCode()); @@ -134,12 +134,12 @@ class UserinfoControllerTest extends TestCase * @param string[] $grantedScopeRoles * @param string[] $roles */ - private function call(ApiClient $apiClient, array $grantedScopeRoles, array $roles = [Role::TEAMER]): Response + private function call(AccountClient $accountClient, array $grantedScopeRoles, array $roles = [Role::TEAMER]): Response { $crypt = $this->createStub(Crypt::class); $crypt->method('decrypt')->willReturn('md5-of-the-password'); - $controller = new UserinfoController($apiClient, $crypt); + $controller = new UserinfoController($accountClient, $crypt); $controller->setContainer($this->container($this->user($roles), $grantedScopeRoles)); return $controller->index(); diff --git a/tests/Controller/Booking/Edit/ParticipantControllerTest.php b/tests/Controller/Booking/Edit/ParticipantControllerTest.php index 7ae29a56..a77010c9 100644 --- a/tests/Controller/Booking/Edit/ParticipantControllerTest.php +++ b/tests/Controller/Booking/Edit/ParticipantControllerTest.php @@ -4,7 +4,7 @@ declare(strict_types=1); namespace App\Tests\Controller\Booking\Edit; -use App\BusProNet\ApiClient; +use App\BusProNet\Client\AccountClient; use App\BusProNet\Model\Booking; use App\BusProNet\Model\Insurance; use App\BusProNet\Model\Travel; @@ -87,7 +87,7 @@ class ParticipantControllerTest extends TestCase ->with($user, 42, $bookingDto); $prepopulationService = new ParticipantDataPrefiller( - $this->createStub(ApiClient::class), + $this->createStub(AccountClient::class), $this->createStub(Crypt::class), $this->createStub(LoggerInterface::class), ); @@ -231,7 +231,7 @@ class ParticipantControllerTest extends TestCase ->willReturn($context); $prepopulationService = new ParticipantDataPrefiller( - $this->createStub(ApiClient::class), + $this->createStub(AccountClient::class), $this->createStub(Crypt::class), $this->createStub(LoggerInterface::class), ); @@ -331,7 +331,7 @@ class ParticipantControllerTest extends TestCase $this->createStub(BookingConfigurator::class), $bookingSessionService, new ParticipantDataPrefiller( - $this->createStub(ApiClient::class), + $this->createStub(AccountClient::class), $this->createStub(Crypt::class), $this->createStub(LoggerInterface::class), ), @@ -409,7 +409,7 @@ class ParticipantControllerTest extends TestCase $this->createStub(BookingConfigurator::class), $bookingSessionService, new ParticipantDataPrefiller( - $this->createStub(ApiClient::class), + $this->createStub(AccountClient::class), $this->createStub(Crypt::class), $this->createStub(LoggerInterface::class), ), diff --git a/tests/Controller/Voucher/Step3ControllerTest.php b/tests/Controller/Voucher/Step3ControllerTest.php index 64260249..c47022c1 100644 --- a/tests/Controller/Voucher/Step3ControllerTest.php +++ b/tests/Controller/Voucher/Step3ControllerTest.php @@ -4,7 +4,7 @@ declare(strict_types=1); namespace App\Tests\Controller\Voucher; -use App\BusProNet\ApiClient; +use App\BusProNet\Client\VoucherClient; use App\BusProNet\Exception\TimeoutException; use App\BusProNet\Model\Notification; use App\BusProNet\Model\VoucherPaymentMethod; @@ -42,11 +42,11 @@ class Step3ControllerTest extends TestCase $dto->termsAccepted = true; $dto->purchaseConfirmed = true; - $apiClient = $this->createMock(ApiClient::class); - $apiClient->expects(self::once())->method('createVoucherSaleInquiry')->willReturn(new VoucherSaleResponse('möglich')); - $apiClient->expects(self::never())->method('createVoucherSale'); + $voucherClient = $this->createMock(VoucherClient::class); + $voucherClient->expects(self::once())->method('createVoucherSaleInquiry')->willReturn(new VoucherSaleResponse('möglich')); + $voucherClient->expects(self::never())->method('createVoucherSale'); - $controller = $this->createController($apiClient); + $controller = $this->createController($voucherClient); $controller->index($request); self::assertTrue($controller->renderParameters['purchasable']); @@ -61,12 +61,12 @@ class Step3ControllerTest extends TestCase { $request = $this->createRequest('GET', $this->createDto()); - $apiClient = $this->createStub(ApiClient::class); - $apiClient->method('createVoucherSaleInquiry')->willReturn( + $voucherClient = $this->createStub(VoucherClient::class); + $voucherClient->method('createVoucherSaleInquiry')->willReturn( new Notification(650, 'Fehlende Adress Daten. Bitte folgende Eingabefelder prüfen: Strasse') ); - $controller = $this->createController($apiClient); + $controller = $this->createController($voucherClient); $response = $controller->index($request); self::assertInstanceOf(RedirectResponse::class, $response); @@ -79,12 +79,12 @@ class Step3ControllerTest extends TestCase { $request = $this->createRequest('GET', $this->createDto()); - $apiClient = $this->createStub(ApiClient::class); - $apiClient->method('createVoucherSaleInquiry')->willReturn( + $voucherClient = $this->createStub(VoucherClient::class); + $voucherClient->method('createVoucherSaleInquiry')->willReturn( new Notification(608, 'Gutscheinbetrag darf nicht größer als 5.000,00 Euro sein') ); - $response = $this->createController($apiClient)->index($request); + $response = $this->createController($voucherClient)->index($request); self::assertInstanceOf(RedirectResponse::class, $response); self::assertSame('/app_voucher_step_1', $response->getTargetUrl()); @@ -94,10 +94,10 @@ class Step3ControllerTest extends TestCase { $request = $this->createRequest('GET', $this->createDto()); - $apiClient = $this->createStub(ApiClient::class); - $apiClient->method('createVoucherSaleInquiry')->willReturn(new Notification(619, 'Agentur-ID fehlt')); + $voucherClient = $this->createStub(VoucherClient::class); + $voucherClient->method('createVoucherSaleInquiry')->willReturn(new Notification(619, 'Agentur-ID fehlt')); - $controller = $this->createController($apiClient); + $controller = $this->createController($voucherClient); $controller->index($request); self::assertFalse($controller->renderParameters['purchasable']); @@ -107,9 +107,9 @@ class Step3ControllerTest extends TestCase { $request = $this->createRequest('POST', $this->createDto()); - $apiClient = $this->createMock(ApiClient::class); - $apiClient->expects(self::never())->method('createVoucherSaleInquiry'); - $apiClient->expects(self::once())->method('createVoucherSale')->willReturn(new VoucherSaleResponse( + $voucherClient = $this->createMock(VoucherClient::class); + $voucherClient->expects(self::never())->method('createVoucherSaleInquiry'); + $voucherClient->expects(self::once())->method('createVoucherSale')->willReturn(new VoucherSaleResponse( status: 'erfolgt', voucherId: 4711, voucherNumber: 'K-001234', @@ -124,7 +124,7 @@ class Step3ControllerTest extends TestCase static fn (array $context) => !\in_array('ABCD1234', $context, true) && 'K-001234' === $context['voucher_number'] )); - $controller = $this->createController($apiClient, $this->createSubmittedForm(), $logger); + $controller = $this->createController($voucherClient, $this->createSubmittedForm(), $logger); $response = $controller->index($request); self::assertInstanceOf(RedirectResponse::class, $response); @@ -143,10 +143,10 @@ class Step3ControllerTest extends TestCase $request = Request::create('/gutschein/uebersicht', 'POST'); $request->setSession(new Session(new MockArraySessionStorage())); - $apiClient = $this->createMock(ApiClient::class); - $apiClient->expects(self::never())->method('createVoucherSale'); + $voucherClient = $this->createMock(VoucherClient::class); + $voucherClient->expects(self::never())->method('createVoucherSale'); - $response = $this->createController($apiClient, $this->createSubmittedForm())->index($request); + $response = $this->createController($voucherClient, $this->createSubmittedForm())->index($request); self::assertInstanceOf(RedirectResponse::class, $response); self::assertSame('/app_voucher_error', $response->getTargetUrl()); @@ -159,10 +159,10 @@ class Step3ControllerTest extends TestCase { $request = $this->createRequest('POST', $this->createDto()); - $apiClient = $this->createStub(ApiClient::class); - $apiClient->method('createVoucherSale')->willThrowException(new TimeoutException('Stream timeout')); + $voucherClient = $this->createStub(VoucherClient::class); + $voucherClient->method('createVoucherSale')->willThrowException(new TimeoutException('Stream timeout')); - $controller = $this->createController($apiClient, $this->createSubmittedForm()); + $controller = $this->createController($voucherClient, $this->createSubmittedForm()); $controller->index($request); self::assertFalse($controller->renderParameters['purchasable']); @@ -205,12 +205,12 @@ class Step3ControllerTest extends TestCase /** * @param FormInterface|null $form */ - private function createController(ApiClient $apiClient, ?FormInterface $form = null, ?LoggerInterface $logger = null): TestableStep3Controller + private function createController(VoucherClient $voucherClient, ?FormInterface $form = null, ?LoggerInterface $logger = null): TestableStep3Controller { return new TestableStep3Controller( $this->sessionManager, $this->createStub(VoucherThumbnailResolver::class), - $apiClient, + $voucherClient, new VoucherSaleRejectionMapper(), $logger ?? new NullLogger(), $form ?? $this->createStub(FormInterface::class), @@ -236,12 +236,12 @@ final class TestableStep3Controller extends Step3Controller public function __construct( VoucherPurchaseSessionManager $sessionManager, VoucherThumbnailResolver $thumbnailResolver, - ApiClient $apiClient, + VoucherClient $voucherClient, VoucherSaleRejectionMapper $rejectionMapper, LoggerInterface $logger, private readonly FormInterface $form, ) { - parent::__construct($sessionManager, $thumbnailResolver, $apiClient, $rejectionMapper, $logger); + parent::__construct($sessionManager, $thumbnailResolver, $voucherClient, $rejectionMapper, $logger); } protected function getUser(): ?UserInterface diff --git a/tests/Security/BpnAuthenticatorTest.php b/tests/Security/BpnAuthenticatorTest.php index 65ebf76d..0449ce8d 100644 --- a/tests/Security/BpnAuthenticatorTest.php +++ b/tests/Security/BpnAuthenticatorTest.php @@ -4,7 +4,7 @@ declare(strict_types=1); namespace App\Tests\Security; -use App\BusProNet\ApiClient; +use App\BusProNet\Client\AccountClient; use App\BusProNet\Model\CrmAttributes; use App\BusProNet\Model\CrmSelectionGroup; use App\BusProNet\Model\PersonalData; @@ -380,9 +380,9 @@ class BpnAuthenticatorTest extends TestCase $personalData->addressId = 4711; $personalData->communication->email = $contactEmail; - $apiClient = $this->createStub(ApiClient::class); - $apiClient->method('getPersonalData')->willReturn($personalData); - $apiClient->method('getCrmAttributes')->willReturn($crmAttributes); + $accountClient = $this->createStub(AccountClient::class); + $accountClient->method('getPersonalData')->willReturn($personalData); + $accountClient->method('getCrmAttributes')->willReturn($crmAttributes); $repository = $this->createStub(EntityRepository::class); $repository @@ -424,7 +424,7 @@ class BpnAuthenticatorTest extends TestCase return new BpnAuthenticator( $this->createStub(UrlGeneratorInterface::class), - $apiClient, + $accountClient, $entityManager, $crypt, $completenessChecker, diff --git a/tests/Service/BookingEditDataLoaderDraftRestoreTest.php b/tests/Service/BookingEditDataLoaderDraftRestoreTest.php index dc5e111d..82e2d287 100644 --- a/tests/Service/BookingEditDataLoaderDraftRestoreTest.php +++ b/tests/Service/BookingEditDataLoaderDraftRestoreTest.php @@ -4,7 +4,7 @@ declare(strict_types=1); namespace App\Tests\Service; -use App\BusProNet\ApiClient; +use App\BusProNet\Client\BookingClient; use App\BusProNet\DataProcessor\BookingDataProcessor; use App\BusProNet\Model\BaseData; use App\BusProNet\Model\Booking; @@ -111,7 +111,7 @@ class BookingEditDataLoaderDraftRestoreTest extends TestCase $crypt->method('decrypt')->willReturn('secret'); return new BookingEditDataLoader( - $this->createStub(ApiClient::class), + $this->createStub(BookingClient::class), $bookingDataProcessor, $this->createStub(BookingSessionManager::class), new BookingChangeTracker(), diff --git a/tests/Service/BookingEditSubmitterTest.php b/tests/Service/BookingEditSubmitterTest.php index 5a1ad0f4..c00c4973 100644 --- a/tests/Service/BookingEditSubmitterTest.php +++ b/tests/Service/BookingEditSubmitterTest.php @@ -4,6 +4,7 @@ declare(strict_types=1); namespace App\Tests\Service; +use App\BusProNet\Client\BookingClient; use App\BusProNet\Exception\ApiClientException; use App\BusProNet\Exception\TimeoutException; use App\BusProNet\Model\Booking; @@ -87,14 +88,14 @@ class BookingEditSubmitterTest extends TestCase ->with($bookingDto, $freshBookingData) ->willReturn(false); - $apiClient = $this->createMock(\App\BusProNet\ApiClient::class); - $apiClient->expects($this->once()) + $bookingClient = $this->createMock(BookingClient::class); + $bookingClient->expects($this->once()) ->method('updateBooking') ->with($bookingDto, true) ->willThrowException($exception); $service = $this->createService( - apiClient: $apiClient, + bookingClient: $bookingClient, dataLoader: $dataLoader, travelDataService: $travelDataService, submitGuard: $submitGuard, @@ -137,17 +138,17 @@ class BookingEditSubmitterTest extends TestCase ->with($bookingDto, $freshBookingData) ->willReturn(false); - $apiClient = $this->createMock(\App\BusProNet\ApiClient::class); + $bookingClient = $this->createMock(BookingClient::class); $bookingUpdate = new BookingUpdate(); $bookingUpdate->success = false; $bookingUpdate->status = 'BPN-FAIL'; - $apiClient->expects($this->once()) + $bookingClient->expects($this->once()) ->method('updateBooking') ->with($bookingDto, true) ->willReturn($bookingUpdate); $service = $this->createService( - apiClient: $apiClient, + bookingClient: $bookingClient, dataLoader: $dataLoader, travelDataService: $travelDataService, submitGuard: $submitGuard, @@ -200,10 +201,10 @@ class BookingEditSubmitterTest extends TestCase ->with($bookingDto, $freshBookingData) ->willReturn(false); - $apiClient = $this->createMock(\App\BusProNet\ApiClient::class); + $bookingClient = $this->createMock(BookingClient::class); $bookingUpdate = new BookingUpdate(); $bookingUpdate->success = true; - $apiClient->expects($this->once()) + $bookingClient->expects($this->once()) ->method('updateBooking') ->with($bookingDto, true) ->willReturn($bookingUpdate); @@ -221,7 +222,7 @@ class BookingEditSubmitterTest extends TestCase ->with($user, 42); $service = $this->createService( - apiClient: $apiClient, + bookingClient: $bookingClient, dataLoader: $dataLoader, draftService: $draftService, travelDataService: $travelDataService, @@ -267,10 +268,10 @@ class BookingEditSubmitterTest extends TestCase ->with($bookingDto, $freshBookingData) ->willReturn(true); - $apiClient = $this->createMock(\App\BusProNet\ApiClient::class); + $bookingClient = $this->createMock(BookingClient::class); $bookingUpdate = new BookingUpdate(); $bookingUpdate->success = true; - $apiClient->expects($this->once()) + $bookingClient->expects($this->once()) ->method('updateBooking') ->with($bookingDto, true) ->willReturn($bookingUpdate); @@ -289,7 +290,7 @@ class BookingEditSubmitterTest extends TestCase ->with($user, 42); $service = $this->createService( - apiClient: $apiClient, + bookingClient: $bookingClient, dataLoader: $dataLoader, draftService: $draftService, travelDataService: $travelDataService, @@ -352,14 +353,14 @@ class BookingEditSubmitterTest extends TestCase ->with($bookingDto, $freshBookingData) ->willReturn(false); - $apiClient = $this->createMock(\App\BusProNet\ApiClient::class); - $apiClient->expects($this->once()) + $bookingClient = $this->createMock(BookingClient::class); + $bookingClient->expects($this->once()) ->method('updateBooking') ->with($bookingDto, true) ->willReturn($notification); $service = $this->createService( - apiClient: $apiClient, + bookingClient: $bookingClient, dataLoader: $dataLoader, travelDataService: $travelDataService, submitGuard: $submitGuard, @@ -407,14 +408,14 @@ class BookingEditSubmitterTest extends TestCase ->with($bookingDto, $freshBookingData) ->willReturn(false); - $apiClient = $this->createMock(\App\BusProNet\ApiClient::class); - $apiClient->expects($this->once()) + $bookingClient = $this->createMock(BookingClient::class); + $bookingClient->expects($this->once()) ->method('updateBooking') ->with($bookingDto, true) ->willThrowException($exception); $service = $this->createService( - apiClient: $apiClient, + bookingClient: $bookingClient, dataLoader: $dataLoader, travelDataService: $travelDataService, submitGuard: $submitGuard, @@ -428,7 +429,7 @@ class BookingEditSubmitterTest extends TestCase } private function createService( - ?\App\BusProNet\ApiClient $apiClient = null, + ?BookingClient $bookingClient = null, ?BookingEditDataLoader $dataLoader = null, ?BookingEditDraftManager $draftService = null, ?TravelDataProvider $travelDataService = null, @@ -436,7 +437,7 @@ class BookingEditSubmitterTest extends TestCase ?BookingSessionManager $bookingSessionService = null, ): BookingEditSubmitter { return new BookingEditSubmitter( - $apiClient ?? $this->createStub(\App\BusProNet\ApiClient::class), + $bookingClient ?? $this->createStub(BookingClient::class), $dataLoader ?? $this->createStub(BookingEditDataLoader::class), $draftService ?? $this->createStub(BookingEditDraftManager::class), $travelDataService ?? $this->createStub(TravelDataProvider::class), diff --git a/tests/Service/ParticipantDataPrefillerTest.php b/tests/Service/ParticipantDataPrefillerTest.php index efaf7ac3..d06d0f4c 100644 --- a/tests/Service/ParticipantDataPrefillerTest.php +++ b/tests/Service/ParticipantDataPrefillerTest.php @@ -4,7 +4,7 @@ declare(strict_types=1); namespace App\Tests\Service; -use App\BusProNet\ApiClient; +use App\BusProNet\Client\AccountClient; use App\BusProNet\Model\Address; use App\BusProNet\Model\Communication; use App\BusProNet\Model\Notification; @@ -20,14 +20,14 @@ use Psr\Log\LoggerInterface; class ParticipantDataPrefillerTest extends TestCase { - private ApiClient $apiClient; + private AccountClient $accountClient; private Crypt $crypt; private LoggerInterface $logger; private ?ParticipantDataPrefiller $service = null; protected function setUp(): void { - $this->apiClient = $this->createStub(ApiClient::class); + $this->accountClient = $this->createStub(AccountClient::class); $this->crypt = $this->createStub(Crypt::class); $this->logger = $this->createStub(LoggerInterface::class); } @@ -35,7 +35,7 @@ class ParticipantDataPrefillerTest extends TestCase private function service(): ParticipantDataPrefiller { return $this->service ??= new ParticipantDataPrefiller( - $this->apiClient, + $this->accountClient, $this->crypt, $this->logger ); @@ -43,7 +43,7 @@ class ParticipantDataPrefillerTest extends TestCase public function testPrepopulateApplicantWithCompletePersonalData(): void { - $this->apiClient = $this->createMock(ApiClient::class); + $this->accountClient = $this->createMock(AccountClient::class); $this->crypt = $this->createMock(Crypt::class); $user = $this->createUser('test@example.com', 'encrypted_password'); @@ -57,7 +57,7 @@ class ParticipantDataPrefillerTest extends TestCase ->with('encrypted_password') ->willReturn('decrypted_password'); - $this->apiClient->expects($this->once()) + $this->accountClient->expects($this->once()) ->method('getPersonalData') ->with('test@example.com', 'decrypted_password') ->willReturn($personalData); @@ -94,7 +94,7 @@ class ParticipantDataPrefillerTest extends TestCase public function testPrepopulateApplicantWithPartialPersonalData(): void { - $this->apiClient = $this->createMock(ApiClient::class); + $this->accountClient = $this->createMock(AccountClient::class); $this->crypt = $this->createMock(Crypt::class); $user = $this->createUser('test@example.com', 'encrypted_password'); @@ -107,7 +107,7 @@ class ParticipantDataPrefillerTest extends TestCase ->method('decrypt') ->willReturn('decrypted_password'); - $this->apiClient->expects($this->once()) + $this->accountClient->expects($this->once()) ->method('getPersonalData') ->willReturn($personalData); @@ -132,7 +132,7 @@ class ParticipantDataPrefillerTest extends TestCase public function testPrepopulateApplicantWithApiNotificationError(): void { - $this->apiClient = $this->createMock(ApiClient::class); + $this->accountClient = $this->createMock(AccountClient::class); $this->crypt = $this->createMock(Crypt::class); $this->logger = $this->createMock(LoggerInterface::class); @@ -146,7 +146,7 @@ class ParticipantDataPrefillerTest extends TestCase ->method('decrypt') ->willReturn('decrypted_password'); - $this->apiClient->expects($this->once()) + $this->accountClient->expects($this->once()) ->method('getPersonalData') ->willReturn($notification); @@ -171,7 +171,7 @@ class ParticipantDataPrefillerTest extends TestCase public function testPrepopulateApplicantWithDecryptionException(): void { - $this->apiClient = $this->createMock(ApiClient::class); + $this->accountClient = $this->createMock(AccountClient::class); $this->crypt = $this->createMock(Crypt::class); $this->logger = $this->createMock(LoggerInterface::class); @@ -183,7 +183,7 @@ class ParticipantDataPrefillerTest extends TestCase ->method('decrypt') ->willThrowException(new \RuntimeException('Decryption failed')); - $this->apiClient->expects($this->never()) + $this->accountClient->expects($this->never()) ->method('getPersonalData'); $this->logger->expects($this->once()) @@ -203,7 +203,7 @@ class ParticipantDataPrefillerTest extends TestCase public function testPrepopulateApplicantWithApiException(): void { - $this->apiClient = $this->createMock(ApiClient::class); + $this->accountClient = $this->createMock(AccountClient::class); $this->crypt = $this->createMock(Crypt::class); $this->logger = $this->createMock(LoggerInterface::class); @@ -215,7 +215,7 @@ class ParticipantDataPrefillerTest extends TestCase ->method('decrypt') ->willReturn('decrypted_password'); - $this->apiClient->expects($this->once()) + $this->accountClient->expects($this->once()) ->method('getPersonalData') ->willThrowException(new \RuntimeException('API connection failed')); @@ -236,7 +236,7 @@ class ParticipantDataPrefillerTest extends TestCase public function testPrepopulatePreservesBookingSpecificFields(): void { - $this->apiClient = $this->createMock(ApiClient::class); + $this->accountClient = $this->createMock(AccountClient::class); $this->crypt = $this->createMock(Crypt::class); $user = $this->createUser('test@example.com', 'encrypted_password'); @@ -251,7 +251,7 @@ class ParticipantDataPrefillerTest extends TestCase ->method('decrypt') ->willReturn('decrypted_password'); - $this->apiClient->expects($this->once()) + $this->accountClient->expects($this->once()) ->method('getPersonalData') ->willReturn($personalData); diff --git a/tests/Service/TravelDataProviderTest.php b/tests/Service/TravelDataProviderTest.php index 14cbbefc..040e5835 100644 --- a/tests/Service/TravelDataProviderTest.php +++ b/tests/Service/TravelDataProviderTest.php @@ -4,7 +4,7 @@ declare(strict_types=1); namespace App\Tests\Service; -use App\BusProNet\ApiClient; +use App\BusProNet\Client\TravelClient; use App\BusProNet\Model\Travel; use App\BusProNet\XmlLoader\TravelLoader; use App\Exception\TravelNotFoundException; @@ -20,7 +20,7 @@ class TravelDataProviderTest extends TestCase { private ?TravelDataProvider $service = null; private TravelLoader $travelLoader; - private ApiClient $apiClient; + private TravelClient $travelClient; private CacheInterface $cache; private LoggerInterface $logger; private TravelSnapshotManager $travelSnapshotService; @@ -30,7 +30,7 @@ class TravelDataProviderTest extends TestCase protected function setUp(): void { $this->travelLoader = $this->createStub(TravelLoader::class); - $this->apiClient = $this->createStub(ApiClient::class); + $this->travelClient = $this->createStub(TravelClient::class); $this->cache = $this->createStub(CacheInterface::class); $this->logger = $this->createStub(LoggerInterface::class); $this->travelSnapshotService = $this->createStub(TravelSnapshotManager::class); @@ -42,7 +42,7 @@ class TravelDataProviderTest extends TestCase { return $this->service ??= new TravelDataProvider( $this->travelLoader, - $this->apiClient, + $this->travelClient, $this->cache, $this->logger, $this->travelSnapshotService, @@ -144,7 +144,7 @@ class TravelDataProviderTest extends TestCase public function testGetTravelDataFromApiSuccess(): void { - $this->apiClient = $this->createMock(ApiClient::class); + $this->travelClient = $this->createMock(TravelClient::class); $this->travelSnapshotService = $this->createMock(TravelSnapshotManager::class); $this->travelLookupService = $this->createMock(TravelIndex::class); $this->travelEnrichmentService = $this->createMock(TravelEnricher::class); @@ -162,7 +162,7 @@ class TravelDataProviderTest extends TestCase ->with($dateId) ->willReturn($productId); - $this->apiClient + $this->travelClient ->expects($this->once()) ->method('getTravelData') ->with($productId, $hotelId) @@ -199,7 +199,7 @@ class TravelDataProviderTest extends TestCase ->method('mapDateIdToProductId') ->willReturn($productId); - $this->apiClient + $this->travelClient ->method('getTravelData') ->willReturn($travel); @@ -221,7 +221,7 @@ class TravelDataProviderTest extends TestCase public function testGetTravelDataFromApiCannotMapDateId(): void { - $this->apiClient = $this->createMock(ApiClient::class); + $this->travelClient = $this->createMock(TravelClient::class); $this->travelLookupService = $this->createMock(TravelIndex::class); $dateId = 12345; @@ -233,7 +233,7 @@ class TravelDataProviderTest extends TestCase ->with($dateId) ->willReturn(null); - $this->apiClient + $this->travelClient ->expects($this->never()) ->method('getTravelData'); diff --git a/tests/Service/TravelSnapshotManagerTest.php b/tests/Service/TravelSnapshotManagerTest.php index 8927afb0..65fc3e2c 100644 --- a/tests/Service/TravelSnapshotManagerTest.php +++ b/tests/Service/TravelSnapshotManagerTest.php @@ -4,7 +4,7 @@ declare(strict_types=1); namespace App\Tests\Service; -use App\BusProNet\ApiClient; +use App\BusProNet\Client\TravelClient; use App\BusProNet\Exception\ApiClientException; use App\BusProNet\Model\ExtendedServiceAvailabilityResponse; use App\BusProNet\Model\Hotel; @@ -21,7 +21,7 @@ class TravelSnapshotManagerTest extends TestCase { private TravelSnapshotRepository $snapshotRepository; private EntityManagerInterface $entityManager; - private ApiClient $apiClient; + private TravelClient $travelClient; private LoggerInterface $logger; private SerializerInterface $serializer; private ?TravelSnapshotManager $service = null; @@ -30,7 +30,7 @@ class TravelSnapshotManagerTest extends TestCase { $this->snapshotRepository = $this->createStub(TravelSnapshotRepository::class); $this->entityManager = $this->createStub(EntityManagerInterface::class); - $this->apiClient = $this->createStub(ApiClient::class); + $this->travelClient = $this->createStub(TravelClient::class); $this->logger = $this->createStub(LoggerInterface::class); $this->serializer = $this->createStub(SerializerInterface::class); } @@ -40,7 +40,7 @@ class TravelSnapshotManagerTest extends TestCase return $this->service ??= new TravelSnapshotManager( $this->snapshotRepository, $this->entityManager, - $this->apiClient, + $this->travelClient, $this->logger, $this->serializer, 14, @@ -309,7 +309,7 @@ class TravelSnapshotManagerTest extends TestCase { $this->snapshotRepository = $this->createMock(TravelSnapshotRepository::class); $this->entityManager = $this->createMock(EntityManagerInterface::class); - $this->apiClient = $this->createMock(ApiClient::class); + $this->travelClient = $this->createMock(TravelClient::class); $this->serializer = $this->createMock(SerializerInterface::class); $travel = new Travel(); @@ -334,7 +334,7 @@ class TravelSnapshotManagerTest extends TestCase ->with($oldPayload, Travel::class, 'json') ->willReturn($travel); - $this->apiClient + $this->travelClient ->expects($this->once()) ->method('getAvailabilitiesExtended') ->with(100) @@ -359,7 +359,7 @@ class TravelSnapshotManagerTest extends TestCase { $this->snapshotRepository = $this->createMock(TravelSnapshotRepository::class); $this->entityManager = $this->createMock(EntityManagerInterface::class); - $this->apiClient = $this->createMock(ApiClient::class); + $this->travelClient = $this->createMock(TravelClient::class); $this->logger = $this->createMock(LoggerInterface::class); $this->serializer = $this->createMock(SerializerInterface::class); @@ -380,7 +380,7 @@ class TravelSnapshotManagerTest extends TestCase ->method('deserialize') ->willReturn($travel); - $this->apiClient + $this->travelClient ->expects($this->once()) ->method('getAvailabilitiesExtended') ->willThrowException(new ApiClientException('API error')); @@ -437,7 +437,7 @@ class TravelSnapshotManagerTest extends TestCase { $this->snapshotRepository = $this->createMock(TravelSnapshotRepository::class); $this->entityManager = $this->createMock(EntityManagerInterface::class); - $this->apiClient = $this->createMock(ApiClient::class); + $this->travelClient = $this->createMock(TravelClient::class); $payload = '{"id":100}'; $snapshot = new TravelSnapshot(100, 200, $payload, hash('sha256', $payload)); @@ -447,7 +447,7 @@ class TravelSnapshotManagerTest extends TestCase ->method('findRefreshCandidates') ->willReturn([$snapshot]); - $this->apiClient + $this->travelClient ->expects($this->never()) ->method('getAvailabilitiesExtended'); @@ -463,7 +463,7 @@ class TravelSnapshotManagerTest extends TestCase public function testRefreshSkipsSnapshotsWithXmlAvailable(): void { $this->snapshotRepository = $this->createMock(TravelSnapshotRepository::class); - $this->apiClient = $this->createMock(ApiClient::class); + $this->travelClient = $this->createMock(TravelClient::class); $payload = '{"id":100}'; $snapshot = new TravelSnapshot(100, 200, $payload, hash('sha256', $payload)); @@ -473,7 +473,7 @@ class TravelSnapshotManagerTest extends TestCase ->method('findRefreshCandidates') ->willReturn([$snapshot]); - $this->apiClient + $this->travelClient ->expects($this->never()) ->method('getAvailabilitiesExtended'); diff --git a/tests/Service/VoucherTemplateProviderTest.php b/tests/Service/VoucherTemplateProviderTest.php index 252a534f..6715587a 100644 --- a/tests/Service/VoucherTemplateProviderTest.php +++ b/tests/Service/VoucherTemplateProviderTest.php @@ -4,7 +4,7 @@ declare(strict_types=1); namespace App\Tests\Service; -use App\BusProNet\ApiClient; +use App\BusProNet\Client\VoucherClient; use App\BusProNet\Model\Notification; use App\BusProNet\Model\VoucherPaymentMethod; use App\BusProNet\Model\VoucherTemplate; @@ -21,10 +21,10 @@ class VoucherTemplateProviderTest extends TestCase public function testTemplatesAreCached(): void { $templates = new VoucherTemplates(10, 5000, [new VoucherTemplate(3, 'K', 'Allgemein')]); - $apiClient = $this->createMock(ApiClient::class); - $apiClient->expects(self::once())->method('getVoucherTemplates')->willReturn($templates); + $voucherClient = $this->createMock(VoucherClient::class); + $voucherClient->expects(self::once())->method('getVoucherTemplates')->willReturn($templates); - $provider = $this->createProvider($apiClient); + $provider = $this->createProvider($voucherClient); self::assertEquals($templates, $provider->getTemplates()); self::assertEquals($templates, $provider->getTemplates()); @@ -33,11 +33,11 @@ class VoucherTemplateProviderTest extends TestCase public function testARejectionIsNotCached(): void { $templates = new VoucherTemplates(10, 5000, [new VoucherTemplate(3, 'K', 'Allgemein')]); - $apiClient = $this->createMock(ApiClient::class); - $apiClient->expects(self::exactly(2))->method('getVoucherTemplates') + $voucherClient = $this->createMock(VoucherClient::class); + $voucherClient->expects(self::exactly(2))->method('getVoucherTemplates') ->willReturnOnConsecutiveCalls(new Notification(104, 'User fehlerhaft'), $templates); - $provider = $this->createProvider($apiClient); + $provider = $this->createProvider($voucherClient); try { $provider->getTemplates(); @@ -50,37 +50,37 @@ class VoucherTemplateProviderTest extends TestCase public function testNoTemplatesOnSaleMeansNoShop(): void { - $apiClient = $this->createStub(ApiClient::class); - $apiClient->method('getVoucherTemplates')->willReturn(new VoucherTemplates(10, 5000, [])); + $voucherClient = $this->createStub(VoucherClient::class); + $voucherClient->method('getVoucherTemplates')->willReturn(new VoucherTemplates(10, 5000, [])); $this->expectException(VoucherShopUnavailableException::class); - $this->createProvider($apiClient)->getTemplates(); + $this->createProvider($voucherClient)->getTemplates(); } public function testThePaymentMethodIsTransfer(): void { - $apiClient = $this->createStub(ApiClient::class); - $apiClient->method('getVoucherPaymentMethods')->willReturn([ + $voucherClient = $this->createStub(VoucherClient::class); + $voucherClient->method('getVoucherPaymentMethods')->willReturn([ new VoucherPaymentMethod(1, 'Lastschrift', 'LAST'), new VoucherPaymentMethod(2, 'Überweisung', 'UEBERW'), ]); - self::assertSame(2, $this->createProvider($apiClient)->getPaymentMethod()->id); + self::assertSame(2, $this->createProvider($voucherClient)->getPaymentMethod()->id); } public function testWithoutTransferThereIsNoShop(): void { - $apiClient = $this->createStub(ApiClient::class); - $apiClient->method('getVoucherPaymentMethods')->willReturn([new VoucherPaymentMethod(1, 'Lastschrift', 'LAST')]); + $voucherClient = $this->createStub(VoucherClient::class); + $voucherClient->method('getVoucherPaymentMethods')->willReturn([new VoucherPaymentMethod(1, 'Lastschrift', 'LAST')]); $this->expectException(VoucherShopUnavailableException::class); - $this->createProvider($apiClient)->getPaymentMethod(); + $this->createProvider($voucherClient)->getPaymentMethod(); } - private function createProvider(ApiClient $apiClient): VoucherTemplateProvider + private function createProvider(VoucherClient $voucherClient): VoucherTemplateProvider { - return new VoucherTemplateProvider($apiClient, new TagAwareAdapter(new ArrayAdapter()), new NullLogger()); + return new VoucherTemplateProvider($voucherClient, new TagAwareAdapter(new ArrayAdapter()), new NullLogger()); } }