From 961646a34f1fd7ef570399a4697bdd117156ced3 Mon Sep 17 00:00:00 2001 From: Edwin van den Belt Date: Tue, 2 Jun 2026 06:29:00 +0200 Subject: [PATCH 01/11] Products of day 1 --- deliverables/1 search offers/mapping-bob.md | 252 ++++ deliverables/1 search offers/mapping-fgw.md | 294 +++++ deliverables/1 search offers/mapping-omsa.md | 327 +++++ deliverables/1 search offers/mapping-osdm.md | 443 +++++++ deliverables/1 search offers/mapping-tm.md | 371 ++++++ deliverables/1 search offers/mapping-tomp.md | 450 +++++++ .../request bodies/test-cases.md | 430 +++++++ .../search-offers-model backup day 1.qea | Bin 0 -> 2740224 bytes .../search-offers-model-old.qea | Bin 0 -> 2654208 bytes .../1 search offers/search-offers-model.qea | Bin 0 -> 2740224 bytes .../1 search offers/search-offers.yaml | 1099 +++++++++++++++++ .../ARCHIVE/buc-a-inspire-and-plan.md | 117 ++ .../ARCHIVE/buc-b-shop-and-price.md | 212 ++++ .../business-use-cases/ARCHIVE/buc-d-pay.md | 245 ++++ .../{ => ARCHIVE}/buc-e-fulfilment.md | 0 .../{ => ARCHIVE}/business_use-case_format.md | 0 .../BUC-A-inspire-and-plan-images/image1.png | Bin 0 -> 110822 bytes .../BUC-A-inspire-and-plan-images/image2.png | Bin 0 -> 379858 bytes .../BUC-A-inspire-and-plan.docx | Bin 0 -> 586396 bytes .../BUC-B-shop-and-price-images/image1.png | Bin 0 -> 234858 bytes .../BUC-B-shop-and-price.docx | Bin 0 -> 348793 bytes .../BUC-C-Order-and-Book.docx | Bin 0 -> 115479 bytes .../BUC-C-Order-and-Book.md | 385 ++++++ .../business-use-cases/BUC-D-pay.docx | Bin 0 -> 69416 bytes .../BUC-E-Ticketing-and-Fulfilment.docx | Bin 0 -> 50748 bytes .../BUC-E-Ticketing-and-Fulfilment.md | 275 +++++ ...UC-F-Pre-Trip (Services & Aftersales).docx | Bin 0 -> 56299 bytes .../BUC-F-Pre-Trip (Services & Aftersales).md | 403 ++++++ ...UC-J-After-Trip (Aftersales & Claims).docx | Bin 0 -> 50035 bytes .../BUC-J-After-Trip (Aftersales & Claims).md | 102 ++ .../BUC-LETTER-main-feature-TEMPLATE.docx | Bin 0 -> 42735 bytes .../BUC-LETTER-main-feature-TEMPLATE.md | 63 + .../buc-a-inspire-and-plan.md | 205 +-- .../buc-b-shop-and-price.md | 392 +++--- .../use-cases/business-use-cases/buc-d-pay.md | 496 +++++--- .../inputs/EUDIT.use.cases_20260324_shared.md | 465 +++++++ 36 files changed, 6596 insertions(+), 430 deletions(-) create mode 100644 deliverables/1 search offers/mapping-bob.md create mode 100644 deliverables/1 search offers/mapping-fgw.md create mode 100644 deliverables/1 search offers/mapping-omsa.md create mode 100644 deliverables/1 search offers/mapping-osdm.md create mode 100644 deliverables/1 search offers/mapping-tm.md create mode 100644 deliverables/1 search offers/mapping-tomp.md create mode 100644 deliverables/1 search offers/request bodies/test-cases.md create mode 100644 deliverables/1 search offers/search-offers-model backup day 1.qea create mode 100644 deliverables/1 search offers/search-offers-model-old.qea create mode 100644 deliverables/1 search offers/search-offers-model.qea create mode 100644 deliverables/1 search offers/search-offers.yaml create mode 100644 wiki/use-cases/business-use-cases/ARCHIVE/buc-a-inspire-and-plan.md create mode 100644 wiki/use-cases/business-use-cases/ARCHIVE/buc-b-shop-and-price.md create mode 100644 wiki/use-cases/business-use-cases/ARCHIVE/buc-d-pay.md rename wiki/use-cases/business-use-cases/{ => ARCHIVE}/buc-e-fulfilment.md (100%) rename wiki/use-cases/business-use-cases/{ => ARCHIVE}/business_use-case_format.md (100%) create mode 100644 wiki/use-cases/business-use-cases/BUC-A-inspire-and-plan-images/image1.png create mode 100644 wiki/use-cases/business-use-cases/BUC-A-inspire-and-plan-images/image2.png create mode 100644 wiki/use-cases/business-use-cases/BUC-A-inspire-and-plan.docx create mode 100644 wiki/use-cases/business-use-cases/BUC-B-shop-and-price-images/image1.png create mode 100644 wiki/use-cases/business-use-cases/BUC-B-shop-and-price.docx create mode 100644 wiki/use-cases/business-use-cases/BUC-C-Order-and-Book.docx create mode 100644 wiki/use-cases/business-use-cases/BUC-C-Order-and-Book.md create mode 100644 wiki/use-cases/business-use-cases/BUC-D-pay.docx create mode 100644 wiki/use-cases/business-use-cases/BUC-E-Ticketing-and-Fulfilment.docx create mode 100644 wiki/use-cases/business-use-cases/BUC-E-Ticketing-and-Fulfilment.md create mode 100644 wiki/use-cases/business-use-cases/BUC-F-Pre-Trip (Services & Aftersales).docx create mode 100644 wiki/use-cases/business-use-cases/BUC-F-Pre-Trip (Services & Aftersales).md create mode 100644 wiki/use-cases/business-use-cases/BUC-J-After-Trip (Aftersales & Claims).docx create mode 100644 wiki/use-cases/business-use-cases/BUC-J-After-Trip (Aftersales & Claims).md create mode 100644 wiki/use-cases/business-use-cases/BUC-LETTER-main-feature-TEMPLATE.docx create mode 100644 wiki/use-cases/business-use-cases/BUC-LETTER-main-feature-TEMPLATE.md create mode 100644 wiki/use-cases/inputs/EUDIT.use.cases_20260324_shared.md diff --git a/deliverables/1 search offers/mapping-bob.md b/deliverables/1 search offers/mapping-bob.md new file mode 100644 index 0000000..b6a84c1 --- /dev/null +++ b/deliverables/1 search offers/mapping-bob.md @@ -0,0 +1,252 @@ +# Mapping: Search Offers → BoB Product API v3.4.0 + +Maps each EUDIT **Search Offers** concept to the corresponding concept/property in the **BoB Product API v3.4.0**. + +- **Endpoint**: `POST /product` +- **EUDIT concept / Property** — as defined in `search-offers.yaml` +- **BoB concept** — the matching schema object in BoB Product API +- **BoB property** — the matching field name +- **Notes** — mapping remarks, gaps, or open questions + +**Important scope note**: BoB operates at the distribution layer. It searches for purchasable *products* +by area/route/group, not by a specific trip pattern with individual service journeys. Travellers are +represented as *category codes* (e.g. ADULT, CHILD) rather than individual profiles. As a result, +many EUDIT concepts have no BoB equivalent, and the mapping is structural rather than semantic. + +--- + +## OfferRequest + +> Root request body for the offer search. + +| Property | Type | Mult. | BoB concept | BoB property | Notes | +|---|---|---|---|---|---| +| tripPatterns | TripPattern | 1..* | `productFilter` | `route?` / `area?` / `group?` | BoB does not accept a trip pattern (timetabled legs). The closest equivalent is a spatial/route filter: `route` (origin–destination pair), `area` (geographic zone), or `group` (product group). | +| travellers | TravellingEntity | 1..* | `productFilter` | `travellers[{ categoryId, quantity }]` | Travellers are expressed as category codes with counts, not individual profiles. `Animal`, `PassengerVehicle`, `VehicleRack`, `Luggage` have no equivalent. | +| filter | SearchOfferFilter | 0..1 | `productFilter` | `fareIds[]`, `genericCategoryIds[]` | No equivalent for `modes`, `classOfUse`, `mediaTypes`, `requestedSections`. | +| policy | SearchOfferPolicy | 0..1 | — | — | No equivalent. BoB is synchronous; no pagination or currency control. | + +--- + +## SearchOfferPolicy + +> Pagination and currency preferences. **No equivalent in BoB.** + +| Property | Type | Mult. | BoB concept | BoB property | Notes | +|---|---|---|---|---|---| +| numberOfResultsBefore | integer | 0..1 | — | — | Not supported. | +| numberOfResultsAfter | integer | 0..1 | — | — | Not supported. | +| currency | string | 0..1 | — | — | Currency is operator configuration, not a request parameter. | + +--- + +## SearchOfferFilter + +> Constraints on which offers to return. + +| Property | Type | Mult. | BoB concept | BoB property | Notes | +|---|---|---|---|---|---| +| modes | string | 0..* | — | — | No equivalent. BoB products are not filtered by transport mode. | +| classOfUse | string | 0..* | — | — | No equivalent. | +| mediaTypes | string | 0..* | — | — | No equivalent. | +| requestedSections | RequestedSections | 0..* | — | — | No equivalent. | + +--- + +## RequestedSections + +> Targets offer search to a subset of legs. **No equivalent in BoB.** + +| Property | Type | Mult. | BoB concept | BoB property | Notes | +|---|---|---|---|---|---| +| (all) | — | — | — | — | No equivalent. | + +--- + +## TravellingEntity + +> Base class. + +| Property | Type | Mult. | BoB concept | BoB property | Notes | +|---|---|---|---|---|---| +| travellingEntityId | string | 1..1 | — | — | No per-traveller identifier in BoB; travellers are aggregated by category. | +| entityType | string | 1..1 | — | — | Discriminator only. `Animal`, `PassengerVehicle`, `Luggage` have no BoB equivalent. | +| entitlementRights | EntitlementRight | 0..* | `productFilter` | `discountCodes[]` | See **EntitlementRight**. | + +--- + +## Traveller + +> Human traveller. + +| Property | Type | Mult. | BoB concept | BoB property | Notes | +|---|---|---|---|---|---| +| travellingEntityId | string | 1..1 | — | — | Not used; travellers aggregated by `categoryId`. | +| age | integer | 0..1 | — | — | Age band encoded in `categoryId` (e.g. a "CHILD" category has age bounds defined in `GET /productcat/traveller`). | +| assistant | boolean | 0..1 | — | — | No equivalent. | +| dateOfBirth | date | 0..1 | — | — | No equivalent. | +| externalReference | string | 0..1 | — | — | No equivalent. | +| personalNeeds | PersonalNeed | 0..* | — | — | No equivalent. | +| qualifyingCharacteristics | TravellerQualifyingCharacteristics | 0..1 | — | — | No equivalent; eligibility is encapsulated in category codes. | + +--- + +## TravellerQualifyingCharacteristics + +> Demographic eligibility data. **No equivalent in BoB.** + +| Property | Type | Mult. | BoB concept | BoB property | Notes | +|---|---|---|---|---|---| +| (all) | — | — | — | — | Demographic eligibility is abstracted into traveller categories obtained via `GET /productcat/traveller`. | + +--- + +## PersonalNeed + +> Accessibility or personal need. **No equivalent in BoB.** + +| Property | Type | Mult. | BoB concept | BoB property | Notes | +|---|---|---|---|---|---| +| type | string | 1..1 | — | — | No equivalent. | + +--- + +## LicenseType + +> Driving licence. **No equivalent in BoB.** + +| Property | Type | Mult. | BoB concept | BoB property | Notes | +|---|---|---|---|---|---| +| type | string | 1..1 | — | — | No equivalent. | + +--- + +## Animal + +> Animal travelling alongside its owner. **No equivalent in BoB.** + +| Property | Type | Mult. | BoB concept | BoB property | Notes | +|---|---|---|---|---|---| +| (all) | — | — | — | — | No equivalent. Pets may be represented as a traveller category if the operator defines one. | + +--- + +## PassengerVehicle + +> Traveller-owned vehicle. **No equivalent in BoB product search.** + +| Property | Type | Mult. | BoB concept | BoB property | Notes | +|---|---|---|---|---|---| +| (all) | — | — | — | — | Vehicle transport outside BoB scope at offer-search level. May appear as a category in some operator configurations. | + +--- + +## VehicleRack + +> Rack on a vehicle. **No equivalent in BoB.** + +| Property | Type | Mult. | BoB concept | BoB property | Notes | +|---|---|---|---|---|---| +| (all) | — | — | — | — | No equivalent. | + +--- + +## Luggage + +> Bulky item. **No equivalent in BoB product search.** + +| Property | Type | Mult. | BoB concept | BoB property | Notes | +|---|---|---|---|---|---| +| (all) | — | — | — | — | May be represented as a traveller category if the operator defines one. No dimension/weight input. | + +--- + +## EntitlementRight + +> Credential qualifying for reduced fares. + +| Property | Type | Mult. | BoB concept | BoB property | Notes | +|---|---|---|---|---|---| +| issuer | string | 0..1 | — | — | No issuer field; discount codes are opaque strings in BoB. | +| entitlementType | string | 1..1 | — | — | Encoded in `discountCodes[]` string value. | +| code | string | 0..1 | `productFilter` | `discountCodes[]` | The discount/promotional code is passed directly. | + +--- + +## TripPattern + +> Proposed sequence of legs. **No equivalent in BoB.** + +| Property | Type | Mult. | BoB concept | BoB property | Notes | +|---|---|---|---|---|---| +| tripPatternId | string | 0..1 | — | — | No equivalent. | +| legs | Leg | 1..* | `productFilter` | `route { from, to }` | At most an origin–destination pair; no leg-level detail. | + +--- + +## TimedLeg / ContinuousLeg / TransferLeg + +> All leg sub-types. **No equivalent in BoB.** + +| EUDIT concept | BoB concept | Notes | +|---|---|---| +| TimedLeg | — | No equivalent. `serviceJourneyRef`, `operatingDate`, `LegBoard`, `LegAlight` not supported. | +| ContinuousLeg | — | No equivalent. | +| TransferLeg | — | No equivalent. | + +--- + +## LegBoard / LegAlight / TrainNumber / StopPlace + +> All stop/boarding concepts. **No equivalent in BoB.** + +| EUDIT concept | BoB concept | Notes | +|---|---|---| +| LegBoard | — | No equivalent. | +| LegAlight | — | No equivalent. | +| TrainNumber | — | No equivalent. | +| StopPlace | — | No equivalent. | + +--- + +## Place / StopPlaceInput / AddressInput / PointOfInterest / TopologicalPlace / GeoPosition + +> Place hierarchy. + +| EUDIT concept | BoB concept | BoB property | Notes | +|---|---|---|---| +| StopPlaceInput | `productFilter` | `route { from, to }` | Station codes (e.g. UIC) if supported. | +| AddressInput | — | — | No equivalent. | +| PointOfInterest | — | — | No equivalent. | +| TopologicalPlace | `productFilter` | `area` | BoB `area` is a zone/area code, not a GeoJSON polygon. | +| GeoPosition | — | — | No equivalent; BoB does not accept geo-coordinates in product search. | + +--- + +## Offer + +> Purchasable combination of offer elements. + +| Property | Type | Mult. | BoB concept | BoB property | Notes | +|---|---|---|---|---|---| +| offerId | string | 1..1 | `product` | `productId` | BoB returns `product` objects rather than `offer` objects. | +| elements | OfferElement | 1..* | `product` | `fareIds[]`, `conditions[]` | No discrete offer-element hierarchy; product has fare IDs and conditions. | +| farePrice | FarePrice | 0..1 | `product` | `price { amount, currency }` | | +| travelDocument | TravelDocument | 0..1 | `product` | `mediaTypes[]` | BoB lists supported media types per product. | + +--- + +## OfferElement / TravelRight / Ancillary / Reservation / CompositeOfferElement + +> Offer element sub-types. + +| EUDIT concept | BoB concept | BoB property | Notes | +|---|---|---|---| +| OfferElement | `fareProduct` | `fareId`, `name`, `conditions[]` | BoB fare products are the closest equivalent. | +| TravelRight | `fareProduct` | — | Right to travel implicit in product conditions. | +| Ancillary | `ancillaryProduct` | — | Some BoB implementations expose ancillary products. | +| Reservation | — | — | Not modelled in BoB product search. | +| CompositeOfferElement | `productBundle` | `products[]` | BoB supports product bundles in some implementations. | +| FarePrice | `price` | `amount`, `currency` | | +| TravelDocument | — | `mediaTypes[]` | Media type list at product level. | +| Guarantee | — | — | No equivalent. | diff --git a/deliverables/1 search offers/mapping-fgw.md b/deliverables/1 search offers/mapping-fgw.md new file mode 100644 index 0000000..e3bdfd4 --- /dev/null +++ b/deliverables/1 search offers/mapping-fgw.md @@ -0,0 +1,294 @@ +# Mapping: Search Offers → FerryGateway 1.3.1 + +Maps each EUDIT **Search Offers** concept to the corresponding concept/property in **FerryGateway 1.3.1**. + +- **EUDIT concept / Property** — as defined in `search-offers.yaml` +- **FerryGateway concept** — the matching XML message / element in FerryGateway 1.3.1 +- **FerryGateway element** — the matching element/attribute name +- **Notes** — mapping remarks, gaps, or open questions + +**Important scope note**: FerryGateway 1.3.1 uses XML request/response messages (not REST/JSON). +There is no single "offer search" endpoint; the closest equivalent is a two-step flow: + +1. **`GetSailingsRequest`** → availability (timetable + availability per sailing) +2. **`GetPriceRequest`** → pricing for selected sailings + +This mapping covers both messages where relevant. The response mapping covers +`GetSailingsResponse` and `GetPriceResponse`. + +--- + +## OfferRequest + +> Root request body for the offer search. + +| Property | Type | Mult. | FerryGateway concept | FerryGateway element | Notes | +|---|---|---|---|---|---| +| tripPatterns | TripPattern | 1..* | `GetSailingsRequest` | `SailingDate`, `RouteCode` | FerryGateway selects sailings by route (UN/LOCODE port pair) and date, not by a NeTEx service journey reference. Multiple trip patterns (e.g. outbound + return) require separate `GetSailingsRequest` calls. | +| travellers | TravellingEntity | 1..* | `GetSailingsRequest` / `GetPriceRequest` | `Passengers`, `Vehicles` | Human travellers → `Passengers`; vehicles → `Vehicles`. `Animal` and `Luggage` have no direct equivalent. | +| filter | SearchOfferFilter | 0..1 | — | — | No filter equivalent in FerryGateway; all offer types for the sailing are returned. | +| policy | SearchOfferPolicy | 0..1 | — | — | No pagination or currency control. | + +--- + +## SearchOfferPolicy + +> Pagination and currency preferences. **No equivalent in FerryGateway.** + +| Property | Type | Mult. | FerryGateway concept | FerryGateway element | Notes | +|---|---|---|---|---|---| +| numberOfResultsBefore | integer | 0..1 | — | — | No equivalent. | +| numberOfResultsAfter | integer | 0..1 | — | — | No equivalent. | +| currency | string | 0..1 | — | — | Currency is operator configuration; not a request parameter. | + +--- + +## SearchOfferFilter + +> Constraints on which offers to return. **No equivalent in FerryGateway.** + +| Property | Type | Mult. | FerryGateway concept | FerryGateway element | Notes | +|---|---|---|---|---|---| +| modes | string | 0..* | — | — | Ferry is the only mode; filter not applicable. | +| classOfUse | string | 0..* | — | — | No equivalent; accommodation types returned from the sailing result. | +| mediaTypes | string | 0..* | — | — | No equivalent. | +| requestedSections | RequestedSections | 0..* | — | — | No equivalent. | + +--- + +## RequestedSections + +> Targets offer search to a subset of legs. **No equivalent in FerryGateway.** + +| Property | Type | Mult. | FerryGateway concept | FerryGateway element | Notes | +|---|---|---|---|---|---| +| (all) | — | — | — | — | No equivalent. | + +--- + +## TravellingEntity + +> Base class. + +| Property | Type | Mult. | FerryGateway concept | FerryGateway element | Notes | +|---|---|---|---|---|---| +| travellingEntityId | string | 1..1 | — | — | No per-entity identifier; passengers aggregated by category code. | +| entityType | string | 1..1 | — | — | Discriminator only. `Animal` has no equivalent. | +| entitlementRights | EntitlementRight | 0..* | `GetOfferCodesRequest` | `OfferCode` | Promotional/discount codes are fetched separately; see **EntitlementRight**. | + +--- + +## Traveller + +> Human traveller. + +| Property | Type | Mult. | FerryGateway concept | FerryGateway element | Notes | +|---|---|---|---|---|---| +| travellingEntityId | string | 1..1 | — | — | Not used; passengers aggregated by `CategoryCode`. | +| age | integer | 0..1 | `Passenger` | `CategoryCode` | Age band encoded in category code (Adult, Child, Infant); age bounds from `GetPassengerAndVehicleTypesRequest`. | +| assistant | boolean | 0..1 | — | — | No equivalent. | +| dateOfBirth | date | 0..1 | — | — | No equivalent. | +| externalReference | string | 0..1 | — | — | No equivalent. | +| personalNeeds | PersonalNeed | 0..* | — | — | No equivalent in FerryGateway offer search; wheelchair/accessibility needs handled at booking. | +| qualifyingCharacteristics | TravellerQualifyingCharacteristics | 0..1 | — | — | No equivalent; eligibility encoded in category code. | + +--- + +## TravellerQualifyingCharacteristics + +> Demographic eligibility data. **No equivalent in FerryGateway.** + +| Property | Type | Mult. | FerryGateway concept | FerryGateway element | Notes | +|---|---|---|---|---|---| +| (all) | — | — | — | — | Eligibility is abstracted into passenger category codes from `GetPassengerAndVehicleTypesRequest`. | + +--- + +## PersonalNeed + +> Accessibility or personal need. **No equivalent in FerryGateway offer search.** + +| Property | Type | Mult. | FerryGateway concept | FerryGateway element | Notes | +|---|---|---|---|---|---| +| type | string | 1..1 | — | — | No equivalent. Accessibility needs provided at booking stage. | + +--- + +## LicenseType + +> Driving licence. **No equivalent in FerryGateway.** + +| Property | Type | Mult. | FerryGateway concept | FerryGateway element | Notes | +|---|---|---|---|---|---| +| type | string | 1..1 | — | — | No equivalent. | + +--- + +## Animal + +> Animal travelling alongside its owner. **No equivalent in FerryGateway offer search.** + +| Property | Type | Mult. | FerryGateway concept | FerryGateway element | Notes | +|---|---|---|---|---|---| +| entityType | string | 1..1 | — | — | Pets may be handled at booking via service codes, not in offer search. | +| type / assistant | various | 0..1 | — | — | No equivalent. | + +--- + +## PassengerVehicle + +> Traveller-owned vehicle to be transported. + +| Property | Type | Mult. | FerryGateway concept | FerryGateway element | Notes | +|---|---|---|---|---|---| +| entityType | string | 1..1 | `Vehicle` | — | Direct concept match; ferry bookings typically involve vehicle transport. | +| type | string | 0..1 | `Vehicle` | `CategoryCode` | Vehicle category from `GetPassengerAndVehicleTypesRequest` (car, motorhome, caravan, motorbike, etc.). | +| height | integer | 0..1 | `Vehicle` | `Height` | In centimetres (same unit). | +| width | integer | 0..1 | `Vehicle` | `Width` | In centimetres. | +| length | integer | 0..1 | `Vehicle` | `Length` | In centimetres. | +| weight | integer | 0..1 | — | — | No weight field on FerryGateway vehicle; some operators handle via category. | +| trailer | PassengerVehicle | 0..1 | `Vehicle` | `TrailerId` | FerryGateway has a `TrailerId` field for a towed trailer; full trailer dimensions not modelled. | +| vehicleRacks | VehicleRack | 0..* | — | — | No equivalent. | + +--- + +## VehicleRack + +> Rack mounted on a vehicle. **No equivalent in FerryGateway.** + +| Property | Type | Mult. | FerryGateway concept | FerryGateway element | Notes | +|---|---|---|---|---|---| +| (all) | — | — | — | — | No equivalent. | + +--- + +## Luggage + +> Bulky item a traveller brings. **No equivalent in FerryGateway offer search.** + +| Property | Type | Mult. | FerryGateway concept | FerryGateway element | Notes | +|---|---|---|---|---|---| +| (all) | — | — | — | — | Not modelled in FerryGateway offer search. Bicycles and special luggage are handled via service codes at booking. | + +--- + +## EntitlementRight + +> Credential qualifying for reduced fares. + +| Property | Type | Mult. | FerryGateway concept | FerryGateway element | Notes | +|---|---|---|---|---|---| +| issuer | string | 0..1 | — | — | Not explicitly modelled; implicit in the offer code value. | +| entitlementType | string | 1..1 | `GetOfferCodesRequest` | `OfferType` | FerryGateway has a dedicated `GetOfferCodesRequest` / `GetOfferCodesResponse` message flow to retrieve applicable promotional and loyalty codes. | +| code | string | 0..1 | `GetPriceRequest` | `OfferCode` | The promotional or discount code passed to `GetPriceRequest`. | + +--- + +## TripPattern + +> Proposed sequence of legs. + +| Property | Type | Mult. | FerryGateway concept | FerryGateway element | Notes | +|---|---|---|---|---|---| +| tripPatternId | string | 0..1 | — | — | No equivalent. | +| legs | Leg | 1..* | `GetSailingsRequest` | `RouteCode`, `SailingDate` | FerryGateway addresses a single sailing route per request, not a multi-leg trip pattern. Consecutive sailings require multiple calls. | + +--- + +## TimedLeg + +> Leg on a fixed timetabled service. + +| Property | Type | Mult. | FerryGateway concept | FerryGateway element | Notes | +|---|---|---|---|---|---| +| serviceJourneyRef | string | 0..1 | `Sailing` | `SailingId` | Returned in `GetSailingsResponse`; passed back in `GetPriceRequest`. | +| operatingDate | date | 0..1 | `GetSailingsRequest` | `SailingDate` | | +| lineNumber | string | 0..1 | `Sailing` | `RouteCode` | Route code (port pair) is the closest equivalent. | +| brand | string | 0..1 | — | — | No equivalent. | +| start (LegBoard) | LegBoard | 0..1 | `GetSailingsRequest` | `RouteCode` (origin port) | Origin port (UN/LOCODE) from `RouteCode`. | +| end (LegAlight) | LegAlight | 0..1 | `GetSailingsRequest` | `RouteCode` (destination port) | Destination port from `RouteCode`. | +| intermediateStops | StopPlace | 0..* | — | — | Not applicable to direct ferry sailings. | + +--- + +## ContinuousLeg / TransferLeg + +> **No equivalent in FerryGateway.** + +| EUDIT concept | Notes | +|---|---| +| ContinuousLeg | Ferry sailings are timetabled; no continuous leg concept. | +| TransferLeg | No equivalent. | + +--- + +## LegBoard + +> Boarding event at the start of a timed leg. + +| Property | Type | Mult. | FerryGateway concept | FerryGateway element | Notes | +|---|---|---|---|---|---| +| stopPlaceRef | string | 1..1 | `GetSailingsRequest` | `RouteCode` (origin part) | UN/LOCODE port code. | +| plannedDepartureTime | dateTime | 1..1 | `Sailing` | `DepartureTime` | Returned in `GetSailingsResponse`. | +| pickupLocation | string | 0..1 | — | — | No equivalent. | +| trainNumbers | TrainNumber | 0..* | — | — | No equivalent. | + +--- + +## LegAlight + +> Alighting event. + +| Property | Type | Mult. | FerryGateway concept | FerryGateway element | Notes | +|---|---|---|---|---|---| +| stopPlaceRef | string | 1..1 | `GetSailingsRequest` | `RouteCode` (destination part) | UN/LOCODE port code. | +| plannedArrivalTime | dateTime | 1..1 | `Sailing` | `ArrivalTime` | Returned in `GetSailingsResponse`. | +| setDownLocation | string | 0..1 | — | — | No equivalent. | + +--- + +## TrainNumber / StopPlace + +| EUDIT concept | FerryGateway concept | Notes | +|---|---|---| +| TrainNumber | — | No equivalent. | +| StopPlace.stopPlaceRef | UN/LOCODE port code | Used in `RouteCode` (e.g. `NLRTM-GBHLL`). | + +--- + +## Place / StopPlaceInput / AddressInput / PointOfInterest / TopologicalPlace / GeoPosition + +| EUDIT concept | FerryGateway concept | FerryGateway element | Notes | +|---|---|---|---| +| StopPlaceInput.placeRef | `GetSailingsRequest` | `RouteCode` (port part) | UN/LOCODE port identifier. | +| AddressInput | — | — | No equivalent. | +| PointOfInterest | — | — | No equivalent. | +| TopologicalPlace | — | — | No equivalent. | +| GeoPosition | — | — | No equivalent; FerryGateway uses port codes only. | + +--- + +## Offer + +> Purchasable combination of offer elements. + +| Property | Type | Mult. | FerryGateway concept | FerryGateway element | Notes | +|---|---|---|---|---|---| +| offerId | string | 1..1 | `GetPriceResponse` | `PriceId` / `QuoteId` | FerryGateway returns a price quote with a reference ID. | +| elements | OfferElement | 1..* | `GetPriceResponse` | `PriceItems[]` | Price items per passenger/vehicle/service category. | +| farePrice | FarePrice | 0..1 | `GetPriceResponse` | `TotalPrice { Amount, Currency }` | | +| travelDocument | TravelDocument | 0..1 | — | — | Not returned at price-quote stage; QR/barcode issued at `ConfirmReservationResponse`. | + +--- + +## OfferElement / TravelRight / Ancillary / Reservation + +| EUDIT concept | FerryGateway concept | FerryGateway element | Notes | +|---|---|---|---| +| TravelRight | `PriceItem` | `Sailing`, `CategoryCode`, `Amount` | Right to travel encoded in a price item per passenger/vehicle. | +| Ancillary | `ServiceItem` | `ServiceCode`, `Amount` | Optional services (meals, pet transport, etc.) are `ServiceItem`s. | +| Reservation | — | — | Reservations created via `CreateReservationRequest`, not at price-quote stage. | +| CompositeOfferElement | — | — | No equivalent. | +| FarePrice | `PriceItem` | `Amount`, `Currency` | | +| TravelDocument | — | — | Issued at booking confirmation as a QR code / PDF. | +| Guarantee | — | — | No equivalent. | diff --git a/deliverables/1 search offers/mapping-omsa.md b/deliverables/1 search offers/mapping-omsa.md new file mode 100644 index 0000000..2fea8e4 --- /dev/null +++ b/deliverables/1 search offers/mapping-omsa.md @@ -0,0 +1,327 @@ +# Mapping: Search Offers → OMSA 0.1.0 + +Maps each EUDIT **Search Offers** concept to the corresponding concept/property in **OMSA 0.1.0**. + +- **Endpoint**: `POST /processes/search-offers/execute` +- **EUDIT concept / Property** — as defined in `search-offers.yaml` +- **OMSA concept** — the matching schema object in OMSA 0.1.0 +- **OMSA property** — the matching field name +- **Notes** — mapping remarks, gaps, or open questions + +OMSA follows the OGC API Processes pattern and is conceptually very close to TOMP-API 2.0.0 +(uses `/execute` instead of TOMP's `/execution`). Key differences are noted below. + +--- + +## OfferRequest + +> Root request body for the offer search. + +| Property | Type | Mult. | OMSA concept | OMSA property | Notes | +|---|---|---|---|---|---| +| tripPatterns | TripPattern | 1..* | `searchOfferInput` | `specification` (tripPattern or travelSpecification) | OMSA accepts either a structured `tripPattern` or an open `travelSpecification`. Multiple EUDIT `TripPattern`s have no direct equivalent. | +| travellers | TravellingEntity | 1..* | `searchOfferInput` | `travellers[]` | `Animal`, `VehicleRack` sub-types have no equivalent. `PassengerVehicle` and `Luggage` map to `assets[]` (see below). | +| filter | SearchOfferFilter | 0..1 | `searchOfferInput` | `travellerRequirements` (per traveller) | Applied per traveller, not as a global filter. `mediaTypes` and `requestedSections` have no equivalent. | +| policy | SearchOfferPolicy | 0..1 | — | — | No equivalent. OMSA is synchronous with no pagination or currency control. | + +--- + +## SearchOfferPolicy + +> Pagination and currency preferences. **No equivalent in OMSA.** + +| Property | Type | Mult. | OMSA concept | OMSA property | Notes | +|---|---|---|---|---|---| +| numberOfResultsBefore | integer | 0..1 | — | — | Not supported. | +| numberOfResultsAfter | integer | 0..1 | — | — | Not supported. | +| currency | string | 0..1 | — | — | Not supported at request level. | + +--- + +## SearchOfferFilter + +> Constraints on which offers to return. Only partially covered in OMSA. + +| Property | Type | Mult. | OMSA concept | OMSA property | Notes | +|---|---|---|---|---|---| +| modes | string | 0..* | `travellerRequirements` | `mode`, `subMode` | Per traveller in OMSA. | +| classOfUse | string | 0..* | `travellerRequirements` | `class` | Per traveller. | +| mediaTypes | string | 0..* | — | — | No equivalent. | +| requestedSections | RequestedSections | 0..* | — | — | No equivalent. | + +--- + +## RequestedSections + +> Targets offer search to a subset of legs. **No equivalent in OMSA.** + +| Property | Type | Mult. | OMSA concept | OMSA property | Notes | +|---|---|---|---|---|---| +| startLegId / endLegId / startPlace / endPlace / tripReference | various | 0..1 | — | — | No equivalent. | + +--- + +## TravellingEntity + +> Base class. + +| Property | Type | Mult. | OMSA concept | OMSA property | Notes | +|---|---|---|---|---|---| +| travellingEntityId | string | 1..1 | `traveller` | `id` | | +| entityType | string | 1..1 | — | — | Discriminator only. `PassengerVehicle` and `Luggage` map to `assets[]`; `Animal` has no equivalent. | +| entitlementRights | EntitlementRight | 0..* | `card` / `entitlement` | (nested in traveller) | See **EntitlementRight**. | + +--- + +## Traveller + +> Human traveller. + +| Property | Type | Mult. | OMSA concept | OMSA property | Notes | +|---|---|---|---|---|---| +| travellingEntityId | string | 1..1 | `traveller` | `id` | | +| age | integer | 0..1 | `traveller` | `age` | | +| assistant | boolean | 0..1 | — | — | No direct field; carer/PRM needs via `travellerRequirements.prmNeeds[]`. | +| dateOfBirth | date | 0..1 | — | — | No equivalent. | +| externalReference | string | 0..1 | `traveller` | `customerReference` | | +| personalNeeds | PersonalNeed | 0..* | `travellerRequirements` | `prmNeeds[]` | | +| qualifyingCharacteristics | TravellerQualifyingCharacteristics | 0..1 | `userProfile` | (see section) | | + +--- + +## TravellerQualifyingCharacteristics + +> Demographic eligibility data. + +| Property | Type | Mult. | OMSA concept | OMSA property | Notes | +|---|---|---|---|---|---| +| fullName | string | 0..1 | `traveller` | `name` | | +| nationality | string | 0..1 | — | — | No equivalent. | +| residency | string | 0..1 | — | — | No equivalent. | +| dateOfBirth | date | 0..1 | — | — | No equivalent. | +| licenseTypes | LicenseType | 0..* | — | — | No equivalent in OMSA offer-search input. | + +--- + +## PersonalNeed + +> Accessibility or personal need. + +| Property | Type | Mult. | OMSA concept | OMSA property | Notes | +|---|---|---|---|---|---| +| type | string | 1..1 | `travellerRequirements` | `prmNeeds[]` | Operator-defined PRM need codes. | + +--- + +## LicenseType + +> Driving licence. **No equivalent in OMSA offer-search input.** + +| Property | Type | Mult. | OMSA concept | OMSA property | Notes | +|---|---|---|---|---|---| +| type | string | 1..1 | — | — | No equivalent. | + +--- + +## Animal + +> Animal travelling alongside its owner. **No equivalent in OMSA.** + +| Property | Type | Mult. | OMSA concept | OMSA property | Notes | +|---|---|---|---|---|---| +| entityType | string | 1..1 | — | — | No equivalent. | +| type | string | 1..1 | — | — | No equivalent. | +| assistant | boolean | 0..1 | `travellerRequirements` | `prmNeeds[]` | Assistance animal status may be expressed as a PRM need on the accompanying traveller. | + +--- + +## PassengerVehicle + +> Traveller-owned vehicle to be transported. Maps to OMSA `assets[]`. + +| Property | Type | Mult. | OMSA concept | OMSA property | Notes | +|---|---|---|---|---|---| +| entityType | string | 1..1 | `asset` | `type` | OMSA uses an `assets[]` array in the request for physical items to transport. | +| type | string | 1..1 | `asset` | `category` | Vehicle category (car, bicycle, etc.). | +| height | integer | 0..1 | `asset` | `height` | | +| width | integer | 0..1 | `asset` | `width` | | +| length | integer | 0..1 | `asset` | `length` | | +| weight | integer | 0..1 | `asset` | `weight` | | +| trailer | PassengerVehicle | 0..1 | — | — | Nested trailer not modelled in OMSA assets. May be a separate asset entry. | +| vehicleRacks | VehicleRack | 0..* | — | — | No equivalent. | + +--- + +## VehicleRack + +> Rack mounted on a vehicle. **No equivalent in OMSA.** + +| Property | Type | Mult. | OMSA concept | OMSA property | Notes | +|---|---|---|---|---|---| +| (all) | — | — | — | — | No equivalent. | + +--- + +## Luggage + +> Bulky item. Maps to OMSA `assets[]`. + +| Property | Type | Mult. | OMSA concept | OMSA property | Notes | +|---|---|---|---|---|---| +| entityType | string | 1..1 | `asset` | `type` | | +| type | string | 1..1 | `asset` | `category` | Luggage category (bicycle, pram, etc.). | +| length / width / height / weight | integer | 0..1 | `asset` | `length` / `width` / `height` / `weight` | | + +--- + +## EntitlementRight + +> Credential qualifying for reduced fares. + +| Property | Type | Mult. | OMSA concept | OMSA property | Notes | +|---|---|---|---|---|---| +| issuer | string | 0..1 | `card` | — / `entitlement` | No explicit issuer field; may be embedded in type code. | +| entitlementType | string | 1..1 | `card` | `type` / `entitlement` `type` | | +| code | string | 0..1 | `card` | `id` / `entitlement` `id` | Card or voucher instance number. | + +--- + +## TripPattern + +> Proposed sequence of legs. + +| Property | Type | Mult. | OMSA concept | OMSA property | Notes | +|---|---|---|---|---|---| +| tripPatternId | string | 0..1 | — | — | No equivalent. | +| legs | Leg | 1..* | `tripPattern` | `serviceJourneys[]` (timed) OR `travelSpecification` (open O&D) | Same pattern as TOMP-API. | + +--- + +## TimedLeg + +> Leg on a fixed timetabled service. + +| Property | Type | Mult. | OMSA concept | OMSA property | Notes | +|---|---|---|---|---|---| +| legType | string | 1..1 | — | — | Discriminator only. | +| legId | string | 0..1 | — | — | No equivalent. | +| sequenceNumber | integer | 0..1 | — | — | Implied by array order. | +| mode | string | 0..1 | `travellerRequirements` | `mode` | Per traveller. | +| serviceJourneyRef | string | 0..1 | `ServiceJourneyReference` | `id` | | +| operatingDate | date | 0..1 | `tripPattern` | `travelDate` | | +| lineNumber | string | 0..1 | `ServiceJourneyReference` | `lineId` | | +| brand | string | 0..1 | — | — | No equivalent. | +| start | LegBoard | 0..1 | — | — | Stop-level boarding data not in OMSA `tripPattern`. | +| end | LegAlight | 0..1 | — | — | No equivalent. | +| intermediateStops | StopPlace | 0..* | — | — | No equivalent. | + +--- + +## ContinuousLeg + +> Leg without timetabled stops. Partially covered. + +| Property | Type | Mult. | OMSA concept | OMSA property | Notes | +|---|---|---|---|---|---| +| startTime | dateTime | 0..1 | `travelSpecification` | `startTime` | | +| endTime | dateTime | 0..1 | `travelSpecification` | `endTime` | | +| startLocation | Place | 0..1 | `travelSpecification` | `origin` (placeReference) | | +| endLocation | Place | 0..1 | `travelSpecification` | `destination` (placeReference) | | + +--- + +## TransferLeg + +> Transfer between services. **No equivalent in OMSA.** + +| Property | Type | Mult. | OMSA concept | OMSA property | Notes | +|---|---|---|---|---|---| +| legType | string | 1..1 | — | — | No equivalent. | + +--- + +## LegBoard + +> Boarding event. + +| Property | Type | Mult. | OMSA concept | OMSA property | Notes | +|---|---|---|---|---|---| +| stopPlaceRef | string | 1..1 | `placeReference` | `id` | | +| plannedDepartureTime | dateTime | 1..1 | `tripPattern` | `travelDate` | Date only; no per-leg departure time. | +| pickupLocation | string | 0..1 | — | — | No equivalent. | +| trainNumbers | TrainNumber | 0..* | — | — | No equivalent. | + +--- + +## LegAlight + +> Alighting event. + +| Property | Type | Mult. | OMSA concept | OMSA property | Notes | +|---|---|---|---|---|---| +| stopPlaceRef | string | 1..1 | `placeReference` | `id` | | +| plannedArrivalTime | dateTime | 1..1 | — | — | No per-leg arrival time in OMSA. | +| setDownLocation | string | 0..1 | — | — | No equivalent. | + +--- + +## TrainNumber + +> Commercial train number. **No equivalent in OMSA offer-search input.** + +| Property | Type | Mult. | OMSA concept | OMSA property | Notes | +|---|---|---|---|---|---| +| trainNumberId | string | 1..1 | — | — | No equivalent. | + +--- + +## StopPlace + +> Reference to an intermediate stop. + +| Property | Type | Mult. | OMSA concept | OMSA property | Notes | +|---|---|---|---|---|---| +| stopPlaceRef | string | 1..1 | `placeReference` | `id` | | + +--- + +## Place / StopPlaceInput / AddressInput / PointOfInterest / TopologicalPlace + +> Same mappings as TOMP-API; OMSA uses the same `placeReference { id?, coordinates?, name? }` pattern. + +| EUDIT concept | OMSA concept | OMSA property | Notes | +|---|---|---|---| +| StopPlaceInput.placeRef | `placeReference` | `id` | | +| AddressInput.addressLine1 | `placeReference` | `name` | No structured address. | +| PointOfInterest.name | `placeReference` | `name` | | +| TopologicalPlace.area | `travellerRequirements` | `zones[]` | Zone IDs, not GeoJSON polygon. | +| GeoPosition.longitude / latitude | `GeoCoordinate` | `lon` / `lat` | | + +--- + +## Offer + +> Purchasable combination of offer elements. + +| Property | Type | Mult. | OMSA concept | OMSA property | Notes | +|---|---|---|---|---|---| +| offerId | string | 1..1 | `offer` | `offerId` | | +| elements | OfferElement | 1..* | `offer` | `legs[].pricing[]` | OMSA returns pricing per leg, similar to TOMP. | +| farePrice | FarePrice | 0..1 | `offer` | aggregated from `legs[].pricing[]` | Client must aggregate. | +| travelDocument | TravelDocument | 0..1 | — | — | Not returned at offer-search stage. | + +--- + +## OfferElement / TravelRight / Ancillary / Reservation / CompositeOfferElement + +> Same pattern as TOMP-API: pricing is per-leg, no discrete offer-element objects in OMSA response. + +| EUDIT concept | OMSA concept | OMSA property | Notes | +|---|---|---|---| +| TravelRight | `leg` | `id`, `pricing[]` | Travel right implicit per leg. | +| Ancillary | — | — | No equivalent in offer-search response. | +| Reservation | — | — | Not at offer-search stage. | +| CompositeOfferElement | — | — | No equivalent. | +| FarePrice | `pricing` | `estimated`, `parts[{ amount, currencyCode }]` | | +| TravelDocument | — | — | Not at offer-search stage. | +| Guarantee | — | — | No equivalent. | diff --git a/deliverables/1 search offers/mapping-osdm.md b/deliverables/1 search offers/mapping-osdm.md new file mode 100644 index 0000000..b63cba5 --- /dev/null +++ b/deliverables/1 search offers/mapping-osdm.md @@ -0,0 +1,443 @@ +# Mapping: Search Offers → OSDM 3.7.1 + +Maps each EUDIT **Search Offers** concept to the corresponding concept/property in **OSDM 3.7.1**. + +- **Endpoint**: `POST /offers` +- **EUDIT concept / Property** — as defined in `search-offers.yaml` +- **OSDM concept** — the matching schema object in OSDM 3.7.1 +- **OSDM property** — the matching field name +- **Notes** — mapping remarks, gaps, or open questions + +--- + +## OfferRequest + +> Root request body for the offer search. + +| Property | Type | Mult. | OSDM concept | OSDM property | Notes | +|---|---|---|---|---|---| +| tripPatterns | TripPattern | 1..* | `offerRequest` | `tripSpecification` / `tripIds[]` / `tripSearchCriteria` | OSDM supports three trip-input modes: (1) explicit `tripSpecification.legs[]`, (2) pre-searched `tripIds[]`, (3) open O&D `tripSearchCriteria`. EUDIT `TripPattern` maps to mode (1). Multiple trip patterns map to `inboundTripSpecification` for a return journey. | +| travellers | TravellingEntity | 1..* | `offerRequest` | `tripCoverage.passengers[]` | Only `Traveller` sub-type maps; `Animal`, `PassengerVehicle`, `VehicleRack`, `Luggage` have no equivalent as passengers. | +| filter | SearchOfferFilter | 0..1 | `offerRequest` | `searchCriteria` | | +| policy | SearchOfferPolicy | 0..1 | `offerRequest` | `searchCriteria` (partial) | Partial; see **SearchOfferPolicy**. | + +--- + +## SearchOfferPolicy + +> Pagination and currency preferences. + +| Property | Type | Mult. | OSDM concept | OSDM property | Notes | +|---|---|---|---|---|---| +| numberOfResultsBefore | integer | 0..1 | — | — | No equivalent. OSDM does not support pagination relative to departure time. | +| numberOfResultsAfter | integer | 0..1 | `searchCriteria` | `maxOffers` | Partial match: `maxOffers` limits total results, not results after a given time. | +| currency | string | 0..1 | `searchCriteria` | `currency` | Direct mapping (ISO 4217). | + +--- + +## SearchOfferFilter + +> Constraints on which offers to return. + +| Property | Type | Mult. | OSDM concept | OSDM property | Notes | +|---|---|---|---|---|---| +| modes | string | 0..* | — | — | No explicit mode filter in OSDM offer request; modes are implicit in the trip specification. | +| classOfUse | string | 0..* | `searchCriteria` | `fareClass` | OSDM `fareClass` (e.g. `FIRST`, `SECOND`). Single value in OSDM vs. array in EUDIT. | +| mediaTypes | string | 0..* | — | — | No equivalent. OSDM does not filter by fulfilment media type at offer-search stage. | +| requestedSections | RequestedSections | 0..* | — | — | No equivalent. | + +--- + +## RequestedSections + +> Targets offer search to a subset of legs. **No equivalent in OSDM.** + +| Property | Type | Mult. | OSDM concept | OSDM property | Notes | +|---|---|---|---|---|---| +| startLegId | string | 0..1 | — | — | No equivalent. | +| endLegId | string | 0..1 | — | — | No equivalent. | +| startPlace | string | 0..1 | — | — | No equivalent. | +| endPlace | string | 0..1 | — | — | No equivalent. | +| tripReference | string | 0..1 | — | — | No equivalent. | + +--- + +## TravellingEntity + +> Base class. + +| Property | Type | Mult. | OSDM concept | OSDM property | Notes | +|---|---|---|---|---|---| +| travellingEntityId | string | 1..1 | `passenger` | `passengerRef` | Caller-assigned reference used for cross-referencing. | +| entityType | string | 1..1 | — | — | Discriminator only. `Animal`, `PassengerVehicle`, `Luggage` not modelled as OSDM passengers. | +| entitlementRights | EntitlementRight | 0..* | `passenger` | `reductionCards[]` | See **EntitlementRight**. | + +--- + +## Traveller + +> Human traveller. + +| Property | Type | Mult. | OSDM concept | OSDM property | Notes | +|---|---|---|---|---|---| +| travellingEntityId | string | 1..1 | `passenger` | `passengerRef` | | +| age | integer | 0..1 | `passenger` | `age` | | +| assistant | boolean | 0..1 | — | — | No equivalent. Carer/assistant needs expressed via `accessibilityNeeds`. | +| dateOfBirth | date | 0..1 | — | — | No date-of-birth field in OSDM passenger; age used instead. | +| externalReference | string | 0..1 | — | — | No equivalent. | +| personalNeeds | PersonalNeed | 0..* | `passenger` | `accessibilityNeeds[]` | | +| qualifyingCharacteristics | TravellerQualifyingCharacteristics | 0..1 | `passenger` | `type` (partial) | OSDM uses a coarse passenger type enum (`ADULT`, `CHILD`, `INFANT`) rather than detailed characteristics. | + +--- + +## TravellerQualifyingCharacteristics + +> Demographic eligibility data. + +| Property | Type | Mult. | OSDM concept | OSDM property | Notes | +|---|---|---|---|---|---| +| fullName | string | 0..1 | — | — | Not a fare-search input in OSDM; provided at booking stage. | +| nationality | string | 0..1 | — | — | No equivalent in OSDM offer request. | +| residency | string | 0..1 | — | — | No equivalent. | +| dateOfBirth | date | 0..1 | — | — | No equivalent. | +| licenseTypes | LicenseType | 0..* | — | — | No equivalent. | + +--- + +## PersonalNeed + +> Accessibility or personal need. + +| Property | Type | Mult. | OSDM concept | OSDM property | Notes | +|---|---|---|---|---|---| +| type | string | 1..1 | `passenger` | `accessibilityNeeds[]` | OSDM uses NeTEx `AccessibilityNeedType` values. | + +--- + +## LicenseType + +> Driving licence. **No equivalent in OSDM.** + +| Property | Type | Mult. | OSDM concept | OSDM property | Notes | +|---|---|---|---|---|---| +| type | string | 1..1 | — | — | No equivalent. | + +--- + +## Animal + +> Animal travelling alongside its owner. **No equivalent as a passenger in OSDM.** + +| Property | Type | Mult. | OSDM concept | OSDM property | Notes | +|---|---|---|---|---|---| +| entityType | string | 1..1 | — | — | Pets may appear as ancillary offer parts in OSDM response but are not modelled as input passengers. | +| type | string | 1..1 | — | — | No equivalent. | +| assistant | boolean | 0..1 | `passenger` | `accessibilityNeeds[]` | Assistance animal may be expressed as an accessibility need on the accompanying traveller. | + +--- + +## PassengerVehicle + +> Traveller-owned vehicle to be transported. **No equivalent in OSDM (rail-focused standard).** + +| Property | Type | Mult. | OSDM concept | OSDM property | Notes | +|---|---|---|---|---|---| +| entityType | string | 1..1 | — | — | Vehicle transport (car/ferry) is outside OSDM scope. | +| type / height / width / length / weight | various | 0..1 | — | — | No equivalent. | +| trailer | PassengerVehicle | 0..1 | — | — | No equivalent. | +| vehicleRacks | VehicleRack | 0..* | — | — | No equivalent. | + +--- + +## VehicleRack + +> Rack on a passenger vehicle. **No equivalent in OSDM.** + +| Property | Type | Mult. | OSDM concept | OSDM property | Notes | +|---|---|---|---|---|---| +| (all) | — | — | — | — | No equivalent. | + +--- + +## Luggage + +> Bulky item a traveller brings. + +| Property | Type | Mult. | OSDM concept | OSDM property | Notes | +|---|---|---|---|---|---| +| entityType | string | 1..1 | — | — | Luggage is not an input entity in OSDM; it may appear as an ancillary in the offer response. | +| type / dimensions / weight | various | 0..1 | — | — | No equivalent as offer-request input. | + +--- + +## EntitlementRight + +> Credential qualifying for reduced fares. + +| Property | Type | Mult. | OSDM concept | OSDM property | Notes | +|---|---|---|---|---|---| +| issuer | string | 0..1 | `reductionCard` | `issuerCode` | | +| entitlementType | string | 1..1 | `reductionCard` | `cardType` | OSDM uses a structured `cardType` enum (e.g. `BAHNCARD`, `RAILPLUS`). | +| code | string | 0..1 | — | — | Card instance number not standard in OSDM reduction card; may be passed as `passengerRef` extension. | + +--- + +## TripPattern + +> Proposed sequence of legs. + +| Property | Type | Mult. | OSDM concept | OSDM property | Notes | +|---|---|---|---|---|---| +| tripPatternId | string | 0..1 | — | — | No equivalent. | +| legs | Leg | 1..* | `tripSpecification` | `legs[]` | Each EUDIT `TimedLeg` maps to an OSDM leg. `ContinuousLeg` and `TransferLeg` have no equivalent. | + +--- + +## TimedLeg + +> Leg on a fixed timetabled service. + +| Property | Type | Mult. | OSDM concept | OSDM property | Notes | +|---|---|---|---|---|---| +| legType | string | 1..1 | — | — | Discriminator only. | +| legId | string | 0..1 | — | — | No equivalent. | +| sequenceNumber | integer | 0..1 | — | — | Implied by array order in `tripSpecification.legs[]`. | +| mode | string | 0..1 | — | — | No explicit mode field on OSDM leg; implicit in `serviceJourneyRef`. | +| serviceJourneyRef | string | 0..1 | `leg` | `serviceJourneyRef` | Direct mapping. | +| operatingDate | date | 0..1 | `leg` | `departureDateTime` (date part) | OSDM uses a full `departureDateTime`; date extracted from it. | +| lineNumber | string | 0..1 | — | — | No equivalent on OSDM leg input. | +| brand | string | 0..1 | — | — | No equivalent. | +| start | LegBoard | 0..1 | `leg` | `originStopPlaceRef`, `departureDateTime` | | +| end | LegAlight | 0..1 | `leg` | `destinationStopPlaceRef`, `arrivalDateTime` | | +| intermediateStops | StopPlace | 0..* | — | — | Not an input field in OSDM. | + +--- + +## ContinuousLeg + +> Leg without fixed timetabled stops. **No equivalent in OSDM.** + +| Property | Type | Mult. | OSDM concept | OSDM property | Notes | +|---|---|---|---|---|---| +| legType | string | 1..1 | — | — | No equivalent. OSDM is timetabled-service only. | +| startTime / endTime | dateTime | 0..1 | — | — | No equivalent. | +| startLocation / endLocation | Place | 0..1 | — | — | No equivalent. | + +--- + +## TransferLeg + +> Transfer between services. **No equivalent in OSDM.** + +| Property | Type | Mult. | OSDM concept | OSDM property | Notes | +|---|---|---|---|---|---| +| legType | string | 1..1 | — | — | No equivalent. Transfers are implicit in the leg sequence. | + +--- + +## LegBoard + +> Boarding event at the start of a timed leg. + +| Property | Type | Mult. | OSDM concept | OSDM property | Notes | +|---|---|---|---|---|---| +| stopPlaceRef | string | 1..1 | `leg` | `originStopPlaceRef` | UIC or NeTEx stop ID. | +| plannedDepartureTime | dateTime | 1..1 | `leg` | `departureDateTime` | | +| pickupLocation | string | 0..1 | — | — | No equivalent. | +| trainNumbers | TrainNumber | 0..* | — | — | Not an input field in OSDM. | + +--- + +## LegAlight + +> Alighting event at the end of a timed leg. + +| Property | Type | Mult. | OSDM concept | OSDM property | Notes | +|---|---|---|---|---|---| +| stopPlaceRef | string | 1..1 | `leg` | `destinationStopPlaceRef` | | +| plannedArrivalTime | dateTime | 1..1 | `leg` | `arrivalDateTime` | | +| setDownLocation | string | 0..1 | — | — | No equivalent. | + +--- + +## TrainNumber + +> Commercial train number. + +| Property | Type | Mult. | OSDM concept | OSDM property | Notes | +|---|---|---|---|---|---| +| trainNumberId | string | 1..1 | — | — | Partially encoded in `serviceJourneyRef`; no separate train-number input in OSDM. | + +--- + +## StopPlace + +> Reference to an intermediate stop. + +| Property | Type | Mult. | OSDM concept | OSDM property | Notes | +|---|---|---|---|---|---| +| stopPlaceRef | string | 1..1 | — | — | Intermediate stops are not input in OSDM; derived from `serviceJourneyRef`. | + +--- + +## Place + +> Base place type. + +| Property | Type | Mult. | OSDM concept | OSDM property | Notes | +|---|---|---|---|---|---| +| placeId | string | 0..1 | — | — | No equivalent. | +| placeType | string | 1..1 | — | — | Discriminator only. | +| location | GeoPosition | 0..1 | — | — | OSDM uses stop references only; geo-coordinate input is not supported. | + +--- + +## StopPlaceInput + +> Stop place identified by reference. + +| Property | Type | Mult. | OSDM concept | OSDM property | Notes | +|---|---|---|---|---|---| +| placeRef | string | 0..1 | `leg` | `originStopPlaceRef` / `destinationStopPlaceRef` | UIC or NeTEx stop ID. | + +--- + +## AddressInput + +> Postal address. **No equivalent in OSDM.** + +| Property | Type | Mult. | OSDM concept | OSDM property | Notes | +|---|---|---|---|---|---| +| addressLine1 / addressLine2 | string | 0..1 | — | — | OSDM does not support address-based place input. | + +--- + +## PointOfInterest + +> Named point of interest. **No equivalent in OSDM.** + +| Property | Type | Mult. | OSDM concept | OSDM property | Notes | +|---|---|---|---|---|---| +| name | string | 0..1 | — | — | No equivalent. | + +--- + +## TopologicalPlace + +> Geographic area or zone. + +| Property | Type | Mult. | OSDM concept | OSDM property | Notes | +|---|---|---|---|---|---| +| area | string | 0..1 | — | — | No equivalent as trip origin/destination input. | +| range | integer | 0..1 | — | — | No equivalent. | + +--- + +## GeoPosition + +> WGS-84 coordinate pair. **No equivalent in OSDM offer-request input.** + +| Property | Type | Mult. | OSDM concept | OSDM property | Notes | +|---|---|---|---|---|---| +| longitude | number | 1..1 | — | — | OSDM uses stop-reference IDs only. | +| latitude | number | 1..1 | — | — | No equivalent. | + +--- + +## Offer + +> Purchasable combination of offer elements. + +| Property | Type | Mult. | OSDM concept | OSDM property | Notes | +|---|---|---|---|---|---| +| offerId | string | 1..1 | `offer` | `offerId` | Direct mapping. | +| elements | OfferElement | 1..* | `offer` | `fareProducts[]`, `reservations[]`, `ancillaryProducts[]` | Sub-types map to different OSDM arrays. | +| farePrice | FarePrice | 0..1 | `offer` | `totalPrice { amount, currency }` | | +| travelDocument | TravelDocument | 0..1 | `offer` | `fulfillmentOptions[]` | OSDM returns fulfilment options (media/barcode type) at offer stage. | + +--- + +## OfferElement + +> Base class for purchasable elements. + +| Property | Type | Mult. | OSDM concept | OSDM property | Notes | +|---|---|---|---|---|---| +| offerElementId | string | 1..1 | `fareProduct` | `fareProductId` | Or `reservationId` for reservation elements. | +| offerElementType | string | 1..1 | — | — | Discriminator only. | +| travellingEntities | string | 0..* | `fareProduct` | `passengerRef` | OSDM links fare products to specific passengers. | +| farePrice | FarePrice | 0..1 | `fareProduct` | `price { amount, currency }` | | +| travelDocument | TravelDocument | 0..1 | — | — | Fulfilment detail at offer level, not per element. | +| guarantees | Guarantee | 0..* | — | — | No direct equivalent; connection guarantee is a separate concept in OSDM. | + +--- + +## TravelRight + +> Right to travel on a specific leg or zone. + +| Property | Type | Mult. | OSDM concept | OSDM property | Notes | +|---|---|---|---|---|---| +| legRef | string | 0..1 | `fareProduct` | `legRef` / `serviceJourneyRef` | OSDM fare products reference the legs they cover. | +| zoneRef | string | 0..1 | `fareProduct` | `tariffZoneRef` | Zone-based fares in OSDM reference tariff zones. | + +--- + +## Ancillary + +> Optional ancillary service. + +| Property | Type | Mult. | OSDM concept | OSDM property | Notes | +|---|---|---|---|---|---| +| ancillaryId | string | 0..1 | `ancillaryProduct` | `ancillaryProductId` | | +| type | string | 0..1 | `ancillaryProduct` | `type` | | + +--- + +## Reservation + +> Seat or space reservation. + +| Property | Type | Mult. | OSDM concept | OSDM property | Notes | +|---|---|---|---|---|---| +| offerElementType | string | 1..1 | `reservation` | — | OSDM has a discrete `reservation` object with `reservationId`, `seatInformation`. | + +--- + +## CompositeOfferElement + +> Grouped offer elements. Partial equivalent in OSDM via offer parts. + +| Property | Type | Mult. | OSDM concept | OSDM property | Notes | +|---|---|---|---|---|---| +| elements | OfferElement | 2..* | `offerPart` | `fareProducts[]` | OSDM groups fare products into offer parts; no explicit "composite" type. | + +--- + +## FarePrice + +> Price of an offer or offer element. (Stub — detail TBD.) + +| Property | Type | Mult. | OSDM concept | OSDM property | Notes | +|---|---|---|---|---|---| +| (TBD) | — | — | `price` | `amount`, `currency` | OSDM `price` object carries amount + ISO 4217 currency code. | + +--- + +## TravelDocument + +> Proof of entitlement. (Stub — detail TBD.) + +| Property | Type | Mult. | OSDM concept | OSDM property | Notes | +|---|---|---|---|---|---| +| (TBD) | — | — | `fulfillmentOption` | `mediaType`, `barcodeType` | OSDM returns available fulfilment options (paper, mobile, smart card) per offer. | + +--- + +## Guarantee + +> Guarantee associated with an offer element. (Stub — detail TBD.) + +| Property | Type | Mult. | OSDM concept | OSDM property | Notes | +|---|---|---|---|---|---| +| (TBD) | — | — | — | — | No direct equivalent. Connection guarantee is a separate concept in OSDM trip search, not offer search. | diff --git a/deliverables/1 search offers/mapping-tm.md b/deliverables/1 search offers/mapping-tm.md new file mode 100644 index 0000000..7e7f141 --- /dev/null +++ b/deliverables/1 search offers/mapping-tm.md @@ -0,0 +1,371 @@ +# Mapping: Search Offers → Transmodel v6.2 + +This file maps each EUDIT **Search Offers** concept to the **Transmodel v6.2** concept(s) it realises. +Unlike the other mapping files, this is not a standard-to-standard API mapping but a conceptual anchor: +it shows which Transmodel concepts underpin each EUDIT schema. + +- **EUDIT concept** — as defined in `search-offers.yaml` +- **Transmodel concept** — the TM v6.2 concept(s) realised +- **TM package** — the Transmodel part / package +- **Notes** — alignment remarks + +--- + +## Request-side concepts + +### OfferRequest + +| EUDIT concept | Transmodel concept | TM package | Notes | +|---|---|---|---| +| OfferRequest | FARE REQUEST | Part 6 — Fare management | Root request for fare calculation; TM FARE REQUEST aggregates the trip context and passenger data. | + +--- + +### SearchOfferPolicy + +| EUDIT property | Transmodel concept | TM package | Notes | +|---|---|---|---| +| numberOfResultsBefore / numberOfResultsAfter | AVAILABILITY CONDITION | Part 1 — Framework | Bounds the time window in which results are sought. | +| currency | CURRENCY | Part 6 | ISO 4217 currency for price expression; TM uses CURRENCY TYPE. | + +--- + +### SearchOfferFilter + +| EUDIT property | Transmodel concept | TM package | Notes | +|---|---|---|---| +| modes | TRANSPORT MODE | Part 1 | TM TRANSPORT MODE (rail, bus, ferry, etc.). | +| classOfUse | FARE CLASS | Part 6 | TM FARE CLASS (first, second, premium). | +| mediaTypes | TRAVEL DOCUMENT TYPE | Part 6 | TM TRAVEL DOCUMENT TYPE categorises fulfilment media (paper, mobile, smart card). | +| requestedSections | SECTION | Part 2 — Public transport network topology | TM SECTION — a part of a route between two points. | + +--- + +### RequestedSections + +| EUDIT property | Transmodel concept | TM package | Notes | +|---|---|---|---| +| startLegId / endLegId | SECTION | Part 2 | Bounds of the requested section identified by leg references. | +| startPlace / endPlace | SCHEDULED STOP POINT / PLACE | Part 2 / Part 1 | Origin and destination of the requested section. | +| tripReference | TRIP | Part 3 — Timing information | The specific trip this section belongs to. | + +--- + +### TravellingEntity + +| EUDIT property | Transmodel concept | TM package | Notes | +|---|---|---|---| +| travellingEntityId | TRAVELLING ENTITY | Part 6 | TM TRAVELLING ENTITY — the root class for all participants in a journey (TM v6.2 §6.4). | +| entityType | (discriminator) | — | Implemented as a discriminator over TM sub-types. | +| entitlementRights | ENTITLEMENT PRODUCT | Part 6 | TM ENTITLEMENT PRODUCT — a product that gives the holder rights to a discount or access condition. | + +--- + +### Traveller + +| EUDIT property | Transmodel concept | TM package | Notes | +|---|---|---|---| +| Traveller (class) | TRANSPORT CUSTOMER | Part 6 | TM TRANSPORT CUSTOMER — an individual (or group) purchasing or using transport services. | +| age | USER PROFILE | Part 6 | Age is a qualifying attribute of USER PROFILE. | +| assistant | ASSISTANCE NEED | Part 1 | Whether this person acts as an assistant for another. | +| dateOfBirth | USER PROFILE | Part 6 | Date of birth is a qualifying attribute used for age-band fare calculation. | +| externalReference | CUSTOMER ACCOUNT | Part 6 | External identifier linking to the customer's account in the origin system. | +| personalNeeds | ACCESSIBILITY NEED | Part 1 | TM ACCESSIBILITY NEED — a specific accessibility requirement of a person. | +| qualifyingCharacteristics | USER PROFILE | Part 6 | See TravellerQualifyingCharacteristics below. | + +--- + +### TravellerQualifyingCharacteristics + +| EUDIT property | Transmodel concept | TM package | Notes | +|---|---|---|---| +| TravellerQualifyingCharacteristics (class) | USER PROFILE | Part 6 | TM USER PROFILE — a demographic / eligibility profile used for fare qualification (§6.4.3). | +| fullName | PASSENGER | Part 1 | Personal identity attribute. | +| nationality | USER PROFILE | Part 6 | Nationality as a qualifying attribute. | +| residency | USER PROFILE | Part 6 | Country of residence as a qualifying attribute. | +| dateOfBirth | USER PROFILE | Part 6 | Date of birth qualifying attribute. | +| licenseTypes | LICENSE TYPE | Part 6 | Driving licence categories held by the traveller. | + +--- + +### PersonalNeed + +| EUDIT property | Transmodel concept | TM package | Notes | +|---|---|---|---| +| type | ACCESSIBILITY NEED | Part 1 | TM ACCESSIBILITY NEED TYPE — enumerated accessibility requirement (wheelchair, visual impairment, etc.). | + +--- + +### LicenseType + +| EUDIT property | Transmodel concept | TM package | Notes | +|---|---|---|---| +| type | LICENSE TYPE | Part 6 | EU driving licence category (AM, A1, B, C, D, etc.). | + +--- + +### Animal + +| EUDIT property | Transmodel concept | TM package | Notes | +|---|---|---|---| +| Animal (class) | TRAVELLING ENTITY | Part 6 | TM TRAVELLING ENTITY sub-type for non-human participants. | +| type | ANIMAL TYPE | Part 6 | Category of animal (dog, cat, other). | +| assistant | ASSISTANCE ANIMAL | Part 1 | Whether the animal is a registered assistance/guide animal. | + +--- + +### PassengerVehicle + +| EUDIT property | Transmodel concept | TM package | Notes | +|---|---|---|---| +| PassengerVehicle (class) | VEHICLE | Part 1 / Part 6 | TM VEHICLE (traveller-owned); distinct from operator-owned VEHICLE used in scheduling. | +| type | VEHICLE TYPE | Part 1 | Category of vehicle (car, motorhome, bicycle, etc.). | +| height / width / length / weight | VEHICLE TYPE | Part 1 | Physical dimensions that may restrict loading capacity. | +| trailer | VEHICLE | Part 1 | Towed trailer modelled as a nested VEHICLE. | +| vehicleRacks | EQUIPMENT | Part 1 | Mounted equipment items (TM INSTALLED EQUIPMENT / PLACE EQUIPMENT). | + +--- + +### VehicleRack + +| EUDIT property | Transmodel concept | TM package | Notes | +|---|---|---|---| +| VehicleRack (class) | EQUIPMENT | Part 1 | TM INSTALLED EQUIPMENT — an item fitted to a vehicle. | +| type / mounting | EQUIPMENT TYPE | Part 1 | Category and attachment method. | +| height / width / length / weight | EQUIPMENT | Part 1 | Physical dimensions of the rack with load. | + +--- + +### Luggage + +| EUDIT property | Transmodel concept | TM package | Notes | +|---|---|---|---| +| Luggage (class) | TRAVELLING ENTITY | Part 6 | TM TRAVELLING ENTITY sub-type for transported items. | +| type | LUGGAGE TYPE | Part 6 | Category of item (bicycle, pram, wheelchair, skis, etc.). | +| length / width / height / weight | LUGGAGE ALLOWANCE | Part 6 | TM LUGGAGE ALLOWANCE defines dimension/weight constraints on transported items. | + +--- + +### EntitlementRight + +| EUDIT property | Transmodel concept | TM package | Notes | +|---|---|---|---| +| EntitlementRight (class) | ENTITLEMENT PRODUCT | Part 6 | TM ENTITLEMENT PRODUCT — a credential (card, concession, voucher) conferring access or discount rights (§6.5.4). | +| issuer | RESPONSIBILITY SET | Part 1 | The organisation issuing the entitlement. | +| entitlementType | ENTITLEMENT PRODUCT TYPE | Part 6 | Classifies the entitlement (loyalty card, discount card, concession, etc.). | +| code | CUSTOMER ENTITLEMENT | Part 6 | The instance identifier linking a specific TRANSPORT CUSTOMER to the ENTITLEMENT PRODUCT. | + +--- + +## Trip-context concepts + +### TripPattern + +| EUDIT property | Transmodel concept | TM package | Notes | +|---|---|---|---| +| TripPattern (class) | TRIP PATTERN | Part 3 | TM TRIP PATTERN — a planned sequence of legs a passenger intends to travel (§3.5). | +| tripPatternId | TRIP PATTERN | Part 3 | Caller-assigned identifier for the pattern. | +| legs | LEG | Part 3 | Each leg in the TRIP PATTERN. | + +--- + +### Trip + +| EUDIT property | Transmodel concept | TM package | Notes | +|---|---|---|---| +| Trip (class) | TRIP | Part 3 | TM TRIP — a specific realisation of a TRIP PATTERN on fixed departures. | +| tripId | TRIP | Part 3 | | +| legs | LEG | Part 3 | | + +--- + +### Leg (base) + +| EUDIT property | Transmodel concept | TM package | Notes | +|---|---|---|---| +| Leg (class) | LEG | Part 3 | TM LEG — a single element of a TRIP PATTERN between two consecutive points (§3.5.2). | +| legId | LEG | Part 3 | | +| sequenceNumber | LEG | Part 3 | Ordering within the TRIP PATTERN. | +| mode | TRANSPORT MODE | Part 1 | TM TRANSPORT MODE associated with the leg. | +| legType | (discriminator) | — | | + +--- + +### TimedLeg + +| EUDIT property | Transmodel concept | TM package | Notes | +|---|---|---|---| +| TimedLeg (class) | SERVICE JOURNEY (LEG) | Part 3 | TM LEG realised by a SERVICE JOURNEY (timetabled). | +| serviceJourneyRef | SERVICE JOURNEY | Part 3 | Reference to TM SERVICE JOURNEY — a passenger-carrying journey on a specific day. | +| operatingDate | OPERATING DAY | Part 3 | TM OPERATING DAY on which the SERVICE JOURNEY runs. | +| lineNumber | LINE | Part 2 | Commercial LINE associated with the SERVICE JOURNEY. | +| brand | BRANDING | Part 1 | TM BRANDING — a commercial identity applied to a service. | +| start | CALL (boarding) | Part 3 | TM CALL at the boarding stop; specifically the departure CALL. | +| end | CALL (alighting) | Part 3 | TM CALL at the alighting stop; specifically the arrival CALL. | +| intermediateStops | CALL | Part 3 | Intermediate TM CALLs passed but not boarded/alighted. | + +--- + +### ContinuousLeg + +| EUDIT property | Transmodel concept | TM package | Notes | +|---|---|---|---| +| ContinuousLeg (class) | CONTINUOUS LEG | Part 3 | TM CONTINUOUS LEG — a leg without fixed timetabled stops (walk, cycle, taxi). | +| startTime / endTime | CONTINUOUS LEG | Part 3 | Planned start/end time. | +| startLocation / endLocation | PLACE | Part 1 | TM PLACE — origin/destination of the continuous leg. | + +--- + +### TransferLeg + +| EUDIT property | Transmodel concept | TM package | Notes | +|---|---|---|---| +| TransferLeg (class) | INTERCHANGE LEG | Part 3 | TM INTERCHANGE (or CONNECTION) — a leg representing a transfer between services. | + +--- + +### LegBoard + +| EUDIT property | Transmodel concept | TM package | Notes | +|---|---|---|---| +| LegBoard (class) | CALL (departure) | Part 3 | TM CALL — the event of a vehicle stopping at a SCHEDULED STOP POINT, specifically the departure event. | +| stopPlaceRef | STOP PLACE / SCHEDULED STOP POINT | Part 2 | NeTEx reference to TM SCHEDULED STOP POINT. | +| plannedDepartureTime | CALL | Part 3 | Planned departure time at the boarding CALL. | +| pickupLocation | QUAY / BOARDING POSITION | Part 2 | Specific platform or bay within the STOP PLACE. | +| trainNumbers | TRAIN NUMBER | Part 3 | TM TRAIN NUMBER — commercial number identifying a train service. | + +--- + +### LegAlight + +| EUDIT property | Transmodel concept | TM package | Notes | +|---|---|---|---| +| LegAlight (class) | CALL (arrival) | Part 3 | TM CALL at the alighting stop, specifically the arrival event. | +| stopPlaceRef | STOP PLACE / SCHEDULED STOP POINT | Part 2 | NeTEx reference to TM SCHEDULED STOP POINT. | +| plannedArrivalTime | CALL | Part 3 | Planned arrival time at the alighting CALL. | +| setDownLocation | QUAY / BOARDING POSITION | Part 2 | Specific platform or bay within the STOP PLACE. | + +--- + +### TrainNumber + +| EUDIT property | Transmodel concept | TM package | Notes | +|---|---|---|---| +| trainNumberId | TRAIN NUMBER | Part 3 | TM TRAIN NUMBER — commercial service number (e.g. ICE 123). | + +--- + +### StopPlace + +| EUDIT property | Transmodel concept | TM package | Notes | +|---|---|---|---| +| stopPlaceRef | STOP PLACE | Part 2 | TM STOP PLACE — a place where passengers board or alight. | + +--- + +### Place hierarchy + +| EUDIT concept | Transmodel concept | TM package | Notes | +|---|---|---|---| +| Place | PLACE | Part 1 | TM PLACE — the root location concept. | +| StopPlaceInput | STOP PLACE / SCHEDULED STOP POINT | Part 2 | Identified by a NeTEx stop reference. | +| AddressInput | ADDRESS | Part 1 | TM ADDRESS — a postal address as a place. | +| PointOfInterest | POINT OF INTEREST | Part 1 | TM POINT OF INTEREST — a named place with no structural role in the network. | +| TopologicalPlace | TOPOGRAPHIC PLACE | Part 1 | TM TOPOGRAPHIC PLACE — a geographic area (municipality, region, zone). | +| GeoPosition | LOCATION | Part 1 | TM LOCATION — a geodetic position (WGS-84 latitude/longitude). | + +--- + +## Response-side concepts + +### Offer + +| EUDIT property | Transmodel concept | TM package | Notes | +|---|---|---|---| +| Offer (class) | SALES OFFER PACKAGE | Part 6 | TM SALES OFFER PACKAGE — a combination of FARE PRODUCTs available for purchase (§6.5.2). | +| offerId | SALES OFFER PACKAGE | Part 6 | Server-assigned identifier for the offer. | +| elements | SALES OFFER PACKAGE ELEMENT | Part 6 | Components of the SALES OFFER PACKAGE. | +| farePrice | FARE PRICE | Part 6 | TM FARE PRICE — the monetary value assigned to a fare element. | +| travelDocument | TRAVEL DOCUMENT | Part 6 | TM TRAVEL DOCUMENT — the document issued as proof of entitlement. | + +--- + +### OfferElement + +| EUDIT property | Transmodel concept | TM package | Notes | +|---|---|---|---| +| OfferElement (class) | SALES OFFER PACKAGE ELEMENT | Part 6 | TM SALES OFFER PACKAGE ELEMENT — a component within a SALES OFFER PACKAGE. | +| offerElementId | SALES OFFER PACKAGE ELEMENT | Part 6 | | +| travellingEntities | TRAVELLING ENTITY | Part 6 | The entities to whom this element applies. | +| farePrice | FARE PRICE | Part 6 | | +| travelDocument | TRAVEL DOCUMENT | Part 6 | | +| guarantees | GUARANTEE | Part 6 | TM GUARANTEE — a commitment associated with an offer element (connection guarantee, seat guarantee). | + +--- + +### TravelRight + +| EUDIT property | Transmodel concept | TM package | Notes | +|---|---|---|---| +| TravelRight (class) | ACCESS RIGHT ASSIGNMENT | Part 6 | TM ACCESS RIGHT ASSIGNMENT — assigns a right to travel to a specific passenger on a specific leg or zone (§6.5.3). | +| legRef | SERVICE JOURNEY | Part 3 | The specific leg to which the travel right applies. | +| zoneRef | TARIFF ZONE | Part 6 | TM TARIFF ZONE — the zone scope of a zone-based travel right. | + +--- + +### Ancillary + +| EUDIT property | Transmodel concept | TM package | Notes | +|---|---|---|---| +| Ancillary (class) | SUPPLEMENTARY PRODUCT | Part 6 | TM SUPPLEMENTARY PRODUCT — an optional add-on service (seat selection, meal, bicycle transport). | +| ancillaryId | SUPPLEMENTARY PRODUCT | Part 6 | | +| type | SUPPLEMENTARY PRODUCT TYPE | Part 6 | Category of ancillary service. | + +--- + +### Reservation + +| EUDIT property | Transmodel concept | TM package | Notes | +|---|---|---|---| +| Reservation (class) | SEAT RESERVATION | Part 6 | TM SEAT RESERVATION — a reserved space on a specific service. | + +--- + +### CompositeOfferElement + +| EUDIT property | Transmodel concept | TM package | Notes | +|---|---|---|---| +| CompositeOfferElement (class) | SALES OFFER PACKAGE | Part 6 | A nested SALES OFFER PACKAGE grouping two or more SALES OFFER PACKAGE ELEMENTs sold as a unit. | +| elements | SALES OFFER PACKAGE ELEMENT | Part 6 | | + +--- + +### FarePrice + +| EUDIT property | Transmodel concept | TM package | Notes | +|---|---|---|---| +| FarePrice (class) | FARE PRICE | Part 6 | TM FARE PRICE — monetary value of a fare or fare element (§6.4.5). Detail TBD. | + +--- + +### FareProduct + +| EUDIT property | Transmodel concept | TM package | Notes | +|---|---|---|---| +| FareProduct (class) | FARE PRODUCT | Part 6 | TM FARE PRODUCT — an immutable element in a fare structure representing a type of access right (§6.5.1). Detail TBD. | + +--- + +### TravelDocument + +| EUDIT property | Transmodel concept | TM package | Notes | +|---|---|---|---| +| TravelDocument (class) | TRAVEL DOCUMENT | Part 6 | TM TRAVEL DOCUMENT — the issued proof of entitlement (ticket, barcode, smart card record) (§6.6.1). Detail TBD. | + +--- + +### Guarantee + +| EUDIT property | Transmodel concept | TM package | Notes | +|---|---|---|---| +| Guarantee (class) | GUARANTEE | Part 6 | TM GUARANTEE — a contractual commitment associated with an offer element. Detail TBD. | diff --git a/deliverables/1 search offers/mapping-tomp.md b/deliverables/1 search offers/mapping-tomp.md new file mode 100644 index 0000000..0a2378e --- /dev/null +++ b/deliverables/1 search offers/mapping-tomp.md @@ -0,0 +1,450 @@ +# Mapping: Search Offers → TOMP-API 2.0.0 + +Maps each EUDIT **Search Offers** concept to the corresponding concept/property in **TOMP-API 2.0.0**. + +- **Endpoint**: `POST /processes/search-offers/execution` +- **EUDIT concept / Property** — as defined in `search-offers.yaml` +- **TOMP concept** — the matching schema object in TOMP-API +- **TOMP property** — the matching field name +- **Notes** — mapping remarks, gaps, or open questions + +--- + +## OfferRequest + +> Root request body for the offer search. + +| Property | Type | Mult. | TOMP concept | TOMP property | Notes | +|---|---|---|---|---|---| +| tripPatterns | TripPattern | 1..* | `searchOfferRequest` | `tripPattern` / `travelSpecification` | TOMP accepts either a fixed `tripPattern` (timetabled journeys) or an open-ended `travelSpecification` (O&D + time window). Multiple EUDIT `TripPattern`s have no direct equivalent; TOMP supports one `tripPattern` or one `travelSpecification` per request. | +| travellers | TravellingEntity | 1..* | `searchOfferRequest` | `travellers[]` | Traveller sub-types map differently; see individual sections below. `Animal`, `PassengerVehicle`, `VehicleRack`, `Luggage` have no equivalent in TOMP offer search. | +| filter | SearchOfferFilter | 0..1 | `searchOfferRequest` | `travellerRequirements` (per traveller) | TOMP applies mode/class/operator preferences per traveller, not as a global filter. `mediaTypes` and `requestedSections` have no equivalent. | +| policy | SearchOfferPolicy | 0..1 | — | — | No equivalent. TOMP offer search is synchronous with no pagination or currency control. | + +--- + +## SearchOfferPolicy + +> Pagination and currency preferences. **No equivalent in TOMP-API.** + +| Property | Type | Mult. | TOMP concept | TOMP property | Notes | +|---|---|---|---|---|---| +| numberOfResultsBefore | integer | 0..1 | — | — | Not supported. TOMP returns results without pagination control. | +| numberOfResultsAfter | integer | 0..1 | — | — | Not supported. | +| currency | string | 0..1 | — | — | Not supported at request level; currency is part of operator configuration. | + +--- + +## SearchOfferFilter + +> Constraints on which offers to return. Only partially covered in TOMP. + +| Property | Type | Mult. | TOMP concept | TOMP property | Notes | +|---|---|---|---|---|---| +| modes | string | 0..* | `travellerRequirements` | `mode`, `subMode` | Applied per traveller in TOMP, not as a global filter. | +| classOfUse | string | 0..* | `travellerRequirements` | `class` | Maps to TOMP `class` (e.g. `FIRST`, `SECOND`). Per traveller. | +| mediaTypes | string | 0..* | — | — | No equivalent. TOMP does not filter by fulfilment media type at offer-search stage. | +| requestedSections | RequestedSections | 0..* | — | — | No equivalent. TOMP does not support section-level offer targeting. | + +--- + +## RequestedSections + +> Targets offer search to a subset of legs. **No equivalent in TOMP-API.** + +| Property | Type | Mult. | TOMP concept | TOMP property | Notes | +|---|---|---|---|---|---| +| startLegId | string | 0..1 | — | — | No equivalent. | +| endLegId | string | 0..1 | — | — | No equivalent. | +| startPlace | string | 0..1 | — | — | No equivalent. | +| endPlace | string | 0..1 | — | — | No equivalent. | +| tripReference | string | 0..1 | — | — | No equivalent. | + +--- + +## TravellingEntity + +> Base class; concrete sub-types mapped below. + +| Property | Type | Mult. | TOMP concept | TOMP property | Notes | +|---|---|---|---|---|---| +| travellingEntityId | string | 1..1 | `traveller` | `id` | Used as correlation identifier. | +| entityType | string | 1..1 | — | — | Discriminator only; no TOMP equivalent. `Animal`, `PassengerVehicle`, `Luggage` sub-types have no TOMP equivalent in offer search. | +| entitlementRights | EntitlementRight | 0..* | `card` / `entitlement` | (nested in traveller) | See **EntitlementRight** section. | + +--- + +## Traveller + +> Human traveller. + +| Property | Type | Mult. | TOMP concept | TOMP property | Notes | +|---|---|---|---|---|---| +| travellingEntityId | string | 1..1 | `traveller` | `id` | | +| age | integer | 0..1 | `traveller` | `age` | Direct mapping. | +| assistant | boolean | 0..1 | — | — | No equivalent. TOMP PRM needs expressed via `travellerRequirements.prmNeeds[]`. | +| dateOfBirth | date | 0..1 | — | — | No equivalent in TOMP traveller object. Age-band eligibility via `userProfile.minimumAge` / `maximumAge`. | +| externalReference | string | 0..1 | `traveller` | `customerReference` | | +| personalNeeds | PersonalNeed | 0..* | `travellerRequirements` | `prmNeeds[]` | TOMP uses operator-defined PRM need codes. | +| qualifyingCharacteristics | TravellerQualifyingCharacteristics | 0..1 | `userProfile` | (see section) | | + +--- + +## TravellerQualifyingCharacteristics + +> Demographic eligibility data. + +| Property | Type | Mult. | TOMP concept | TOMP property | Notes | +|---|---|---|---|---|---| +| fullName | string | 0..1 | `traveller` | `name` | TOMP has a top-level `name` field on traveller. | +| nationality | string | 0..1 | — | — | No equivalent in TOMP. | +| residency | string | 0..1 | — | — | No equivalent in TOMP. | +| dateOfBirth | date | 0..1 | — | — | No equivalent in TOMP. | +| licenseTypes | LicenseType | 0..* | — | — | Driver licence held by traveller. TOMP exposes licence types via `GET /collections/license-types/items` but does not accept them in offer-search input. | + +--- + +## PersonalNeed + +> Accessibility or personal need. + +| Property | Type | Mult. | TOMP concept | TOMP property | Notes | +|---|---|---|---|---|---| +| type | string | 1..1 | `travellerRequirements` | `prmNeeds[]` | TOMP uses operator-defined PRM need codes (e.g. `WHEELCHAIR`, `VISUAL_IMPAIRMENT`). | + +--- + +## LicenseType + +> Driving licence held by a traveller. **No equivalent in TOMP offer-search input.** + +| Property | Type | Mult. | TOMP concept | TOMP property | Notes | +|---|---|---|---|---|---| +| type | string | 1..1 | — | — | TOMP exposes licence categories via a separate collection endpoint; not an input to offer search. | + +--- + +## Animal + +> Animal travelling alongside its owner. **No equivalent in TOMP offer-search input.** + +| Property | Type | Mult. | TOMP concept | TOMP property | Notes | +|---|---|---|---|---|---| +| entityType | string | 1..1 | — | — | TOMP does not model pet transport in the offer-search request. | +| type | string | 1..1 | — | — | No equivalent. | +| assistant | boolean | 0..1 | `travellerRequirements` | `prmNeeds[]` | Assistance animal status may be expressed as a PRM need on the accompanying traveller. | + +--- + +## PassengerVehicle + +> Traveller-owned vehicle to be transported. **No equivalent in TOMP offer-search input.** + +| Property | Type | Mult. | TOMP concept | TOMP property | Notes | +|---|---|---|---|---|---| +| entityType | string | 1..1 | — | — | TOMP does not support vehicle transport in offer search. | +| type | string | 1..1 | — | — | No equivalent. | +| height / width / length / weight | integer | 0..1 | — | — | No equivalent. | +| trailer | PassengerVehicle | 0..1 | — | — | No equivalent. | +| vehicleRacks | VehicleRack | 0..* | — | — | No equivalent. | + +--- + +## VehicleRack + +> Rack mounted on a passenger vehicle. **No equivalent in TOMP-API.** + +| Property | Type | Mult. | TOMP concept | TOMP property | Notes | +|---|---|---|---|---|---| +| type | string | 0..1 | — | — | No equivalent. | +| mounting | string | 0..1 | — | — | No equivalent. | +| height / width / length / weight | integer | 0..1 | — | — | No equivalent. | + +--- + +## Luggage + +> Bulky item a traveller brings. **No equivalent in TOMP offer-search input.** + +| Property | Type | Mult. | TOMP concept | TOMP property | Notes | +|---|---|---|---|---|---| +| entityType | string | 1..1 | — | — | No equivalent. TOMP shared-mobility asset catalogue is separate from offer search. | +| type | string | 1..1 | — | — | No equivalent. | +| length / width / height / weight | integer | 0..1 | — | — | No equivalent. | + +--- + +## EntitlementRight + +> Credential qualifying for reduced fares. + +| Property | Type | Mult. | TOMP concept | TOMP property | Notes | +|---|---|---|---|---|---| +| issuer | string | 0..1 | `card` | — / `entitlement` | No explicit issuer field in TOMP; issuer may be embedded in the `type` code or `id`. | +| entitlementType | string | 1..1 | `card` | `type` / `entitlement` `type` | Maps to `card.type` (e.g. `DISCOUNT_CARD`) or `entitlement.type`. | +| code | string | 0..1 | `card` | `id` / `entitlement` `id` | The instance identifier (card number, voucher code). | + +--- + +## TripPattern + +> Proposed sequence of legs. + +| Property | Type | Mult. | TOMP concept | TOMP property | Notes | +|---|---|---|---|---|---| +| tripPatternId | string | 0..1 | — | — | No equivalent; TOMP identifies the trip by the journey reference set, not a caller ID. | +| legs | Leg | 1..* | `tripPattern` | `serviceJourneys[]` (timed) OR `travelSpecification` (open O&D) | A `TripPattern` containing `TimedLeg`s maps to `tripPattern.serviceJourneys[]`. An open-ended trip maps to `travelSpecification`. `ContinuousLeg` and `TransferLeg` have no TOMP equivalent. | + +--- + +## TimedLeg + +> Leg on a fixed timetabled service. + +| Property | Type | Mult. | TOMP concept | TOMP property | Notes | +|---|---|---|---|---|---| +| legType | string | 1..1 | — | — | Discriminator only. | +| legId | string | 0..1 | — | — | No equivalent. | +| sequenceNumber | integer | 0..1 | — | — | Implied by order in `serviceJourneys[]`. | +| mode | string | 0..1 | `travellerRequirements` | `mode` | TOMP applies mode at traveller-requirements level, not per leg. | +| serviceJourneyRef | string | 0..1 | `ServiceJourneyReference` | `id` | Direct mapping. | +| operatingDate | date | 0..1 | `tripPattern` | `travelDate` | TOMP has a single `travelDate` for the whole trip pattern. | +| lineNumber | string | 0..1 | `ServiceJourneyReference` | `lineId` | | +| brand | string | 0..1 | — | — | No equivalent. | +| start | LegBoard | 0..1 | — | — | TOMP `tripPattern` does not include stop-level boarding data; only `serviceJourneys[]` and `travelDate`. | +| end | LegAlight | 0..1 | — | — | No equivalent. | +| intermediateStops | StopPlace | 0..* | — | — | No equivalent. | + +--- + +## ContinuousLeg + +> Leg without fixed timetabled stops (walk, taxi, etc.). **Partially covered by `travelSpecification`.** + +| Property | Type | Mult. | TOMP concept | TOMP property | Notes | +|---|---|---|---|---|---| +| legType | string | 1..1 | — | — | Discriminator only. | +| startTime | dateTime | 0..1 | `travelSpecification` | `startTime` | | +| endTime | dateTime | 0..1 | `travelSpecification` | `endTime` | | +| startLocation | Place | 0..1 | `travelSpecification` | `from` (placeReference) | | +| endLocation | Place | 0..1 | `travelSpecification` | `to` (placeReference) | | + +--- + +## TransferLeg + +> Transfer between services. **No equivalent in TOMP-API.** + +| Property | Type | Mult. | TOMP concept | TOMP property | Notes | +|---|---|---|---|---|---| +| legType | string | 1..1 | — | — | No equivalent. TOMP does not model interchange legs in offer-search input. | + +--- + +## LegBoard + +> Boarding event at the start of a timed leg. + +| Property | Type | Mult. | TOMP concept | TOMP property | Notes | +|---|---|---|---|---|---| +| stopPlaceRef | string | 1..1 | `placeReference` | `id` | TOMP references places by ID or coordinates. Stop references in a timed-leg context are not part of `tripPattern.serviceJourneys[]`. | +| plannedDepartureTime | dateTime | 1..1 | `tripPattern` | `travelDate` | TOMP has date only, not full departure time per leg. | +| pickupLocation | string | 0..1 | — | — | No equivalent. | +| trainNumbers | TrainNumber | 0..* | — | — | No equivalent; train number not in TOMP offer search. | + +--- + +## LegAlight + +> Alighting event at the end of a timed leg. + +| Property | Type | Mult. | TOMP concept | TOMP property | Notes | +|---|---|---|---|---|---| +| stopPlaceRef | string | 1..1 | `placeReference` | `id` | See LegBoard note above. | +| plannedArrivalTime | dateTime | 1..1 | — | — | No equivalent per-leg arrival time in TOMP. | +| setDownLocation | string | 0..1 | — | — | No equivalent. | + +--- + +## TrainNumber + +> Commercial train number. **No equivalent in TOMP offer-search input.** + +| Property | Type | Mult. | TOMP concept | TOMP property | Notes | +|---|---|---|---|---|---| +| trainNumberId | string | 1..1 | — | — | No equivalent. | + +--- + +## StopPlace + +> Reference to an intermediate stop along a timed leg. + +| Property | Type | Mult. | TOMP concept | TOMP property | Notes | +|---|---|---|---|---|---| +| stopPlaceRef | string | 1..1 | `placeReference` | `id` | TOMP `placeReference` accepts a stop ID or coordinates. | + +--- + +## Place + +> Base place type. + +| Property | Type | Mult. | TOMP concept | TOMP property | Notes | +|---|---|---|---|---|---| +| placeId | string | 0..1 | `placeReference` | — | Caller-assigned ID; no direct field in TOMP `placeReference`. | +| placeType | string | 1..1 | — | — | Discriminator only; TOMP does not distinguish place sub-types explicitly. | +| location | GeoPosition | 0..1 | `placeReference` | `coordinates` (GeoCoordinate) | See **GeoPosition** section. | + +--- + +## StopPlaceInput + +> Stop place identified by reference. + +| Property | Type | Mult. | TOMP concept | TOMP property | Notes | +|---|---|---|---|---|---| +| placeRef | string | 0..1 | `placeReference` | `id` | | + +--- + +## AddressInput + +> Postal address as a place. + +| Property | Type | Mult. | TOMP concept | TOMP property | Notes | +|---|---|---|---|---|---| +| addressLine1 | string | 0..1 | `placeReference` | `name` | TOMP `placeReference` has a single `name` field; no structured address. | +| addressLine2 | string | 0..1 | — | — | No equivalent. | + +--- + +## PointOfInterest + +> Named point of interest. + +| Property | Type | Mult. | TOMP concept | TOMP property | Notes | +|---|---|---|---|---|---| +| name | string | 0..1 | `placeReference` | `name` | | + +--- + +## TopologicalPlace + +> Geographic area or zone. + +| Property | Type | Mult. | TOMP concept | TOMP property | Notes | +|---|---|---|---|---|---| +| area | string | 0..1 | `travellerRequirements` | `zones[]` | TOMP supports zone-based filtering via `zones[]` (zone IDs), not GeoJSON polygons. | +| range | integer | 0..1 | — | — | No equivalent; TOMP does not support radius-based place references. | + +--- + +## GeoPosition + +> WGS-84 coordinate pair. + +| Property | Type | Mult. | TOMP concept | TOMP property | Notes | +|---|---|---|---|---|---| +| longitude | number | 1..1 | `GeoCoordinate` | `lon` | | +| latitude | number | 1..1 | `GeoCoordinate` | `lat` | | + +--- + +## Offer + +> Purchasable combination of offer elements returned by the server. + +| Property | Type | Mult. | TOMP concept | TOMP property | Notes | +|---|---|---|---|---|---| +| offerId | string | 1..1 | `leg` | `id` (leg-level) | TOMP does not return a discrete "offer" object; pricing is returned per leg via `leg.pricing[]`. No offer-level ID. | +| elements | OfferElement | 1..* | `leg.pricing` | (array) | See **OfferElement** section. | +| farePrice | FarePrice | 0..1 | `leg.pricing` | `estimated`, `parts[]` | Aggregated across legs by the client. | +| travelDocument | TravelDocument | 0..1 | — | — | Not returned in offer-search response; issued at booking stage. | + +--- + +## OfferElement + +> Base class for purchasable elements within an offer. + +| Property | Type | Mult. | TOMP concept | TOMP property | Notes | +|---|---|---|---|---|---| +| offerElementId | string | 1..1 | — | — | No equivalent per-element ID in TOMP pricing. | +| offerElementType | string | 1..1 | — | — | Discriminator only. | +| travellingEntities | string | 0..* | — | — | TOMP pricing is leg-level, not traveller-level. | +| farePrice | FarePrice | 0..1 | `leg.pricing` | `parts[{ amount, currencyCode }]` | | +| travelDocument | TravelDocument | 0..1 | — | — | Not in offer-search response. | +| guarantees | Guarantee | 0..* | — | — | No equivalent. | + +--- + +## TravelRight + +> Right to travel on a specific leg or zone. + +| Property | Type | Mult. | TOMP concept | TOMP property | Notes | +|---|---|---|---|---|---| +| legRef | string | 0..1 | `leg` | `id` | TOMP prices are attached to `leg` objects; the leg ID is the implicit travel-right scope. | +| zoneRef | string | 0..1 | `travellerRequirements` | `zones[]` | Zone scope expressed as zone filter, not a response field. | + +--- + +## Ancillary + +> Optional ancillary service. **No direct equivalent in TOMP offer-search response.** + +| Property | Type | Mult. | TOMP concept | TOMP property | Notes | +|---|---|---|---|---|---| +| ancillaryId | string | 0..1 | — | — | No equivalent. | +| type | string | 0..1 | — | — | No equivalent. | + +--- + +## Reservation + +> Seat or space reservation. **No equivalent in TOMP offer-search response.** + +| Property | Type | Mult. | TOMP concept | TOMP property | Notes | +|---|---|---|---|---|---| +| offerElementType | string | 1..1 | — | — | No equivalent at offer-search stage in TOMP. | + +--- + +## CompositeOfferElement + +> Grouped offer elements sold as a unit. **No equivalent in TOMP.** + +| Property | Type | Mult. | TOMP concept | TOMP property | Notes | +|---|---|---|---|---|---| +| elements | OfferElement | 2..* | — | — | No equivalent. | + +--- + +## FarePrice + +> Price of an offer or offer element. (Stub — detail TBD.) + +| Property | Type | Mult. | TOMP concept | TOMP property | Notes | +|---|---|---|---|---|---| +| (TBD) | — | — | `leg.pricing` | `estimated` (bool), `parts[{ amount, currencyCode }]` | TOMP pricing is per leg; totals must be aggregated. | + +--- + +## TravelDocument + +> Proof of entitlement issued to the traveller. (Stub — detail TBD.) + +| Property | Type | Mult. | TOMP concept | TOMP property | Notes | +|---|---|---|---|---|---| +| (TBD) | — | — | — | — | Not part of TOMP offer-search response; issued at booking/confirmation stage. | + +--- + +## Guarantee + +> Guarantee associated with an offer element. (Stub — detail TBD.) **No equivalent in TOMP.** + +| Property | Type | Mult. | TOMP concept | TOMP property | Notes | +|---|---|---|---|---|---| +| (TBD) | — | — | — | — | No equivalent. | diff --git a/deliverables/1 search offers/request bodies/test-cases.md b/deliverables/1 search offers/request bodies/test-cases.md new file mode 100644 index 0000000..65bd4e5 --- /dev/null +++ b/deliverables/1 search offers/request bodies/test-cases.md @@ -0,0 +1,430 @@ +# Search Offers — Test Cases for Request Bodies + +This document describes the test cases for the `POST /offers`, `POST /processes/search-offers/execute`, +and `POST /processes/search-offers/execution` endpoints of the *OTI Search Offers* API. + +Each test case has a corresponding JSON example file with the same number prefix. + +The test cases are organised in two sections: + +1. **Generic test cases (TC-001 – TC-010)** — applicable to all three endpoints. +2. **Standard-specific test cases** — grouped by the standard that primarily drives the scenario: + - **TC-011 – TC-013**: OSDM 3.7.1 (`POST /offers`) + - **TC-014 – TC-016**: OMSA 0.1.0 (`POST /processes/search-offers/execute`) + - **TC-017 – TC-019**: TOMP-API 2.0.0 (`POST /processes/search-offers/execution`) + +--- + +## Generic Test Cases + +These cases cover the core request model and apply regardless of which endpoint or standard is used. + +--- + +### TC-001 — Single traveller, single timed leg + +**Purpose:** the most basic possible request: one traveller, one timetabled leg, no filter or policy. + +**Scenario:** +An adult traveller wants to travel by train from Amsterdam Centraal to Utrecht Centraal on +15 September 2025, departing at 09:12. No special requirements or discounts apply. +The system must return a list of available offers for this trip. + +**Key characteristics:** +- 1 traveller (`entityType: traveller`), no age specified +- 1 trip pattern containing 1 timed leg +- Service: Intercity 930, operating date 2025-09-15 +- No filter, no policy + +**Example file:** `TC-001-single-traveller.json` + +--- + +### TC-002 — Family group, two adults and two children + +**Purpose:** verify that the API correctly processes multiple travellers with different ages and +can return age-banded fares. + +**Scenario:** +A family of four wants to travel from Den Haag Centraal to Rotterdam Centraal on 20 October 2025, +departing at 14:00. The travel party consists of two adults and two children aged 8 and 12. +The system must be able to compose a suitable offer for each member of the family. + +**Key characteristics:** +- 2 travellers without age (adults) +- 2 travellers with `age: 12` and `age: 8` +- 1 trip pattern containing 1 timed leg +- No filter, no policy + +**Example file:** `TC-002-family.json` + +--- + +### TC-003 — Traveller with a discount entitlement right + +**Purpose:** verify that an entitlement right (e.g. a rail discount subscription or Railcard) is +correctly transmitted and can result in adjusted fares. + +**Scenario:** +A traveller holds an off-peak discount subscription (40% reduction outside peak hours). +The journey is from Utrecht Centraal to Eindhoven on 3 November 2025, departing at 11:30 +(off-peak). The system must take the entitlement into account when determining offers. + +**Key characteristics:** +- 1 traveller with 1 entitlement right: `entitlementType: discountSubscription`, `issuer: NS`, `code: DALVDL` +- 1 trip pattern containing 1 timed leg (mode: rail) +- No filter, no policy + +**Example file:** `TC-003-entitlement-right.json` + +--- + +### TC-004 — Traveller with accessibility need (PRM) + +**Purpose:** verify that wheelchair-related personal needs are correctly transmitted, so that +the operator returns only accessible products and spaces. + +**Scenario:** +A traveller uses a motorised wheelchair. The journey is from Leiden Centraal to Schiphol on +5 December 2025, departing at 07:45. The system must transmit the personal need so that the +operator returns only wheelchair-accessible offers and seat assignments. + +**Key characteristics:** +- 1 traveller with `personalNeeds: [{ type: motorizedWheelchair }]` +- 1 trip pattern containing 1 timed leg (mode: rail) +- No filter, no policy + +**Example file:** `TC-004-prm-traveller.json` + +--- + +### TC-005 — Traveller with a passenger vehicle (ferry) + +**Purpose:** verify that a passenger travelling with a vehicle can be correctly specified as a +travel party for a ferry crossing. + +**Scenario:** +A traveller wants to cross from Harwich to Hoek van Holland with their car on 10 January 2026, +sailing at 23:00. The car is 430 cm long, 180 cm wide, and 155 cm tall. In addition to the +vehicle transport, the traveller expects the server to return a cabin as an ancillary offer. + +**Key characteristics:** +- 1 traveller (`entityType: traveller`) +- 1 vehicle (`entityType: vehicle`, `type: car`, dimensions specified) +- 1 trip pattern containing 1 timed leg (mode: ferry) +- No filter, no policy + +**Example file:** `TC-005-vehicle-ferry.json` + +--- + +### TC-006 — Traveller with a bicycle as luggage + +**Purpose:** verify that a bulky luggage item (bicycle) can be included as a separate travelling +entity, enabling the operator to return a bicycle ticket or reservation alongside the passenger offer. + +**Scenario:** +A traveller takes their road bicycle on the train from Amsterdam to Zwolle on 22 March 2026, +departing at 08:30. The bicycle weighs 8 kg. The API should return offers for both the +traveller and the bicycle transport. + +**Key characteristics:** +- 1 traveller (`entityType: traveller`) +- 1 luggage item (`entityType: luggage`, `type: bicycle`, `weight: 8`) +- 1 trip pattern containing 1 timed leg (mode: rail) +- No filter, no policy + +**Example file:** `TC-006-luggage-bicycle.json` + +--- + +### TC-007 — Return journey with two trip patterns + +**Purpose:** verify that the API can process multiple trip patterns in a single request — such as +an outbound and a return leg — to enable combined offers (return tickets). + +**Scenario:** +A traveller wants to book a day return from Breda to Amsterdam Centraal. Outbound on 14 April 2026 +at 08:00, returning the same day at 18:30. The API must return offers for both trip patterns, +potentially combined as a return fare. + +**Key characteristics:** +- 1 traveller (`entityType: traveller`) +- 2 trip patterns, each containing 1 timed leg (mode: rail) +- No filter, no policy + +**Example file:** `TC-007-return-journey.json` + +--- + +### TC-008 — Filter on travel class and media type + +**Purpose:** verify that the `classOfUse` and `mediaTypes` filter parameters are correctly +transmitted and that the server returns only matching offers. + +**Scenario:** +A business traveller wants to receive only first-class offers available as a mobile ticket. +The journey is from Rotterdam Centraal to Amsterdam Centraal on 2 June 2026, departing at 07:15. + +**Key characteristics:** +- 1 traveller (`entityType: traveller`) +- 1 trip pattern containing 1 timed leg (mode: rail) +- Filter: `classOfUse: [first]`, `mediaTypes: [mobileTicket]` +- No policy + +**Example file:** `TC-008-filter-class-media.json` + +--- + +### TC-009 — Policy with pagination and currency + +**Purpose:** verify that policy parameters are correctly transmitted, specifically pagination +around the requested departure time and the desired currency for price display. + +**Scenario:** +A traveller wants to take the train from Amsterdam to Berlin on 25 July 2026, preferably +departing around 10:00. The caller wants at most 2 alternatives before and 5 after this time, +with prices expressed in euros. + +**Key characteristics:** +- 1 traveller (`entityType: traveller`) +- 1 trip pattern containing 1 timed leg (mode: rail, international) +- Policy: `numberOfResultsBefore: 2`, `numberOfResultsAfter: 5`, `currency: EUR` +- No filter + +**Example file:** `TC-009-policy-pagination.json` + +--- + +### TC-010 — Traveller with an assistance animal + +**Purpose:** verify that a guide dog or assistance animal can be included as a separate travelling +entity (animal), flagged as an assistance animal, alongside its owner. + +**Scenario:** +A visually impaired traveller travels with their guide dog from Groningen to Leeuwarden on +8 August 2026, departing at 13:20. The guide dog travels free of charge; the system must +recognise the animal as an assistance animal and return only offers that permit it. + +**Key characteristics:** +- 1 traveller with `personalNeeds: [{ type: accompanyingDog }]` +- 1 animal (`entityType: animal`, `type: dog`, `assistant: true`) +- 1 trip pattern containing 1 timed leg (mode: rail) +- No filter, no policy + +**Example file:** `TC-010-assistance-animal.json` + +--- + +## OSDM-Specific Test Cases (`POST /offers`) + +These test cases target scenarios typical of the **OSDM 3.7.1** standard, which covers +international rail sales across multiple operators, promotions, and group travel. + +--- + +### TC-011 — International multi-operator rail journey + +**Purpose:** verify that an international journey spanning services from multiple operators +(e.g. Eurostar + SNCF) is correctly expressed as a multi-leg trip pattern, with each operator's +service journey identified separately. + +**Scenario:** +A traveller wants to travel from Amsterdam Centraal to Paris Gare du Nord on 10 March 2026. +The journey consists of a Thalys/Eurostar high-speed service with a single through service +journey. The traveller holds a standard second-class ticket. No entitlement rights apply. +The OSDM server is expected to return cross-border fare combinations from all participating operators. + +**Key characteristics:** +- 1 traveller, no entitlement rights +- 1 trip pattern with 1 timed leg (international high-speed rail) +- Service: Eurostar 9300 Amsterdam – Paris Nord, 2026-03-10, departure 08:17 +- Filter: `classOfUse: [second]` +- Policy: `currency: EUR` + +**Example file:** `TC-011-osdm-international-rail.json` + +--- + +### TC-012 — Promotional code as entitlement right + +**Purpose:** verify that a promotional discount code is correctly transmitted as an entitlement +right so that the OSDM server can apply campaign pricing where applicable. + +**Scenario:** +A traveller has received a promotional discount code (`PROMO25`) from a campaign run by an +operator. The traveller wants to travel from Brussels-Midi to Cologne on 15 May 2026, departing +at 11:07. The server should recognise the code and include discounted offers where the promotion +applies, alongside full-price offers. + +**Key characteristics:** +- 1 traveller with 1 entitlement right: `entitlementType: promotionCode`, `issuer: DB`, `code: PROMO25` +- 1 trip pattern with 1 timed leg (mode: rail, international) +- No filter, no policy + +**Example file:** `TC-012-osdm-promo-code.json` + +--- + +### TC-013 — Large group booking + +**Purpose:** verify that a large travel party (10 travellers) is correctly processed and that +the OSDM server can return group fares where applicable, which typically require a minimum party size. + +**Scenario:** +A group of 10 adults (e.g. a corporate team) wants to travel from Paris Gare de Lyon to Lyon +Part-Dieu by TGV on 22 June 2026, departing at 07:00. The server should detect the group size +and return group-rate offers alongside individual offers where available. + +**Key characteristics:** +- 10 travellers (`entityType: traveller`), no ages specified +- 1 trip pattern with 1 timed leg (mode: rail, high-speed) +- `travelParty.type: group` +- No filter, no policy + +**Example file:** `TC-013-osdm-group-booking.json` + +--- + +## OMSA-Specific Test Cases (`POST /processes/search-offers/execute`) + +These test cases target scenarios typical of the **OMSA 0.1.0** standard, which emphasises +flexible origin–destination search, partial journey sections, and urban/regional mobility. + +--- + +### TC-014 — Flexible origin–destination search with mode filter + +**Purpose:** verify that an OMSA request can express an origin–destination pair without a fixed +service journey reference (i.e. an open search), combined with a mode filter. + +**Scenario:** +A traveller wants to travel from Den Haag Centraal to Delft on any rail or bus service on +18 September 2026, arriving before 09:00. The caller does not know the exact service; the server +must search for all matching departures and return offers. Only bus and rail modes are accepted. + +**Key characteristics:** +- 1 traveller +- 1 trip pattern with 1 timed leg, no `serviceJourneyRef` (open search) +- Filter: `modes: [rail, bus]` +- Policy: `numberOfResultsAfter: 5` + +**Example file:** `TC-014-omsa-flexible-od.json` + +--- + +### TC-015 — Requested sections on a through journey + +**Purpose:** verify that the `requestedSections` filter correctly limits the offer search to a +specific portion of a longer through journey (e.g. boarding mid-route or alighting early). + +**Scenario:** +A traveller is already on a through train from Amsterdam to Eindhoven but wants to purchase +a ticket only for the Utrecht–Eindhoven section. The request includes the full trip pattern +but a `requestedSections` entry restricts the offer search to the segment starting at Utrecht. + +**Key characteristics:** +- 1 traveller +- 1 trip pattern with 2 timed legs (Amsterdam→Utrecht, Utrecht→Eindhoven) +- Filter: `requestedSections` specifying `startLegId: leg-002` (Utrecht onwards) +- No policy + +**Example file:** `TC-015-omsa-requested-sections.json` + +--- + +### TC-016 — Traveller with qualifying characteristics (nationality/residency) + +**Purpose:** verify that nationality and country of residency, which determine eligibility for +domestic vs. international fares in OMSA scenarios, are correctly transmitted via +`qualifyingCharacteristics`. + +**Scenario:** +A traveller with Belgian nationality and French residency wants to travel from Paris to Brussels +on 5 October 2026. The traveller's qualifying characteristics must be transmitted so that the +server can determine eligibility for domestic Belgian fares, domestic French fares, or full +international pricing. + +**Key characteristics:** +- 1 traveller with `qualifyingCharacteristics: { nationality: BE, residency: FR }` +- 1 trip pattern with 1 timed leg (mode: rail, international) +- No filter, no policy + +**Example file:** `TC-016-omsa-qualifying-characteristics.json` + +--- + +## TOMP-Specific Test Cases (`POST /processes/search-offers/execution`) + +These test cases target scenarios typical of the **TOMP-API 2.0.0** standard, which covers +multi-modal MaaS journeys including continuous legs, geo-coordinate–based places, and transfers. + +--- + +### TC-017 — Multi-modal journey: timed leg + continuous leg (walk) + +**Purpose:** verify that a trip pattern combining a timed public transport leg with a +continuous leg (e.g. a walking segment to the final destination) is correctly expressed and +that the server can return offers covering the timed portion. + +**Scenario:** +A traveller wants to go from Rotterdam Centraal to a hotel near Beurs square. The trip consists +of a Metro leg (timed) followed by a 7-minute walk (continuous). The TOMP server should return +offers for the Metro leg; the walking segment requires no fare product. + +**Key characteristics:** +- 1 traveller +- 1 trip pattern with 2 legs: + - Leg 1: timed, Metro (mode: metro), Rotterdam Centraal → Beurs + - Leg 2: continuous, walk (mode: other), `startTime`/`endTime` provided, `startLocation`/`endLocation` as geo-coordinates +- No filter, no policy + +**Example file:** `TC-017-tomp-multimodal-walk.json` + +--- + +### TC-018 — Place specified by geo-coordinates + +**Purpose:** verify that a `ContinuousLeg` (e.g. on-demand ride or last-mile service) can +specify its origin and destination as geo-coordinate–based places rather than stop references, +as required by TOMP for demand-responsive and MaaS services. + +**Scenario:** +A traveller wants to book a taxi or shared-ride from their current geo-location (52.3667°N, +4.9041°E — near Amsterdam Sloterdijk) to Amsterdam Centraal on 12 November 2026 around 08:00. +The leg is continuous (no fixed timetable). The server must accept the coordinate-based +`Place` objects and return mobility offers. + +**Key characteristics:** +- 1 traveller +- 1 trip pattern with 1 continuous leg +- `startLocation`: `{ placeType: topologicalPlace, location: { latitude: 52.3667, longitude: 4.9041 } }` +- `endLocation`: `{ placeType: stopPlace, placeRef: NL:StopPlace:AmsterdamCentraal }` +- No filter, no policy + +**Example file:** `TC-018-tomp-geo-coordinates.json` + +--- + +### TC-019 — Multi-leg journey with an explicit transfer leg + +**Purpose:** verify that a trip pattern containing an explicit transfer leg between two timed +services is correctly expressed, and that the server does not attempt to price the transfer +itself but correctly associates offers with the surrounding timed legs. + +**Scenario:** +A traveller travels from Antwerp-Centraal to Amsterdam Centraal, requiring a change at +Rotterdam Centraal. The trip pattern contains three legs: a timed Thalys/IC service +(Antwerp→Rotterdam), an explicit transfer leg (platform change at Rotterdam), and a second +timed IC service (Rotterdam→Amsterdam). The TOMP server must return separate offers for each +timed leg and handle the transfer gracefully. + +**Key characteristics:** +- 1 traveller +- 1 trip pattern with 3 legs: + - Leg 1: timed (mode: rail), Antwerp-Centraal → Rotterdam Centraal + - Leg 2: transfer, Rotterdam Centraal (platform change, ~12 min) + - Leg 3: timed (mode: rail), Rotterdam Centraal → Amsterdam Centraal +- No filter, no policy + +**Example file:** `TC-019-tomp-transfer-leg.json` diff --git a/deliverables/1 search offers/search-offers-model backup day 1.qea b/deliverables/1 search offers/search-offers-model backup day 1.qea new file mode 100644 index 0000000000000000000000000000000000000000..7c5472e0fdab2f0067cacb15f31bdd53da5c4860 GIT binary patch literal 2740224 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

HyDQxdsYEfB}| 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