refactor: split buspro ApiClient into domain clients

This commit is contained in:
fromme committed 2026-10-02 13:55:30 +02:00
1 parent 0a55544ca8
commit b755a6f43e
52 files changed
+805 -695

No files matched your search

+7 -7
View File
@@ -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 |
|---|---|---|