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