feat: turn search_trips into the website's travel search
This commit is contained in:
1 parent
bfdedefae3
commit
4ab2714bde
12 files changed
+693
-151
No files matched your search
+30
-5
@@ -39,7 +39,7 @@ that prices and availability are a snapshot (`dataAsOf`) and only the booking pa
|
||||
|
||||
| Tool | Use | Returns |
|
||||
|---|---|---|
|
||||
| `search_trips` | Which trips exist, when, where, how much | Up to 10 trips with their next 3 matching dates, `priceFrom`, availability, `dataAsOf` |
|
||||
| `search_trips` | The website's travel search: which trips exist, when, where, how much | One result per trip × hotel × travel date (default 10, max 25), with "ab" price, nights, inclusions, room types, availability, link; `total` and `dataAsOf` |
|
||||
| `get_trip` | One trip by product `code`, or one date of it by date code such as `SSLMP061226` (optionally `hotelCode`) | Product text with FAQs, hotels with facts, all upcoming dates with bookable rooms, pickups for the first 3 dates |
|
||||
| `search_content` | Questions not about dates or prices | Up to 8 hits with a ~600-character excerpt |
|
||||
| `get_document` | The full text of one `search_content` hit, by `url` | Markdown body, truncated at 20 000 characters |
|
||||
@@ -52,15 +52,40 @@ Trip rules (`App\Chatbot\TripCatalog`):
|
||||
- TYPO3 products are joined to the export on `product.code`. Several products can share a code, and
|
||||
each is listed as its own trip. Hotels are joined on any entry of the TYPO3 hotel's `codes` (BusPro
|
||||
uses the matchcode aliases). A code that is one hotel's own and another's alias resolves to its owner.
|
||||
- A room is bookable unless its status is `Buchungsstop`. `available` counts rooms, so the places of a
|
||||
date at a hotel are `Σ available × maxPax` over its bookable rooms. `persons` filters on that sum, and
|
||||
`maxPrice` on the lowest bookable room price. The tools never output room counts, only `frei` or
|
||||
`auf Anfrage`.
|
||||
- A room is bookable unless its status is `Buchungsstop`. The baby row (room code `Baby`) is not a room.
|
||||
`available` counts rooms, so the places of a date at a hotel are `Σ available × maxPax` over its
|
||||
bookable rooms. The tools never output room counts, only `frei` or `auf Anfrage`.
|
||||
- `search_trips` only offers products that TYPO3 lists in its own website search (`searchable`) and does
|
||||
not mark as unbookable. Closed group trips and staff trainings are `searchable: false`. `get_trip` still
|
||||
answers when someone names their code.
|
||||
- The export's `guide` (name, phone) and all BusPro ids are never output.
|
||||
|
||||
`search_trips` mirrors the search page (`/skireisen/suche/`), whose data is TYPO3's import of our own
|
||||
product export. Its rules follow TYPO3's `DateImportService` and search repository, derived per date and
|
||||
hotel in `App\Model\Chatbot\TravelDateFacts`:
|
||||
|
||||
- **"ab" price:** the cheapest bookable room with places left, otherwise the cheapest bookable room.
|
||||
`priceMin`/`priceMax` apply to it. The site's price bands are presets of this.
|
||||
- **Travel period:** `dateFrom`/`dateTo` match by containment (start on or after, end on or before), as on
|
||||
the site, not by overlap. `period` names one of the site's presets, from the `chatbot_travel_periods`
|
||||
parameter in `config/services.yaml`. It's duplicated from the TYPO3 search configuration on purpose, so
|
||||
update both each season. Expired periods are no longer offered.
|
||||
- **`persons`:** the site's condition (a room takes groups this small: smallest `minPax` ≤ persons) **and**
|
||||
enough places left. The site checks only the first.
|
||||
- **Room type:** capacity, as TYPO3's `RoomTypeResolver` (`App\Enum\RoomType`): `maxPax` 1–8, 9 or more
|
||||
is `9er+`. A label containing "bett im" or "mit ander" is `mit anderen` (a shared bed, sold per bed).
|
||||
- **Accommodation:** the TYPO3 hotel `type` (1 Ferienwohnung, 2 Sportclub, 3 Apartment, 4 Gästehaus,
|
||||
5 Pension), `App\Enum\HotelType`.
|
||||
- **Board:** the items of selection group 71 ("4x Abendessen", "Frühstück inkl. … Lunchpaket", "Vollpension",
|
||||
…), matched by word against any item. The site keys on the first item only. "Halbpension" occurs in no
|
||||
label, so dinner is asked as "Abendessen".
|
||||
- **Inclusions:** selection groups 7 (Skipass), 71 (board), 86 (Programm), 87 (Kurse), 89 (Events), and the
|
||||
outbound bus when its price is 0. `bus: true` asks for any bookable outbound bus.
|
||||
- **Nights:** days between start and end. The site's "short" is ≤ 4 and its "long" is ≥ 5.
|
||||
- **Order:** by start date, then "ab" price. The site sorts by concept first, which the feed doesn't carry.
|
||||
- Results link to the product page. Links with the hotel preselected and the site's "Restplätze" badge need
|
||||
two fields the TYPO3 content feed doesn't send yet (`hotelUrls`, `lowContingent`).
|
||||
|
||||
Search (`App\Chatbot\Search\ContentSearch`) is MariaDB full text in boolean mode over
|
||||
`title, breadcrumb, body_md`. Each term becomes a prefix match, because InnoDB has no German stemming,
|
||||
and German stopwords are dropped in PHP. Relevance is weighted by type: products and hotels, then
|
||||
|
||||
Reference in new issue
Block a user