feat: sync contingents for TYPO3 calendar hotels
This commit is contained in:
1 parent
ec36b61275
commit
97c6330a9a
24 files changed
+1067
-180
No files matched your search
@@ -526,7 +526,35 @@ Two differences from `calendar`:
|
||||
- **No price rule.** A day without a maintained price keeps the status the contingent reports; it is not forced to `BLOCKED`.
|
||||
- **Days the snapshot lacks are left out**, not returned as `BLOCKED`. The response is not contiguous: a day without an entry has no availability data, and the feed shows it as free, as it did when it read the upstream service directly.
|
||||
|
||||
Errors are the same as for `calendar`: `400 {"error":"Hotel not found for hotelCode."}`, `400` with violations for invalid parameters, and `502 {"error":"Failed to fetch contingent data."}` when there is no usable snapshot. For this endpoint the `502` is the important one: an empty list would show every day as free, so a consumer should answer with an error and let the portals keep their last import.
|
||||
- **Not limited to accommodations.** `hotelCode` may be any synced hotel code: an accommodation's calendar code, or the calendar hotel of a visible TYPO3 product (TYPO3's `/api/calendar-hotels`). Winter-only hotels without an accommodation are therefore served here, while `calendar` and `prices` still need an accommodation, since they need its prices.
|
||||
|
||||
Errors are the same as for `calendar`: `400 {"error":"Hotel not found for hotelCode."}` when the code is not synced, `400` with violations for invalid parameters, and `502 {"error":"Failed to fetch contingent data."}` when there is no usable snapshot. For this endpoint the `502` is the important one: an empty list would show every day as free, so a consumer should answer with an error and let the portals keep their last import.
|
||||
|
||||
#### `GET /api/contingents/status` — scope `api`
|
||||
|
||||
One row per synced hotel code, sorted by code, for an overview of which hotel supports which calendar:
|
||||
|
||||
```json
|
||||
{
|
||||
"hotelCode": "DGS",
|
||||
"name": "Sportclub Spinabad",
|
||||
"sources": ["accommodation", "typo3"],
|
||||
"accommodation": {"name": "Davos Glaris - Gruppenhaus Spinabad", "cmsCode": "DGSGRP"},
|
||||
"pricedFrom": "2027-06-01",
|
||||
"pricedTo": "2027-09-30",
|
||||
"syncedAt": "2026-10-29T10:15:00+01:00",
|
||||
"lastError": null,
|
||||
"failureCount": 0,
|
||||
"available": true
|
||||
}
|
||||
```
|
||||
|
||||
- `sources`: where the code comes from, `accommodation` and/or `typo3`.
|
||||
- `name`: the hotel's name in TYPO3's calendar hotel list, `null` for a code TYPO3 does not list.
|
||||
- `accommodation`: `null` without one; `cmsCode` is the code the accommodation is known by in TYPO3, which may differ from `hotelCode`.
|
||||
- `pricedFrom`/`pricedTo`: the span of the accommodation's prices, `null` without prices. `calendar` and `prices` work only for hotels that have them.
|
||||
- `syncedAt`, `lastError`, `failureCount`: the last successful sync (`null` if none) and the failures since.
|
||||
- `available`: whether `availability` currently serves the hotel, i.e. it has synced within the last 6 hours. `false` means that endpoint answers `502`.
|
||||
|
||||
---
|
||||
|
||||
@@ -543,6 +571,8 @@ Rollout order:
|
||||
|
||||
Thereafter the scheduler keeps it current; a sync failing for one hotel puts only that hotel into `502` and leaves the rest serving normally.
|
||||
|
||||
**Which hotels are synced.** Every accommodation's calendar code plus every code in TYPO3's `/api/calendar-hotels` (same `APP_CMS_API_KEY` as the other CMS calls). Each run fetches TYPO3's list first and stores it in `calendar_hotel`; when TYPO3 errors or answers with an empty list, the run logs a warning and uses the stored list, so TYPO3 being down never drops its hotels. `--hotel=<code>` accepts any code from either source. A full run deletes the snapshot of codes that are in neither source any more; they answer `400` from then on, and come back with the next run if they reappear.
|
||||
|
||||
### Freshness and propagation
|
||||
|
||||
There is deliberately **no change-notification endpoint**. Availability changes slowly, and the measured cost of simply refetching on a TTL is low enough that a polling/revision mechanism was not worth the extra moving parts on either side.
|
||||
|
||||
Reference in new issue
Block a user