docs: include previously ignored documentation files
This commit is contained in:
@@ -0,0 +1,391 @@
|
|||||||
|
# API Consumer Guide
|
||||||
|
|
||||||
|
This document describes the public JSON API exposed under `/api`, written for developers implementing a **client** in another application. It is self-contained: no access to this codebase is required to use it.
|
||||||
|
|
||||||
|
## Overview
|
||||||
|
|
||||||
|
A Symfony application exposing a read-mostly JSON API under the `/api` prefix. All `/api/*` requests are stateless and authenticated via OAuth2 Bearer tokens (League OAuth2 Server, JWT access tokens). Responses are `application/json`. HTTPS is enforced on all routes.
|
||||||
|
|
||||||
|
## Authentication
|
||||||
|
|
||||||
|
- Token endpoint: `POST /token` (unauthenticated).
|
||||||
|
- Enabled grants: **client_credentials**, **authorization_code** (PKCE required for public clients), **refresh_token**. Password and implicit grants are disabled.
|
||||||
|
- Access token TTL: **10 minutes** — clients must refresh/re-request frequently.
|
||||||
|
- Available scopes: `email`, `id`, `profile`, `roles`, `api`. Default scope if none requested: `email`.
|
||||||
|
- Each granted scope maps to a role `ROLE_OAUTH2_<SCOPE_UPPERCASE>` (e.g. scope `api` → `ROLE_OAUTH2_API`).
|
||||||
|
- Send the token as `Authorization: Bearer <access_token>`.
|
||||||
|
|
||||||
|
Scope required per endpoint:
|
||||||
|
|
||||||
|
| Scope needed | Endpoints |
|
||||||
|
|---|---|
|
||||||
|
| `api` | everything except the two below |
|
||||||
|
| `profile` | `GET /api/crm-attributes` |
|
||||||
|
| `email` | `GET /api/userinfo` (optional extra scopes `id`, `profile`, `roles` widen the response) |
|
||||||
|
|
||||||
|
`/api/userinfo` and `/api/crm-attributes` act on the **authenticated end user**, so they require an authorization_code token issued for a user. All other endpoints are machine-to-machine and work with client_credentials.
|
||||||
|
|
||||||
|
### Machine-to-machine example
|
||||||
|
|
||||||
|
```
|
||||||
|
POST /token
|
||||||
|
Content-Type: application/x-www-form-urlencoded
|
||||||
|
|
||||||
|
grant_type=client_credentials&client_id=...&client_secret=...&scope=api
|
||||||
|
```
|
||||||
|
|
||||||
|
```
|
||||||
|
GET /api/hotels
|
||||||
|
Authorization: Bearer eyJ0eXAi...
|
||||||
|
```
|
||||||
|
|
||||||
|
## Error conventions
|
||||||
|
|
||||||
|
There is no single error envelope; three shapes occur:
|
||||||
|
|
||||||
|
- `{"message": "..."}` — commonly with 404 / 400.
|
||||||
|
- `{"error": "...", "type": "api_error"}` — upstream failures on some endpoints. **Caution:** on `/api/products` and `/api/travels/{dateId}/{hotelId}/{dateTo}/availability` this shape is returned with HTTP **200**, so clients must check for the presence of an `error` key, not only the status code.
|
||||||
|
- `{"success": false, "message": "..."}` — the write endpoints (contact form, newsletter).
|
||||||
|
|
||||||
|
Validation failures on endpoints using mapped query strings / payloads (`/api/contingents/*`, `/api/newsletter-subscriptions`) return **400** with Symfony's constraint-violation body. Missing/invalid token yields **401**; insufficient scope yields **403**.
|
||||||
|
|
||||||
|
The HTTP methods listed below are the intended ones. Several read routes do not restrict methods server-side; clients should still use `GET` for them.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Endpoints
|
||||||
|
|
||||||
|
### Reference data (BusProNet master data)
|
||||||
|
|
||||||
|
#### `GET /api/hotels` — scope `api`
|
||||||
|
|
||||||
|
List of hotels. Array of objects: `id` (int), `code` (string), `name`, `city`, `street`, `phone`, `country`.
|
||||||
|
|
||||||
|
#### `GET /api/hotels/{id}` — scope `api`
|
||||||
|
|
||||||
|
Single hotel by numeric id, same field set as the list. `404 {"message":"Not found"}` if unknown.
|
||||||
|
|
||||||
|
#### `GET /api/countries` — scope `api`
|
||||||
|
|
||||||
|
Array of `{id, name, token, nationality}`.
|
||||||
|
|
||||||
|
#### `GET /api/products` — scope `api`
|
||||||
|
|
||||||
|
Product master data from the upstream BusProNet system, cached server-side for 1 hour. On upstream failure returns `{"error": "...", "type": "api_error"}` **with status 200**.
|
||||||
|
|
||||||
|
#### `GET /api/last-update` — scope `api`
|
||||||
|
|
||||||
|
Timestamp of the last upstream data export: `{"timestamp": "YYYY-MM-DD HH:MM:SS"}`. Note: if no export marker file exists the current implementation errors (500) rather than returning null — treat a non-JSON/500 response as "unknown".
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Pickups (bus boarding points)
|
||||||
|
|
||||||
|
#### `GET /api/pickups` — scope `api`
|
||||||
|
|
||||||
|
Array of `{id, code, city, postalCode, street}`.
|
||||||
|
|
||||||
|
#### `GET /api/pickups/{id}` — scope `api`
|
||||||
|
|
||||||
|
Single pickup by numeric id, same fields as the list.
|
||||||
|
|
||||||
|
#### `GET /api/pickups-planning/{travelCode}` — scope `api`
|
||||||
|
|
||||||
|
Planned outbound (HIN) boarding stops for one travel code. Returns an array, chronologically sorted:
|
||||||
|
|
||||||
|
```json
|
||||||
|
[{"city": "...", "location": "...", "datetime": "YYYY-MM-DD HH:MM", "busNumber": "..."}]
|
||||||
|
```
|
||||||
|
|
||||||
|
`404 {"error":"Planning data not available"}` if no planning has been uploaded yet, `404 {"error":"Travel code not found"}` for an unknown code, `500 {"error":"Failed to read planning data"}` on storage errors.
|
||||||
|
|
||||||
|
#### `POST /api/pickups-planning` — scope `api`
|
||||||
|
|
||||||
|
Bulk-replaces the planning dataset. Body: a JSON **array** of raw planning rows using the upstream German keys:
|
||||||
|
|
||||||
|
```json
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"PlanungsArt": "HIN",
|
||||||
|
"Reisecode": "ABC123",
|
||||||
|
"Zustieg/Ausstieg Ort": "Köln",
|
||||||
|
"Zustieg/Ausstieg Strasse": "Hauptbahnhof",
|
||||||
|
"Zeit": "24.12.2026 07:30",
|
||||||
|
"BusNummer": "1"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
```
|
||||||
|
|
||||||
|
Rows without `PlanungsArt === "HIN"` or without `Reisecode` are dropped; duplicates (same city + location + datetime + bus) are de-duplicated; results are grouped by `Reisecode` and sorted by time. Response `{"status":"ok"}` (200). `400 {"error":"Invalid JSON payload"}`, `500 {"error":"Failed to write pickups planning data"}`.
|
||||||
|
|
||||||
|
This is a full overwrite, not a merge.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Travels
|
||||||
|
|
||||||
|
#### `GET /api/travels` — scope `api`
|
||||||
|
|
||||||
|
Index/mapping of all known travel dates. Object keyed by numeric travel id, each value `{id, code, label, dateFrom, dateTo, hotels: [...]}`.
|
||||||
|
|
||||||
|
#### `GET /api/travels/{dateId}/{hotelId}` — scope `api`
|
||||||
|
|
||||||
|
Single travel by **numeric** ids (`hotelId` optional). Route matches only when both segments are digits.
|
||||||
|
|
||||||
|
#### `GET /api/travels/{dateCode}/{hotelCode}` — scope `api`
|
||||||
|
|
||||||
|
Same, addressed by **string** codes (`hotelCode` optional). The date code is sanitized (separators stripped) before lookup. `404 {"message":"Not found"}` if the date code is unknown, `404 {"message":"Travel not found"}` if no data exists.
|
||||||
|
|
||||||
|
Both variants accept optional query parameters:
|
||||||
|
|
||||||
|
- `source=local` — force the local XML/snapshot data.
|
||||||
|
- `source=remote` — force a live upstream call.
|
||||||
|
- `prefer_remote=1` — used only when `source` is absent; prefers upstream with local fallback.
|
||||||
|
|
||||||
|
Response fields: `id`, `code`, `productCode`, `productId`, `label`, `hotelId`, `hotel` (hotel object), `dateFrom`, `dateTo`, `type`, `status`, `allowedBookingStatus[]`, `priceFrom`, `selectionGroups[]`, `additionalServices[]`, `transportationServices[]`, `pickups[]`, `dropOffs[]`, `rooms[]`, `guide`, `insurances[]`.
|
||||||
|
|
||||||
|
#### `GET /api/travels/{dateId}/{hotelId}/{dateTo}/availability` — scope `api`
|
||||||
|
|
||||||
|
Live hotel availability from the upstream system. `dateTo` must be `Y-m-d`. On upstream failure returns `{"error":"...","type":"api_error"}` **with status 200**.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Contingents & accommodation prices
|
||||||
|
|
||||||
|
#### `GET /api/contingents/prices?hotelCode=…&year=…` — scope `api`
|
||||||
|
|
||||||
|
Price timeline for one accommodation and calendar year, collapsed into contiguous segments (adjacent days with the same effective price are merged into one row). The timeline never starts before today; if the requested year is entirely in the past the response is `[]`.
|
||||||
|
|
||||||
|
- `hotelCode`: required, max 16 chars, `[A-Za-z0-9_-]+` (matches the accommodation's calendar code).
|
||||||
|
- `year`: required int, 1000–9999.
|
||||||
|
|
||||||
|
Each row:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"dateFrom": "2026-06-01",
|
||||||
|
"dateTo": "2026-06-14",
|
||||||
|
"season": "high|low|...|null",
|
||||||
|
"includedPax": 2,
|
||||||
|
"pricePerNight": 89.5,
|
||||||
|
"priceAdditionalPerson": 25.0,
|
||||||
|
"defaultPricePerNight": 99.0,
|
||||||
|
"defaultPriceAdditionalPerson": 30.0,
|
||||||
|
"currency": "EUR",
|
||||||
|
"type": "discount|null"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Prices are **decimal major units** (converted from integer minor units server-side). `default*` fields are non-null only when the winning price is a discount, and then carry the undiscounted price. `400 {"error":"Hotel not found for hotelCode."}` for an unknown code; `400` with violations for invalid parameters.
|
||||||
|
|
||||||
|
#### `GET /api/contingents/calendar?hotelCode=…&dateFrom=…&dateTo=…` — scope `api`
|
||||||
|
|
||||||
|
Per-day availability enriched with prices. Both dates are `Y-m-d` and **inclusive** (`dateTo` is the last night, not the checkout day); the range may not exceed 366 days and `dateTo` must not precede `dateFrom`.
|
||||||
|
|
||||||
|
Availability is served from a **local snapshot** refreshed over a 24-month horizon — every 15 minutes during the day, hourly overnight — not fetched from the upstream contingent service per request. The endpoint therefore responds in single-digit milliseconds and stays available during an upstream outage, at the cost of being at most one sync interval stale.
|
||||||
|
|
||||||
|
The response format is unchanged from the previous upstream-backed implementation: same fields, same order, same types, same `status` values. One behavioural note — the endpoint now returns **one entry per requested day**. Previously days the upstream service did not mention were simply absent, so a response may now contain days it would not have contained before. It is a superset, never a different shape.
|
||||||
|
|
||||||
|
Two kinds of day resolve to `BLOCKED` regardless of the underlying contingent:
|
||||||
|
|
||||||
|
- **days in the past** — the snapshot is maintained from today forward only (`prices` likewise refuses past ranges)
|
||||||
|
- **days beyond the synced horizon** — currently 24 months out
|
||||||
|
|
||||||
|
Each entry:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"date": "2026-06-01",
|
||||||
|
"status": "Free|Blocked|...",
|
||||||
|
"type": "discount|null",
|
||||||
|
"pricePerNight": 89.5,
|
||||||
|
"defaultPricePerNight": 99.0,
|
||||||
|
"priceAdditionalPerson": 25.0,
|
||||||
|
"defaultPriceAdditionalPerson": 30.0,
|
||||||
|
"currency": "EUR",
|
||||||
|
"includedPax": 2,
|
||||||
|
"minNights": 2
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Important rule: **a day with no maintained price is forced to `Blocked`** regardless of what the upstream contingent says. Price fields may be `null` in that case.
|
||||||
|
|
||||||
|
Errors: `400 {"error":"Hotel not found for hotelCode."}`, `400` with violations for invalid parameters.
|
||||||
|
|
||||||
|
`502 {"error":"Failed to fetch contingent data."}` is still returned — with the same body as before — but it now means **"no usable local snapshot for this hotel"** rather than "the upstream call failed": either the hotel has never synced successfully, or its last successful sync is more than 6 hours old. Treat it as before: the data is unavailable, not empty. This matters because the alternative would be a `200` reporting every day as `BLOCKED`, which is indistinguishable from a genuinely fully-booked hotel.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Operating the snapshot (deployment)
|
||||||
|
|
||||||
|
The snapshot is a new table populated by the scheduler, so it is **empty immediately after a deploy that runs the migration**. Until the first successful sync every hotel returns `502` — deliberately, so no consumer caches a fully-blocked calendar as if it were real availability.
|
||||||
|
|
||||||
|
Rollout order:
|
||||||
|
|
||||||
|
1. **Confirm `BPN_CONNECT_API_KEY` is valid for the target environment before deploying.** If it is rejected the sync cannot populate anything and the endpoint stays at `502`.
|
||||||
|
2. Deploy; `database:migrate` creates the empty tables.
|
||||||
|
3. Run `bin/console app:bpn:sync-contingents` on the host, promptly and ideally off-peak — a consumer that page-caches whatever it renders from a `502` may hold that for the length of its own cache period.
|
||||||
|
4. Verify: `contingent_sync_state.synced_at` populated and `failure_count` at 0 for every hotel, then spot-check one calendar response.
|
||||||
|
|
||||||
|
Thereafter the scheduler keeps it current; a sync failing for one hotel puts only that hotel into `502` and leaves the rest serving normally.
|
||||||
|
|
||||||
|
### Freshness and propagation
|
||||||
|
|
||||||
|
There is deliberately **no change-notification endpoint**. Availability changes slowly, and the measured cost of simply refetching on a TTL is low enough that a polling/revision mechanism was not worth the extra moving parts on either side.
|
||||||
|
|
||||||
|
That leaves two levers, and consumers should know both:
|
||||||
|
|
||||||
|
- **Their own cache TTL** bounds how stale a rendered calendar can be. A one-hour TTL is the current agreed budget.
|
||||||
|
- **Direct cache invalidation** is the only fast path when something must propagate sooner — a hotel closing, or bad availability that got cached. Consumers should keep this targeted rather than flushing everything; the TYPO3 site, for example, tags its cached calendar and price entries per hotel, so a single hotel can be flushed and re-warmed on its own.
|
||||||
|
|
||||||
|
On this side, staleness is bounded by the sync cadence and hard-capped by the 6-hour guard: past that, the endpoint returns `502` rather than presenting stale availability as current.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Accommodation bookings (group bookings)
|
||||||
|
|
||||||
|
#### `GET /api/accommodation-bookings/{uuid}` — scope `api`
|
||||||
|
|
||||||
|
Single booking by UUID. `404 {"message":"Not found"}` if unknown.
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"uuid": "...",
|
||||||
|
"status": "...",
|
||||||
|
"type": "...",
|
||||||
|
"dateFrom": "2026-06-01",
|
||||||
|
"dateTo": "2026-06-08",
|
||||||
|
"nights": 7,
|
||||||
|
"paxCount": 40,
|
||||||
|
"minorsCount": 12,
|
||||||
|
"childrenCount": 3,
|
||||||
|
"groupName": "...",
|
||||||
|
"acceptedAt": "2026-05-01T10:00:00+00:00",
|
||||||
|
"personalData": {},
|
||||||
|
"accommodation": {},
|
||||||
|
"boardService": {},
|
||||||
|
"additionalServices": [],
|
||||||
|
"accommodationDiscount": null,
|
||||||
|
"boardServiceDiscount": null,
|
||||||
|
"additionalServicesDiscount": null,
|
||||||
|
"totalPrice": 123456,
|
||||||
|
"pricingCurrency": "EUR",
|
||||||
|
"pricingVersion": 3,
|
||||||
|
"priceBreakdown": {}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
`totalPrice` and the `*Discount` fields are integer **minor units** (cents) — unlike the contingent endpoints. `dateFrom`/`dateTo` are `Y-m-d`; `acceptedAt` is a full ISO-8601 datetime and is `null` until accepted. `priceBreakdown` is a computed nested structure.
|
||||||
|
|
||||||
|
#### `POST /api/accommodation-bookings/{uuid}/accept` — scope `api`
|
||||||
|
|
||||||
|
Marks the booking as accepted (server-side side effects: status change, `acceptedAt`, notifications). No request body. Returns the same booking representation as the GET. `404` if unknown. Not idempotent in terms of side effects — call once.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Contact form
|
||||||
|
|
||||||
|
#### `POST /api/contactform` — scope `api`
|
||||||
|
|
||||||
|
Creates or matches an address record in the upstream CRM.
|
||||||
|
|
||||||
|
Request body (all fields optional strings; the upstream system decides what is required):
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"lastName": "...", "firstName": "...", "gender": "...",
|
||||||
|
"street": "...", "zipCode": "...", "city": "...",
|
||||||
|
"email": "...", "phone": "..."
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
- `201` — `{"success": true, "addressId": 123, "personId": 456, "isNewRecord": true}`
|
||||||
|
- `409` — `{"success": false, "message": "<upstream notification>"}` (upstream rejected/conflicted)
|
||||||
|
- `400` — `{"success": false, "message": "<error>"}` (upstream call failed)
|
||||||
|
- `422` — malformed payload
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Newsletter
|
||||||
|
|
||||||
|
#### `GET /api/newsletters` — scope `api`
|
||||||
|
|
||||||
|
The configured newsletter lists as an array of `{id, name, ...}` mapping objects. Use the returned `id` values as `listIds` below.
|
||||||
|
|
||||||
|
#### `POST /api/newsletter-subscriptions` — scope `api`
|
||||||
|
|
||||||
|
Request:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"email": "[email protected]",
|
||||||
|
"firstName": "Ada",
|
||||||
|
"lastName": "Lovelace",
|
||||||
|
"listIds": [1, 2]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
- `email`: required, strict email validation.
|
||||||
|
- `firstName` / `lastName`: optional, max 255 chars.
|
||||||
|
- `listIds`: required, at least one positive integer; every id must be one of the configured lists.
|
||||||
|
|
||||||
|
Responses:
|
||||||
|
|
||||||
|
- `200` — subscription completed, `state: "subscribed"`.
|
||||||
|
- `202` — a double-opt-in confirmation mail was requested, `state: "confirmation_requested"`.
|
||||||
|
- Body in both cases:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"success": true,
|
||||||
|
"email": "[email protected]",
|
||||||
|
"lists": [{"id": 1, "name": "...", "state": "success|pending|already_registered"}],
|
||||||
|
"state": "subscribed|pending_confirmation|confirmation_requested",
|
||||||
|
"confirmationRequested": true
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
- `400` — unknown or disallowed list ids: `{"success": false, "message": "...", "listIds": [...], "unknownListIds": [...]}`, or validation violations.
|
||||||
|
- `503` — `{"success": false, "email": "...", "listIds": [...], "message": "Newsletter subscription request could not be processed."}` when the newsletter provider is unavailable. Safe to retry.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### End-user endpoints (require a user-bound token)
|
||||||
|
|
||||||
|
#### `GET /api/userinfo` — scope `email` (+ optional `id`, `profile`, `roles`)
|
||||||
|
|
||||||
|
OIDC-style claims for the authenticated user. The response contains only the claims covered by the granted scopes:
|
||||||
|
|
||||||
|
- always: `email`
|
||||||
|
- scope `id`: `person_id`, `address_id`
|
||||||
|
- scope `roles`: `roles` (array; only the roles that actually grant something are exported — the implicit baseline role is stripped, and so are the `*_PENDING` markers of roles the BusPro CRM claims but nobody has approved yet, see `docs/user-roles.md`)
|
||||||
|
- scope `profile`: `profile` object:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"first_name": "...", "last_name": "...", "title": "...", "salutation": "...",
|
||||||
|
"gender": "...", "date_of_birth": "1990-01-01", "nationality": "...",
|
||||||
|
"address": {"street": "...", "postcode": "...", "city": "...", "district": "...", "country": "..."},
|
||||||
|
"communication": {"email": "...", "mobile": "...", "phone": "...", "newsletter": true},
|
||||||
|
"hotel_codes": ["..."], "height": null, "weight": null, "shoe_size": null, "remarks": "..."
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Note: `profile.communication.email` comes from the CRM address record and is **not necessarily** the login email — a single address can hold several contacts. Use the top-level `email` claim for identity.
|
||||||
|
|
||||||
|
`400 {"message": "...", "code": "..."}` when the upstream lookup fails or rejects the credentials.
|
||||||
|
|
||||||
|
#### `GET /api/crm-attributes` — scope `profile`
|
||||||
|
|
||||||
|
CRM selection attributes/segments for the authenticated user. `400 {"message": "...", "code": "..."}` on upstream failure.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Client implementation notes
|
||||||
|
|
||||||
|
1. **Token lifetime is 10 minutes** — implement refresh/re-fetch with a safety margin and retry once on 401.
|
||||||
|
2. **Check for an `error` key even on 200 responses** for `/api/products` and the travel availability endpoint.
|
||||||
|
3. **Money units are inconsistent across endpoints**: contingent endpoints return decimal major units; accommodation-booking fields return integer cents. Normalize at the client boundary.
|
||||||
|
4. **Dates**: `Y-m-d` everywhere except `acceptedAt` (ISO-8601 datetime) and pickup planning (`Y-m-d H:i`). Contingent `dateFrom`/`dateTo` are inclusive night boundaries.
|
||||||
|
5. **Server-side caching** (1 h on products) means upstream changes may not be visible immediately. The contingent calendar is snapshot-backed instead: it is at most one sync interval behind upstream. There is no change-notification endpoint — clients are expected to cache on their own TTL and, when something must propagate sooner, invalidate their cache directly.
|
||||||
|
6. **Route ambiguity**: `/api/travels/{a}/{b}` resolves to the id-based route when both segments are numeric, otherwise to the code-based route. Non-numeric codes are safe; purely numeric *codes* will hit the id route.
|
||||||
@@ -0,0 +1,898 @@
|
|||||||
|
# bpn-connect Query Reference
|
||||||
|
|
||||||
|
> **Scope: endpoint design and the XML→SQL migration plan for the `bpn-connect` Go proxy.**
|
||||||
|
> For schema semantics, conventions and confidence marks see
|
||||||
|
> [`docs/buspro-database-reference.md`](buspro-database-reference.md), which is authoritative
|
||||||
|
> and wins on any conflict. The table descriptions below are kept for endpoint context.
|
||||||
|
|
||||||
|
This document summarizes the BusProNet schema exports in
|
||||||
|
`docs/buspronet-schema` for future `bpn-connect` endpoint/query development.
|
||||||
|
|
||||||
|
Generated from:
|
||||||
|
|
||||||
|
- `docs/buspronet-schema/BusPronet_20260601-1517.csv`: table columns
|
||||||
|
- `docs/buspronet-schema/BusPronet_20260601-1518.csv`: foreign keys
|
||||||
|
|
||||||
|
Current limitation: the visible exports do not include primary-key or index
|
||||||
|
catalog data, even though those were expected. Identity flags are not a reliable
|
||||||
|
primary-key substitute in this database because many `ID...` columns are not
|
||||||
|
marked as identity. Add PK/index exports before finalizing performance-sensitive
|
||||||
|
queries.
|
||||||
|
|
||||||
|
## Naming Conventions
|
||||||
|
|
||||||
|
- Primary identifiers usually follow `ID<TableName>`, for example
|
||||||
|
`Buchung.IDBuchung`, `Adresse.IDAdresse`, `AdressePerson.IDAdressePerson`.
|
||||||
|
- Foreign key columns usually include `_FS`, for example
|
||||||
|
`BuchungTN.IDBuchung_FS`.
|
||||||
|
- Address data is split into:
|
||||||
|
- `Adresse`: address/customer account root.
|
||||||
|
- `AdressePerson`: person attached to an address.
|
||||||
|
- `AdresseAnschrift`: postal address.
|
||||||
|
- `AdresseKommunikation`: communication values such as email/phone.
|
||||||
|
- Booking data is split into:
|
||||||
|
- `Buchung`: booking header.
|
||||||
|
- `BuchungTN`: booking participants.
|
||||||
|
- `BuchungTNFerienziel`, `BuchungTNLeistung`: participant travel/service rows.
|
||||||
|
- Public booking number appears to be `Buchung.Vorgang`.
|
||||||
|
- Internal booking id is `Buchung.IDBuchung`.
|
||||||
|
- Many tables have `Status` fields. Based on observed data, `Status = 'L'`
|
||||||
|
appears to be a soft-delete marker and should be excluded from portal lookup
|
||||||
|
queries. Other status values still need table-specific business validation.
|
||||||
|
|
||||||
|
## Core Tables
|
||||||
|
|
||||||
|
### `Buchung`
|
||||||
|
|
||||||
|
Booking header. Important columns:
|
||||||
|
|
||||||
|
| Column | Type | Nullable | Notes |
|
||||||
|
| --- | --- | --- | --- |
|
||||||
|
| `IDBuchung` | `bigint` | no | Internal booking id. |
|
||||||
|
| `Vorgang` | `nvarchar(100)` | no | Public booking number/reference. |
|
||||||
|
| `IDReise_FS` | `bigint` | yes | Links to `Reise.IDReise`; no FK was present in the export. |
|
||||||
|
| `IDAdresse_FS_Anmelder` | `bigint` | yes | Applicant address id; no FK was present in the export. |
|
||||||
|
| `IDAdresseAnschrift_FS_Anmelder` | `bigint` | yes | Applicant postal address id; no FK was present in the export. |
|
||||||
|
| `IdAdressePerson_FS_Anmelder` | `bigint` | yes | Applicant person id; FK exists. |
|
||||||
|
| `IDAdresse_FS_Agentur` | `bigint` | no | Agency address; FK exists. |
|
||||||
|
| `IDAdresse_FS_Mandant` | `bigint` | no | Tenant/client address; FK exists. |
|
||||||
|
| `LoginWert1` | `nvarchar(100)` | no | Possible login-related value; semantics unknown. |
|
||||||
|
| `LoginWert2` | `nvarchar(100)` | no | Possible login-related value; semantics unknown. |
|
||||||
|
| `LoginWert3` | `nvarchar(100)` | no | Possible login-related value; semantics unknown. |
|
||||||
|
|
||||||
|
Known exported foreign keys:
|
||||||
|
|
||||||
|
- `Buchung.IdAdressePerson_FS_Anmelder -> AdressePerson.IDAdressePerson`
|
||||||
|
- `Buchung.IDAdresse_FS_Agentur -> Adresse.IDAdresse`
|
||||||
|
- `Buchung.IDAdresse_FS_ErsterSachb -> Adresse.IDAdresse`
|
||||||
|
- `Buchung.IDAdresse_FS_LetzterSachb -> Adresse.IDAdresse`
|
||||||
|
- `Buchung.IDAdresse_FS_Mandant -> Adresse.IDAdresse`
|
||||||
|
|
||||||
|
Notable missing FKs in the export:
|
||||||
|
|
||||||
|
- `Buchung.IDAdresse_FS_Anmelder`
|
||||||
|
- `Buchung.IDAdresseAnschrift_FS_Anmelder`
|
||||||
|
- `Buchung.IDReise_FS`
|
||||||
|
|
||||||
|
Treat those as likely relationships but verify against real data.
|
||||||
|
|
||||||
|
### `BuchungTN`
|
||||||
|
|
||||||
|
Booking participant.
|
||||||
|
|
||||||
|
| Column | Type | Nullable | Notes |
|
||||||
|
| --- | --- | --- | --- |
|
||||||
|
| `IDBuchungTN` | `bigint` | no | Participant row id. |
|
||||||
|
| `IDBuchung_FS` | `bigint` | no | Booking header id. |
|
||||||
|
| `IDAdressePerson_FS` | `bigint` | no | Participant person id. |
|
||||||
|
| `IDAdresseAnschrift_FS` | `bigint` | yes | Participant postal address id. |
|
||||||
|
| `Status` | `nvarchar(2)` | no | Participant status; values need business validation. |
|
||||||
|
| `BuchungsDatum` | `datetime` | no | Booking date. |
|
||||||
|
| `StornoStatusKV` | `nvarchar(2)` | yes | Cancellation-related status. |
|
||||||
|
| `StornoDatum` | `datetime` | yes | Cancellation date. |
|
||||||
|
| `Position` | `smallint` | no | Participant position within booking. |
|
||||||
|
|
||||||
|
Known exported foreign keys:
|
||||||
|
|
||||||
|
- `BuchungTN.IDBuchung_FS -> Buchung.IDBuchung`
|
||||||
|
- `BuchungTN.IDAdressePerson_FS -> AdressePerson.IDAdressePerson`
|
||||||
|
|
||||||
|
### `Adresse`
|
||||||
|
|
||||||
|
Customer/address root.
|
||||||
|
|
||||||
|
| Column | Type | Nullable | Notes |
|
||||||
|
| --- | --- | --- | --- |
|
||||||
|
| `IDAdresse` | `bigint` | no | Address/customer id needed by the local user record. |
|
||||||
|
| `SuchName` | `nvarchar(402)` | no | Search/display name. |
|
||||||
|
| `Status` | `nvarchar(2)` | no | Address status; active values need validation. |
|
||||||
|
| `Art` | `tinyint` | no | Address type; values need validation. |
|
||||||
|
| `IDAdresseAnschrift_FS_Versandanschrift` | `bigint` | no | Default shipping/postal address. |
|
||||||
|
| `IDAdressePerson_FS_ReferenzM` | `bigint` | no | Reference person. |
|
||||||
|
| `DatumLöschungDSGVO` | `datetime` | yes | GDPR deletion marker. Exclude rows where this is not null for portal access. |
|
||||||
|
|
||||||
|
### `AdressePerson`
|
||||||
|
|
||||||
|
Person attached to an address.
|
||||||
|
|
||||||
|
| Column | Type | Nullable | Notes |
|
||||||
|
| --- | --- | --- | --- |
|
||||||
|
| `IDAdressePerson` | `bigint` | no | Person id needed by the local user record. |
|
||||||
|
| `IDAdresse_FS` | `bigint` | no | Parent address id. |
|
||||||
|
| `Name` | `nvarchar(200)` | no | Last name. |
|
||||||
|
| `Vorname` | `nvarchar(200)` | yes | First name. |
|
||||||
|
| `Geschlecht` | `nvarchar(2)` | no | Gender/salutation code. |
|
||||||
|
| `Status` | `nvarchar(2)` | no | Person status; active values need validation. |
|
||||||
|
| `Passwort` | `nvarchar(200)` | no | Legacy BusProNet password field. Do not use from `bpn-connect`; password migration remains on the BusProNet XML API until the algorithm is known. |
|
||||||
|
| `Registrierung` | `bit` | no | Registration flag; semantics need validation. |
|
||||||
|
| `IDFremd` | `nvarchar(100)` | no | External id field. |
|
||||||
|
|
||||||
|
Known exported foreign key:
|
||||||
|
|
||||||
|
- `AdressePerson.IDAdresse_FS -> Adresse.IDAdresse`
|
||||||
|
|
||||||
|
### `AdresseKommunikation`
|
||||||
|
|
||||||
|
Communication values for an address/person.
|
||||||
|
|
||||||
|
| Column | Type | Nullable | Notes |
|
||||||
|
| --- | --- | --- | --- |
|
||||||
|
| `IDAdresseKommunikation` | `bigint` | no | Communication row id. |
|
||||||
|
| `IDAdresse_FS` | `bigint` | no | Address id. |
|
||||||
|
| `IDAdressePerson_FS` | `bigint` | no | Person id. No FK was present in the export, but the name strongly implies `AdressePerson.IDAdressePerson`. |
|
||||||
|
| `Wert` | `nvarchar(512)` | no | Communication value, likely email/phone depending on type. |
|
||||||
|
| `WertTelefonie` | `nvarchar(100)` | yes | Phone-specific normalized value. |
|
||||||
|
| `IDArtKommunikation_FS` | `bigint` | no | Communication type. |
|
||||||
|
| `Status` | `nvarchar(2)` | no | Communication status; active values need validation. |
|
||||||
|
| `Newsletter` | `bit` | no | Newsletter flag. |
|
||||||
|
| `DoubleOptIn` | `bit` | no | Double opt-in flag. |
|
||||||
|
|
||||||
|
Known exported foreign keys:
|
||||||
|
|
||||||
|
- `AdresseKommunikation.IDAdresse_FS -> Adresse.IDAdresse`
|
||||||
|
- `AdresseKommunikation.IDArtKommunikation_FS -> ArtKommunikation.IDArtKommunikation`
|
||||||
|
|
||||||
|
Important missing FK:
|
||||||
|
|
||||||
|
- `AdresseKommunikation.IDAdressePerson_FS` is not exported as a FK. Join it to
|
||||||
|
`AdressePerson.IDAdressePerson` only after validating with real data.
|
||||||
|
|
||||||
|
### `ArtKommunikation`
|
||||||
|
|
||||||
|
Communication type lookup.
|
||||||
|
|
||||||
|
| Column | Type | Nullable | Notes |
|
||||||
|
| --- | --- | --- | --- |
|
||||||
|
| `IDArtKommunikation` | `bigint` | no | Type id. |
|
||||||
|
| `Langtext` | `nvarchar(200)` | yes | Long label. |
|
||||||
|
| `Kurztext` | `nvarchar(40)` | yes | Short label. |
|
||||||
|
| `Code` | `nvarchar(20)` | yes | Type code. Find the email code/id here. |
|
||||||
|
| `Status` | `nvarchar(2)` | yes | Type status. |
|
||||||
|
|
||||||
|
Before relying on email lookup queries, run:
|
||||||
|
|
||||||
|
```sql
|
||||||
|
SELECT IDArtKommunikation, Langtext, Kurztext, Code, Status
|
||||||
|
FROM dbo.ArtKommunikation
|
||||||
|
ORDER BY IDArtKommunikation;
|
||||||
|
```
|
||||||
|
|
||||||
|
Then hard-code or configure the email type ids/codes in `bpn-connect`.
|
||||||
|
|
||||||
|
### `AdresseAnschrift`
|
||||||
|
|
||||||
|
Postal address.
|
||||||
|
|
||||||
|
| Column | Type | Nullable | Notes |
|
||||||
|
| --- | --- | --- | --- |
|
||||||
|
| `IDAdresseAnschrift` | `bigint` | no | Postal address id. |
|
||||||
|
| `IDAdresse_FS` | `bigint` | no | Address id. |
|
||||||
|
| `IDAdressePerson_FS` | `bigint` | yes | Person id. |
|
||||||
|
| `Anrede` | `nvarchar(100)` | yes | Salutation. |
|
||||||
|
| `Name` | `nvarchar(400)` | yes | Postal name. |
|
||||||
|
| `Strasse` | `nvarchar(200)` | no | Street. |
|
||||||
|
| `PLZ` | `nvarchar(20)` | no | Postal code. |
|
||||||
|
| `Ort` | `nvarchar(200)` | no | City. |
|
||||||
|
| `Status` | `nvarchar(2)` | no | Postal address status. |
|
||||||
|
|
||||||
|
No direct FK from `AdresseAnschrift` to `Adresse` or `AdressePerson` was present
|
||||||
|
in the export subset shown by the current FK file. Treat these as likely
|
||||||
|
relationships and validate them with data.
|
||||||
|
|
||||||
|
### `Reise` and `Produkt`
|
||||||
|
|
||||||
|
Travel/product metadata.
|
||||||
|
|
||||||
|
`Reise` important columns:
|
||||||
|
|
||||||
|
- `IDReise`
|
||||||
|
- `IDProdukt_FS`
|
||||||
|
- `Bezeichnung`
|
||||||
|
- `Code`
|
||||||
|
- `TerminVon`
|
||||||
|
- `TerminBis`
|
||||||
|
- `Status`
|
||||||
|
- `StornoDatum`
|
||||||
|
|
||||||
|
`Produkt` important columns:
|
||||||
|
|
||||||
|
- `IDProdukt`
|
||||||
|
- `Bezeichnung`
|
||||||
|
- `Code`
|
||||||
|
- `Suchfeld`
|
||||||
|
- `Status`
|
||||||
|
|
||||||
|
Known exported foreign key:
|
||||||
|
|
||||||
|
- `Reise.IDProdukt_FS -> Produkt.IDProdukt`
|
||||||
|
|
||||||
|
## Relationship Map
|
||||||
|
|
||||||
|
Most relevant joins for portal access:
|
||||||
|
|
||||||
|
```text
|
||||||
|
Buchung.IDBuchung
|
||||||
|
-> BuchungTN.IDBuchung_FS
|
||||||
|
-> BuchungTN.IDAdressePerson_FS
|
||||||
|
-> AdressePerson.IDAdressePerson
|
||||||
|
-> AdressePerson.IDAdresse_FS
|
||||||
|
-> Adresse.IDAdresse
|
||||||
|
```
|
||||||
|
|
||||||
|
Applicant joins:
|
||||||
|
|
||||||
|
```text
|
||||||
|
Buchung.IdAdressePerson_FS_Anmelder
|
||||||
|
-> AdressePerson.IDAdressePerson
|
||||||
|
-> AdressePerson.IDAdresse_FS
|
||||||
|
-> Adresse.IDAdresse
|
||||||
|
```
|
||||||
|
|
||||||
|
Email joins to validate:
|
||||||
|
|
||||||
|
```text
|
||||||
|
AdresseKommunikation.IDAdressePerson_FS
|
||||||
|
-> AdressePerson.IDAdressePerson
|
||||||
|
|
||||||
|
AdresseKommunikation.IDAdresse_FS
|
||||||
|
-> Adresse.IDAdresse
|
||||||
|
|
||||||
|
AdresseKommunikation.IDArtKommunikation_FS
|
||||||
|
-> ArtKommunikation.IDArtKommunikation
|
||||||
|
```
|
||||||
|
|
||||||
|
## Required bpn-connect Endpoints
|
||||||
|
|
||||||
|
All endpoints are private and authenticated by API key:
|
||||||
|
|
||||||
|
```http
|
||||||
|
X-API-Key: {apiKey}
|
||||||
|
Accept: application/json
|
||||||
|
```
|
||||||
|
|
||||||
|
Keep responses narrow. `bpn-connect` should return only fields needed by the
|
||||||
|
Symfony portal and should never return BusProNet passwords, bank data, credit
|
||||||
|
card data, or broad customer records by default.
|
||||||
|
|
||||||
|
Authentication rule: Symfony owns portal passwords after a user has been
|
||||||
|
bootstrapped locally. The BusProNet legacy password algorithm is currently
|
||||||
|
unknown, so `bpn-connect` must not verify passwords from the database. Keep the
|
||||||
|
existing BusProNet XML password check only for first-time legacy migration. Once
|
||||||
|
the local Symfony password hash exists, all subsequent login/profile refresh
|
||||||
|
logic should use local authentication plus `bpn-connect` read endpoints.
|
||||||
|
|
||||||
|
### `GET /api/bookings/applicant-lookup`
|
||||||
|
|
||||||
|
Purpose: resolve an applicant by email and public booking number. This is the
|
||||||
|
core endpoint for local user creation after a booking and for the portal access
|
||||||
|
request flow.
|
||||||
|
|
||||||
|
Request:
|
||||||
|
|
||||||
|
```http
|
||||||
|
GET /api/bookings/applicant-lookup?email={email}&bookingNumber={vorgang}
|
||||||
|
```
|
||||||
|
|
||||||
|
Response `200`:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"bookingNumber": "111386",
|
||||||
|
"bookingId": 123456,
|
||||||
|
"addressId": 98765,
|
||||||
|
"personId": 54321,
|
||||||
|
"email": "[email protected]",
|
||||||
|
"firstName": "Example",
|
||||||
|
"lastName": "Customer"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Response rules:
|
||||||
|
|
||||||
|
- Return `200` when `email` belongs to `Buchung.IdAdressePerson_FS_Anmelder`
|
||||||
|
for the given `Buchung.Vorgang`.
|
||||||
|
- Return `404` when there is no matching non-deleted applicant.
|
||||||
|
- Return `409` if the query returns more than one applicant row after
|
||||||
|
deduplication. This should be rare and indicates inconsistent BusProNet data.
|
||||||
|
- Normalize input email by trimming and lowercasing before querying.
|
||||||
|
|
||||||
|
SQL:
|
||||||
|
|
||||||
|
```sql
|
||||||
|
DECLARE @Email nvarchar(512) = LOWER(LTRIM(RTRIM(@email)));
|
||||||
|
DECLARE @Vorgang nvarchar(100) = LTRIM(RTRIM(@bookingNumber));
|
||||||
|
|
||||||
|
SELECT TOP (2)
|
||||||
|
b.Vorgang AS bookingNumber,
|
||||||
|
b.IDBuchung AS bookingId,
|
||||||
|
a.IDAdresse AS addressId,
|
||||||
|
ap.IDAdressePerson AS personId,
|
||||||
|
@Email AS email,
|
||||||
|
ap.Vorname AS firstName,
|
||||||
|
ap.Name AS lastName
|
||||||
|
FROM dbo.Buchung b
|
||||||
|
INNER JOIN dbo.AdressePerson ap
|
||||||
|
ON ap.IDAdressePerson = b.IdAdressePerson_FS_Anmelder
|
||||||
|
INNER JOIN dbo.Adresse a
|
||||||
|
ON a.IDAdresse = ap.IDAdresse_FS
|
||||||
|
WHERE b.Vorgang = @Vorgang
|
||||||
|
AND a.DatumLöschungDSGVO IS NULL
|
||||||
|
AND a.Status <> 'L'
|
||||||
|
AND ap.Status <> 'L'
|
||||||
|
AND EXISTS (
|
||||||
|
SELECT 1
|
||||||
|
FROM dbo.AdresseKommunikation ak
|
||||||
|
WHERE ak.IDAdresse_FS = ap.IDAdresse_FS
|
||||||
|
AND ak.IDAdressePerson_FS = ap.IDAdressePerson
|
||||||
|
AND LOWER(LTRIM(RTRIM(ak.Wert))) = @Email
|
||||||
|
AND ak.Status <> 'L'
|
||||||
|
-- TODO: restrict to validated email communication type.
|
||||||
|
-- AND ak.IDArtKommunikation_FS IN (...)
|
||||||
|
)
|
||||||
|
ORDER BY ap.IDAdressePerson;
|
||||||
|
```
|
||||||
|
|
||||||
|
### `GET /api/customers/{addressId}/persons/{personId}`
|
||||||
|
|
||||||
|
Purpose: fetch the personal data for a known BusProNet person. Use this after a
|
||||||
|
local user exists and already stores `addressId` and `personId`. Do not use email
|
||||||
|
as the identifier because multiple `Adresse` rows can share an email address.
|
||||||
|
|
||||||
|
Request:
|
||||||
|
|
||||||
|
```http
|
||||||
|
GET /api/customers/{addressId}/persons/{personId}
|
||||||
|
```
|
||||||
|
|
||||||
|
Response `200`:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"addressId": 98765,
|
||||||
|
"personId": 54321,
|
||||||
|
"firstName": "Example",
|
||||||
|
"lastName": "Customer",
|
||||||
|
"email": "[email protected]",
|
||||||
|
"genderCode": "F",
|
||||||
|
"title": null,
|
||||||
|
"birthDate": "1980-01-01T00:00:00Z",
|
||||||
|
"nationality": "deutsch",
|
||||||
|
"nationalityCountryName": "Deutschland",
|
||||||
|
"street": "Example Street 1",
|
||||||
|
"postalCode": "12345",
|
||||||
|
"city": "Example City",
|
||||||
|
"addressCountryName": "Deutschland"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Response rules:
|
||||||
|
|
||||||
|
- Return `200` for a non-deleted address/person pair.
|
||||||
|
- Return `404` if the address/person pair does not exist or has `Status = 'L'`.
|
||||||
|
- Return only portal-editable or portal-visible fields.
|
||||||
|
|
||||||
|
SQL:
|
||||||
|
|
||||||
|
```sql
|
||||||
|
DECLARE @AddressId bigint = @addressId;
|
||||||
|
DECLARE @PersonId bigint = @personId;
|
||||||
|
|
||||||
|
SELECT
|
||||||
|
a.IDAdresse AS addressId,
|
||||||
|
ap.IDAdressePerson AS personId,
|
||||||
|
ap.Name AS lastName,
|
||||||
|
ap.Vorname AS firstName,
|
||||||
|
ap.Geschlecht AS genderCode,
|
||||||
|
ap.Titel AS title,
|
||||||
|
ap.Geburtsdatum AS birthDate,
|
||||||
|
ap.Briefanrede AS letterSalutation,
|
||||||
|
ap.Anrede AS salutation,
|
||||||
|
ap.Newsletter AS newsletter,
|
||||||
|
email.Wert AS email,
|
||||||
|
|
||||||
|
manifest.IDArtNationalitaet_FS AS nationalityId,
|
||||||
|
person_nat.Langtext AS nationalityCountryName,
|
||||||
|
person_nat.Kurztext AS nationality,
|
||||||
|
person_nat.Code AS nationalityCode,
|
||||||
|
|
||||||
|
aa.IDAdresseAnschrift AS postalAddressId,
|
||||||
|
aa.Anrede AS postalSalutation,
|
||||||
|
aa.Name AS postalName,
|
||||||
|
aa.Strasse AS street,
|
||||||
|
aa.PLZ AS postalCode,
|
||||||
|
aa.Ort AS city,
|
||||||
|
aa.Ortsteil AS district,
|
||||||
|
aa.IDArtNationalitaet_FS_Land AS addressCountryId,
|
||||||
|
address_country.Langtext AS addressCountryName,
|
||||||
|
address_country.Kurztext AS addressCountryNationality,
|
||||||
|
address_country.Code AS addressCountryCode,
|
||||||
|
|
||||||
|
ad.TelefonOK AS phoneAllowed,
|
||||||
|
ad.MailOK AS mailAllowed,
|
||||||
|
ad.PostOK AS postAllowed
|
||||||
|
FROM dbo.AdressePerson ap
|
||||||
|
INNER JOIN dbo.Adresse a
|
||||||
|
ON a.IDAdresse = ap.IDAdresse_FS
|
||||||
|
OUTER APPLY (
|
||||||
|
SELECT TOP (1)
|
||||||
|
ak.Wert
|
||||||
|
FROM dbo.AdresseKommunikation ak
|
||||||
|
WHERE ak.IDAdresse_FS = ap.IDAdresse_FS
|
||||||
|
AND ak.IDAdressePerson_FS = ap.IDAdressePerson
|
||||||
|
AND ak.Status <> 'L'
|
||||||
|
-- TODO: restrict to validated email communication type.
|
||||||
|
-- AND ak.IDArtKommunikation_FS IN (...)
|
||||||
|
ORDER BY ak.IDAdresseKommunikation DESC
|
||||||
|
) email
|
||||||
|
LEFT JOIN dbo.AdresseAnschrift aa
|
||||||
|
ON aa.IDAdresseAnschrift = ap.IDAdresseAnschrift_FS_Versandanschrift
|
||||||
|
AND aa.Status <> 'L'
|
||||||
|
LEFT JOIN dbo.ArtNationalitaet address_country
|
||||||
|
ON address_country.IDArtNationalitaet = aa.IDArtNationalitaet_FS_Land
|
||||||
|
AND COALESCE(address_country.Status, '') <> 'L'
|
||||||
|
OUTER APPLY (
|
||||||
|
SELECT TOP (1)
|
||||||
|
m.IDArtNationalitaet_FS
|
||||||
|
FROM dbo.AdressePersonManifest m
|
||||||
|
WHERE m.IDAdressePerson_FS = ap.IDAdressePerson
|
||||||
|
AND m.IDAdresse_FS = ap.IDAdresse_FS
|
||||||
|
AND COALESCE(m.Status, '') <> 'L'
|
||||||
|
ORDER BY m.IDAdressePersonManifest DESC
|
||||||
|
) manifest
|
||||||
|
LEFT JOIN dbo.ArtNationalitaet person_nat
|
||||||
|
ON person_nat.IDArtNationalitaet = manifest.IDArtNationalitaet_FS
|
||||||
|
AND COALESCE(person_nat.Status, '') <> 'L'
|
||||||
|
LEFT JOIN dbo.AdresseDatenschutz ad
|
||||||
|
ON ad.IdAdresse_FS = a.IDAdresse
|
||||||
|
WHERE a.IDAdresse = @AddressId
|
||||||
|
AND ap.IDAdressePerson = @PersonId
|
||||||
|
AND a.DatumLöschungDSGVO IS NULL
|
||||||
|
AND a.Status <> 'L'
|
||||||
|
AND ap.Status <> 'L';
|
||||||
|
```
|
||||||
|
|
||||||
|
### Optional Debug Endpoint: `GET /api/customers/by-email`
|
||||||
|
|
||||||
|
Purpose: manual investigation only. Email is not unique across `Adresse`, so this
|
||||||
|
endpoint should return a list and should not be used as a local user identifier.
|
||||||
|
|
||||||
|
Request:
|
||||||
|
|
||||||
|
```http
|
||||||
|
GET /api/customers/by-email?email={email}
|
||||||
|
```
|
||||||
|
|
||||||
|
Use the same joins as `GET /api/customers/{addressId}/persons/{personId}`, but
|
||||||
|
start from `AdresseKommunikation` and return all non-deleted matching persons.
|
||||||
|
Do not use this for account creation unless the user also provides a booking
|
||||||
|
number or another disambiguating key.
|
||||||
|
|
||||||
|
## Symfony Login And Bootstrap Replacement Plan
|
||||||
|
|
||||||
|
Current Symfony login behavior:
|
||||||
|
|
||||||
|
- Existing local users authenticate against the local Symfony password hash.
|
||||||
|
- Existing legacy local users may still have an encrypted legacy password in the
|
||||||
|
local `User.password` column. Symfony validates it locally once, then replaces
|
||||||
|
it with a Symfony password hash.
|
||||||
|
- If no local user exists, `BpnAuthenticator::bootstrapUser()` currently calls
|
||||||
|
the BusProNet XML API with email and password:
|
||||||
|
- `getPersonalDataWithPassword(email, password)`
|
||||||
|
- `getCrmAttributesWithPassword(email, password)`
|
||||||
|
- After any successful local login, `BpnAuthenticator::refreshBpnSnapshot()`
|
||||||
|
calls the BusProNet XML API by local `addressId` and `personId`:
|
||||||
|
- `getPersonalData(email, addressId, personId)`
|
||||||
|
- `getCrmAttributes(email, addressId, personId)`
|
||||||
|
|
||||||
|
Replacement rule:
|
||||||
|
|
||||||
|
- Keep login password validation local to Symfony.
|
||||||
|
- Keep the current XML password-based bootstrap for users that exist in
|
||||||
|
BusProNet but do not yet have a local Symfony user.
|
||||||
|
- On successful XML legacy verification, Symfony creates a local user with a
|
||||||
|
Symfony password hash from the submitted password.
|
||||||
|
- Future logins use only the local hash and must not call XML for password
|
||||||
|
verification.
|
||||||
|
- Replace post-login snapshot refresh with `bpn-connect` id-based read endpoints.
|
||||||
|
|
||||||
|
### Login Endpoint Usage
|
||||||
|
|
||||||
|
No `bpn-connect` endpoint is needed to authenticate a password.
|
||||||
|
|
||||||
|
Existing local user login should do:
|
||||||
|
|
||||||
|
1. Find local `User` by normalized email.
|
||||||
|
2. Validate local Symfony password hash.
|
||||||
|
3. If the local row still has a legacy encrypted local password, migrate it to a
|
||||||
|
Symfony hash without contacting BusProNet.
|
||||||
|
4. Call `GET /api/customers/{addressId}/persons/{personId}` to refresh profile
|
||||||
|
completeness.
|
||||||
|
5. Call `GET /api/customers/{addressId}/crm-attributes` to refresh roles and
|
||||||
|
hotel codes.
|
||||||
|
|
||||||
|
Missing local user login should do:
|
||||||
|
|
||||||
|
1. Call the existing BusProNet XML password-based bootstrap.
|
||||||
|
2. If valid, create a local `User` with a Symfony hash of the submitted password.
|
||||||
|
3. Store returned `addressId`, `personId`, `roles`, `hotelCodes`, and
|
||||||
|
`profileComplete`.
|
||||||
|
4. Persist and continue login.
|
||||||
|
5. If invalid, fail with the generic invalid-login message.
|
||||||
|
|
||||||
|
Do not add a `bpn-connect` password verification endpoint until the BusProNet
|
||||||
|
password algorithm is known and validated against real examples. The observed
|
||||||
|
database values do not currently match simple MD5/SHA/Base64 derivations.
|
||||||
|
|
||||||
|
### `GET /api/customers/{addressId}/crm-attributes`
|
||||||
|
|
||||||
|
Purpose: replace XML `SelektionCRM` reads used during login refresh and by the
|
||||||
|
OAuth CRM attributes endpoint.
|
||||||
|
|
||||||
|
Request:
|
||||||
|
|
||||||
|
```http
|
||||||
|
GET /api/customers/{addressId}/crm-attributes
|
||||||
|
```
|
||||||
|
|
||||||
|
Minimal response:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"roles": ["ROLE_CUSTOMER"],
|
||||||
|
"hotelCodes": []
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Detailed response may also include selection groups and CRM actions if the
|
||||||
|
current `/api/crm-attributes` response must remain compatible.
|
||||||
|
|
||||||
|
Known role mapping from the XML parser:
|
||||||
|
|
||||||
|
- `Selektionsstamm.IDSelektionsstamm = 1292` selected: `ROLE_ADMIN` and
|
||||||
|
`ROLE_HOUSE_MANAGER`
|
||||||
|
- `Selektionsstamm.IDSelektionsstamm = 1293` selected: `ROLE_MANAGER`
|
||||||
|
- `Selektionsstamm.IDSelektionsstamm = 1070` selected: `ROLE_TEAMER`
|
||||||
|
- selected `Selektionsstamm.Selektion` matching `Hausleitung {CODE}`:
|
||||||
|
`ROLE_HOUSE_MANAGER` and hotel code `{CODE}`
|
||||||
|
- admin users also receive default hotel code `SSL`
|
||||||
|
- no matched role means `ROLE_CUSTOMER`
|
||||||
|
|
||||||
|
Candidate SQL for selected customer selections:
|
||||||
|
|
||||||
|
```sql
|
||||||
|
DECLARE @AddressId bigint = @addressId;
|
||||||
|
|
||||||
|
SELECT
|
||||||
|
sg.IDSelektionsgruppenstamm AS groupId,
|
||||||
|
sg.Selektionsgruppe AS groupLabel,
|
||||||
|
s.IDSelektionsstamm AS selectionId,
|
||||||
|
s.Selektion AS selectionLabel,
|
||||||
|
CAST(1 AS bit) AS selected
|
||||||
|
FROM dbo.Selektionen sel
|
||||||
|
INNER JOIN dbo.Selektionsstamm s
|
||||||
|
ON s.IDSelektionsstamm = sel.IDSelektionsstamm_FS
|
||||||
|
LEFT JOIN dbo.Selektionsgruppe sg_map
|
||||||
|
ON sg_map.IDSelektionsstamm_FS = s.IDSelektionsstamm
|
||||||
|
LEFT JOIN dbo.Selektionsgruppenstamm sg
|
||||||
|
ON sg.IDSelektionsgruppenstamm = sg_map.IDSelektionsgruppenstamm_FS
|
||||||
|
WHERE sel.IDAdresse_FS = @AddressId
|
||||||
|
AND COALESCE(s.Status, '') <> 'L'
|
||||||
|
AND COALESCE(sg.Status, '') <> 'L'
|
||||||
|
ORDER BY sg.Position, sg.Selektionsgruppe, sg_map.Position, s.Selektion;
|
||||||
|
```
|
||||||
|
|
||||||
|
The Go service can derive `roles` and `hotelCodes` from this result with the
|
||||||
|
mapping above. Before shipping, verify whether XML `SelektionCRM` includes
|
||||||
|
unselected mutable options; if the portal only needs roles/hotel codes, selected
|
||||||
|
rows are enough.
|
||||||
|
|
||||||
|
Candidate SQL for CRM actions if compatibility is required:
|
||||||
|
|
||||||
|
```sql
|
||||||
|
DECLARE @AddressId bigint = @addressId;
|
||||||
|
|
||||||
|
SELECT
|
||||||
|
ca.IDCRMAktion AS id,
|
||||||
|
ca.Code AS code,
|
||||||
|
ca.Bezeichnung AS label,
|
||||||
|
ca.Aktiv AS selected
|
||||||
|
FROM dbo.CRMZuweisung cz
|
||||||
|
INNER JOIN dbo.CRMAktion ca
|
||||||
|
ON ca.IDCRMAktion = cz.IDCRMAktion_FS
|
||||||
|
WHERE cz.IDAdresse_FS = @AddressId
|
||||||
|
AND ca.Status <> 'L'
|
||||||
|
ORDER BY ca.Bezeichnung;
|
||||||
|
```
|
||||||
|
|
||||||
|
This needs data validation against the XML response before compatibility is
|
||||||
|
guaranteed.
|
||||||
|
|
||||||
|
## XML Calls To Replace For Local User Processes
|
||||||
|
|
||||||
|
| Current Symfony call | Current XML purpose | Replacement |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| `getPersonalData(email, addressId, personId)` | Load profile by known user ids. | `GET /api/customers/{addressId}/persons/{personId}` |
|
||||||
|
| `updatePersonalData(email, personalData)` | Persist profile edits. | Future `PATCH /api/customers/{addressId}/persons/{personId}` with transaction-safe updates. |
|
||||||
|
| `getCrmAttributes(email, addressId, personId)` | Refresh roles/hotel codes and expose CRM attributes. | `GET /api/customers/{addressId}/crm-attributes` |
|
||||||
|
| `getPersonalDataWithPassword(email, password)` | Missing-local-user bootstrap by BPN password. | Keep XML until the local user has been created/migrated. |
|
||||||
|
| `getCrmAttributesWithPassword(email, password)` | Roles for missing-local-user bootstrap by BPN password. | Keep XML until the local user has been created/migrated. |
|
||||||
|
| `register(registrationData)` | Create BusProNet address/person and local user. | Future `POST /api/customers` if direct DB writes are allowed; otherwise keep XML until write rules are known. |
|
||||||
|
| `createAddress(personalData)` | Create BusProNet address/person without mail. | Future `POST /api/customers` if direct DB writes are allowed; otherwise keep XML until write rules are known. |
|
||||||
|
|
||||||
|
Recommended migration sequence:
|
||||||
|
|
||||||
|
1. Keep XML for legacy password bootstrap only.
|
||||||
|
2. Replace booking applicant lookup for guest provisioning and portal access.
|
||||||
|
3. Replace post-login profile/CRM refresh reads.
|
||||||
|
4. Replace personal-data page reads.
|
||||||
|
5. Replace OAuth/userinfo and CRM API reads.
|
||||||
|
6. Replace booking form prefill reads.
|
||||||
|
7. Defer personal-data writes until update rules are validated.
|
||||||
|
8. Defer registration/create-address until the insert graph is known.
|
||||||
|
|
||||||
|
### Phase 1: Keep XML For Legacy Password Bootstrap
|
||||||
|
|
||||||
|
Keep these XML calls temporarily:
|
||||||
|
|
||||||
|
- `getPersonalDataWithPassword(email, password)`
|
||||||
|
- `getCrmAttributesWithPassword(email, password)`
|
||||||
|
|
||||||
|
Scope:
|
||||||
|
|
||||||
|
- Only used when no local Symfony user exists yet.
|
||||||
|
- On success, create the local user with a Symfony password hash from the
|
||||||
|
submitted password.
|
||||||
|
- Store `addressId`, `personId`, `roles`, `hotelCodes`, and `profileComplete`.
|
||||||
|
- Future logins for that user use only the local Symfony password hash.
|
||||||
|
|
||||||
|
Do not implement a `bpn-connect` password verification endpoint until the
|
||||||
|
BusProNet password algorithm is known and verified.
|
||||||
|
|
||||||
|
### Phase 2: Booking Applicant Lookup
|
||||||
|
|
||||||
|
Replace XML/fragile booking lookup plumbing with:
|
||||||
|
|
||||||
|
```http
|
||||||
|
GET /api/bookings/applicant-lookup?email={email}&bookingNumber={vorgang}
|
||||||
|
```
|
||||||
|
|
||||||
|
Symfony integration points:
|
||||||
|
|
||||||
|
- `BookingGuestAccountManager::provisionGuestAccountForBooking()`
|
||||||
|
- `BookingGuestAccountManager::requestPortalAccess()`
|
||||||
|
- booking-created welcome account provisioning
|
||||||
|
|
||||||
|
This endpoint returns only the fields needed for local user creation:
|
||||||
|
|
||||||
|
- `bookingNumber`
|
||||||
|
- `bookingId`
|
||||||
|
- `addressId`
|
||||||
|
- `personId`
|
||||||
|
- `email`
|
||||||
|
- `firstName`
|
||||||
|
- `lastName`
|
||||||
|
|
||||||
|
### Phase 3: Post-login Snapshot Refresh
|
||||||
|
|
||||||
|
Replace XML reads in `BpnAuthenticator::refreshBpnSnapshot()` with:
|
||||||
|
|
||||||
|
```http
|
||||||
|
GET /api/customers/{addressId}/persons/{personId}
|
||||||
|
GET /api/customers/{addressId}/crm-attributes
|
||||||
|
```
|
||||||
|
|
||||||
|
Symfony keeps local password validation. `bpn-connect` only refreshes ids,
|
||||||
|
profile completeness, roles, and hotel codes after the password has already been
|
||||||
|
validated locally.
|
||||||
|
|
||||||
|
### Phase 4: Personal-data Page Reads
|
||||||
|
|
||||||
|
Replace XML read in `PersonalDataController::loadPersonalData()` with:
|
||||||
|
|
||||||
|
```http
|
||||||
|
GET /api/customers/{addressId}/persons/{personId}
|
||||||
|
```
|
||||||
|
|
||||||
|
Keep `updatePersonalData()` on XML for now. Reads are low-risk; writes require
|
||||||
|
validated BusProNet update semantics.
|
||||||
|
|
||||||
|
### Phase 5: OAuth/Userinfo And CRM Reads
|
||||||
|
|
||||||
|
Replace XML reads in:
|
||||||
|
|
||||||
|
- `UserinfoController`
|
||||||
|
- `CrmAttributeController`
|
||||||
|
|
||||||
|
with:
|
||||||
|
|
||||||
|
```http
|
||||||
|
GET /api/customers/{addressId}/persons/{personId}
|
||||||
|
GET /api/customers/{addressId}/crm-attributes
|
||||||
|
```
|
||||||
|
|
||||||
|
### Phase 6: Booking Form Prefill Reads
|
||||||
|
|
||||||
|
Replace XML read in `ParticipantDataPrefiller::prefillApplicantFromUser()` with:
|
||||||
|
|
||||||
|
```http
|
||||||
|
GET /api/customers/{addressId}/persons/{personId}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Phase 7: Defer Personal-data Writes
|
||||||
|
|
||||||
|
Keep XML call:
|
||||||
|
|
||||||
|
- `updatePersonalData(email, personalData)`
|
||||||
|
|
||||||
|
Future replacement:
|
||||||
|
|
||||||
|
```http
|
||||||
|
PATCH /api/customers/{addressId}/persons/{personId}
|
||||||
|
```
|
||||||
|
|
||||||
|
Do this only after write rules are validated for:
|
||||||
|
|
||||||
|
- `AdressePerson`
|
||||||
|
- `AdresseAnschrift`
|
||||||
|
- `AdresseKommunikation`
|
||||||
|
- `AdressePersonManifest`
|
||||||
|
- `AdresseZusatzfeld` or other tables holding height, weight, shoe size, and
|
||||||
|
remarks if those are not in the core person/address tables.
|
||||||
|
|
||||||
|
### Phase 8: Defer Registration And Create-address
|
||||||
|
|
||||||
|
Keep XML calls:
|
||||||
|
|
||||||
|
- `register(registrationData)`
|
||||||
|
- `createAddress(personalData)`
|
||||||
|
|
||||||
|
Future replacement:
|
||||||
|
|
||||||
|
```http
|
||||||
|
POST /api/customers
|
||||||
|
```
|
||||||
|
|
||||||
|
This is higher risk than read replacement because it requires the full BusProNet
|
||||||
|
insert graph, required defaults, and side effects.
|
||||||
|
|
||||||
|
## Candidate SQL: Find Email Communication Type
|
||||||
|
|
||||||
|
Run once during `bpn-connect` development:
|
||||||
|
|
||||||
|
```sql
|
||||||
|
SELECT
|
||||||
|
IDArtKommunikation,
|
||||||
|
Langtext,
|
||||||
|
Kurztext,
|
||||||
|
Code,
|
||||||
|
Status
|
||||||
|
FROM dbo.ArtKommunikation
|
||||||
|
WHERE
|
||||||
|
LOWER(COALESCE(Langtext, '')) LIKE '%mail%'
|
||||||
|
OR LOWER(COALESCE(Kurztext, '')) LIKE '%mail%'
|
||||||
|
OR LOWER(COALESCE(Code, '')) LIKE '%mail%'
|
||||||
|
ORDER BY IDArtKommunikation;
|
||||||
|
```
|
||||||
|
|
||||||
|
If the data uses German labels, also inspect all rows manually. The schema alone
|
||||||
|
cannot prove the canonical email type.
|
||||||
|
|
||||||
|
## Candidate SQL: Validate Missing Relationships
|
||||||
|
|
||||||
|
Use these checks before shipping lookup logic:
|
||||||
|
|
||||||
|
```sql
|
||||||
|
-- Check whether AdresseKommunikation.IDAdressePerson_FS is a real person link.
|
||||||
|
SELECT TOP (20)
|
||||||
|
ak.IDAdresseKommunikation,
|
||||||
|
ak.IDAdresse_FS,
|
||||||
|
ak.IDAdressePerson_FS,
|
||||||
|
ap.IDAdressePerson,
|
||||||
|
ap.IDAdresse_FS AS PersonAddressId,
|
||||||
|
ak.Wert
|
||||||
|
FROM dbo.AdresseKommunikation ak
|
||||||
|
LEFT JOIN dbo.AdressePerson ap
|
||||||
|
ON ap.IDAdressePerson = ak.IDAdressePerson_FS
|
||||||
|
WHERE ak.IDAdressePerson_FS <> 0
|
||||||
|
AND ap.IDAdressePerson IS NULL;
|
||||||
|
```
|
||||||
|
|
||||||
|
```sql
|
||||||
|
-- Check whether Buchung.IDAdresse_FS_Anmelder matches the applicant person's address.
|
||||||
|
SELECT TOP (100)
|
||||||
|
b.IDBuchung,
|
||||||
|
b.Vorgang,
|
||||||
|
b.IDAdresse_FS_Anmelder,
|
||||||
|
b.IdAdressePerson_FS_Anmelder,
|
||||||
|
ap.IDAdresse_FS AS ApplicantPersonAddressId
|
||||||
|
FROM dbo.Buchung b
|
||||||
|
LEFT JOIN dbo.AdressePerson ap
|
||||||
|
ON ap.IDAdressePerson = b.IdAdressePerson_FS_Anmelder
|
||||||
|
WHERE b.IDAdresse_FS_Anmelder IS NOT NULL
|
||||||
|
AND ap.IDAdresse_FS <> b.IDAdresse_FS_Anmelder;
|
||||||
|
```
|
||||||
|
|
||||||
|
```sql
|
||||||
|
-- Inspect status values before adding active-only predicates.
|
||||||
|
SELECT 'Adresse' AS table_name, Status, COUNT(*) AS rows
|
||||||
|
FROM dbo.Adresse
|
||||||
|
GROUP BY Status
|
||||||
|
UNION ALL
|
||||||
|
SELECT 'AdressePerson', Status, COUNT(*)
|
||||||
|
FROM dbo.AdressePerson
|
||||||
|
GROUP BY Status
|
||||||
|
UNION ALL
|
||||||
|
SELECT 'AdresseKommunikation', Status, COUNT(*)
|
||||||
|
FROM dbo.AdresseKommunikation
|
||||||
|
GROUP BY Status
|
||||||
|
UNION ALL
|
||||||
|
SELECT 'BuchungTN', Status, COUNT(*)
|
||||||
|
FROM dbo.BuchungTN
|
||||||
|
GROUP BY Status
|
||||||
|
ORDER BY table_name, Status;
|
||||||
|
```
|
||||||
|
|
||||||
|
## Indexes To Confirm Or Add
|
||||||
|
|
||||||
|
The current CSV files do not include index definitions. For the lookup endpoint,
|
||||||
|
confirm whether these access paths already exist:
|
||||||
|
|
||||||
|
- `Buchung(Vorgang)` including `IDBuchung`, `IdAdressePerson_FS_Anmelder`
|
||||||
|
- `BuchungTN(IDBuchung_FS)` including `IDAdressePerson_FS`, `Status`
|
||||||
|
- `AdressePerson(IDAdressePerson)` including `IDAdresse_FS`, `Vorname`, `Name`,
|
||||||
|
`Status`
|
||||||
|
- `AdresseKommunikation(IDAdressePerson_FS, Wert)` including `IDAdresse_FS`,
|
||||||
|
`IDArtKommunikation_FS`, `Status`
|
||||||
|
- `AdresseKommunikation(IDAdresse_FS, Wert)` including `IDAdressePerson_FS`,
|
||||||
|
`IDArtKommunikation_FS`, `Status`
|
||||||
|
|
||||||
|
If the database collation is case-sensitive and email lookup must be
|
||||||
|
case-insensitive, avoid `LOWER(Wert)` on large tables unless a computed
|
||||||
|
normalized-email column or suitable index exists.
|
||||||
|
|
||||||
|
## Future Endpoint Candidates
|
||||||
|
|
||||||
|
The XML plumbing can be replaced incrementally by small read endpoints backed by
|
||||||
|
targeted SQL:
|
||||||
|
|
||||||
|
| Endpoint | Purpose | Core tables |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| `GET /api/bookings/lookup` | Resolve email + public booking number to booking/person/address ids. | `Buchung`, `BuchungTN`, `AdressePerson`, `AdresseKommunikation`, `Adresse` |
|
||||||
|
| `GET /api/bookings/{bookingId}` | Fetch booking header/detail by internal id. | `Buchung`, `Reise`, `Produkt`, `BuchungTN` |
|
||||||
|
| `GET /api/bookings/{bookingId}/participants` | Fetch participants for a booking. | `BuchungTN`, `AdressePerson`, `AdresseAnschrift` |
|
||||||
|
| `GET /api/customers/{addressId}/persons/{personId}` | Fetch a minimal customer/person profile. | `Adresse`, `AdressePerson`, `AdresseKommunikation`, `AdresseAnschrift` |
|
||||||
|
|
||||||
|
Keep endpoint responses narrow. Return only ids and fields needed by the Symfony
|
||||||
|
portal so the Go service does not become a broad BusProNet data mirror.
|
||||||
|
|
||||||
|
## Regeneration Notes
|
||||||
|
|
||||||
|
When new catalog exports are added, regenerate this document with:
|
||||||
|
|
||||||
|
1. Columns export from `sys.tables`, `sys.schemas`, `sys.columns`, `sys.types`.
|
||||||
|
2. Foreign key export from `sys.foreign_keys` and related FK columns.
|
||||||
|
3. Primary-key export from `sys.key_constraints`.
|
||||||
|
4. Index export from `sys.indexes`, `sys.index_columns`, and `sys.columns`.
|
||||||
|
|
||||||
|
Primary keys and indexes should be added to the table sections and the lookup
|
||||||
|
query should be revisited once the real access paths are known.
|
||||||
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,971 @@
|
|||||||
|
"foreign_key_name";"child_schema";"child_table";"child_column";"parent_schema";"parent_table";"parent_column"
|
||||||
|
"FK_Tarif_Schulamt";"dbo";"ABOSummeFahrscheine";"IDAdresse_FS_Schulamt";"dbo";"Schulamt";"IDSchulamt"
|
||||||
|
"FK_Tarif_Schule";"dbo";"ABOSummeFahrscheine";"IDAdresse_FS_Schule";"dbo";"Schule";"IDSchule"
|
||||||
|
"FK_Tarif_Schuljahr";"dbo";"ABOSummeFahrscheine";"IDABOSchuljahr_FS";"dbo";"ABOSchuljahr";"IDABOSchuljahr"
|
||||||
|
"FK_AdressAuswertungProtokoll_Adresse";"dbo";"AdressAuswertungProtokoll";"IDAdresse_FS_Sachbearbeiter";"dbo";"Adresse";"IDAdresse"
|
||||||
|
"FK_AdresseAgenturKatalog_Adresse";"dbo";"AdresseAgenturKatalog";"IDAdresse_FS";"dbo";"Adresse";"IDAdresse"
|
||||||
|
"FK_AdresseAgenturKatalog_ArtKatalog";"dbo";"AdresseAgenturKatalog";"IDArtKatalog_FS";"dbo";"ArtKatalog";"IDArtKatalog"
|
||||||
|
"FK_AdresseAgenturOrganisation_Adresse";"dbo";"AdresseAgenturOrganisation";"IDAdresse_FS";"dbo";"Adresse";"IDAdresse"
|
||||||
|
"FK_AdresseAgenturOrganisation_ArtAgenturOrganisation";"dbo";"AdresseAgenturOrganisation";"IDArtAgenturOrganisation_FS";"dbo";"ArtAgenturOrganisation";"IDArtAgenturOrganisation"
|
||||||
|
"FK_AdresseAgenturProvision_Adresse";"dbo";"AdresseAgenturProvision";"IDArtProvisionsstaffel_FS";"dbo";"ArtProvisionsstaffel";"IDArtProvisionsstaffel"
|
||||||
|
"FK_AdresseAgenturProvision_Adresse1";"dbo";"AdresseAgenturProvision";"IDAdresse_FS";"dbo";"Adresse";"IDAdresse"
|
||||||
|
"FK_AdresseAgenturZusatz_Adresse";"dbo";"AdresseAgenturZusatz";"IDAdresse_FS";"dbo";"Adresse";"IDAdresse"
|
||||||
|
"FK_AdresseAgenturZusatz_ArtAgenturPreisgruppe";"dbo";"AdresseAgenturZusatz";"IDArtAgenturPreisgruppe_FS";"dbo";"ArtAgenturPreisgruppe";"IDArtAgenturPreisgruppe"
|
||||||
|
"FK_AdresseAgenturZusatz_ArtPreisschema";"dbo";"AdresseAgenturZusatz";"IDArtPreisschema_FS";"dbo";"ArtPreisschema";"IDArtPreisschema"
|
||||||
|
"FK_AdresseAnruf_Adresse";"dbo";"AdresseAnruf";"IDAdresse_FS";"dbo";"Adresse";"IDAdresse"
|
||||||
|
"FK_AdresseAnschriftKoordinate_AdresseAnschrift";"dbo";"AdresseAnschriftKoordinate";"IDAdresseAnschrift_FS";"dbo";"AdresseAnschrift";"IDAdresseAnschrift"
|
||||||
|
"FK_AdresseAnschriftKoordinate_ArtZustiegKoordinaten";"dbo";"AdresseAnschriftKoordinate";"IDArtZustiegKoordinaten_FS";"dbo";"ArtZustiegKoordinaten";"IDArtZustiegKoordinaten"
|
||||||
|
"FK_Adresse_Bankverbindung";"dbo";"AdresseBankverbindung";"IDAdresse_FS";"dbo";"Adresse";"IDAdresse"
|
||||||
|
"FK_Adresse_Bearbeitung";"dbo";"AdresseBearbeitung";"IDAdresse_FS";"dbo";"Adresse";"IDAdresse"
|
||||||
|
"FK_Adresse_Bearbeitung_ErsterSachbearbeiter";"dbo";"AdresseBearbeitung";"IDAdresse_FS_ErsterSachbearbeiter";"dbo";"Adresse";"IDAdresse"
|
||||||
|
"FK_Adresse_Bearbeitung_LetzterSachbearbeiter";"dbo";"AdresseBearbeitung";"IDAdresse_FS_LetzterSachbearbeiter";"dbo";"Adresse";"IDAdresse"
|
||||||
|
"FK_AdresseCRS_Adresse";"dbo";"AdresseCRS";"IDAdresse_FS";"dbo";"Adresse";"IDAdresse"
|
||||||
|
"FK_AdresseCRS_ArtCRS";"dbo";"AdresseCRS";"IDArtCRS_FS";"dbo";"ArtCRS";"IDArtCRS"
|
||||||
|
"FK_AdresseDatenschutz_Adresse";"dbo";"AdresseDatenschutz";"IdAdresse_FS";"dbo";"Adresse";"IDAdresse"
|
||||||
|
"FK_AdresseEmpfehlerKonto_Adresse";"dbo";"AdresseEmpfehlerKonto";"IDAdresse_FS_Empfehler";"dbo";"Adresse";"IDAdresse"
|
||||||
|
"FK_AdresseEmpfehlerKonto_Adresse1";"dbo";"AdresseEmpfehlerKonto";"IDAdresse_FS_Empfohlener";"dbo";"Adresse";"IDAdresse"
|
||||||
|
"FK_AdresseHinweis_Adresse";"dbo";"AdresseHinweis";"IDAdresse_FS";"dbo";"Adresse";"IDAdresse"
|
||||||
|
"FK_AdresseHistorie_Adresse";"dbo";"AdresseHistorie";"IDAdresse_FS";"dbo";"Adresse";"IDAdresse"
|
||||||
|
"FK_AdresseHistorieBuchungTN_Adresse";"dbo";"AdresseHistorieBuchungTN";"IDAdresseHistorie_FS";"dbo";"Adresse";"IDAdresse"
|
||||||
|
"FK_AdresseHistorieMietbus_Adresse";"dbo";"AdresseHistorieMietbus";"IDAdresse_FS";"dbo";"Adresse";"IDAdresse"
|
||||||
|
"FK_Adresse_Kommunikation";"dbo";"AdresseKommunikation";"IDAdresse_FS";"dbo";"Adresse";"IDAdresse"
|
||||||
|
"FK_AdresseKommunikation_ArtKommunikation";"dbo";"AdresseKommunikation";"IDArtKommunikation_FS";"dbo";"ArtKommunikation";"IDArtKommunikation"
|
||||||
|
"FK_Adresse_Kreditkarte";"dbo";"AdresseKreditkarte";"IDAdresse_FS";"dbo";"Adresse";"IDAdresse"
|
||||||
|
"FK_AdresseLandSteuer_Adresse";"dbo";"AdresseLandSteuer";"IDAdresse_FS";"dbo";"Adresse";"IDAdresse"
|
||||||
|
"FK_AdresseLandSteuer_Land";"dbo";"AdresseLandSteuer";"IDLand_FS";"dbo";"Land";"IDLand"
|
||||||
|
"FK_AdresseLinieAuftraggeber_Adresse";"dbo";"AdresseLinieAuftraggeber";"IDAdresse_FS";"dbo";"Adresse";"IDAdresse"
|
||||||
|
"FK_AdresseLinieAuftraggeber_ArtStatistikGruppe";"dbo";"AdresseLinieAuftraggeber";"IDArtStatistikGruppe_FS";"dbo";"ArtStatistikGruppe";"IDArtStatistikGruppe"
|
||||||
|
"FK_AdresseLinieAuftraggeberBlock_Adresse";"dbo";"AdresseLinieAuftraggeberBlock";"IDAdresse_FS";"dbo";"Adresse";"IDAdresse"
|
||||||
|
"FK_AdresseLinieAuftraggeberBlock_AdresseLinieAuftraggeber";"dbo";"AdresseLinieAuftraggeberBlock";"IDAdresseLinieAuftraggeber_FS";"dbo";"AdresseLinieAuftraggeber";"IDAdresseLinieAuftraggeber"
|
||||||
|
"FK_AdresseLinieAuftraggeberLinie_Adresse";"dbo";"AdresseLinieAuftraggeberLinie";"IDAdresse_FS";"dbo";"Adresse";"IDAdresse"
|
||||||
|
"FK_AdresseLinieAuftraggeberLinie_AdresseLinieAuftraggeber";"dbo";"AdresseLinieAuftraggeberLinie";"IDAdresseLinieAuftraggeber_FS";"dbo";"AdresseLinieAuftraggeber";"IDAdresseLinieAuftraggeber"
|
||||||
|
"FK_AdresseLinieAuftraggeberTour_Adresse";"dbo";"AdresseLinieAuftraggeberTour";"IDAdresse_FS";"dbo";"Adresse";"IDAdresse"
|
||||||
|
"FK_AdresseLinieAuftraggeberTour_AdresseLinieAuftraggeber";"dbo";"AdresseLinieAuftraggeberTour";"IDAdresseLinieAuftraggeber_FS";"dbo";"AdresseLinieAuftraggeber";"IDAdresseLinieAuftraggeber"
|
||||||
|
"FK_AdressMandant_Adresse";"dbo";"AdresseMandant";"IDAdresse_FS";"dbo";"Adresse";"IDAdresse"
|
||||||
|
"FK_AdresseMandantDokumentAusgabe_Adresse";"dbo";"AdresseMandantDokumentAusgabe";"IDAdresse_FS";"dbo";"Adresse";"IDAdresse"
|
||||||
|
"FK_AdresseMandantDokumentAusgabe_ArtDokumentAusgabe";"dbo";"AdresseMandantDokumentAusgabe";"IDArtDokumentAusgabe_FS";"dbo";"ArtDokumentAusgabe";"IDArtDokumentAusgabe"
|
||||||
|
"FK_AdresseMandantERechnung_Adresse";"dbo";"AdresseMandantERechnung";"IDAdresse_FS_Mandant";"dbo";"Adresse";"IDAdresse"
|
||||||
|
"FK_AdresseMandantERechnungBV_AdresseBankverbindung";"dbo";"AdresseMandantERechnungBV";"IDAdresseBankverbindung_FS";"dbo";"AdresseBankverbindung";"IDAdresseBankverbindung"
|
||||||
|
"FK_AdresseMandantERechnungBV_AdresseMandantERechnung";"dbo";"AdresseMandantERechnungBV";"IDAdresseMandantERechnung_FS";"dbo";"AdresseMandantERechnung";"IDAdresseMandantERechnung"
|
||||||
|
"FK_AdresseMandantNummernkreis_Adresse";"dbo";"AdresseMandantNummernkreis";"IDAdresse_FS";"dbo";"Adresse";"IDAdresse"
|
||||||
|
"FK_AdresseMandantNummernkreis_Nummernkreis";"dbo";"AdresseMandantNummernkreis";"IDNummernkreis_FS";"dbo";"Nummernkreis";"IDNummernkreis"
|
||||||
|
"FK_Adresse_Person";"dbo";"AdressePerson";"IDAdresse_FS";"dbo";"Adresse";"IDAdresse"
|
||||||
|
"FK_AdressePersonal_Adresse";"dbo";"AdressePersonal";"IDAdresse_FS";"dbo";"Adresse";"IDAdresse"
|
||||||
|
"FK_AdressePersonal_ArtBetriebshof";"dbo";"AdressePersonal";"IDArtBetriebshof_FS";"dbo";"ArtBetriebshof";"IDArtBetriebshof"
|
||||||
|
"FK_AdressePersonal_ArtLohnMandant";"dbo";"AdressePersonal";"IDArtLohnMandant_FS";"dbo";"ArtLohnMandant";"IDArtLohnMandant"
|
||||||
|
"FK_AdressePersonal_ArtPersonalEinsatz";"dbo";"AdressePersonal";"IDArtPersonalEinsatz_FS";"dbo";"ArtPersonalEinsatz";"IDArtPersonalEinsatz"
|
||||||
|
"FK_AdressePersonal_ArtPersonalGruppeKompetenz";"dbo";"AdressePersonal";"IDArtPersonalGruppeKompetenz_FS";"dbo";"ArtPersonalGruppeKompetenz";"IDArtPersonalGruppeKompetenz"
|
||||||
|
"FK_AdressePersonalArt_Adresse";"dbo";"AdressePersonalArt";"IDAdresse_FS";"dbo";"Adresse";"IDAdresse"
|
||||||
|
"FK_AdressePersonalGruppeProdukt_Adresse";"dbo";"AdressePersonalGruppeProdukt";"IDAdresse_FS";"dbo";"Adresse";"IDAdresse"
|
||||||
|
"FK_AdressePersonalGruppeProdukt_ArtPersonalGruppeProdukt";"dbo";"AdressePersonalGruppeProdukt";"IDArtPersonalGruppeProdukt_FS";"dbo";"ArtPersonalGruppeProdukt";"IDArtPersonalGruppeProdukt"
|
||||||
|
"FK_AdressePersonalKleidung_Adresse";"dbo";"AdressePersonalKleidung";"IDAdresse_FS";"dbo";"Adresse";"IDAdresse"
|
||||||
|
"FK_AdressePersonalKleidung_ArtPersonalKleidung";"dbo";"AdressePersonalKleidung";"IDArtPersonalKleidung_FS";"dbo";"ArtPersonalKleidung";"IDArtPersonalKleidung"
|
||||||
|
"FK_AdressePersonalNummer_Adresse";"dbo";"AdressePersonalNummer";"IDAdresse_FS";"dbo";"Adresse";"IDAdresse"
|
||||||
|
"FK_AdressePersonalNummer_ArtPersonalNummer";"dbo";"AdressePersonalNummer";"IDArtPersonalNummer_FS";"dbo";"ArtPersonalNummer";"IDArtPersonalNummer"
|
||||||
|
"FK_AdressePersonalPunkte_Adresse";"dbo";"AdressePersonalPunkte";"IDAdresse_FS";"dbo";"Adresse";"IDAdresse"
|
||||||
|
"FK_AdressePersonalSonstGegenstaende_Adresse";"dbo";"AdressePersonalSonstGegenstaende";"IDAdresse_FS";"dbo";"Adresse";"IDAdresse"
|
||||||
|
"FK_AdressePersonalSonstGegenstaende_ArtPersonalSonstGegenstaende";"dbo";"AdressePersonalSonstGegenstaende";"IDArtPersonalSonstGegenstaende_FS";"dbo";"ArtPersonalSonstGegenstaende";"IDArtPersonalSonstGegenstaende"
|
||||||
|
"FK_AdressePersonalSperrKasse_Adresse";"dbo";"AdressePersonalSperrKasse";"IDAdresse_FS";"dbo";"Adresse";"IDAdresse"
|
||||||
|
"FK_AdressePersonalSperrKasse_ZahlungStamm";"dbo";"AdressePersonalSperrKasse";"IDZahlungStamm_FS";"dbo";"ZahlungStamm";"IDZahlungStamm"
|
||||||
|
"FK_AdressePersonalUnfall_Adresse";"dbo";"AdressePersonalUnfall";"IDAdresse_FS";"dbo";"Adresse";"IDAdresse"
|
||||||
|
"FK_AdressePersonalVerwendung_Adresse";"dbo";"AdressePersonalVerwendung";"IDAdresse_FS";"dbo";"Adresse";"IDAdresse"
|
||||||
|
"FK_AdressePersonalZusatz_Adresse";"dbo";"AdressePersonalZusatz";"IDAdresse_FS";"dbo";"Adresse";"IDAdresse"
|
||||||
|
"FK_AdressePersonalZusatz_SpracheMaske";"dbo";"AdressePersonalZusatz";"IDSpracheMaske_FS";"dbo";"SpracheMaske";"IDSpracheMaske"
|
||||||
|
"FK_AdressePunkte_Adresse";"dbo";"AdressePunkte";"IDAdresse_FS";"dbo";"Adresse";"IDAdresse"
|
||||||
|
"FK_AdressePunkte_Adresse1";"dbo";"AdressePunkte";"IDAdresse_FS_Sachbearbeiter";"dbo";"Adresse";"IDAdresse"
|
||||||
|
"FK_AdresseSteueraufteilungDetail_Adresse";"dbo";"AdresseSteueraufteilungDetail";"IDAdresse_FS";"dbo";"Adresse";"IDAdresse"
|
||||||
|
"FK_AdresseSteueraufteilungDetail_Steueraufteilung";"dbo";"AdresseSteueraufteilungDetail";"IDSteueraufteilungDetail_FS";"dbo";"SteueraufteilungDetail";"IDSteueraufteilungDetail"
|
||||||
|
"FK_AdresseZusatz_Adresse";"dbo";"AdresseZusatz";"IDAdresse_FS";"dbo";"Adresse";"IDAdresse"
|
||||||
|
"FK_AdresseZusatzfeld_Adresse";"dbo";"AdresseZusatzfeld";"IDAdresse_FS";"dbo";"Adresse";"IDAdresse"
|
||||||
|
"FK_AdresseZusatzfeld_AdressePerson";"dbo";"AdresseZusatzfeld";"IDAdressePerson_FS";"dbo";"AdressePerson";"IDAdressePerson"
|
||||||
|
"FK_AdresseZusatzfeld_ArtAdresseZusatzfeld";"dbo";"AdresseZusatzfeld";"IDArtAdresseZusatzfeld_FS";"dbo";"ArtAdresseZusatzfeld";"IDArtAdresseZusatzfeld"
|
||||||
|
"FK_AdresseMietbusZusatz_Adresse";"dbo";"AdresseZusatzMietbus";"IDAdresse_FS";"dbo";"Adresse";"IDAdresse"
|
||||||
|
"FK_Adresse_AgenturSelektion";"dbo";"AgenturSelektionenKunde";"IDAdresse_FS";"dbo";"Adresse";"IDAdresse"
|
||||||
|
"FK_Selektionsstamm_AgenturSelektion";"dbo";"AgenturSelektionenKunde";"IDSelektionsstamm_FS";"dbo";"Selektionsstamm";"IDSelektionsstamm"
|
||||||
|
"FK_ArbeitswertMaterial_Arbeitswert";"dbo";"ArbeitswertMaterial";"IDArbeitswert_FS";"dbo";"Arbeitswert";"IDArbeitswert"
|
||||||
|
"FK_ArbeitswertMaterial_Artikel";"dbo";"ArbeitswertMaterial";"IDArtikel_FS";"dbo";"Artikel";"IDArtikel"
|
||||||
|
"FK_ArbeitswertPersonal_Arbeitswert";"dbo";"ArbeitswertPersonal";"IDArbeitswert_FS";"dbo";"Arbeitswert";"IDArbeitswert"
|
||||||
|
"FK_ArbeitswertPersonal_Arbeitszeitwert";"dbo";"ArbeitswertPersonal";"IDArbeitszeitwert_FS";"dbo";"Arbeitszeitwert";"IDArbeitszeitwert"
|
||||||
|
"FK_ArtArbeitszeitZusatzEinst_ArtArbeitszeitZusatz";"dbo";"ArtArbeitszeitZusatzEinst";"IDArtArbeitszeitZusatz_FS";"dbo";"ArtArbeitszeitzusatz";"IDArtArbeitszeitzusatz"
|
||||||
|
"FK_ArtikelBewegung_Artikel";"dbo";"ArtikelBewegung";"IDArtikel_FS";"dbo";"Artikel";"IDArtikel"
|
||||||
|
"FK_ArtikelImport_ArtArtikelImport";"dbo";"ArtikelImport";"IDArtArtikelImport_FS";"dbo";"ArtArtikelImport";"IDArtArtikelImport"
|
||||||
|
"FK_Artikelzusatz_ArtEinheit";"dbo";"Artikelzusatz";"IDArtEinheit_FS";"dbo";"ArtEinheit";"IDArtEinheit"
|
||||||
|
"FK_ArtikelZuweisungWarengruppe_Artikel";"dbo";"ArtikelZuweisungWarengruppe";"IDArtikel_FS";"dbo";"Artikel";"IDArtikel"
|
||||||
|
"FK_ArtikelZuweisungWarengruppe_Warengruppe";"dbo";"ArtikelZuweisungWarengruppe";"IDArtWarengruppe_FS";"dbo";"ArtWarengruppe";"IDArtWarengruppe"
|
||||||
|
"FK_Auftrag_Adresse3";"dbo";"Auftrag";"IDAdresse_FS_Kunde";"dbo";"Adresse";"IDAdresse"
|
||||||
|
"FK_Auftrag_Auftragsart";"dbo";"Auftrag";"IDAuftragsart_FS";"dbo";"Auftragsart";"IDAuftragsart"
|
||||||
|
"FK_AuftragBlock_Auftrag";"dbo";"AuftragBlock";"IDAuftrag_FS";"dbo";"Auftrag";"IDAuftrag"
|
||||||
|
"FK_AuftragFahrer_Auftrag";"dbo";"AuftragFahrer";"IDAuftrag_FS";"dbo";"Auftrag";"IDAuftrag"
|
||||||
|
"FK_AuftragFahrer_AuftragFahrzeug";"dbo";"AuftragFahrer";"IDAuftragFahrzeug_FS";"dbo";"AuftragFahrzeug";"IDAuftragFahrzeug"
|
||||||
|
"FK_AuftragFahrer_AuftragTeilauftrag";"dbo";"AuftragFahrer";"IDAuftragTeilauftrag_FS";"dbo";"AuftragTeilauftrag";"IDAuftragTeilauftrag"
|
||||||
|
"FK_AuftragFahrerArbeitszeit_ArtArbeitszeitzusatz";"dbo";"AuftragFahrerArbeitszeit";"IDArtArbeitszeitzusatz_FS";"dbo";"ArtArbeitszeitzusatz";"IDArtArbeitszeitzusatz"
|
||||||
|
"FK_AuftragFahrerArbeitszeit_AuftragFahrer";"dbo";"AuftragFahrerArbeitszeit";"IDAuftragFahrer_FS";"dbo";"AuftragFahrer";"IDAuftragFahrer"
|
||||||
|
"FK_AuftragFahrerArbeitszeitSpesen_AuftragFahrer";"dbo";"AuftragFahrerArbeitszeitSpesen";"IDAuftragFahrer_FS";"dbo";"AuftragFahrer";"IDAuftragFahrer"
|
||||||
|
"FK_AuftragFahrerTagesStunden_AuftragFahrer";"dbo";"AuftragFahrerTagesStunden";"IDAuftragFahrer_FS";"dbo";"AuftragFahrer";"IDAuftragFahrer"
|
||||||
|
"FK_AuftragFahrzeug_Auftrag";"dbo";"AuftragFahrzeug";"IDAuftrag_FS";"dbo";"Auftrag";"IDAuftrag"
|
||||||
|
"FK_AuftragFahrzeug_AuftragTeilauftrag";"dbo";"AuftragFahrzeug";"IDAuftragTeilauftrag_FS";"dbo";"AuftragTeilauftrag";"IDAuftragTeilauftrag"
|
||||||
|
"FK_AuftragFahrzeugNavi_AuftragFahrzeug";"dbo";"AuftragFahrzeugNavi";"IDAuftragFahrzeug_FS";"dbo";"AuftragFahrzeug";"IDAuftragFahrzeug"
|
||||||
|
"FK_AuftragFahrzeugNavi_Fahrzeug";"dbo";"AuftragFahrzeugNavi";"IDFahrzeug_FS";"dbo";"Fahrzeug";"IDFahrzeug"
|
||||||
|
"FK_AuftragFahrzeugNaviGrenzuebertritt_AuftragFahrzeug";"dbo";"AuftragFahrzeugNaviGrenzuebertritt";"IDAuftragFahrzeug_FS";"dbo";"AuftragFahrzeug";"IDAuftragFahrzeug"
|
||||||
|
"FK_AuftragFahrzeugTagesKM_AuftragFahrzeug";"dbo";"AuftragFahrzeugTagesKM";"IDAuftragFahrzeug_FS";"dbo";"AuftragFahrzeug";"IDAuftragFahrzeug"
|
||||||
|
"FK_AuftragInkludierteLeistung_Auftrag";"dbo";"AuftragInkludierteLeistung";"IDAuftrag_FS";"dbo";"Auftrag";"IDAuftrag"
|
||||||
|
"FK_AuftragInkludierteLeistung_AuftragTeilauftrag";"dbo";"AuftragInkludierteLeistung";"IDAuftragTeilauftrag_FS";"dbo";"AuftragTeilauftrag";"IDAuftragTeilauftrag"
|
||||||
|
"FK_AuftragNebenleistung_Auftrag";"dbo";"AuftragInkludierteLeistung";"IDAuftrag_FS";"dbo";"Auftrag";"IDAuftrag"
|
||||||
|
"FK_AuftragNebenleistung_AuftragTeilauftrag";"dbo";"AuftragInkludierteLeistung";"IDAuftragTeilauftrag_FS";"dbo";"AuftragTeilauftrag";"IDAuftragTeilauftrag"
|
||||||
|
"FK_AuftragKalkulationswert_Auftrag";"dbo";"AuftragKalkulationswert";"IDAuftrag_FS";"dbo";"Auftrag";"IDAuftrag"
|
||||||
|
"FK_AuftragKalkulationswert_AuftragTeilauftrag";"dbo";"AuftragKalkulationswert";"IDAuftragTeilauftrag_FS";"dbo";"AuftragTeilauftrag";"IDAuftragTeilauftrag"
|
||||||
|
"FK_AuftragKilometer_Auftrag";"dbo";"AuftragKilometer";"IDAuftrag_FS";"dbo";"Auftrag";"IDAuftrag"
|
||||||
|
"FK_AuftragKilometer_AuftragFahrzeug";"dbo";"AuftragKilometer";"IDAuftragFahrzeug_FS";"dbo";"AuftragFahrzeug";"IDAuftragFahrzeug"
|
||||||
|
"FK_AuftragKilometer_AuftragTeilauftrag";"dbo";"AuftragKilometer";"IDAuftragTeilauftrag_FS";"dbo";"AuftragTeilauftrag";"IDAuftragTeilauftrag"
|
||||||
|
"FK_AuftragKilometerLand_Auftrag";"dbo";"AuftragKilometerLand";"IDAuftrag_FS";"dbo";"Auftrag";"IDAuftrag"
|
||||||
|
"FK_AuftragKilometerLand_AuftragFahrzeug";"dbo";"AuftragKilometerLand";"IDAuftragFahrzeug_FS";"dbo";"AuftragFahrzeug";"IDAuftragFahrzeug"
|
||||||
|
"FK_AuftragKilometerLand_AuftragKilometer";"dbo";"AuftragKilometerLand";"IDAuftragKilometer_FS";"dbo";"AuftragKilometer";"IDAuftragKilometer"
|
||||||
|
"FK_AuftragKilometerLand_AuftragTeilauftrag";"dbo";"AuftragKilometerLand";"IDAuftragTeilauftrag_FS";"dbo";"AuftragTeilauftrag";"IDAuftragTeilauftrag"
|
||||||
|
"FK_AuftragKilometerLand_Land";"dbo";"AuftragKilometerLand";"IDLand_FS";"dbo";"Land";"IDLand"
|
||||||
|
"FK_AuftragsartMwst_Auftragsart";"dbo";"AuftragsartMwst";"IDAuftragsart_FS";"dbo";"Auftragsart";"IDAuftragsart"
|
||||||
|
"FK_AuftragSuche_Adresse1";"dbo";"AuftragSuche";"IDAdresse_FS_Kunde";"dbo";"Adresse";"IDAdresse"
|
||||||
|
"FK_AuftragSuche_Auftrag";"dbo";"AuftragSuche";"IDAuftrag_FS";"dbo";"Auftrag";"IDAuftrag"
|
||||||
|
"FK_AuftragSuche_Auftragsart";"dbo";"AuftragSuche";"IDAuftragsArt_FS";"dbo";"Auftragsart";"IDAuftragsart"
|
||||||
|
"FK_AuftragTAAbholstelle_AuftragTeilauftrag";"dbo";"AuftragTAAbholstelle";"IDAuftragTeilauftrag_FS";"dbo";"AuftragTeilauftrag";"IDAuftragTeilauftrag"
|
||||||
|
"FK_AuftragTARoute_Auftrag";"dbo";"AuftragTARoute";"IDAuftrag_FS";"dbo";"Auftrag";"IDAuftrag"
|
||||||
|
"FK_AuftragTARoute_AuftragTeilauftrag";"dbo";"AuftragTARoute";"IDAuftragTeilauftrag_FS";"dbo";"AuftragTeilauftrag";"IDAuftragTeilauftrag"
|
||||||
|
"FK_AuftragTARoute_Land";"dbo";"AuftragTARoute";"IDLand_FS";"dbo";"Land";"IDLand"
|
||||||
|
"FK_AuftragTeilauftrag_Auftrag";"dbo";"AuftragTeilauftrag";"IDAuftrag_FS";"dbo";"Auftrag";"IDAuftrag"
|
||||||
|
"FK_AuftragTeilauftragPreis_Auftrag";"dbo";"AuftragTeilauftragPreis";"IDAuftrag_FS";"dbo";"Auftrag";"IDAuftrag"
|
||||||
|
"FK_AuftragTeilauftragPreis_AuftragTeilauftrag";"dbo";"AuftragTeilauftragPreis";"IDAuftragTeilauftrag_FS";"dbo";"AuftragTeilauftrag";"IDAuftragTeilauftrag"
|
||||||
|
"FK_AuftragTeilauftragPreisErweitert_AuftragTeilauftrag";"dbo";"AuftragTeilauftragPreisErweitert";"IDAuftragTeilauftrag_FS";"dbo";"AuftragTeilauftrag";"IDAuftragTeilauftrag"
|
||||||
|
"FK_AuftragTeilauftragPreisErweitert_Ausstattung";"dbo";"AuftragTeilauftragPreisErweitert";"IDAusstattung_FS";"dbo";"Ausstattung";"IDAusstattung"
|
||||||
|
"FK_AuftragText_ArtAuftragstext";"dbo";"AuftragText";"IDArtAuftragstext_FS";"dbo";"ArtAuftragstext";"IDArtAuftragstext"
|
||||||
|
"FK_AuftragText_Auftrag";"dbo";"AuftragText";"IDAuftrag_FS";"dbo";"Auftrag";"IDAuftrag"
|
||||||
|
"FK_AuftragZusatz_ArtStornogrund";"dbo";"AuftragZusatz";"IDArtStornogrund_FS";"dbo";"ArtStornogrund";"IDArtStornogrund"
|
||||||
|
"FK_AuftragZusatz_Auftrag";"dbo";"AuftragZusatz";"IDAuftrag_FS";"dbo";"Auftrag";"IDAuftrag"
|
||||||
|
"FK_AuftragZusatzleistung_Auftrag";"dbo";"AuftragZusatzleistung";"IDAuftrag_FS";"dbo";"Auftrag";"IDAuftrag"
|
||||||
|
"FK_AuftragZusatzleistung_AuftragTeilauftrag";"dbo";"AuftragZusatzleistung";"IDAuftragTeilauftrag_FS";"dbo";"AuftragTeilauftrag";"IDAuftragTeilauftrag"
|
||||||
|
"FK_AusstattungFahrzeugAusstattung_ArtFahrzeugAusstattungMerkmal";"dbo";"AusstattungFahrzeugAusstattung";"IDArtFahrzeugAusstattungMerkmal_FS";"dbo";"ArtFahrzeugAusstattungMerkmal";"IDArtFahrzeugAusstattungMerkmal"
|
||||||
|
"FK_AusstattungFahrzeugAusstattung_Ausstattung";"dbo";"AusstattungFahrzeugAusstattung";"IDAusstattung_FS";"dbo";"Ausstattung";"IDAusstattung"
|
||||||
|
"FK_AusstattungKalkulationsWert_Ausstattung";"dbo";"AusstattungKalkulationsWert";"IDAusstattung_FS";"dbo";"Ausstattung";"IDAusstattung"
|
||||||
|
"FK_AusstattungKalkulationsWert_KalkulationswertBezeichnung";"dbo";"AusstattungKalkulationsWert";"IDKalkulationsWertBezeichnung_FS";"dbo";"KalkulationswertBezeichnung";"IDKalkulationswertBezeichnung"
|
||||||
|
"FK_AusstattungKalkulationswertPersonen_AusstattungKalkulationsWert";"dbo";"AusstattungKalkulationswertPersonen";"IDAusstattungKalkulationswert_FS";"dbo";"AusstattungKalkulationsWert";"IDAusstattungKalkulationsWert"
|
||||||
|
"FK_AZKImport_Adresse";"dbo";"AZKImport";"IDAdresse_FS";"dbo";"Adresse";"IDAdresse"
|
||||||
|
"FK_AZKImport_AZKImportEinstellung";"dbo";"AZKImport";"IDAZKImportEinstellung_FS";"dbo";"AZKImportEinstellung";"IDAZKImportEinstellung"
|
||||||
|
"FK_Befoerderungsvertrag_Adresse";"dbo";"Befoerderungsvertrag";"IDAdresse_FS_Partner";"dbo";"Adresse";"IDAdresse"
|
||||||
|
"FK_Befoerderungsvertrag_AdresseAnschrift";"dbo";"Befoerderungsvertrag";"IDAdresseAnschrift_FS_Partner";"dbo";"AdresseAnschrift";"IDAdresseAnschrift"
|
||||||
|
"FK_BefoerderungsvertragTeilauftrag_AuftragTeilauftrag";"dbo";"BefoerderungsvertragTeilauftrag";"IDAuftragTeilauftrag_FS";"dbo";"AuftragTeilauftrag";"IDAuftragTeilauftrag"
|
||||||
|
"FK_BefoerderungsvertragTeilauftrag_Befoerderungsvertrag";"dbo";"BefoerderungsvertragTeilauftrag";"IDBefoerderungsvertrag_FS";"dbo";"Befoerderungsvertrag";"IDBefoerderungsvertrag"
|
||||||
|
"FK_Block_Adresse";"dbo";"Block";"IDAdresse_FS_Fahrer";"dbo";"Adresse";"IDAdresse"
|
||||||
|
"FK_Block_ArtBetriebshof";"dbo";"Block";"IDArtBetriebshof_FS_Anfang";"dbo";"ArtBetriebshof";"IDArtBetriebshof"
|
||||||
|
"FK_Block_ArtBetriebshof1";"dbo";"Block";"IDArtBetriebshof_FS_Ende";"dbo";"ArtBetriebshof";"IDArtBetriebshof"
|
||||||
|
"FK_Block_ArtBlockArt";"dbo";"Block";"IDArtBlockart_FS";"dbo";"ArtBlockArt";"IDArtBlockArt"
|
||||||
|
"FK_Block_ArtFahrplanVersion";"dbo";"Block";"IDArtFahrplanVersion_FS";"dbo";"ArtFahrplanVersion";"IDArtFahrplanVersion"
|
||||||
|
"FK_Block_ArtFremdunternehmen";"dbo";"Block";"IDArtFremdunternehmen_FS";"dbo";"ArtFremdunternehmen";"IDArtFremdunternehmen"
|
||||||
|
"FK_Block_ArtReichweitentyp";"dbo";"Block";"IDArtReichweitentyp_FS";"dbo";"ArtReichweitentyp";"IDArtReichweitentyp"
|
||||||
|
"FK_Block_Fahrzeug";"dbo";"Block";"IDFahrzeug_FS";"dbo";"Fahrzeug";"IDFahrzeug"
|
||||||
|
"FK_Block_Ort_AbstellAnfang";"dbo";"Block";"IDOrt_FS_AbstellAnfang";"dbo";"Ort";"IDOrt"
|
||||||
|
"FK_Block_Ort_AbstellEnde";"dbo";"Block";"IDOrt_FS_AbstellEnde";"dbo";"Ort";"IDOrt"
|
||||||
|
"FK_BlockFahrzeugtyp_ArtFahrzeugTypen";"dbo";"BlockFahrzeugtyp";"IDArtFahrzeugTypen_FS";"dbo";"ArtFahrzeugTypen";"IDArtFahrzeugTypen"
|
||||||
|
"FK_BlockFahrzeugtyp_Block";"dbo";"BlockFahrzeugtyp";"IDBlock_FS";"dbo";"Block";"IDBlock"
|
||||||
|
"FK_BlockGruppeVerkehrstag_ArtGruppeVerkehrstag";"dbo";"BlockGruppeVerkehrstag";"IDArtGruppeVerkehrstag_FS";"dbo";"ArtGruppeVerkehrstag";"IDArtGruppeVerkehrstag"
|
||||||
|
"FK_BlockGruppeVerkehrstag_Block";"dbo";"BlockGruppeVerkehrstag";"IDBlock_FS";"dbo";"Block";"IDBlock"
|
||||||
|
"FK_Blockkombination_ArtFahrplanVersion";"dbo";"Blockkombination";"IDArtFahrplanVersion_FS";"dbo";"ArtFahrplanVersion";"IDArtFahrplanVersion"
|
||||||
|
"FK_BlockkombinationBlock_Block";"dbo";"BlockkombinationBlock";"IDBlock_FS";"dbo";"Block";"IDBlock"
|
||||||
|
"FK_BlockkombinationBlock_Blockkombination";"dbo";"BlockkombinationBlock";"IDBlockkombination_FS";"dbo";"Blockkombination";"IDBlockkombination"
|
||||||
|
"FK_BlockkombinationGruppeVerkehrstag_ArtGruppeVerkehrstag";"dbo";"BlockkombinationGruppeVerkehrstag";"IDArtGruppeVerkehrstag_FS";"dbo";"ArtGruppeVerkehrstag";"IDArtGruppeVerkehrstag"
|
||||||
|
"FK_BlockkombinationGruppeVerkehrstag_Blockkombination";"dbo";"BlockkombinationGruppeVerkehrstag";"IDBlockkombination_FS";"dbo";"Blockkombination";"IDBlockkombination"
|
||||||
|
"FK_BlockPause_Block";"dbo";"BlockPause";"IDBlock_FS";"dbo";"Block";"IDBlock"
|
||||||
|
"FK_BlockPause_Ort";"dbo";"BlockPause";"IDOrt_FS";"dbo";"Ort";"IDOrt"
|
||||||
|
"FK_BlockPlanung_Adresse";"dbo";"BlockPlanung";"IDAdresse_FS_Fahrer";"dbo";"Adresse";"IDAdresse"
|
||||||
|
"FK_BlockPlanung_Adresse2";"dbo";"BlockPlanung";"LoeschenManuellIDAdresse_FS_SB";"dbo";"Adresse";"IDAdresse"
|
||||||
|
"FK_BlockPlanung_ArtBetriebshof";"dbo";"BlockPlanung";"IDArtBetriebshof_FS_Anfang";"dbo";"ArtBetriebshof";"IDArtBetriebshof"
|
||||||
|
"FK_BlockPlanung_ArtBetriebshof1";"dbo";"BlockPlanung";"IDArtBetriebshof_FS_Ende";"dbo";"ArtBetriebshof";"IDArtBetriebshof"
|
||||||
|
"FK_BlockPlanung_ArtBlockArt";"dbo";"BlockPlanung";"IDArtBlockart_FS";"dbo";"ArtBlockArt";"IDArtBlockArt"
|
||||||
|
"FK_BlockPlanung_ArtFahrplanVersion";"dbo";"BlockPlanung";"IDArtFahrplanVersion_FS";"dbo";"ArtFahrplanVersion";"IDArtFahrplanVersion"
|
||||||
|
"FK_BlockPlanung_ArtFremdunternehmen";"dbo";"BlockPlanung";"IDArtFremdunternehmen_FS";"dbo";"ArtFremdunternehmen";"IDArtFremdunternehmen"
|
||||||
|
"FK_BlockPlanung_ArtReichweitentyp";"dbo";"BlockPlanung";"IDArtReichweitentyp_FS";"dbo";"ArtReichweitentyp";"IDArtReichweitentyp"
|
||||||
|
"FK_BlockPlanung_Block";"dbo";"BlockPlanung";"IDBlock_FS_Basis";"dbo";"Block";"IDBlock"
|
||||||
|
"FK_BlockPlanung_Fahrzeug";"dbo";"BlockPlanung";"IDFahrzeug_FS";"dbo";"Fahrzeug";"IDFahrzeug"
|
||||||
|
"FK_BlockPlanung_Ort_AbstellAnfang";"dbo";"BlockPlanung";"IDOrt_FS_AbstellAnfang";"dbo";"Ort";"IDOrt"
|
||||||
|
"FK_BlockPlanung_Ort_AbstellEnde";"dbo";"BlockPlanung";"IDOrt_FS_AbstellEnde";"dbo";"Ort";"IDOrt"
|
||||||
|
"FK_BlockPlanungFahrzeugtyp_ArtFahrzeugTypen";"dbo";"BlockPlanungFahrzeugtyp";"IDArtFahrzeugTypen_FS";"dbo";"ArtFahrzeugTypen";"IDArtFahrzeugTypen"
|
||||||
|
"FK_BlockPlanungFahrzeugtyp_BlockPlanung";"dbo";"BlockPlanungFahrzeugtyp";"IDBlockPlanung_FS";"dbo";"BlockPlanung";"IDBlockPlanung"
|
||||||
|
"FK_BlockPlanungPause_BlockPlanung";"dbo";"BlockPlanungPause";"IDBlockPlanung_FS";"dbo";"BlockPlanung";"IDBlockPlanung"
|
||||||
|
"FK_BlockPlanungPause_Ort";"dbo";"BlockPlanungPause";"IDOrt_FS";"dbo";"Ort";"IDOrt"
|
||||||
|
"FK_BlockPlanungPreisMehrMinder_TourPlanung";"dbo";"BlockPlanungPreisMehrMinder";"IDTourPlanung_FS";"dbo";"TourPlanung";"IDTourPlanung"
|
||||||
|
"FK_BlockPlanungZusatz_BlockPlanung";"dbo";"BlockPlanungZusatz";"IDBlockPlanung_FS";"dbo";"BlockPlanung";"IDBlockPlanung"
|
||||||
|
"FK_BlockSitzenbleiber_Block";"dbo";"BlockSitzenbleiber";"IDBlock_FS";"dbo";"Block";"IDBlock"
|
||||||
|
"FK_BlockSitzenbleiber_TourNach";"dbo";"BlockSitzenbleiber";"IdTour_FS_Nach";"dbo";"Tour";"IDTour"
|
||||||
|
"FK_BlockSitzenbleiber_TourVon";"dbo";"BlockSitzenbleiber";"IdTour_FS_Von";"dbo";"Tour";"IDTour"
|
||||||
|
"FK_BlockTour_Block";"dbo";"BlockTour";"IDBlock_FS";"dbo";"Block";"IDBlock"
|
||||||
|
"FK_BlockTour_Tour";"dbo";"BlockTour";"IDTour_FS";"dbo";"Tour";"IDTour"
|
||||||
|
"FK_BlockZusatz_Block";"dbo";"BlockZusatz";"IDBlock_FS";"dbo";"Block";"IDBlock"
|
||||||
|
"FK_Buchung_Adresse";"dbo";"Buchung";"IDAdresse_FS_Agentur";"dbo";"Adresse";"IDAdresse"
|
||||||
|
"FK_Buchung_Adresse1";"dbo";"Buchung";"IDAdresse_FS_ErsterSachb";"dbo";"Adresse";"IDAdresse"
|
||||||
|
"FK_Buchung_Adresse2";"dbo";"Buchung";"IDAdresse_FS_LetzterSachb";"dbo";"Adresse";"IDAdresse"
|
||||||
|
"FK_Buchung_Adresse3";"dbo";"Buchung";"IDAdresse_FS_Mandant";"dbo";"Adresse";"IDAdresse"
|
||||||
|
"FK_Buchung_IdAdressePerson";"dbo";"Buchung";"IdAdressePerson_FS_Anmelder";"dbo";"AdressePerson";"IDAdressePerson"
|
||||||
|
"FK_BuchungBemerkung_Buchung";"dbo";"BuchungBemerkung";"IDBuchung_FS";"dbo";"Buchung";"IDBuchung"
|
||||||
|
"FK_BuchungDokument_Adresse";"dbo";"BuchungDokument";"IDAdresse_FS_Sachbearbeiter";"dbo";"Adresse";"IDAdresse"
|
||||||
|
"FK_BuchungDokument_ArtDokument";"dbo";"BuchungDokument";"IDArtDokument_FS";"dbo";"ArtDokument";"IDArtDokument"
|
||||||
|
"FK_BuchungDokument_Buchung";"dbo";"BuchungDokument";"IDBuchung_FS";"dbo";"Buchung";"IDBuchung"
|
||||||
|
"FK_BuchungDruck_Buchung";"dbo";"BuchungDruck";"IDBuchung_FS";"dbo";"Buchung";"IDBuchung"
|
||||||
|
"FK_BuchungMeldung_Adresse";"dbo";"BuchungMeldung";"IDAdresse_FS_Mitarbeiter_Eingabe";"dbo";"Adresse";"IDAdresse"
|
||||||
|
"FK_BuchungMeldung_Adresse1";"dbo";"BuchungMeldung";"IDAdresse_FS_Mitarbeiter_Meldung";"dbo";"Adresse";"IDAdresse"
|
||||||
|
"FK_BuchungMeldung_ArtMeldungArt";"dbo";"BuchungMeldung";"IDArtMeldungart_FS";"dbo";"ArtMeldungArt";"IDArtMeldungArt"
|
||||||
|
"FK_BuchungMeldung_Buchung";"dbo";"BuchungMeldung";"IDBuchung_FS";"dbo";"Buchung";"IDBuchung"
|
||||||
|
"FK_BuchungMeldung_BuchungTNFerienziel";"dbo";"BuchungMeldung";"IDBuchungTNFerienziel_FS";"dbo";"BuchungTNFerienziel";"IDBuchungTNFerienziel"
|
||||||
|
"FK_BuchungMeldung_BuchungTNLeistung";"dbo";"BuchungMeldung";"IDBuchungTNLeistung_FS";"dbo";"BuchungTNLeistung";"IDBuchungTNLeistung"
|
||||||
|
"FK_BuchungReisebüro_Buchung";"dbo";"BuchungReisebüro";"IDBuchung_FS";"dbo";"Buchung";"IDBuchung"
|
||||||
|
"FK_BuchungReisebüroVersicherungsGruppe_ArtVersicherungsGruppe";"dbo";"BuchungReisebüroVersicherungsGruppe";"IDArtVersicherungsGruppe_FS";"dbo";"ArtVersicherungsGruppe";"IDArtVersicherungsGruppe"
|
||||||
|
"FK_BuchungReisebüroVersicherungsGruppe_BuchungReisebüro";"dbo";"BuchungReisebüroVersicherungsGruppe";"IDBuchungReisebüro_FS";"dbo";"BuchungReisebüro";"IDBuchungReisebüro"
|
||||||
|
"FK_BuchungReisebüroVisum_BuchungReisebüro";"dbo";"BuchungReisebüroVisum";"IDBuchungReisebüro_FS";"dbo";"BuchungReisebüro";"IDBuchungReisebüro"
|
||||||
|
"FK_BuchungTextbaustein_Buchung";"dbo";"BuchungTextbaustein";"IDBuchung_FS";"dbo";"Buchung";"IDBuchung"
|
||||||
|
"FK_BuchungTextbaustein_Textbaustein";"dbo";"BuchungTextbaustein";"IDTextbaustein_FS";"dbo";"Textbaustein";"IDTextbaustein"
|
||||||
|
"FK_BuchungTN_AdressePerson";"dbo";"BuchungTN";"IDAdressePerson_FS";"dbo";"AdressePerson";"IDAdressePerson"
|
||||||
|
"FK_BuchungTN_ArtTeilnahmeStornoGrund";"dbo";"BuchungTN";"IDArtTeilnahmeStornoGrund_FS";"dbo";"ArtTeilnahmeStornoGrund";"IDArtTeilnahmeStornoGrund"
|
||||||
|
"FK_BuchungTN_Buchung";"dbo";"BuchungTN";"IDBuchung_FS";"dbo";"Buchung";"IDBuchung"
|
||||||
|
"FK_BuchungTNFerienziel_Adresse";"dbo";"BuchungTNFerienziel";"IDAdresse_FS_Partner";"dbo";"Adresse";"IDAdresse"
|
||||||
|
"FK_BuchungTNFerienziel_ArtVerpflegung";"dbo";"BuchungTNFerienziel";"IDArtVerpflegung_FS";"dbo";"ArtVerpflegung";"IDArtVerpflegung"
|
||||||
|
"FK_BuchungTNFerienziel_BuchungTN";"dbo";"BuchungTNFerienziel";"IDBuchungTN_FS";"dbo";"BuchungTN";"IDBuchungTN"
|
||||||
|
"FK_BuchungTNFerienziel_Zimmerart";"dbo";"BuchungTNFerienziel";"IDZimmerart_FS";"dbo";"Zimmerart";"IDZimmerart"
|
||||||
|
"FK_BuchungTNFerienzielPreis_BuchungTNFerienziel";"dbo";"BuchungTNFerienzielPreis";"IDBuchungTNFerienziel_FS";"dbo";"BuchungTNFerienziel";"IDBuchungTNFerienziel"
|
||||||
|
"FK_BuchungTNFerienzielPreis_BuchungTNPreis";"dbo";"BuchungTNFerienzielPreis";"IDBuchungTNPreis_FS";"dbo";"BuchungTNPreis";"IDBuchungTNPreis"
|
||||||
|
"FK_BuchungTNLeistung_BuchungTN";"dbo";"BuchungTNLeistung";"IDBuchungTN_FS";"dbo";"BuchungTN";"IDBuchungTN"
|
||||||
|
"FK_BuchungTNLeistung_Leistung";"dbo";"BuchungTNLeistung";"IDLeistung_FS";"dbo";"Leistung";"IDLeistung"
|
||||||
|
"FK_BuchungTNLeistungPreis_BuchungTNLeistung";"dbo";"BuchungTNLeistungPreis";"IDBuchungTNLeistung_FS";"dbo";"BuchungTNLeistung";"IDBuchungTNLeistung"
|
||||||
|
"FK_BuchungTNLeistungPreis_BuchungTNPreis";"dbo";"BuchungTNLeistungPreis";"IDBuchungTNPreis_FS";"dbo";"BuchungTNPreis";"IDBuchungTNPreis"
|
||||||
|
"FK_BuchungTNLeistungZusatz_BuchungTNLeistung";"dbo";"BuchungTNLeistungZusatz";"IDBuchungTNLeistung_FS";"dbo";"BuchungTNLeistung";"IDBuchungTNLeistung"
|
||||||
|
"FK_BuchungTNPreis_Adresse";"dbo";"BuchungTNPreis";"IDAdresse_FS_Sachb";"dbo";"Adresse";"IDAdresse"
|
||||||
|
"FK_BuchungTNPreis_ArtPreisschema";"dbo";"BuchungTNPreis";"IDArtPreisschema_FS";"dbo";"ArtPreisschema";"IDArtPreisschema"
|
||||||
|
"FK_BuchungTNPreis_BuchungTN";"dbo";"BuchungTNPreis";"IDBuchungTN_FS";"dbo";"BuchungTN";"IDBuchungTN"
|
||||||
|
"FK_BuchungTNPreisErm_BuchungTNPreis";"dbo";"BuchungTNPreisErm";"IDBuchungTNPreis_FS";"dbo";"BuchungTNPreis";"IDBuchungTNPreis"
|
||||||
|
"FK_BuchungTNVersicherung_BuchungTN";"dbo";"BuchungTNVersicherung";"IDBuchungTN_FS";"dbo";"BuchungTN";"IDBuchungTN"
|
||||||
|
"FK_BuchungTNVersicherung_Leistung";"dbo";"BuchungTNVersicherung";"IDLeistung_FS_Versicherung";"dbo";"Leistung";"IDLeistung"
|
||||||
|
"FK_BuchungTNVersicherungPreis_BuchungTNPreis";"dbo";"BuchungTNVersicherungPreis";"IDBuchungTNPreis_FS";"dbo";"BuchungTNPreis";"IDBuchungTNPreis"
|
||||||
|
"FK_BuchungTNVersicherungPreis_BuchungTNVersicherung";"dbo";"BuchungTNVersicherungPreis";"IDBuchungTNVersicherung_FS";"dbo";"BuchungTNVersicherung";"IDBuchungTNVersicherung"
|
||||||
|
"FK_BuchungTNWunsch_BuchungTN";"dbo";"BuchungTNWunsch";"IDBuchungTN_FS";"dbo";"BuchungTN";"IDBuchungTN"
|
||||||
|
"FK_BuchungTNZahlung_BuchungTN";"dbo";"BuchungTNZahlung";"IDBuchungTN_FS";"dbo";"BuchungTN";"IDBuchungTN"
|
||||||
|
"FK_BuchungTNZahlung_Zahlung";"dbo";"BuchungTNZahlung";"IDZahlung_FS";"dbo";"Zahlung";"IDZahlung"
|
||||||
|
"FK_BuchungTNZuschlag_BuchungTN";"dbo";"BuchungTNZuschlag";"IDBuchungTN_FS";"dbo";"BuchungTN";"IDBuchungTN"
|
||||||
|
"FK_BuchungTNZuschlagPreis_BuchungTNPreis";"dbo";"BuchungTNZuschlagPreis";"IDBuchungTNPreis_FS";"dbo";"BuchungTNPreis";"IDBuchungTNPreis"
|
||||||
|
"FK_BuchungTNZuschlagPreis_BuchungTNZuschlag";"dbo";"BuchungTNZuschlagPreis";"IDBuchungTNZuschlag_FS";"dbo";"BuchungTNZuschlag";"IDBuchungTNZuschlag"
|
||||||
|
"FK_BuchungTNZuschlagZusatz_BuchungTNZuschlag";"dbo";"BuchungTNZuschlagZusatz";"IDBuchungTNZuschlag_FS";"dbo";"BuchungTNZuschlag";"IDBuchungTNZuschlag"
|
||||||
|
"FK_BuchungUnterlagenStatus_Adresse";"dbo";"BuchungUnterlagenStatus";"IDAdresse_FS_Sachbearbeiter";"dbo";"Adresse";"IDAdresse"
|
||||||
|
"FK_BuchungUnterlagenStatus_ArtUnterlagenStatus";"dbo";"BuchungUnterlagenStatus";"IDArtUnterlagenStatus_FS";"dbo";"ArtUnterlagenStatus";"IDArtUnterlagenStatus"
|
||||||
|
"FK_BuchungUnterlagenStatus_Buchung";"dbo";"BuchungUnterlagenStatus";"IDBuchung_FS";"dbo";"Buchung";"IDBuchung"
|
||||||
|
"FK_BuchungVersicherungAngebot_Buchung";"dbo";"BuchungVersicherungAngebot";"IDBuchung_FS";"dbo";"Buchung";"IDBuchung"
|
||||||
|
"FK_BuchungVersicherungAngebot_Leistung";"dbo";"BuchungVersicherungAngebot";"IDLeistung_FS_Versicherung";"dbo";"Leistung";"IDLeistung"
|
||||||
|
"FK_BuchungZahlung_ArtZahlungsart";"dbo";"BuchungZahlung";"IDArtZahlungsart_FS";"dbo";"ArtZahlungsart";"IDArtZahlungsart"
|
||||||
|
"FK_BuchungZahlung_Buchung";"dbo";"BuchungZahlung";"IDBuchung_FS";"dbo";"Buchung";"IDBuchung"
|
||||||
|
"FK_BundeslandPLZOrt_ArtBundesland";"dbo";"BundeslandPLZOrt";"IDArtBundesland_FS";"dbo";"ArtBundesland";"IDArtBundesland"
|
||||||
|
"FK_ConnectChat_ArtConnectChatKategorie";"dbo";"ConnectChat";"IDArtConnectChatKategorie_FS";"dbo";"ArtConnectChatKategorie";"IDArtConnectChatKategorie"
|
||||||
|
"FK_ConnectChatKategorieKompetenz_ArtPersonalGruppeKompetenz";"dbo";"ConnectChatKategorieKompetenz";"IDArtPersonalGruppeKompetenz_FS";"dbo";"ArtPersonalGruppeKompetenz";"IDArtPersonalGruppeKompetenz"
|
||||||
|
"FK_ChatNachricht_ChatRaum";"dbo";"ConnectChatNachricht";"IDChat_FS";"dbo";"ConnectChat";"IDChat"
|
||||||
|
"FK_ChatTeilnehmer_ChatRaum";"dbo";"ConnectChatTeilnehmer";"IDChat_FS";"dbo";"ConnectChat";"IDChat"
|
||||||
|
"FK_ConnectDokumentReferenzen_ConnectDokument";"dbo";"ConnectDokumentReferenzen";"IDConnectDokument_FS";"dbo";"ConnectDokument";"IDConnectDokument"
|
||||||
|
"FK_ConnectKompetenz_ArtPersonalGruppeKompetenz";"dbo";"ConnectKompetenz";"IDArtPersonalGruppeKompetenz_FS";"dbo";"ArtPersonalGruppeKompetenz";"IDArtPersonalGruppeKompetenz"
|
||||||
|
"FK_ConnectNotificationsReceiver_ConnectNotifications";"dbo";"ConnectNotificationsReceiver";"IDConnectNotification";"dbo";"ConnectNotifications";"Id"
|
||||||
|
"FK_ConnectOrdner_ConnectOrdner";"dbo";"ConnectOrdner";"IDConnectOrdner_FS_Parent";"dbo";"ConnectOrdner";"IDConnectOrdner"
|
||||||
|
"FK_Connect_Planungsabruf_Adresse_Aenderung";"dbo";"ConnectPlanungsabruf";"IDAdresse_FS_Aenderung";"dbo";"Adresse";"IDAdresse"
|
||||||
|
"FK_Connect_Planungsabruf_Adresse_Fahrer";"dbo";"ConnectPlanungsabruf";"IDAdresse_FS_Fahrer";"dbo";"Adresse";"IDAdresse"
|
||||||
|
"FK_ConnectPlanungsabrufHistorie_Adresse";"dbo";"ConnectPlanungsabrufHistorie";"IDAdresse_FS_Fahrer";"dbo";"Adresse";"IDAdresse"
|
||||||
|
"FK_ConnectRueckmeldungMB_AuftragFahrer";"dbo";"ConnectRueckmeldungMB";"IDAuftragFahrer_FS";"dbo";"AuftragFahrer";"IDAuftragFahrer"
|
||||||
|
"FK_ConnectRueckmeldungMBFoto_ConnectRueckmeldungMB";"dbo";"ConnectRueckmeldungMBFoto";"IDConnectRueckmeldungMB_FS";"dbo";"ConnectRueckmeldungMB";"IDConnectRueckmeldungMB"
|
||||||
|
"FK_ConnectRueckmeldungMBKilometer_ConnectRueckmeldungMB";"dbo";"ConnectRueckmeldungMBKilometer";"IDConnectRueckmeldungMB_FS";"dbo";"ConnectRueckmeldungMB";"IDConnectRueckmeldungMB"
|
||||||
|
"FK_ArtConnectRueckmeldungMBText_ConnectRueckmeldungMBText";"dbo";"ConnectRueckmeldungMBText";"IDArtConnectRueckmeldungMBText_FS";"dbo";"ArtConnectRueckmeldungMBText";"IDArtConnectRueckmeldungMBText"
|
||||||
|
"FK_ConnectRueckmeldungMBText_ConnectRueckmeldungMB";"dbo";"ConnectRueckmeldungMBText";"IDConnectRueckmeldungMB_FS";"dbo";"ConnectRueckmeldungMB";"IDConnectRueckmeldungMB"
|
||||||
|
"FK_CRMAktionDesignSeite_CRMAktion";"dbo";"CRMAktionDesignSeite";"IDCRMAktion_FS";"dbo";"CRMAktion";"IDCRMAktion"
|
||||||
|
"FK_CRMAktionDesignSeiteZuweisung_CRMAktionDesignSeite";"dbo";"CRMAktionDesignSeiteZuweisung";"IDCRMAktionDesignSeite_FS";"dbo";"CRMAktionDesignSeite";"IDCRMAktionDesignSeite"
|
||||||
|
"FK_CRMAktionPLZ_CRMAktion";"dbo";"CRMAktionPLZ";"IDCRMAktion_FS";"dbo";"CRMAktion";"IDCRMAktion"
|
||||||
|
"FK_CRMAktionZuGruppe_CRMAktion";"dbo";"CRMAktionZuGruppe";"IDCRMAktion_FS";"dbo";"CRMAktion";"IDCRMAktion"
|
||||||
|
"FK_CRMAktionZuGruppe_CRMAktionZuGruppe";"dbo";"CRMAktionZuGruppe";"IDArtCRMGruppe_FS";"dbo";"ArtCRMGruppe";"IDArtCRMGruppe"
|
||||||
|
"FK_CRMAktionZuProdukt_CRMAktion";"dbo";"CRMAktionZuProdukt";"IDCRMAktion_FS";"dbo";"CRMAktion";"IDCRMAktion"
|
||||||
|
"FK_CRMAktionZuProdukt_Produkt";"dbo";"CRMAktionZuProdukt";"IDProdukt_FS";"dbo";"Produkt";"IDProdukt"
|
||||||
|
"FK_CRMAktionZuReise_CRMAktion";"dbo";"CRMAktionZuReise";"IDCRMAktion_FS";"dbo";"CRMAktion";"IDCRMAktion"
|
||||||
|
"FK_CRMAktionZuReise_Reise";"dbo";"CRMAktionZuReise";"IDReise_FS";"dbo";"Reise";"IDReise"
|
||||||
|
"FK_CRMDesignSegment_CRMDesign";"dbo";"CRMDesignSegment";"IDCRMDesign_FS";"dbo";"CRMDesign";"IDCRMDesign"
|
||||||
|
"FK_CRMInternetZuweisung_ArtCRMInternet";"dbo";"CRMInternetZuweisung";"IDArtCRMInternet_FS";"dbo";"ArtCRMInternet";"IDArtCRMInternet"
|
||||||
|
"FK_CRMInternetZuweisung_Buchung";"dbo";"CRMInternetZuweisung";"IDBuchung_FS";"dbo";"Buchung";"IDBuchung"
|
||||||
|
"FK_CRMWerbepartner_Adresse";"dbo";"CRMWerbepartner";"IDAdresse_FS_Partner";"dbo";"Adresse";"IDAdresse"
|
||||||
|
"FK_CRMWerbepartnerDesign_CRMDesign";"dbo";"CRMWerbepartnerDesign";"IDCRMDesign_FS";"dbo";"CRMDesign";"IDCRMDesign"
|
||||||
|
"FK_CRMWerbepartnerDesign_CRMWerbepartner";"dbo";"CRMWerbepartnerDesign";"IDCRMWerbepartner_FS";"dbo";"CRMWerbepartner";"IDCRMWerbepartner"
|
||||||
|
"FK_CRMWerbepartnerPLZ_CRMWerbepartner";"dbo";"CRMWerbepartnerPLZ";"IDCRMWerbepartner_FS";"dbo";"CRMWerbepartner";"IDCRMWerbepartner"
|
||||||
|
"FK_CRMZuweisung_Adresse";"dbo";"CRMZuweisung";"IDAdresse_FS";"dbo";"Adresse";"IDAdresse"
|
||||||
|
"FK_CRMZuweisung_Adresse1";"dbo";"CRMZuweisung";"IDAdresse_FS_VonPersonal";"dbo";"Adresse";"IDAdresse"
|
||||||
|
"FK_DienstplandruckExport_ArtDienstplandruckExport";"dbo";"DienstplandruckExport";"IDArtDienstplandruckExport_FS";"dbo";"ArtDienstplandruckExport";"IDArtDienstplandruckExport"
|
||||||
|
"FK_DispoAenderung_Adresse";"dbo";"DispoAenderung";"IDAdresse_FS_Disponent";"dbo";"Adresse";"IDAdresse"
|
||||||
|
"FK_DispoAenderungDisponent_DispoAenderung";"dbo";"DispoAenderungDisponent";"IDDispoAenderung_FS";"dbo";"DispoAenderung";"IDDispoAenderung"
|
||||||
|
"FK_DispoAenderungDisponent_DispoAnmeldungDisponent";"dbo";"DispoAenderungDisponent";"IDDispoAnmeldungDisponent_FS";"dbo";"DispoAnmeldungDisponent";"IDDispoAnmeldungDisponent"
|
||||||
|
"FK_DispoAnmeldungDisponent_Adresse";"dbo";"DispoAnmeldungDisponent";"IDAdresse_FS_Disponent";"dbo";"Adresse";"IDAdresse"
|
||||||
|
"FK_DispoEinstellungKompetenzen_ArtPersonalGruppeKompetenz";"dbo";"DispoEinstellungKompetenz";"IDArtPersonalGruppeKompetenz_FS";"dbo";"ArtPersonalGruppeKompetenz";"IDArtPersonalGruppeKompetenz"
|
||||||
|
"FK_DispoEinstellungKompetenzBetriebshofAnzeige_ArtBetriebshof";"dbo";"DispoEinstellungKompetenzBetriebshofAnzeige";"IDArtBetriebshof_FS";"dbo";"ArtBetriebshof";"IDArtBetriebshof"
|
||||||
|
"FK_DispoEinstellungKompetenzBetriebshofAnzeige_DispoEinstellungKompetenz";"dbo";"DispoEinstellungKompetenzBetriebshofAnzeige";"IDDispoEinstellungKompetenz_FS";"dbo";"DispoEinstellungKompetenz";"IDDispoEinstellungKompetenz"
|
||||||
|
"FK_DispoEinstellungKompetenzMandantAnzeige_Adresse";"dbo";"DispoEinstellungKompetenzMandantAnzeige";"IDAdresse_FS_Mandant";"dbo";"Adresse";"IDAdresse"
|
||||||
|
"FK_DispoEinstellungKompetenzMandantAnzeige_DispoEinstellungKompetenzen";"dbo";"DispoEinstellungKompetenzMandantAnzeige";"IDDispoEinstellungKompetenz_FS";"dbo";"DispoEinstellungKompetenz";"IDDispoEinstellungKompetenz"
|
||||||
|
"FK_Dokument_Adresse";"dbo";"Dokument";"IDAdresse_FS_Sachbearbeiter";"dbo";"Adresse";"IDAdresse"
|
||||||
|
"FK_Dokument_ArtDokument";"dbo";"Dokument";"IDArtDokument_FS";"dbo";"ArtDokument";"IDArtDokument"
|
||||||
|
"FK_DruckArchiv_Adresse";"dbo";"DruckArchiv";"IDAdresse_FS_SB";"dbo";"Adresse";"IDAdresse"
|
||||||
|
"FK_DruckArchivZIP_Adresse";"dbo";"DruckArchivZIP";"IDAdresse_FS_Sachbearbeiter";"dbo";"Adresse";"IDAdresse"
|
||||||
|
"FK_DTAMeldung_RechnungHaupt";"dbo";"DTAMeldung";"IDRechnungHaupt_FS";"dbo";"RechnungHaupt";"IDRechnungHaupt"
|
||||||
|
"FK_EinreisebestimmungText_Einreisebestimmung";"dbo";"EinreisebestimmungText";"IDEinreisebestimmung_FS";"dbo";"Einreisebestimmung";"IDEinreisebestimmung"
|
||||||
|
"FK_ExportInternetSpalte_ExportInternet";"dbo";"ExportInternetSpalte";"IDExportInternetZeile_FS";"dbo";"ExportInternetZeile";"IDExportInternetZeile"
|
||||||
|
"FK_ExportInternetZeile_ExportInternetZeile";"dbo";"ExportInternetZeile";"IDExportInternet_FS";"dbo";"ExportInternet";"IDExportInternet"
|
||||||
|
"FK_FahrtArt_ArtFahrtArt";"dbo";"FahrtArtKonten";"IdArtFahrtArt_FS";"dbo";"ArtFahrtArt";"IDArtFahrtArt"
|
||||||
|
"FK_Fahrzeug_ArtFahrzeugBriefOrt";"dbo";"Fahrzeug";"IDArtFahrzeugBriefOrt_FS";"dbo";"ArtFahrzeugBriefOrt";"IDArtFahrzeugBriefOrt"
|
||||||
|
"FK_Fahrzeug_ArtReichweitentyp";"dbo";"Fahrzeug";"IDArtReichweitentyp_FS";"dbo";"ArtReichweitentyp";"IDArtReichweitentyp"
|
||||||
|
"FK_Fahrzeug_FahrzeugBetriebshof";"dbo";"Fahrzeug";"IDArtBetriebshof_FS";"dbo";"ArtBetriebshof";"IDArtBetriebshof"
|
||||||
|
"FK_Fahrzeug_FahrzeugEinsatz";"dbo";"Fahrzeug";"IDArtFahrzeugEinsatz_FS";"dbo";"ArtFahrzeugEinsatz";"IDArtFahrzeugEinsatz"
|
||||||
|
"FK_Fahrzeug_FahrzeugTypen";"dbo";"Fahrzeug";"IDArtFahrzeugTypen_FS";"dbo";"ArtFahrzeugTypen";"IDArtFahrzeugTypen"
|
||||||
|
"FK_FahrzeugAusstattung_AusstattungsMerkmale";"dbo";"FahrzeugAusstattung";"IDArtFahrzeugAusstattungMerkmal_FS";"dbo";"ArtFahrzeugAusstattungMerkmal";"IDArtFahrzeugAusstattungMerkmal"
|
||||||
|
"FK_FahrzeugAusstattung_Fahrzeug";"dbo";"FahrzeugAusstattung";"IDFahrzeug_FS";"dbo";"Fahrzeug";"IDFahrzeug"
|
||||||
|
"FK_FahrzeugEinbauten_Fahrzeug";"dbo";"FahrzeugEinbauten";"IDFahrzeug_FS";"dbo";"Fahrzeug";"IDFahrzeug"
|
||||||
|
"FK_FahrzeugGerät_ArtFahrzeugGerätTyp";"dbo";"FahrzeugGerät";"IDArtFahrzeugGerätTyp_FS";"dbo";"ArtFahrzeugGerätTyp";"IDArtFahrzeugGerätTyp"
|
||||||
|
"FK_FahrzeugGerätHistorie_ArtFahrzeugGerätOrt";"dbo";"FahrzeugGerätHistorie";"IDArtFahrzeugGerätOrt_FS";"dbo";"ArtFahrzeugGerätOrt";"IDArtFahrzeugGerätOrt"
|
||||||
|
"FK_FahrzeugGerätHistorie_Fahrzeug";"dbo";"FahrzeugGerätHistorie";"IDFahrzeug_FS";"dbo";"Fahrzeug";"IDFahrzeug"
|
||||||
|
"FK_FahrzeugGerätHistorie_FahrzeugGerät";"dbo";"FahrzeugGerätHistorie";"IDFahrzeugGerät_FS";"dbo";"FahrzeugGerät";"IDFahrzeugGerät"
|
||||||
|
"FK_FahrzeugLeasing_Fahrzeug";"dbo";"FahrzeugLeasing";"IDFahrzeug_FS";"dbo";"Fahrzeug";"IDFahrzeug"
|
||||||
|
"FK_FahrzeugNummer_ArtFahrzeugNummer";"dbo";"FahrzeugNummer";"IDArtFahrzeugNummer_FS";"dbo";"ArtFahrzeugNummer";"IDArtFahrzeugNummer"
|
||||||
|
"FK_FahrzeugNummer_Fahrzeug";"dbo";"FahrzeugNummer";"IDFahrzeug_FS";"dbo";"Fahrzeug";"IDFahrzeug"
|
||||||
|
"FK_FahrzeugStatistikAnmelder_Fahrzeug";"dbo";"FahrzeugStatistikAnmelder";"IDFahrzeug_FS";"dbo";"Fahrzeug";"IDFahrzeug"
|
||||||
|
"FK_FahrzeugTerminKettenAufbau_FahrzeugTermin";"dbo";"FahrzeugTerminKettenAufbau";"IDFahrzeugTermin_FS";"dbo";"FahrzeugTermin";"IDFahrzeugTermin"
|
||||||
|
"FK_FahrzeugTerminKettenAufbau_FahrzeugTerminHaeufigkeit";"dbo";"FahrzeugTerminKettenAufbau";"IDFahrzeugTerminHaeufigkeit_FS";"dbo";"FahrzeugTerminHaeufigkeit";"IDFahrzeugTerminHaeufigkeit"
|
||||||
|
"FK_FahrzeugTerminKettenAufbau_FahrzeugTerminkette";"dbo";"FahrzeugTerminKettenAufbau";"IDFahrzeugTerminkette_FS";"dbo";"FahrzeugTerminkette";"IDFahrzeugTerminkette"
|
||||||
|
"FK_FahrzeugTerminZuweisung_Fahrzeug";"dbo";"FahrzeugTerminZuweisung";"IDFahrzeug_FS";"dbo";"Fahrzeug";"IDFahrzeug"
|
||||||
|
"FK_FahrzeugTerminZuweisung_FahrzeugTerminKettenAufbau";"dbo";"FahrzeugTerminZuweisung";"IDFahrzeugTerminKettenAufbau_FS";"dbo";"FahrzeugTerminKettenAufbau";"IDFahrzeugTerminKettenAufbau"
|
||||||
|
"FK_FahrzeugVermietung_Fahrzeug";"dbo";"FahrzeugVermietung";"IDFahrzeug_FS";"dbo";"Fahrzeug";"IDFahrzeug"
|
||||||
|
"FK_FahrzeugVersicherung_Fahrzeug";"dbo";"FahrzeugVersicherung";"IDFahrzeug_FS";"dbo";"Fahrzeug";"IDFahrzeug"
|
||||||
|
"FK_FahrzeugVerwendung_Fahrzeug";"dbo";"FahrzeugVerwendung";"IDFahrzeug_FS";"dbo";"Fahrzeug";"IDFahrzeug"
|
||||||
|
"FK_FahrzeugWerbung_Fahrzeug";"dbo";"FahrzeugWerbung";"IDFahrzeug_FS";"dbo";"Fahrzeug";"IDFahrzeug"
|
||||||
|
"FK_FehlerProtokoll_Adresse";"dbo";"FehlerProtokoll";"IDAdresse_FS";"dbo";"Adresse";"IDAdresse"
|
||||||
|
"FK_FehlerProtokoll_FehlerProtokollTyp";"dbo";"FehlerProtokoll";"IDFehlerProtokollTyp_FS";"dbo";"FehlerProtokollTyp";"IDFehlerProtokollTyp"
|
||||||
|
"FK_FehlerProtokollTypEinstellung_FehlerProtokollTyp_FS";"dbo";"FehlerProtokollTypEinstellung";"IDFehlerProtokollTyp_FS";"dbo";"FehlerProtokollTyp";"IDFehlerProtokollTyp"
|
||||||
|
"FK_FehlerProtokollTypEinstellung_Kommunikation_FS";"dbo";"FehlerProtokollTypEinstellung";"IDKommunikation_FS";"dbo";"Kommunikation";"IDKommunikation"
|
||||||
|
"FK_FerienzielZwischenPartner_Adresse";"dbo";"FerienzielZwischenPartner";"IDAdresse_FS";"dbo";"Adresse";"IDAdresse"
|
||||||
|
"FK_FerienzielZwischenPartner_FerienzielZwischenZeitraum";"dbo";"FerienzielZwischenPartner";"IDFerienzielZwischenZeitraum_FS";"dbo";"FerienzielZwischenZeitraum";"IDFerienzielZwischenZeitraum"
|
||||||
|
"FK_FerienzielZwischenZeitraum_Produkt";"dbo";"FerienzielZwischenZeitraum";"IDProdukt_FS";"dbo";"Produkt";"IDProdukt"
|
||||||
|
"FK_Fibuaufteilung_ArtFibuaufteilung";"dbo";"Fibuaufteilung";"IdArtFibuaufteilung_FS";"dbo";"ArtFibuaufteilung";"IDArtFibuaufteilung"
|
||||||
|
"FK_Fibuaufteilung_Kontenplan";"dbo";"Fibuaufteilung";"IdKontenplan_FS";"dbo";"Kontenplan";"IDKontenplan"
|
||||||
|
"FK_FibuAufteilungWerte_Buchung";"dbo";"FibuAufteilungWerte";"IDBuchung_FS";"dbo";"Buchung";"IDBuchung"
|
||||||
|
"FK_FibuAufteilungWerte_Fibuaufteilung";"dbo";"FibuAufteilungWerte";"IDFibuAufteilung_FS";"dbo";"Fibuaufteilung";"IdFibuaufteilung"
|
||||||
|
"FK_FPAllgemein_ArtFahrplanVersion";"dbo";"FPAllgemein";"IDArtFahrplanVersion_FS";"dbo";"ArtFahrplanVersion";"IDArtFahrplanVersion"
|
||||||
|
"FK_FPLinie_ArtFahrplanVersion";"dbo";"FPLinie";"IDArtFahrplanVersion_FS";"dbo";"ArtFahrplanVersion";"IDArtFahrplanVersion"
|
||||||
|
"FK_FPLinie_ArtFPLinienTyp";"dbo";"FPLinie";"IDArtFPLinienTyp_FS";"dbo";"ArtFPLinienTyp";"IDArtFPLinienTyp"
|
||||||
|
"FK_FPLinie_ArtLinieVerbund";"dbo";"FPLinie";"IDArtLinieVerbund_FS";"dbo";"ArtLinieVerbund";"IDArtLinieVerbund"
|
||||||
|
"FK_FPLinie_ArtLinieVUBereich";"dbo";"FPLinie";"IDArtLinieVUBereich_FS";"dbo";"ArtLinieVUBereich";"IDArtLinieVUBereich"
|
||||||
|
"FK_FPLinie_ArtStatistikGruppe";"dbo";"FPLinie";"IDArtStatistikgruppe_FS";"dbo";"ArtStatistikGruppe";"IDArtStatistikGruppe"
|
||||||
|
"FK_FPLinieAnschluss_FPLinie";"dbo";"FPLinieAnschluss";"IDFPLinie_FS";"dbo";"FPLinie";"IDFPLinie"
|
||||||
|
"FK_FPLinieAnschluss_FPLinie_Bringer";"dbo";"FPLinieAnschluss";"IDFPLinie_FS_Bringer";"dbo";"FPLinie";"IDFPLinie"
|
||||||
|
"FK_FPLinieAnschluss_FPLinieHaltestelle";"dbo";"FPLinieAnschluss";"IDFPLinieHaltestelle_FS_Position";"dbo";"FPLinieHaltestelle";"IDFPLinieHaltestelle"
|
||||||
|
"FK_FPLinieAnschluss_FPLinieHaltestelleZubringer";"dbo";"FPLinieAnschluss";"IDFPLinieHaltestelle_FS_Position_Zubringer";"dbo";"FPLinieHaltestelle";"IDFPLinieHaltestelle"
|
||||||
|
"FK_FPLinieAnschluss_FPLinieSymbol";"dbo";"FPLinieAnschluss";"IDFPLinieSymbol_FS";"dbo";"FPLinieSymbol";"IDFPLinieSymbol"
|
||||||
|
"FK_FPLinieAnschlussDefinition_ArtFahrplanVersion";"dbo";"FPLinieAnschlussDefinition";"IDArtFahrplanVersion_FS";"dbo";"ArtFahrplanVersion";"IDArtFahrplanVersion"
|
||||||
|
"FK_FPLinieAnschlussDefinition_FPLinie_Abbringer";"dbo";"FPLinieAnschlussDefinition";"IDFPLinie_FS_Abbringer";"dbo";"FPLinie";"IDFPLinie"
|
||||||
|
"FK_FPLinieAnschlussDefinition_FPLinie_Zubringer";"dbo";"FPLinieAnschlussDefinition";"IDFPLinie_FS_Zubringer";"dbo";"FPLinie";"IDFPLinie"
|
||||||
|
"FK_FPLinieAnschlussDefinition_Haltepunkt_Abbringer";"dbo";"FPLinieAnschlussDefinition";"IDHaltepunkt_FS_Abbringer";"dbo";"Haltepunkt";"IDHaltepunkt"
|
||||||
|
"FK_FPLinieAnschlussDefinition_Haltepunkt_Zubringer";"dbo";"FPLinieAnschlussDefinition";"IDHaltepunkt_FS_Zubringer";"dbo";"Haltepunkt";"IDHaltepunkt"
|
||||||
|
"FK_FPLinieAnschlussDefinition_Haltestelle_Abbringer";"dbo";"FPLinieAnschlussDefinition";"IDHaltestelle_FS_Abbringer";"dbo";"Haltestelle";"IDHaltestelle"
|
||||||
|
"FK_FPLinieAnschlussDefinition_Haltestelle_Zubringer";"dbo";"FPLinieAnschlussDefinition";"IDHaltestelle_FS_Zubringer";"dbo";"Haltestelle";"IDHaltestelle"
|
||||||
|
"FK_FPLinieAnschlussDefinitionUmstieg_FPLinieAnschlussDefinition";"dbo";"FPLinieAnschlussDefinitionUmstieg";"IDFPLinieAnschlussDefinition_FS";"dbo";"FPLinieAnschlussDefinition";"IDFPLinieAnschlussDefinition"
|
||||||
|
"FK_FPLinieAnschlussDefinitionUmstiegGruppeVT_FPLinieAnschlussDefinitionUmstieg";"dbo";"FPLinieAnschlussDefinitionUmstiegGruppeVT";"IDFPLinieAnschlussDefinitionUmstieg_FS";"dbo";"FPLinieAnschlussDefinitionUmstieg";"IDFPLinieAnschlussDefinitionUmstieg"
|
||||||
|
"FK_FPLinieBeschraenkung_ArtLaufzeitschema";"dbo";"FPLinieBeschraenkung";"IDArtLaufzeitschema_FS";"dbo";"ArtLaufzeitschema";"IDArtLaufzeitschema"
|
||||||
|
"FK_FPLinieBeschraenkung_FPSondererklaerung";"dbo";"FPLinieBeschraenkung";"IDFPSondererklaerung_FS";"dbo";"FPSondererklaerung";"IDFPSondererklaerung"
|
||||||
|
"FK_FPLinieBeschraenkungFerienFeier_FPLinieBeschraenkung";"dbo";"FPLinieBeschraenkungFerienFeier";"IDFPLinieBeschraenkung_FS";"dbo";"FPLinieBeschraenkung";"IDFPLinieBeschraenkung"
|
||||||
|
"FK_FPLinieBeschraenkungLaufzeit_FPLinieBeschraenkung";"dbo";"FPLinieBeschraenkungLaufzeit";"IDFPLinieBeschraenkung_FS";"dbo";"FPLinieBeschraenkung";"IDFPLinieBeschraenkung"
|
||||||
|
"FK_FPLinieBeschraenkungWochentyp_ArtWochentyp";"dbo";"FPLinieBeschraenkungWochentyp";"IDArtWochentyp_FS";"dbo";"ArtWochentyp";"IDArtWochentyp"
|
||||||
|
"FK_FPLinieBeschraenkungWochentyp_FPLinieBeschraenkung";"dbo";"FPLinieBeschraenkungWochentyp";"IDFPLinieBeschraenkung_FS";"dbo";"FPLinieBeschraenkung";"IDFPLinieBeschraenkung"
|
||||||
|
"FK_FPLinieDruck_FPLinie";"dbo";"FPLinieDruck";"IDFPLinie_FS";"dbo";"FPLinie";"IDFPLinie"
|
||||||
|
"FK_FPLinieFahrplanAdresse_FahrplanAdresse";"dbo";"FPLinieFahrplanAdresse";"IDFahrplanAdresse_FS";"dbo";"FahrplanAdresse";"IDFahrplanAdresse"
|
||||||
|
"FK_FPLinieFahrplanAdresse_FPLinie";"dbo";"FPLinieFahrplanAdresse";"IDFPLinie_FS";"dbo";"FPLinie";"IDFPLinie"
|
||||||
|
"FK_FPLinieFahrt_ArtFremdunternehmen";"dbo";"FPLinieFahrt";"IDArtFremdunternehmen_FS";"dbo";"ArtFremdunternehmen";"IDArtFremdunternehmen"
|
||||||
|
"FK_FPLinieFahrt_FPLinie";"dbo";"FPLinieFahrt";"IDFPLinie_FS";"dbo";"FPLinie";"IDFPLinie"
|
||||||
|
"FK_FPLinieFahrt_FPLinieFahrt";"dbo";"FPLinieFahrt";"IDFPLinieFahrt_FS_VerstaerkerVon";"dbo";"FPLinieFahrt";"IDFPLinieFahrt"
|
||||||
|
"FK_FPLinieFahrt_FPLinieFahrt_TeilenOriginal";"dbo";"FPLinieFahrt";"IDFPLinieFahrt_FS_TeilenOriginal";"dbo";"FPLinieFahrt";"IDFPLinieFahrt"
|
||||||
|
"FK_FPLinieFahrt_FPLinieZeitart";"dbo";"FPLinieFahrt";"IDFPLinieZeitart_FS";"dbo";"FPLinieZeitart";"IDFPLinieZeitart"
|
||||||
|
"FK_FPLinieFahrtAnschluss_FPLinieAnschluss";"dbo";"FPLinieFahrtAnschluss";"IDFPLinieAnschluss_FS";"dbo";"FPLinieAnschluss";"IDFPLinieAnschluss"
|
||||||
|
"FK_FPLinieFahrtAnschluss_FPLinieFahrt";"dbo";"FPLinieFahrtAnschluss";"IDFPLinieFahrt_FS";"dbo";"FPLinieFahrt";"IDFPLinieFahrt"
|
||||||
|
"FK_FPLinieFahrtAnschluss_FPLinieFahrt_Bringer";"dbo";"FPLinieFahrtAnschluss";"IDFPLinieFahrt_FS_Bringer";"dbo";"FPLinieFahrt";"IDFPLinieFahrt"
|
||||||
|
"FK_FPLinieFahrtAnschluss_FPLinieHaltestelle_Bringer";"dbo";"FPLinieFahrtAnschluss";"IDFPLinieHaltestelle_FS_Bringer";"dbo";"FPLinieHaltestelle";"IDFPLinieHaltestelle"
|
||||||
|
"FK_FPLinieFahrtAnschlussBeschraenkung_FPLinieBeschraenkung";"dbo";"FPLinieFahrtAnschlussBeschraenkung";"IDFPLinieBeschraenkung_FS";"dbo";"FPLinieBeschraenkung";"IDFPLinieBeschraenkung"
|
||||||
|
"FK_FPLinieFahrtAnschlussBeschraenkung_FPLinieFahrtAnschluss";"dbo";"FPLinieFahrtAnschlussBeschraenkung";"IDFPLinieFahrtAnschluss_FS";"dbo";"FPLinieFahrtAnschluss";"IDFPLinieFahrtAnschluss"
|
||||||
|
"FK_FPLinieFahrtBeschraenkung_FPLinieBeschraenkung";"dbo";"FPLinieFahrtBeschraenkung";"IDFPLinieBeschraenkung_FS";"dbo";"FPLinieBeschraenkung";"IDFPLinieBeschraenkung"
|
||||||
|
"FK_FPLinieFahrtBeschraenkung_FPLinieFahrt";"dbo";"FPLinieFahrtBeschraenkung";"IDFPLinieFahrt_FS";"dbo";"FPLinieFahrt";"IDFPLinieFahrt"
|
||||||
|
"FK_FPLinieHaltestelle_ArtKreisGebiet";"dbo";"FPLinieHaltestelle";"IDArtKreisGebiet_FS";"dbo";"ArtKreisGebiet";"IDArtKreisGebiet"
|
||||||
|
"FK_FPLinieHaltestelle_FPLinie";"dbo";"FPLinieHaltestelle";"IDFPLinie_FS";"dbo";"FPLinie";"IDFPLinie"
|
||||||
|
"FK_FPLinieHaltestelle_FPLinieHaltestelle";"dbo";"FPLinieHaltestelle";"IDFPLinieHaltestelle_FS_VerschiebenAuf";"dbo";"FPLinieHaltestelle";"IDFPLinieHaltestelle"
|
||||||
|
"FK_FPLinieHaltestelle_Haltepunkt";"dbo";"FPLinieHaltestelle";"IDHaltepunkt_FS";"dbo";"Haltepunkt";"IDHaltepunkt"
|
||||||
|
"FK_FPLinieHaltestelle_Haltestelle";"dbo";"FPLinieHaltestelle";"IDHaltestelle_FS";"dbo";"Haltestelle";"IDHaltestelle"
|
||||||
|
"FK_FPLinieHaltestelleBemerkung_FPLinieHaltestelle";"dbo";"FPLinieHaltestelleBemerkung";"IDFPLinieHaltestelle_FS";"dbo";"FPLinieHaltestelle";"IDFPLinieHaltestelle"
|
||||||
|
"FK_FPLinieHaltestelleBemerkung_HaltestelleBemerkung";"dbo";"FPLinieHaltestelleBemerkung";"IDHaltestelleBemerkung_FS";"dbo";"HaltestelleBemerkung";"IDHaltestelleBemerkung"
|
||||||
|
"FK_FPLinieHaltestelleZeitart_ArtKreisGebiet";"dbo";"FPLinieHaltestelleZeitart";"IDArtKreisGebiet_FS";"dbo";"ArtKreisGebiet";"IDArtKreisGebiet"
|
||||||
|
"FK_FPLinieHaltestelleZeitart_FPLinieHaltestelle";"dbo";"FPLinieHaltestelleZeitart";"IDFPLinieHaltestelle_FS";"dbo";"FPLinieHaltestelle";"IDFPLinieHaltestelle"
|
||||||
|
"FK_FPLinieHaltestelleZeitart_FPLinieZeitart";"dbo";"FPLinieHaltestelleZeitart";"IDFPLinieZeitart_FS";"dbo";"FPLinieZeitart";"IDFPLinieZeitart"
|
||||||
|
"FK_FPLinieHaltestelleZeitart_HaltestelleBemerkung";"dbo";"FPLinieHaltestelleZeitart";"IDHaltestelleBemerkung_FS";"dbo";"HaltestelleBemerkung";"IDHaltestelleBemerkung"
|
||||||
|
"FK_FPLinieHaltestelleZeitart_LinieZiel";"dbo";"FPLinieHaltestelleZeitart";"IDLinieZiel_FS";"dbo";"LinieZiel";"IDLinieZiel"
|
||||||
|
"FK_FPLinieZeitart_ArtStatistikGruppe";"dbo";"FPLinieZeitart";"IDArtStatistikgruppe_FS";"dbo";"ArtStatistikGruppe";"IDArtStatistikGruppe"
|
||||||
|
"FK_FPLinieZeitart_FPLinie";"dbo";"FPLinieZeitart";"IDFPLinie_FS";"dbo";"FPLinie";"IDFPLinie"
|
||||||
|
"FK_FPLinieZeitart_FPLinieHaltestelle_TeilenAbschnittBis";"dbo";"FPLinieZeitart";"IDFPLinieHaltestelle_FS_TeilenAbschnittBis";"dbo";"FPLinieHaltestelle";"IDFPLinieHaltestelle"
|
||||||
|
"FK_FPLinieZeitart_FPLinieHaltestelle_TeilenAbschnittVon";"dbo";"FPLinieZeitart";"IDFPLinieHaltestelle_FS_TeilenAbschnittVon";"dbo";"FPLinieHaltestelle";"IDFPLinieHaltestelle"
|
||||||
|
"FK_FPLinieZeitart_FPLinieZeitart";"dbo";"FPLinieZeitart";"IDFPLinieZeitart_FS_TeilenOriginal";"dbo";"FPLinieZeitart";"IDFPLinieZeitart"
|
||||||
|
"FK_FPSchuelerAbsage_Adresse";"dbo";"FPSchuelerAbsage";"IdAdresse_FS_Bearbeitet";"dbo";"Adresse";"IDAdresse"
|
||||||
|
"FK_FPSchuelerAbsage_FPSchueler";"dbo";"FPSchuelerAbsage";"IDFPSchueler_FS";"dbo";"FPSchueler";"IDFPSchueler"
|
||||||
|
"FK_FPSchuelerBefoerderung_FPSchueler";"dbo";"FPSchuelerBefoerderung";"IDFPSchueler_FS";"dbo";"FPSchueler";"IDFPSchueler"
|
||||||
|
"FK_FPSchuelerBefoerderung_FPSchule";"dbo";"FPSchuelerBefoerderung";"IDFPSchule_FS";"dbo";"FPSchule";"IDFPSchule"
|
||||||
|
"FK_FPSchuelerBefoerderung_FPSchuljahr";"dbo";"FPSchuelerBefoerderung";"IDFPSchuljahr_FS";"dbo";"FPSchuljahr";"IDFPSchuljahr"
|
||||||
|
"FK_FPSchuelerBefoerderungBewegung_Haltepunkt_Ausstieg";"dbo";"FPSchuelerBefoerderungBewegung";"IDHaltepunkt_FS_Ausstieg";"dbo";"Haltepunkt";"IDHaltepunkt"
|
||||||
|
"FK_FPSchuelerBefoerderungBewegung_Haltepunkt_Einstieg";"dbo";"FPSchuelerBefoerderungBewegung";"IDHaltepunkt_FS_Einstieg";"dbo";"Haltepunkt";"IDHaltepunkt"
|
||||||
|
"FK_FPSchuelerBefoerderungBewegung_Haltestelle_Ausstieg";"dbo";"FPSchuelerBefoerderungBewegung";"IDHaltestelle_FS_Ausstieg";"dbo";"Haltestelle";"IDHaltestelle"
|
||||||
|
"FK_FPSchuelerBefoerderungBewegung_Haltestelle_Einstieg";"dbo";"FPSchuelerBefoerderungBewegung";"IDHaltestelle_FS_Einstieg";"dbo";"Haltestelle";"IDHaltestelle"
|
||||||
|
"FK_FPSchuelerBefoerderungBewegung_IDFPSchuelerBefoerderung";"dbo";"FPSchuelerBefoerderungBewegung";"IDFPSchuelerBefoerderung_FS";"dbo";"FPSchuelerBefoerderung";"IDFPSchuelerBefoerderung"
|
||||||
|
"FK_FPSchuelerBefoerderungBewegungAbsage_FPSchuelerAbsage";"dbo";"FPSchuelerBefoerderungBewegungAbsage";"IDFPSchuelerAbsage_FS";"dbo";"FPSchuelerAbsage";"IDFPSchuelerAbsage"
|
||||||
|
"FK_FPSchuelerBefoerderungBewegungAbsage_FPSchuelerBefoerderungBewegung";"dbo";"FPSchuelerBefoerderungBewegungAbsage";"IDFPSchuelerBefoerderungBewegung_FS";"dbo";"FPSchuelerBefoerderungBewegung";"IDFPSchuelerBefoerderungBewegung"
|
||||||
|
"FK_FPSchuelerBefoerderungBewegungZuordnung_FPLinieFahrt";"dbo";"FPSchuelerBefoerderungBewegungZuordnung";"IDFPLinieFahrt_FS";"dbo";"FPLinieFahrt";"IDFPLinieFahrt"
|
||||||
|
"FK_FPSchuelerBefoerderungBewegungZuordnung_FPLinieHaltestelle";"dbo";"FPSchuelerBefoerderungBewegungZuordnung";"IDFPLinieHaltestelle_FS";"dbo";"FPLinieHaltestelle";"IDFPLinieHaltestelle"
|
||||||
|
"FK_FPSchuelerBefoerderungBewegungZuordnung_FPSchuelerBefoerderungBewegung";"dbo";"FPSchuelerBefoerderungBewegungZuordnung";"IDFPSchuelerBefoerderungBewegung_FS";"dbo";"FPSchuelerBefoerderungBewegung";"IDFPSchuelerBefoerderungBewegung"
|
||||||
|
"FK_FPSchuelerBefoerderungBewegungZuordnung_FPZeitart";"dbo";"FPSchuelerBefoerderungBewegungZuordnung";"IDFPLinieZeitart_FS";"dbo";"FPLinieZeitart";"IDFPLinieZeitart"
|
||||||
|
"FK_FPSchuleHaltestelleHaltepunkt_FPSchule";"dbo";"FPSchuleHaltestelleHaltepunkt";"IDFPSchule_FS";"dbo";"FPSchule";"IDFPSchule"
|
||||||
|
"FK_FPSchuleHaltestelleHaltepunkt_Haltepunkt";"dbo";"FPSchuleHaltestelleHaltepunkt";"IDHaltepunkt_FS";"dbo";"Haltepunkt";"IDHaltepunkt"
|
||||||
|
"FK_FPSchuleHaltestelleHaltepunkt_Haltestelle";"dbo";"FPSchuleHaltestelleHaltepunkt";"IDHaltestelle_FS";"dbo";"Haltestelle";"IDHaltestelle"
|
||||||
|
"FK_FreibescheinigungManuelleEingabe_Adresse";"dbo";"FreibescheinigungManuelleEingabe";"IDAdresse_FS_Fahrer";"dbo";"Adresse";"IDAdresse"
|
||||||
|
"FK_FreibescheinigungRuhetag_Adresse";"dbo";"FreibescheinigungRuhetag";"IDAdresse_FS_Fahrer";"dbo";"Adresse";"IDAdresse"
|
||||||
|
"FK_GruppeVerkehrstag_ArtGruppeVerkehrstag";"dbo";"GruppeVerkehrstag";"IDArtGruppeVerkehrstag_FS";"dbo";"ArtGruppeVerkehrstag";"IDArtGruppeVerkehrstag"
|
||||||
|
"FK_GruppeVerkehrstagFerien_ArtGruppeVerkehrstag";"dbo";"GruppeVerkehrstagFerien";"IDArtGruppeVerkehrstag_FS";"dbo";"ArtGruppeVerkehrstag";"IDArtGruppeVerkehrstag"
|
||||||
|
"FK_Gutschein_ArtGutscheinversand";"dbo";"Gutschein";"IDArtGutscheinversand_FS";"dbo";"ArtGutscheinversand";"IDArtGutscheinversand"
|
||||||
|
"FK_GutscheinlayoutInternet_ArtGutscheinlayout";"dbo";"GutscheinlayoutInternet";"IDArtGutscheinlayout_FS";"dbo";"ArtGutscheinlayout";"IDArtGutscheinlayout"
|
||||||
|
"FK_Gutscheinzuschlag_Gutschein";"dbo";"GutscheinZuschlag";"IDGutschein_FS";"dbo";"Gutschein";"IDGutschein"
|
||||||
|
"FK_Gutscheinzuschlag_Kontenplan";"dbo";"GutscheinZuschlag";"IDKontenplan_FS";"dbo";"Kontenplan";"IDKontenplan"
|
||||||
|
"FK_Haltepunkt_ArtHaltepunktArt";"dbo";"Haltepunkt";"IDArtHaltepunktArt_FS";"dbo";"ArtHaltepunktArt";"IDArtHaltepunktArt"
|
||||||
|
"FK_Haltepunkt_Haltestelle";"dbo";"Haltepunkt";"IDHaltestelle_FS";"dbo";"Haltestelle";"IDHaltestelle"
|
||||||
|
"FK_HaltepunktFahrplankasten_ArtHaltepunktFahrplankasten";"dbo";"HaltepunktFahrplankasten";"IDArtHaltepunktFahrplankasten_FS";"dbo";"ArtHaltepunktFahrplankasten";"IDArtHaltepunktFahrplankasten"
|
||||||
|
"FK_HaltepunktFahrplankasten_HaltestelleHaltepunkt";"dbo";"HaltepunktFahrplankasten";"IDHaltestelleHaltepunkt_FS";"dbo";"HaltestelleHaltepunkt";"IDHaltestelleHaltepunkt"
|
||||||
|
"FK_Haltestelle_ArtHaltestelleZwischenpunkttyp";"dbo";"Haltestelle";"IDArtHaltestelleZwischenpunkttyp_FS";"dbo";"ArtHaltestelleZwischenpunkttyp";"IDArtHaltestelleZwischenpunkttyp"
|
||||||
|
"FK_Haltestelle_HaltestelleNach";"dbo";"Haltestelle";"IDHaltestelle_FS_ZwNach";"dbo";"Haltestelle";"IDHaltestelle"
|
||||||
|
"FK_Haltestelle_HaltestelleVon";"dbo";"Haltestelle";"IDHaltestelle_FS_ZwVon";"dbo";"Haltestelle";"IDHaltestelle"
|
||||||
|
"FK_HaltestelleDruck_Haltestelle";"dbo";"HaltestelleDruck";"IDHaltestelle_FS";"dbo";"Haltestelle";"IDHaltestelle"
|
||||||
|
"FK_HaltestelleFahrplanAdresse_FahrplanAdresse";"dbo";"HaltestelleFahrplanAdresse";"IDFahrplanAdresse_FS";"dbo";"FahrplanAdresse";"IDFahrplanAdresse"
|
||||||
|
"FK_HaltestelleFahrplanAdresse_Haltestelle";"dbo";"HaltestelleFahrplanAdresse";"IDHaltestelle_FS";"dbo";"Haltestelle";"IDHaltestelle"
|
||||||
|
"FK_HaltestelleHaltepunkt_ArtBetriebshof";"dbo";"HaltestelleHaltepunkt";"IDArtBetriebshof_FS";"dbo";"ArtBetriebshof";"IDArtBetriebshof"
|
||||||
|
"FK_HaltestelleHaltepunkt_ArtHaltepunktAbfallbehaelter";"dbo";"HaltestelleHaltepunkt";"IDArtHaltepunktAbfallbehaelter_FS";"dbo";"ArtHaltepunktAbfallbehaelter";"IDArtHaltepunktAbfallbehaelter"
|
||||||
|
"FK_HaltestelleHaltepunkt_ArtHaltepunktBlindenleitsystem";"dbo";"HaltestelleHaltepunkt";"IDArtHaltepunktBlindenleitsystem_FS";"dbo";"ArtHaltepunktBlindenleitsystem";"IDArtHaltepunktBlindenleitsystem"
|
||||||
|
"FK_HaltestelleHaltepunkt_ArtHaltepunktBlinkaufforderung";"dbo";"HaltestelleHaltepunkt";"IDArtHaltepunktBlinkaufforderung_FS";"dbo";"ArtHaltepunktBlinkaufforderung";"IDArtHaltepunktBlinkaufforderung"
|
||||||
|
"FK_HaltestelleHaltepunkt_ArtHaltepunktBusbordstein";"dbo";"HaltestelleHaltepunkt";"IDArtHaltepunktBusbordstein_FS";"dbo";"ArtHaltepunktBusbordstein";"IDArtHaltepunktBusbordstein"
|
||||||
|
"FK_HaltestelleHaltepunkt_Haltepunkt";"dbo";"HaltestelleHaltepunkt";"IDHaltepunkt_FS";"dbo";"Haltepunkt";"IDHaltepunkt"
|
||||||
|
"FK_HaltestelleHaltepunkt_Haltestelle";"dbo";"HaltestelleHaltepunkt";"IDHaltestelle_FS";"dbo";"Haltestelle";"IDHaltestelle"
|
||||||
|
"FK_HaltestelleHaltepunkt_Ort";"dbo";"HaltestelleHaltepunkt";"IDOrt_FS";"dbo";"Ort";"IDOrt"
|
||||||
|
"FK_ImportAdressen_ArtImportAdressen";"dbo";"ImportAdressen";"IDArtImportAdressen_FS";"dbo";"ArtImportAdressen";"IDArtImportAdressen"
|
||||||
|
"FK_ImportMatrix_ArtBuchungsImport";"dbo";"ImportMatrix";"IDArtBuchungsImport_FS";"dbo";"ArtBuchungsImport";"IDArtBuchungsImport"
|
||||||
|
"FK_InternetCRMZuweisung_ArtCRMGruppe";"dbo";"InternetCRMZuweisung";"IDArtCRMGruppe_FS";"dbo";"ArtCRMGruppe";"IDArtCRMGruppe"
|
||||||
|
"FK_InternetCRMZuweisung_ArtCRMInternet";"dbo";"InternetCRMZuweisung";"IDArtCRMInternet_FS";"dbo";"ArtCRMInternet";"IDArtCRMInternet"
|
||||||
|
"FK_KalenderFahrplanversion_ArtFahrplanVersion";"dbo";"KalenderFahrplanversion";"IDArtFahrplanversion_FS";"dbo";"ArtFahrplanVersion";"IDArtFahrplanVersion"
|
||||||
|
"FK_KalenderLaufzeitschema_ArtLaufzeitschema";"dbo";"KalenderLaufzeitschema";"IDArtLaufzeitschema_FS";"dbo";"ArtLaufzeitschema";"IDArtLaufzeitschema"
|
||||||
|
"FK_KalenderSondergruppen_ArtGruppeVerkehrstag";"dbo";"KalenderSondergruppen";"IDArtSondergruppen_FS";"dbo";"ArtGruppeVerkehrstag";"IDArtGruppeVerkehrstag"
|
||||||
|
"FK_KalenderWochentypen_ArtWochentyp";"dbo";"KalenderWochentypen";"IDArtWochentyp_FS";"dbo";"ArtWochentyp";"IDArtWochentyp"
|
||||||
|
"FK_KalkulationBeförderung_Kalkulation";"dbo";"KalkulationBeförderung";"IDKalkulation_FS";"dbo";"Kalkulation";"IDKalkulation"
|
||||||
|
"FK_KalkulationBeförderungLand_KalkulationBeförderung";"dbo";"KalkulationBeförderungLand";"IDKalkulationBeförderung_FS";"dbo";"KalkulationBeförderung";"IDKalkulationBeförderung"
|
||||||
|
"FK_KalkulationBusleistung_Kalkulation";"dbo";"KalkulationBusleistung";"IDKalkulation_FS";"dbo";"Kalkulation";"IDKalkulation"
|
||||||
|
"FK_KalkulationBusleistungPreis_KalkulationBusleistung";"dbo";"KalkulationBusleistungPreis";"IDKalkulationBusleistung_FS";"dbo";"KalkulationBusleistung";"IDKalkulationBusleistung"
|
||||||
|
"FK_KalkulationBusleistungPreis_Kalkulationswertbezeichnung";"dbo";"KalkulationBusleistungPreis";"IDKalkulationswertbezeichnung_FS";"dbo";"KalkulationswertBezeichnung";"IDKalkulationswertBezeichnung"
|
||||||
|
"FK_KalkulationErgebnis_Kalkulation";"dbo";"KalkulationErgebnis";"IDKalkulation_FS";"dbo";"Kalkulation";"IDKalkulation"
|
||||||
|
"FK_KalkulationErgebnisM_Kalkulation";"dbo";"KalkulationErgebnisM";"IDKalkulation_FS";"dbo";"Kalkulation";"IDKalkulation"
|
||||||
|
"FK_KalkulationErgebnisZimmerPreis_KalkulationErgebnis";"dbo";"KalkulationErgebnisZimmerPreis";"IDKalkulationErgebnis_FS";"dbo";"KalkulationErgebnis";"IDKalkulationErgebnis"
|
||||||
|
"FK_KalkulationErgebnisZimmerPreis_Zimmerart";"dbo";"KalkulationErgebnisZimmerPreis";"IDZimmerart_FS";"dbo";"Zimmerart";"IDZimmerart"
|
||||||
|
"FK_KalkulationFZAusgrenzung_KalkulationFZ";"dbo";"KalkulationFZAusgrenzung";"IDKalkulationFZ_FS";"dbo";"KalkulationFZ";"IDKalkulationFZ"
|
||||||
|
"FK_KalkulationFZBeförderung_KalkulationFZ";"dbo";"KalkulationFZBeförderung";"IDKalkulationFZ_FS";"dbo";"KalkulationFZ";"IDKalkulationFZ"
|
||||||
|
"FK_KalkulationFZErgebnis_ArtPartnerPreisCode";"dbo";"KalkulationFZErgebnis";"IdArtPartnerPreisCode_FS";"dbo";"ArtPartnerPreisCode";"IDArtPartnerPreisCode"
|
||||||
|
"FK_KalkulationFZErgebnis_ArtVerpflegung";"dbo";"KalkulationFZErgebnis";"IDArtVerpflegung_FS";"dbo";"ArtVerpflegung";"IDArtVerpflegung"
|
||||||
|
"FK_KalkulationFZErgebnis_KalkulationFZ";"dbo";"KalkulationFZErgebnis";"IDKalkulationFZ_FS";"dbo";"KalkulationFZ";"IDKalkulationFZ"
|
||||||
|
"FK_KalkulationFZTag_KalkulationFZ";"dbo";"KalkulationFZTag";"IDKalkulationFZ_FS";"dbo";"KalkulationFZ";"IDKalkulationFZ"
|
||||||
|
"FK_KalkulationPax_Kalkulation";"dbo";"KalkulationPax";"IDKalkulation_FS";"dbo";"Kalkulation";"IDKalkulation"
|
||||||
|
"FK_KalkulationReise_Kalkulation";"dbo";"KalkulationReise";"IDKalkulation_FS";"dbo";"Kalkulation";"IDKalkulation"
|
||||||
|
"FK_KalkulationReise_Reise";"dbo";"KalkulationReise";"IDReise_FS";"dbo";"Reise";"IDReise"
|
||||||
|
"FK_KalkulationSonstiges_Kalkulation";"dbo";"KalkulationSonstiges";"IDKalkulation_FS";"dbo";"Kalkulation";"IDKalkulation"
|
||||||
|
"FK_KalkulationSonstigesPreis_KalkulationSonstiges";"dbo";"KalkulationSonstigesPreis";"IDKalkulationSonstiges_FS";"dbo";"KalkulationSonstiges";"IDKalkulationSonstiges"
|
||||||
|
"FK_KalkulationUnterbringung_Kalkulation";"dbo";"KalkulationUnterbringung";"IDKalkulation_FS";"dbo";"Kalkulation";"IDKalkulation"
|
||||||
|
"FK_KalkulationUnterbringungM_Kalkulation";"dbo";"KalkulationUnterbringungM";"IDKalkulation_FS";"dbo";"Kalkulation";"IDKalkulation"
|
||||||
|
"FK_KalkulationUnterbringungMPreis_KalkulationUnterbringungM";"dbo";"KalkulationUnterbringungMPreis";"IDKalkulationUnterbringungM_FS";"dbo";"KalkulationUnterbringungM";"IDKalkulationUnterbringungM"
|
||||||
|
"FK_KalkulationUnterbringungPartner_Adresse";"dbo";"KalkulationUnterbringungPartner";"IDAdresse_FS_Partner";"dbo";"Adresse";"IDAdresse"
|
||||||
|
"FK_KalkulationUnterbringungPartner_KalkulationUnterbringung";"dbo";"KalkulationUnterbringungPartner";"IDKalkulationUnterbringung_FS";"dbo";"KalkulationUnterbringung";"IDKalkulationUnterbringung"
|
||||||
|
"FK_KalkulationUnterbringungPreis_KalkulationUnterbringung";"dbo";"KalkulationUnterbringungPreis";"IDKalkulationUnterbringung_FS";"dbo";"KalkulationUnterbringung";"IDKalkulationUnterbringung"
|
||||||
|
"FK_KalkulationUnterbringungPreis_KalkulationUnterbringungPartner";"dbo";"KalkulationUnterbringungPreis";"IDKalkulationUnterbringungPartner_FS";"dbo";"KalkulationUnterbringungPartner";"IDKalkulationUnterbringungPartner"
|
||||||
|
"FK_KalkulationUnterbringungPreis_KalkulationUnterbringungZimmer";"dbo";"KalkulationUnterbringungPreis";"IDKalkulationUnterbringungZimmer_FS";"dbo";"KalkulationUnterbringungZimmer";"IDKalkulationUnterbringungZimmer"
|
||||||
|
"FK_KalkulationUnterbringungZimmer_KalkulationUnterbringung";"dbo";"KalkulationUnterbringungZimmer";"IDKalkulationUnterbringung_FS";"dbo";"KalkulationUnterbringung";"IDKalkulationUnterbringung"
|
||||||
|
"FK_KalkulationUnterbringungZimmer_Zimmerart";"dbo";"KalkulationUnterbringungZimmer";"IDZimmerart_FS";"dbo";"Zimmerart";"IDZimmerart"
|
||||||
|
"FK_KalkulationUnterbringungZimmerPreis_KalkulationUnterbringung";"dbo";"KalkulationUnterbringungZimmerPreis";"IDKalkulationUnterbringung_FS";"dbo";"KalkulationUnterbringung";"IDKalkulationUnterbringung"
|
||||||
|
"FK_KalkulationUnterbringungZimmerPreis_KalkulationUnterbringungZimmer";"dbo";"KalkulationUnterbringungZimmerPreis";"IDKalkulationUnterbringungZimmerPreis";"dbo";"KalkulationUnterbringungZimmer";"IDKalkulationUnterbringungZimmer"
|
||||||
|
"FK_KalkulationZuschlag_Kalkulation";"dbo";"KalkulationZuschlag";"IDKalkulation_FS";"dbo";"Kalkulation";"IDKalkulation"
|
||||||
|
"FK_KalkulationZuschlagPosten_KalkulationZuschlag";"dbo";"KalkulationZuschlagPosten";"IDKalkulationZuschlag_FS";"dbo";"KalkulationZuschlag";"IDKalkulationZuschlag"
|
||||||
|
"FK_KommunikationEinstellung_Kommunikation";"dbo";"KommunikationEinstellung";"IDKommunikation_FS";"dbo";"Kommunikation";"IDKommunikation"
|
||||||
|
"FK_KonstantenErmäßigungProdukt_KonstantenErmäßigung";"dbo";"KonstantenErmäßigungProdukt";"IDKonstantenErmäßigungStaffel_FS";"dbo";"KonstantenErmäßigungStaffel";"IDKonstantenErmäßigungStaffel"
|
||||||
|
"FK_KonstantenErmäßigungProdukt_Produkt";"dbo";"KonstantenErmäßigungProdukt";"IDProdukt_FS";"dbo";"Produkt";"IDProdukt"
|
||||||
|
"FK_KonstantenErmäßigungStaffel_KonstantenErmäßigung";"dbo";"KonstantenErmäßigungStaffel";"IDKonstantenErmäßigung_FS";"dbo";"KonstantenErmäßigung";"IDKonstantenErmäßigung"
|
||||||
|
"FK_KonstantenErmäßigungZimmer_KonstantenErmäßigung";"dbo";"KonstantenErmäßigungZimmer";"IDKonstantenErmäßigungStaffel_FS";"dbo";"KonstantenErmäßigungStaffel";"IDKonstantenErmäßigungStaffel"
|
||||||
|
"FK_KonstantenErmäßigungZimmer_Zimmerart";"dbo";"KonstantenErmäßigungZimmer";"IDZimmerart_FS";"dbo";"Zimmerart";"IDZimmerart"
|
||||||
|
"FK_KonstantenErmäßigungZustieg_KonstantenErmäßigung";"dbo";"KonstantenErmäßigungZustieg";"IDKonstantenErmäßigungStaffel_FS";"dbo";"KonstantenErmäßigungStaffel";"IDKonstantenErmäßigungStaffel"
|
||||||
|
"FK_KonstantenErmäßigungZustieg_Zustieg";"dbo";"KonstantenErmäßigungZustieg";"IDZustieg_FS";"dbo";"Zustieg";"IDZustieg"
|
||||||
|
"FK_KonstantenFlexTarifStaffel_KonstantenFlexTarif";"dbo";"KonstantenFlexTarifStaffel";"IDKonstantenFlexTarif_FS";"dbo";"KonstantenFlexTarif";"IDKonstantenFlexTarif"
|
||||||
|
"FK_KonstantenFlexTarifStaffel_Leistung";"dbo";"KonstantenFlexTarifStaffel";"IDLeistung_FS";"dbo";"Leistung";"IDLeistung"
|
||||||
|
"FK_KonstantenGruppenermStaffel_KonstantenGruppenerm";"dbo";"KonstantenGruppenermStaffel";"IDKonstantenGruppenerm_FS";"dbo";"KonstantenGruppenerm";"IDKonstantenGruppenerm"
|
||||||
|
"FK_KonstantenRabattStaffelEingabe_KonstantenRabattStaffel";"dbo";"KonstantenRabattStaffelEingabe";"IDKonstantenRabattStaffel_FS";"dbo";"KonstantenRabattStaffel";"IDKonstantenRabattStaffel"
|
||||||
|
"FK_KonstantenStAuftZuschlag_Land";"dbo";"KonstantenStAuftZuschlag";"IDLand_FS";"dbo";"Land";"IDLand"
|
||||||
|
"FK_KonstantenSteueraufteilung_SteueraufteilungArt";"dbo";"KonstantenSteueraufteilung";"IDSteueraufteilungArt_FS";"dbo";"SteueraufteilungArt";"IDSteueraufteilungArt"
|
||||||
|
"FK_KonstantenSteueraufteilungDetail_KonstantenSteueraufteilung";"dbo";"KonstantenSteueraufteilungDetail";"IDKonstantenSteueraufteilung_FS";"dbo";"KonstantenSteueraufteilung";"IDKonstantenSteueraufteilung"
|
||||||
|
"FK_KonstantenSteueraufteilungDetail_Steueraufteilung";"dbo";"KonstantenSteueraufteilungDetail";"IDSteueraufteilungDetail_FS";"dbo";"SteueraufteilungDetail";"IDSteueraufteilungDetail"
|
||||||
|
"FK_KonstantenStornoStaffelTage_KonstantenStornoStaffel";"dbo";"KonstantenStornoStaffelTage";"IDKonstantenStornoStaffel_FS";"dbo";"KonstantenStornoStaffel";"IDKonstantenStornoStaffel"
|
||||||
|
"FK_ArtikelLagerort_Artikel";"dbo";"LagerRegal";"IDLager_FS";"dbo";"Lager";"IDLager"
|
||||||
|
"FK_LandFiskal_Land";"dbo";"LandFiskal";"IDLand_Fs";"dbo";"Land";"IDLand"
|
||||||
|
"FK_LandHinweis_Land";"dbo";"LandHinweis";"IDLand_FS";"dbo";"Land";"IDLand"
|
||||||
|
"FK_LandKonto_Land";"dbo";"LandKonto";"IDLand_FS";"dbo";"Land";"IDLand"
|
||||||
|
"FK_LandMwst_Land";"dbo";"LandMwst";"IDLand_FS";"dbo";"Land";"IDLand"
|
||||||
|
"FK_LandVerpflegungSpesen_ArtSpesenLand";"dbo";"LandVerpflegungSpesen";"IDArtSpesenLand_FS";"dbo";"ArtSpesenLand";"IDArtSpesenLand"
|
||||||
|
"FK_LandVerpflegungSpesen_ArtSpesenVerpflegung";"dbo";"LandVerpflegungSpesen";"IDArtSpesenVerpflegung_FS";"dbo";"ArtSpesenVerpflegung";"IDArtSpesenVerpflegung"
|
||||||
|
"FK_Leistung_ArtLeistungSonstigesUnterart";"dbo";"Leistung";"IDArtLeistungSonstigesUnterart_FS";"dbo";"ArtLeistungSonstigesUnterart";"IDArtLeistungSonstigesUnterart"
|
||||||
|
"FK_Leistung_LeistungBefoerderung";"dbo";"LeistungBefoerderung";"IDLeistung_FS";"dbo";"Leistung";"IDLeistung"
|
||||||
|
"FK_Leistung_LeistungExternSystem";"dbo";"LeistungExternSystem";"IDLeistung_FS";"dbo";"Leistung";"IDLeistung"
|
||||||
|
"FK_LeistungHotelMoeglich_Adresse";"dbo";"LeistungHotelGesperrt";"IDAdresse_FS_Partner";"dbo";"Adresse";"IDAdresse"
|
||||||
|
"FK_LeistungHotelMoeglich_LeistungBefoerderung";"dbo";"LeistungHotelGesperrt";"IDLeistungBefoerderung_FS";"dbo";"LeistungBefoerderung";"IDLeistungBefoerderung"
|
||||||
|
"FK_Adresse_LeistungMandantMoeglich";"dbo";"LeistungMandantMoeglich";"IDAdresse_FS";"dbo";"Adresse";"IDAdresse"
|
||||||
|
"FK_Leistung_LeistungMandantMoeglich";"dbo";"LeistungMandantMoeglich";"IDLeistung_FS";"dbo";"Leistung";"IDLeistung"
|
||||||
|
"FK_Adresse_LeistungPartnerMoeglich";"dbo";"LeistungPartnerMoeglich";"IDAdresse_FS";"dbo";"Adresse";"IDAdresse"
|
||||||
|
"FK_Leistung_LeistungPartnerMoeglich";"dbo";"LeistungPartnerMoeglich";"IDLeistung_FS";"dbo";"Leistung";"IDLeistung"
|
||||||
|
"FK_LeistungPreis_ArtPreisschema";"dbo";"LeistungPreis";"IDArtPreisSchema_FS";"dbo";"ArtPreisschema";"IDArtPreisschema"
|
||||||
|
"FK_LeistungPreis_Leistung";"dbo";"LeistungPreis";"IDLeistung_FS";"dbo";"Leistung";"IDLeistung"
|
||||||
|
"FK_LeistungProdukt_Leistung";"dbo";"LeistungProdukt";"IDLeistung_FS";"dbo";"Leistung";"IDLeistung"
|
||||||
|
"FK_LeistungProdukt_Produkt";"dbo";"LeistungProdukt";"IDProdukt_FS";"dbo";"Produkt";"IDProdukt"
|
||||||
|
"FK_Leistung_LeistungSelektion";"dbo";"LeistungSelektionenKunde";"IDLeistung_FS";"dbo";"Leistung";"IDLeistung"
|
||||||
|
"FK_Selektionsstamm_LeistungSelektion";"dbo";"LeistungSelektionenKunde";"IDSelektionsstamm_FS";"dbo";"Selektionsstamm";"IDSelektionsstamm"
|
||||||
|
"FK_LeistungSitzplan_Leistung";"dbo";"LeistungSitzplan";"IDLeistung_FS";"dbo";"Leistung";"IDLeistung"
|
||||||
|
"FK_LeistungSitzplan_Sitzplan";"dbo";"LeistungSitzplan";"IDSitzplan_FS";"dbo";"Sitzplan";"IDSitzplan"
|
||||||
|
"FK_Leistung_LeistungText";"dbo";"LeistungText";"IDLeistung_FS";"dbo";"Leistung";"IDLeistung"
|
||||||
|
"FK_Leistung_LeistungTicket";"dbo";"LeistungTicket";"IDLeistung_FS";"dbo";"Leistung";"IDLeistung"
|
||||||
|
"FK_LeistungTicketZusatz_LeistungTicket";"dbo";"LeistungTicketZusatz";"IDLeistungTicket_FS";"dbo";"LeistungTicket";"IDLeistungTicket"
|
||||||
|
"FK_LeistungVersicherung_Leistung";"dbo";"LeistungVersicherung";"IDLeistung_FS";"dbo";"Leistung";"IDLeistung"
|
||||||
|
"FK_LeistungVersicherung_Versicherungsbedingung_Leistung";"dbo";"LeistungVersicherung_Versicherungsbedingung";"IDLeistung_FS";"dbo";"Leistung";"IDLeistung"
|
||||||
|
"FK_LeistungVersicherung_Versicherungsbedingung_Versicherungsbedingung";"dbo";"LeistungVersicherung_Versicherungsbedingung";"IDVersicherungsbedingung_FS";"dbo";"Versicherungsbedingung";"IDVersicherungsbedingung"
|
||||||
|
"FK_LeistungVersicherungsGruppe_ArtVersicherungsGruppe";"dbo";"LeistungVersicherungsGruppe";"IDArtVersicherungsGruppe_FS";"dbo";"ArtVersicherungsGruppe";"IDArtVersicherungsGruppe"
|
||||||
|
"FK_LeistungVersicherungsGruppe_LeistungVersicherung";"dbo";"LeistungVersicherungsGruppe";"IDLeistungVersicherung_FS";"dbo";"LeistungVersicherung";"IDLeistungVersicherung"
|
||||||
|
"FK_Leistung_LeistungVoucher";"dbo";"LeistungVoucher";"IDLeistung_FS";"dbo";"Leistung";"IDLeistung"
|
||||||
|
"FK_LeistungZusatz_ArtAgenturPreisgruppe";"dbo";"LeistungZusatz";"IDArtAgenturPreisgruppe_FS";"dbo";"ArtAgenturPreisgruppe";"IDArtAgenturPreisgruppe"
|
||||||
|
"FK_LeistungZusatz_KonstantenSteueraufteilung";"dbo";"LeistungZusatz";"IDKonstantenSteueraufteilung_FS";"dbo";"KonstantenSteueraufteilung";"IDKonstantenSteueraufteilung"
|
||||||
|
"FK_LeistungZusatz_Leistung";"dbo";"LeistungZusatz";"IDLeistung_FS";"dbo";"Leistung";"IDLeistung"
|
||||||
|
"FK_LeistungZustiegMoeglich_LeistungBefoerderung";"dbo";"LeistungZustiegMoeglichGesperrt";"IDLeistungBefoerderung_FS";"dbo";"LeistungBefoerderung";"IDLeistungBefoerderung"
|
||||||
|
"FK_Zustieg_LeistungZustiegMoeglich";"dbo";"LeistungZustiegMoeglichGesperrt";"IDZustieg_FS";"dbo";"Zustieg";"IDZustieg"
|
||||||
|
"FK_LiniePlanungEinstellung_Adresse";"dbo";"LiniePlanungEinstellung";"IDAdresse_FS_Personal";"dbo";"Adresse";"IDAdresse"
|
||||||
|
"FK_LiniePlanungEinstellung_ArtPersonalGruppeKompetenz";"dbo";"LiniePlanungEinstellung";"IDArtPersonalGruppeKompetenz_FS";"dbo";"ArtPersonalGruppeKompetenz";"IDArtPersonalGruppeKompetenz"
|
||||||
|
"FK_LinieStatistikAufteilungSpalteZuordnung_ArtStatistikGruppe";"dbo";"LinieStatistikAufteilungSpalteZuordnung";"IDArtStatistikGruppe_FS";"dbo";"ArtStatistikGruppe";"IDArtStatistikGruppe"
|
||||||
|
"FK_LinieStatistikAufteilungSpalteZuordnung_Auftragsart";"dbo";"LinieStatistikAufteilungSpalteZuordnung";"IDAuftragsart_FS";"dbo";"Auftragsart";"IDAuftragsart"
|
||||||
|
"FK_LinieStatistikAufteilungSpalteZuordnung_LinieStatistikAufteilungSpalte";"dbo";"LinieStatistikAufteilungSpalteZuordnung";"IDLinieStatistikAufteilungSpalte_FS";"dbo";"LinieStatistikAufteilungSpalte";"IDLinieStatistikAufteilungSpalte"
|
||||||
|
"FK_LinieStatistikSummeSpalte_ArtLinieStatistikSumme";"dbo";"LinieStatistikSummeSpalte";"IDArtLinieStatistikSumme_FS";"dbo";"ArtLinieStatistikSumme";"IDArtLinieStatistikSumme"
|
||||||
|
"FK_LinieStatistikSummeSpalteZuordnung_ArtStatistikGruppe";"dbo";"LinieStatistikSummeSpalteZuordnung";"IDArtStatistikGruppe_FS";"dbo";"ArtStatistikGruppe";"IDArtStatistikGruppe"
|
||||||
|
"FK_LinieStatistikSummeSpalteZuordnung_Auftragsart";"dbo";"LinieStatistikSummeSpalteZuordnung";"IDAuftragsart_FS";"dbo";"Auftragsart";"IDAuftragsart"
|
||||||
|
"FK_LinieStatistikSummeSpalteZuordnung_LinieStatistikSummeSpalte";"dbo";"LinieStatistikSummeSpalteZuordnung";"IDLinieStatistikSummeSpalte_FS";"dbo";"LinieStatistikSummeSpalte";"IDLinieStatistikSummeSpalte"
|
||||||
|
"FK_LinieWegPunkteGM_Haltestelle";"dbo";"LinieWegPunkteGM";"IDHaltestelle_FS_von";"dbo";"Haltestelle";"IDHaltestelle"
|
||||||
|
"FK_LinieWegPunkteGM_Haltestelle1";"dbo";"LinieWegPunkteGM";"IDHaltestelle_FS_nach";"dbo";"Haltestelle";"IDHaltestelle"
|
||||||
|
"FK_LinieZiel_ArtLinieZielSonderzeichen";"dbo";"LinieZiel";"IDArtLinieZielSonderzeichen_FS";"dbo";"ArtLinieZielSonderzeichen";"IDArtLinieZielSonderzeichen"
|
||||||
|
"FK_LinieZusatzKilometer_ArtStatistikGruppe";"dbo";"LinieZusatzKilometer";"IDArtStatistikgruppe_FS";"dbo";"ArtStatistikGruppe";"IDArtStatistikGruppe"
|
||||||
|
"FK_LinieZusatzKilometer_Auftragsart";"dbo";"LinieZusatzKilometer";"IDAuftragsart_FS";"dbo";"Auftragsart";"IDAuftragsart"
|
||||||
|
"FK_LinieZusatzKilometer_Fahrzeug";"dbo";"LinieZusatzKilometer";"IDFahrzeug_FS";"dbo";"Fahrzeug";"IDFahrzeug"
|
||||||
|
"FK_ListenterminalEinstellung_Adresse";"dbo";"ListenterminalEinstellung";"IDAdresse_FS_Personal";"dbo";"Adresse";"IDAdresse"
|
||||||
|
"FK_ListenterminalEinstellung_ArtPersonalGruppeKompetenz";"dbo";"ListenterminalEinstellung";"IDArtPersonalGruppeKompetenz_FS";"dbo";"ArtPersonalGruppeKompetenz";"IDArtPersonalGruppeKompetenz"
|
||||||
|
"FK_Lohnart_ArtLohnsystem";"dbo";"Lohnart";"IDArtLohnsystem_FS";"dbo";"ArtLohnsystem";"IDArtLohnsystem"
|
||||||
|
"FK_LohnartPersonalSperrung_Adresse";"dbo";"LohnartPersonalSperrung";"IDAdresse_FS_Fahrer";"dbo";"Adresse";"IDAdresse"
|
||||||
|
"FK_LohnartPersonalSperrung_Lohnart";"dbo";"LohnartPersonalSperrung";"IDLohnart_FS";"dbo";"Lohnart";"IDLohnart"
|
||||||
|
"FK_LohnartTag_Lohnart";"dbo";"LohnartTag";"IDLohnart_FS";"dbo";"Lohnart";"IDLohnart"
|
||||||
|
"FK_LohnDruckLobuPersonalSperrung_Adresse";"dbo";"LohnDruckLobuPersonalSperrung";"IDAdresse_FS_Fahrer";"dbo";"Adresse";"IDAdresse"
|
||||||
|
"FK_LohnDruckLobuPersonalSperrung_ArtLohnDruckLobu";"dbo";"LohnDruckLobuPersonalSperrung";"IDArtLohnDruckLobu_FS";"dbo";"ArtLohnDruckLobu";"IDArtLohnDruckLobu"
|
||||||
|
"FK_Lohnextra_Adresse";"dbo";"Lohnextra";"IDAdresse_FS_Personal";"dbo";"Adresse";"IDAdresse"
|
||||||
|
"FK_Lohnextra_ArtLohnextra";"dbo";"Lohnextra";"IDArtLohnextra_FS";"dbo";"ArtLohnextra";"IDArtLohnextra"
|
||||||
|
"FK_LohnParameter_Adresse";"dbo";"LohnParameter";"IDAdresse_FS_Fahrer";"dbo";"Adresse";"IDAdresse"
|
||||||
|
"FK_LohnParameter_ArtLohnsystem";"dbo";"LohnParameter";"IDArtLohnsystem_FS";"dbo";"ArtLohnsystem";"IDArtLohnsystem"
|
||||||
|
"FK_LohnStundenkonto_Adresse";"dbo";"LohnStundenkonto";"IDAdresse_FS_Fahrer";"dbo";"Adresse";"IDAdresse"
|
||||||
|
"FK_LohnStundenkonto_ArtLohnStundenkonto";"dbo";"LohnStundenkonto";"IDArtLohnStundenkonto_FS";"dbo";"ArtLohnStundenkonto";"IDArtLohnStundenkonto"
|
||||||
|
"FK_LohnsystemPersonalSperrung_Adresse";"dbo";"LohnsystemPersonalSperrung";"IDAdresse_FS_Fahrer";"dbo";"Adresse";"IDAdresse"
|
||||||
|
"FK_LohnsystemPersonalSperrung_ArtLohnsystem";"dbo";"LohnsystemPersonalSperrung";"IDArtLohnsystem_FS";"dbo";"ArtLohnsystem";"IDArtLohnsystem"
|
||||||
|
"FK_LohnTagesdaten_Adresse";"dbo";"LohnTagesdaten";"IDAdresse_FS_Personal";"dbo";"Adresse";"IDAdresse"
|
||||||
|
"FK_LohnUebergabe_Adresse";"dbo";"LohnUebergabe";"IDAdresse_FS";"dbo";"Adresse";"IDAdresse"
|
||||||
|
"FK_LohnUebergabe_ArtLohnsystem";"dbo";"LohnUebergabe";"IDArtLohnsystem_FS";"dbo";"ArtLohnsystem";"IDArtLohnsystem"
|
||||||
|
"FK_MandantZuordnungZahlung_Adresse";"dbo";"MandantZuordnungKontenplan";"IDAdresse_FS_Mandant";"dbo";"Adresse";"IDAdresse"
|
||||||
|
"FK_MandantZuordnungZahlung_ZahlungCode";"dbo";"MandantZuordnungKontenplan";"IDMandantZuordnung_FS";"dbo";"Kontenplan";"IDKontenplan"
|
||||||
|
"FK_MandantZuordnungReise_Adresse";"dbo";"MandantZuordnungReise";"IDAdresse_FS_Mandant";"dbo";"Adresse";"IDAdresse"
|
||||||
|
"FK_MandantZuordnungReise_Reise";"dbo";"MandantZuordnungReise";"IDMandantZuordnung_FS";"dbo";"Reise";"IDReise"
|
||||||
|
"FK_MandantZuordnungZustieg_Adresse";"dbo";"MandantZuordnungZustieg";"IDAdresse_FS_Mandant";"dbo";"Adresse";"IDAdresse"
|
||||||
|
"FK_MandantZuordnungZustieg_Zustieg";"dbo";"MandantZuordnungZustieg";"IDMandantZuordnung_FS";"dbo";"Zustieg";"IDZustieg"
|
||||||
|
"FK_MitgliedAdresse_ArtMitgliedsstufen";"dbo";"MitgliedsstufeAdresse";"IDArtMitgliedsstufe_FS";"dbo";"ArtMitgliedsstufe";"IDArtMitgliedsstufe"
|
||||||
|
"FK_MitgliedAdresse_ArtZahlungsart";"dbo";"MitgliedsstufeAdresse";"IDArtZahlungsart_FS";"dbo";"ArtZahlungsart";"IDArtZahlungsart"
|
||||||
|
"FK_MitgliedsstufeAdresse_Adresse";"dbo";"MitgliedsstufeAdresse";"IDAdresse_FS";"dbo";"Adresse";"IDAdresse"
|
||||||
|
"FK_MitgliedsEinstellungBetrag_ArtMitgliedsstufen";"dbo";"MitgliedsstufeBetrag";"IDArtMitgliedsstufe_FS";"dbo";"ArtMitgliedsstufe";"IDArtMitgliedsstufe"
|
||||||
|
"FK_MitgliedVorteilBezeichnungArtMitgliedsstufe_ArtMitgliedsstufe";"dbo";"MitgliedsVorteilBezeichnungArtMitgliedsstufe";"IDArtMitgliedsstufe_FS";"dbo";"ArtMitgliedsstufe";"IDArtMitgliedsstufe"
|
||||||
|
"FK_Newsletter_Adresse";"dbo";"Newsletter";"IDAdresse_FS_ErsterSB";"dbo";"Adresse";"IDAdresse"
|
||||||
|
"FK_Newsletter_Adresse1";"dbo";"Newsletter";"IDAdresse_FS_LetzterSB";"dbo";"Adresse";"IDAdresse"
|
||||||
|
"FK_NewsletterAdressat_Adresse";"dbo";"NewsletterAdressat";"IDAdresse_FS";"dbo";"Adresse";"IDAdresse"
|
||||||
|
"FK_NewsletterAdressat_Newsletter";"dbo";"NewsletterAdressat";"IDNewsletter_FS";"dbo";"Newsletter";"IDNewsletter"
|
||||||
|
"FK_NewsletterAdressat_NewsletterVersand";"dbo";"NewsletterAdressat";"IDNewsletterVersand_FS";"dbo";"NewsletterVersand";"IDNewsletterVersand"
|
||||||
|
"FK_NewsletterBlock_Newsletter";"dbo";"NewsletterBlock";"IDNewsletter_FS";"dbo";"Newsletter";"IDNewsletter"
|
||||||
|
"FK_NewsletterVersand_Adresse";"dbo";"NewsletterVersand";"IDAdresse_FS_Sachbearbeiter";"dbo";"Adresse";"IDAdresse"
|
||||||
|
"FK_NewsletterVersand_Newsletter";"dbo";"NewsletterVersand";"IDNewsletter_FS";"dbo";"Newsletter";"IDNewsletter"
|
||||||
|
"FK_NotizFahrerFahrzeug_ArtNotizart";"dbo";"NotizFahrerFahrzeug";"IDArtNotizart_FS";"dbo";"ArtNotizart";"IDArtNotizart"
|
||||||
|
"FK_NummernVerwaltung_Nummernkreis";"dbo";"NummernVerwaltung";"IDNummernkreis_FS";"dbo";"Nummernkreis";"IDNummernkreis"
|
||||||
|
"FK_OrtBeziehung_Ort";"dbo";"OrtBeziehung";"IDOrt_FS_Ort1";"dbo";"Ort";"IDOrt"
|
||||||
|
"FK_OrtBeziehung_Ort1";"dbo";"OrtBeziehung";"IDOrt_FS_Ort2";"dbo";"Ort";"IDOrt"
|
||||||
|
"FK_PartnerBefoederungsvertragspreis_Adresse";"dbo";"PartnerBefoederungsvertragspreis";"IDAdresse_FS_Partner";"dbo";"Adresse";"IDAdresse"
|
||||||
|
"FK_PartnerDokument_Adresse";"dbo";"PartnerDokument";"IDAdresse_FS";"dbo";"Adresse";"IDAdresse"
|
||||||
|
"FK_PartnerGebiet_Land";"dbo";"PartnerGebiet";"IDLand_FS";"dbo";"Land";"IDLand"
|
||||||
|
"FK_PartnerGebietPreis_PartnerGebiet";"dbo";"PartnerGebietPreis";"IDPartnergebiet_FS";"dbo";"PartnerGebiet";"IDPartnergebiet"
|
||||||
|
"FK_PartnerKontingent_Adresse";"dbo";"PartnerKontingent";"IDAdresse_FS";"dbo";"Adresse";"IDAdresse"
|
||||||
|
"FK_PartnerLeistung_Adresse";"dbo";"PartnerLeistung";"IDAdresse_FS";"dbo";"Adresse";"IDAdresse"
|
||||||
|
"FK_PartnerLeistungPreis_PartnerLeistung";"dbo";"PartnerLeistungPreis";"IDPartnerLeistung_FS";"dbo";"PartnerLeistung";"IDPartnerLeistung"
|
||||||
|
"FK_PartnerLeistungPreis_PartnerSaisontafel";"dbo";"PartnerLeistungPreis";"IDPartnerSaisontafel_FS";"dbo";"PartnerSaisontafel";"IDPartnerSaisontafel"
|
||||||
|
"FK_PartnerPreis_ArtPreisschema";"dbo";"PartnerPreis";"IDPartnerSaisonTafel_FS";"dbo";"PartnerSaisontafel";"IDPartnerSaisontafel"
|
||||||
|
"FK_PartnerPreis_PartnerPreisKategorie";"dbo";"PartnerPreis";"IDPartnerPreisKategorie_FS";"dbo";"PartnerPreisKategorie";"IDPartnerPreisKategorie"
|
||||||
|
"FK_PartnerPreisKategorie_Adresse";"dbo";"PartnerPreisKategorie";"IDAdresse_FS";"dbo";"Adresse";"IDAdresse"
|
||||||
|
"FK_PartnerPreisKategorie_ArtPartnerPreisCode";"dbo";"PartnerPreisKategorie";"IDArtPartnerPreisCode_FS";"dbo";"ArtPartnerPreisCode";"IDArtPartnerPreisCode"
|
||||||
|
"FK_PartnerPreisKategorie_ArtVerpflegung";"dbo";"PartnerPreisKategorie";"IDArtVerpflegung_FS";"dbo";"ArtVerpflegung";"IDArtVerpflegung"
|
||||||
|
"FK_PartnerProdukt_Adresse";"dbo";"PartnerProdukt";"IDAdresse_FS";"dbo";"Adresse";"IDAdresse"
|
||||||
|
"FK_PartnerProdukt_Produkt";"dbo";"PartnerProdukt";"IDProdukt_FS";"dbo";"Produkt";"IDProdukt"
|
||||||
|
"FK_PartnerSaisontafel_Adresse";"dbo";"PartnerSaisontafel";"IDAdresse_FS";"dbo";"Adresse";"IDAdresse"
|
||||||
|
"FK_PartnerSaisonzeit_Adresse";"dbo";"PartnerSaisonzeit";"IDAdresse_FS";"dbo";"Adresse";"IDAdresse"
|
||||||
|
"FK_PartnerSaisonzeit_PartnerSaisontafel";"dbo";"PartnerSaisonzeit";"IDPartnerSaisonTafel_FS";"dbo";"PartnerSaisontafel";"IDPartnerSaisontafel"
|
||||||
|
"FK_Adresse_PartnerSelektion";"dbo";"PartnerSelektionenKunde";"IDAdresse_FS";"dbo";"Adresse";"IDAdresse"
|
||||||
|
"FK_Selektionsstamm_PartnerSelektion";"dbo";"PartnerSelektionenKunde";"IDSelektionsstamm_FS";"dbo";"Selektionsstamm";"IDSelektionsstamm"
|
||||||
|
"FK_PartnerZimmer_Adresse";"dbo";"PartnerZimmer";"IDAdresse_FS";"dbo";"Adresse";"IDAdresse"
|
||||||
|
"FK_PartnerZimmer_ArtPartnerPreisCode";"dbo";"PartnerZimmer";"IDArtPartnerPreisCode_FS";"dbo";"ArtPartnerPreisCode";"IDArtPartnerPreisCode"
|
||||||
|
"FK_PartnerZimmer_Zimmerart";"dbo";"PartnerZimmer";"IDZimmerart_FS";"dbo";"Zimmerart";"IDZimmerart"
|
||||||
|
"FK_PartnerZusatz_Adresse";"dbo";"PartnerZusatz";"IDAdresse_FS";"dbo";"Adresse";"IDAdresse"
|
||||||
|
"FK_PartnerZusatz_ArtAgenturPreisgruppe";"dbo";"PartnerZusatz";"IDArtAgenturPreisgruppe_FS";"dbo";"ArtAgenturPreisgruppe";"IDArtAgenturPreisgruppe"
|
||||||
|
"FK_PartnerZusatz_KonstantenSteueraufteilung";"dbo";"PartnerZusatz";"IDKonstantenSteueraufteilung_FS";"dbo";"KonstantenSteueraufteilung";"IDKonstantenSteueraufteilung"
|
||||||
|
"FK_PersonalGruppeDatenschutz_ArtPersonalGruppeKompetenz";"dbo";"PersonalGruppeDatenschutz";"IDArtPersonalGruppeKompetenz_FS";"dbo";"ArtPersonalGruppeKompetenz";"IDArtPersonalGruppeKompetenz"
|
||||||
|
"FK_PersonalGruppeDatenschutzDarstellung_ArtPersonalGruppeKompetenz";"dbo";"PersonalGruppeDatenschutzDarstellung";"IDArtPersonalGruppeKompetenz_FS";"dbo";"ArtPersonalGruppeKompetenz";"IDArtPersonalGruppeKompetenz"
|
||||||
|
"FK_PersonalGruppeDatenschutzLöschung_ArtPersonalGruppeKompetenz";"dbo";"PersonalGruppeDatenschutzLöschung";"IDArtPersonalGruppeKompetenz_FS";"dbo";"ArtPersonalGruppeKompetenz";"IDArtPersonalGruppeKompetenz"
|
||||||
|
"FK_PersonalGruppeKompetenz_ArtPersonalGruppeKompetenz";"dbo";"PersonalGruppeKompetenz";"IDArtPersonalGruppeKompetenz_FS";"dbo";"ArtPersonalGruppeKompetenz";"IDArtPersonalGruppeKompetenz"
|
||||||
|
"FK_Personalkapazitaet_Adresse";"dbo";"Personalkapazitaet";"IDAdresse_FS_Personal";"dbo";"Adresse";"IDAdresse"
|
||||||
|
"FK_Personalkapazitaet_ArtPersonalkapazitaet";"dbo";"Personalkapazitaet";"IDArtPersonalkapazitaet_FS";"dbo";"ArtPersonalkapazitaet";"IDArtPersonalkapazitaet"
|
||||||
|
"FK_PersonalkapazitaetArbeitszeit_ArtPersonalkapazitaet";"dbo";"PersonalkapazitaetArbeitszeit";"IDArtPersonalkapazitaet_FS";"dbo";"ArtPersonalkapazitaet";"IDArtPersonalkapazitaet"
|
||||||
|
"FK_PersonalkapazitaetEingabe_Adresse";"dbo";"PersonalkapazitaetEingabe";"IDAdresse_FS_Personal";"dbo";"Adresse";"IDAdresse"
|
||||||
|
"FK_PersonalkapazitaetMindestbesetzung_ArtBetriebshof";"dbo";"PersonalkapazitaetMindestbesetzung";"IDArtBetriebshof_FS";"dbo";"ArtBetriebshof";"IDArtBetriebshof"
|
||||||
|
"FK_PersonalkapazitaetMindestbesetzung_ArtMindestbesetzungZeitraum";"dbo";"PersonalkapazitaetMindestbesetzung";"IDArtMindestbesetzungZeitraum_FS";"dbo";"ArtMindestbesetzungZeitraum";"IDArtMindestbesetzungZeitraum"
|
||||||
|
"FK_PersonalkapazitaetMindestbesetzungZeitraum_ArtMindestbesetzungZeitraum";"dbo";"PersonalkapazitaetMindestbesetzungZeitraum";"IDArtMindestbesetzungZeitraum_FS";"dbo";"ArtMindestbesetzungZeitraum";"IDArtMindestbesetzungZeitraum"
|
||||||
|
"FK_PlanungSoll_Adresse";"dbo";"PlanungSoll";"IDAdresse_FS_Fahrer";"dbo";"Adresse";"IDAdresse"
|
||||||
|
"FK_PlanungSoll_ArtPersonalkapazitaet";"dbo";"PlanungSoll";"IDArtPersonalkapazitaet_FS_Schema";"dbo";"ArtPersonalkapazitaet";"IDArtPersonalkapazitaet"
|
||||||
|
"FK_PlanungSollBlock_BlockPlanung";"dbo";"PlanungSollBlock";"IDBlockPlanung_FS";"dbo";"BlockPlanung";"IDBlockPlanung"
|
||||||
|
"FK_PlanungSollBlock_PlanungSoll";"dbo";"PlanungSollBlock";"IDPlanungSoll_FS";"dbo";"PlanungSoll";"IDPlanungSoll"
|
||||||
|
"FK_PlanungSollLohnarten_Lohnart";"dbo";"PlanungSollLohnart";"IDLohnart_FS";"dbo";"Lohnart";"IDLohnart"
|
||||||
|
"FK_PlanungSollLohnarten_PlanungSoll";"dbo";"PlanungSollLohnart";"IDPlanungSoll_FS";"dbo";"PlanungSoll";"IDPlanungSoll"
|
||||||
|
"FK_PortalBemerkung_PortalBuchung";"dbo";"PortalBemerkung";"IDPortalBuchung_FS";"dbo";"PortalBuchung";"IDPortalBuchung"
|
||||||
|
"FK_PortalLeistung_PortalBuchung";"dbo";"PortalLeistung";"IDPortalBuchung_FS";"dbo";"PortalBuchung";"IDPortalBuchung"
|
||||||
|
"FK_PortalLeistungTN_PortalLeistung";"dbo";"PortalLeistungTN";"IDPortalLeistung_FS";"dbo";"PortalLeistung";"IDPortalLeistung"
|
||||||
|
"FK_PortalLeistungTN_PortalTN";"dbo";"PortalLeistungTN";"IDPortalTN_FS";"dbo";"PortalTN";"IDPortalTN"
|
||||||
|
"FK_PortalLeistungZusatz_PortalBuchung";"dbo";"PortalLeistungZusatz";"IDPortalBuchung_FS";"dbo";"PortalBuchung";"IDPortalBuchung"
|
||||||
|
"FK_PortalTN_PortalBuchung";"dbo";"PortalTN";"IDPortalBuchung_FS";"dbo";"PortalBuchung";"IDPortalBuchung"
|
||||||
|
"FK_Produkt_KonstantenSteueraufteilung";"dbo";"Produkt";"IDKonstantenSteueraufteilung_FS";"dbo";"KonstantenSteueraufteilung";"IDKonstantenSteueraufteilung"
|
||||||
|
"FK_ProduktArtPersonalGruppe_ArtPersonalGruppeProdukt";"dbo";"ProduktArtPersonalGruppe";"IDArtPersonalGruppeProdukt_FS";"dbo";"ArtPersonalGruppeProdukt";"IDArtPersonalGruppeProdukt"
|
||||||
|
"FK_ProduktArtPersonalGruppe_Produkt";"dbo";"ProduktArtPersonalGruppe";"IDProdukt_FS";"dbo";"Produkt";"IDProdukt"
|
||||||
|
"FK_ProduktBeschreibungInhalt_ProduktBeschreibung";"dbo";"ProduktBeschreibungInhalt";"IDProduktBeschreibung_FS";"dbo";"ProduktBeschreibung";"IDProduktBeschreibung"
|
||||||
|
"FK_ProduktbeschreibungKategorie_ProduktBeschreibung";"dbo";"ProduktbeschreibungKategorie";"IDProduktbeschreibung_FS";"dbo";"ProduktBeschreibung";"IDProduktBeschreibung"
|
||||||
|
"FK_ProduktbeschreibungKategorie_WWSuchKategorie";"dbo";"ProduktbeschreibungKategorie";"IDWWSuchKategorie_FS";"dbo";"WWSuchKategorie";"IDWWSuchKategorie"
|
||||||
|
"FK_ProduktbeschreibungKategorie_WWSuchKategorieEintrag";"dbo";"ProduktbeschreibungKategorie";"IDWWSuchKategorieEintrag_FS";"dbo";"WWSuchKategorieEintrag";"IDWWSuchKategorieEintrag"
|
||||||
|
"FK_ProduktBeschreibungZusatz_ProduktBeschreibung";"dbo";"ProduktBeschreibungZusatz";"IDProduktBeschreibung_FS";"dbo";"ProduktBeschreibung";"IDProduktBeschreibung"
|
||||||
|
"FK_ProduktDokument_Produkt";"dbo";"ProduktDokument";"IDProdukt_FS";"dbo";"Produkt";"IDProdukt"
|
||||||
|
"FK_ProduktSachbearbeiter_Adresse";"dbo";"ProduktSachbearbeiter";"IDAdresse_FS_Personal";"dbo";"Adresse";"IDAdresse"
|
||||||
|
"FK_ProduktSachbearbeiter_Produkt";"dbo";"ProduktSachbearbeiter";"IDProdukt_FS";"dbo";"Produkt";"IDProdukt"
|
||||||
|
"FK_Produkt_ProduktText";"dbo";"ProduktText";"IDProdukt_FS";"dbo";"Produkt";"IDProdukt"
|
||||||
|
"FK_Qualitaet_ArtFahrplanVersion";"dbo";"Qualitaet";"IDArtFahrplanversion_FS";"dbo";"ArtFahrplanVersion";"IDArtFahrplanVersion"
|
||||||
|
"FK_QualitaetDefinition_ArtBlockArt";"dbo";"QualitaetDefinition";"IDArtBlockArt_FS";"dbo";"ArtBlockArt";"IDArtBlockArt"
|
||||||
|
"FK_QualitaetDefinition_ArtGruppeVerkehrstag";"dbo";"QualitaetDefinition";"IDArtGruppeVerkehrstag_FS";"dbo";"ArtGruppeVerkehrstag";"IDArtGruppeVerkehrstag"
|
||||||
|
"FK_QualitaetDefinition_Qualitaet";"dbo";"QualitaetDefinition";"IDQualitaet_FS";"dbo";"Qualitaet";"IDQualitaet"
|
||||||
|
"FK_QualitaetDefinitionAuftragsart_Auftragsart";"dbo";"QualitaetDefinitionAuftragsart";"IDAuftragsart_FS";"dbo";"Auftragsart";"IDAuftragsart"
|
||||||
|
"FK_QualitaetDefinitionAuftragsart_Qualitaet";"dbo";"QualitaetDefinitionAuftragsart";"IDQualitaet_FS";"dbo";"Qualitaet";"IDQualitaet"
|
||||||
|
"FK_QualitaetDefinitionFahrzeug_Fahrzeug";"dbo";"QualitaetDefinitionFahrzeug";"IDFahrzeug_FS";"dbo";"Fahrzeug";"IDFahrzeug"
|
||||||
|
"FK_QualitaetDefinitionFahrzeug_Qualitaet";"dbo";"QualitaetDefinitionFahrzeug";"IDQualitaet_FS";"dbo";"Qualitaet";"IDQualitaet"
|
||||||
|
"FK_QualitaetDefinitionLinie_Qualitaet";"dbo";"QualitaetDefinitionLinie";"IDQualitaet_FS";"dbo";"Qualitaet";"IDQualitaet"
|
||||||
|
"FK_QualitaetZuordnung_Qualitaet";"dbo";"QualitaetZuordnung";"IDQualitaet_FS";"dbo";"Qualitaet";"IDQualitaet"
|
||||||
|
"FK_QuittierungAusfahrt_AuftragFahrer";"dbo";"QuittierungAusfahrt";"IDAuftragFahrer_FS";"dbo";"AuftragFahrer";"IDAuftragFahrer"
|
||||||
|
"FK_QuittierungAusfahrt_BlockPlanung";"dbo";"QuittierungAusfahrt";"IDBlockPlanung_FS";"dbo";"BlockPlanung";"IDBlockPlanung"
|
||||||
|
"FK_Rechnung_AdresseAnschrift";"dbo";"Rechnung";"IDAdresseAnschrift_FS";"dbo";"AdresseAnschrift";"IDAdresseAnschrift"
|
||||||
|
"FK_Rechnung_ArtZahlungsart";"dbo";"Rechnung";"IDArtZahlungsart_FS";"dbo";"ArtZahlungsart";"IDArtZahlungsart"
|
||||||
|
"FK_Rechnung_RechnungHaupt";"dbo";"Rechnung";"IDRechnungHaupt_FS";"dbo";"RechnungHaupt";"IDRechnungHaupt"
|
||||||
|
"FK_RechnungBetrag_Rechnung";"dbo";"RechnungBetrag";"IDRechnung_FS";"dbo";"Rechnung";"IDRechnung"
|
||||||
|
"FK_RechnungBetragMahnung_RechnungBetrag";"dbo";"RechnungBetragMahnung";"IdRechnungBetrag_FS";"dbo";"RechnungBetrag";"IDRechnungBetrag"
|
||||||
|
"FK_RechnungBuchung_Buchung";"dbo";"RechnungBuchung";"IDBuchung_FS";"dbo";"Buchung";"IDBuchung"
|
||||||
|
"FK_RechnungBuchung_RechnungHaupt";"dbo";"RechnungBuchung";"IDRechnungHaupt_FS";"dbo";"RechnungHaupt";"IDRechnungHaupt"
|
||||||
|
"FK_RechnungHaupt_Adresse";"dbo";"RechnungHaupt";"IDAdresse_FS_Mandant";"dbo";"Adresse";"IDAdresse"
|
||||||
|
"FK_RechnungHaupt_Adresse1";"dbo";"RechnungHaupt";"IDAdresse_FS";"dbo";"Adresse";"IDAdresse"
|
||||||
|
"FK_RechnungPosten_Rechnung";"dbo";"RechnungPosten";"IDRechnung_FS";"dbo";"Rechnung";"IDRechnung"
|
||||||
|
"FK_RechnungPosten_Teilnehmer_BuchungTNPreis";"dbo";"RechnungPosten_Teilnehmer";"IDBuchungTN_FS";"dbo";"BuchungTNPreis";"IDBuchungTNPreis"
|
||||||
|
"FK_RechnungPosten_Teilnehmer_RechnungPostenBetragTOU";"dbo";"RechnungPosten_Teilnehmer";"IDRechnungPostenBetragTOU_FS";"dbo";"RechnungPostenBetragTOU";"IDRechnungPostenBetragTOU"
|
||||||
|
"FK_RechnungPostenBetragALL_RechnungPosten";"dbo";"RechnungPostenBetragALL";"IDRechnungPosten_FS";"dbo";"RechnungPosten";"IDRechnungPosten"
|
||||||
|
"FK_RechnungPostenBetragTOU_RechnungPosten";"dbo";"RechnungPostenBetragTOU";"IDRechnungPosten_FS";"dbo";"RechnungPosten";"IDRechnungPosten"
|
||||||
|
"FK_RechnungPostenLinieAufteilungTour_RechnungPostenLinieAufteilung";"dbo";"RechnungPostenLinieAufteilungTour";"IDRechnungPostenLinieAufteilung_FS";"dbo";"RechnungPostenLinieAufteilung";"IDRechnungPostenLinieAufteilung"
|
||||||
|
"FK_RechnungPostenMietbusAufteilung_RechnungPostenBetragALL";"dbo";"RechnungPostenMietbusAufteilung";"IDRechnungPostenBetragAll_FS";"dbo";"RechnungPostenBetragALL";"IDRechnungPostenBetragALL"
|
||||||
|
"FK_RechnungSteueraufteilung_Rechnung";"dbo";"RechnungSteueraufteilung";"IDRechnung_FS";"dbo";"Rechnung";"IDRechnung"
|
||||||
|
"FK_ReisabBefoerderung_Reisab";"dbo";"ReisabBefoerderung";"IdReisab_FS";"dbo";"Reisab";"IdReisab"
|
||||||
|
"FK_ReisabLand_Land";"dbo";"ReisabLand";"IdLand_FS";"dbo";"Land";"IDLand"
|
||||||
|
"FK_ReisabLand_Reisab";"dbo";"ReisabLand";"IDReisab_FS";"dbo";"Reisab";"IdReisab"
|
||||||
|
"FK_ReisabLeistung_ArtReiseKosten";"dbo";"ReisabLeistung";"IdArtReiseKosten_FS";"dbo";"ArtReiseKosten";"IDArtReiseKosten"
|
||||||
|
"FK_ReisabLeistung_Reisab";"dbo";"ReisabLeistung";"IdReisab_FS";"dbo";"Reisab";"IdReisab"
|
||||||
|
"FK_ReisabReise_Reisab";"dbo";"ReisabReise";"IDReisab_FS";"dbo";"Reisab";"IdReisab"
|
||||||
|
"FK_ReisabReise_Reise";"dbo";"ReisabReise";"IDReise_FS";"dbo";"Reise";"IDReise"
|
||||||
|
"FK_ReisabUmsatz_Reisab";"dbo";"ReisabUmsatz";"IdReisab_FS";"dbo";"Reisab";"IdReisab"
|
||||||
|
"FK_Reise_Produkt";"dbo";"Reise";"IDProdukt_FS";"dbo";"Produkt";"IDProdukt"
|
||||||
|
"FK_ReiseBeleg_Reise";"dbo";"ReiseBeleg";"IDReise_FS";"dbo";"Reise";"IDReise"
|
||||||
|
"FK_ReiseBelegDokument_ReiseBeleg";"dbo";"ReiseBelegDokument";"IDReiseBeleg_FS";"dbo";"ReiseBeleg";"IDReiseBeleg"
|
||||||
|
"FK_ReiseBelegPosten_ReiseBeleg";"dbo";"ReiseBelegPosten";"IDReiseBeleg_FS";"dbo";"ReiseBeleg";"IDReiseBeleg"
|
||||||
|
"FK_ReiseDevise_ArtWaehrung";"dbo";"ReiseDevise";"IDArtWaehrung_FS";"dbo";"ArtWaehrung";"IDArtWaehrung"
|
||||||
|
"FK_ReiseDevise_Reise";"dbo";"ReiseDevise";"IDReise_FS";"dbo";"Reise";"IDReise"
|
||||||
|
"FK_ReiseDokument_Reise";"dbo";"ReiseDokument";"IDReise_FS";"dbo";"Reise";"IDReise"
|
||||||
|
"FK_ReiseFlexTarif_KonstantenFlexTarif";"dbo";"ReiseFlexTarif";"IDKonstantenFlexTarif_FS";"dbo";"KonstantenFlexTarif";"IDKonstantenFlexTarif"
|
||||||
|
"FK_ReiseFlexTarif_Reise";"dbo";"ReiseFlexTarif";"IDReise_FS";"dbo";"Reise";"IDReise"
|
||||||
|
"FK_ReiseGuides_ArtReiseGuides";"dbo";"ReiseGuides";"IDArtReiseGuides_FS";"dbo";"ArtReiseGuides";"IDArtReiseGuides"
|
||||||
|
"FK_ReiseKosten_Reise";"dbo";"ReiseKosten";"IDReise_FS";"dbo";"Reise";"IDReise"
|
||||||
|
"FK_ReiseLand_Land";"dbo";"ReiseLand";"IDLand_FS";"dbo";"Land";"IDLand"
|
||||||
|
"FK_ReiseLand_Reise";"dbo";"ReiseLand";"IDReise_FS";"dbo";"Reise";"IDReise"
|
||||||
|
"FK_ReiseLeistung_Leistung";"dbo";"ReiseLeistung";"IDLeistung_FS";"dbo";"Leistung";"IDLeistung"
|
||||||
|
"FK_ReiseLeistung_Reise";"dbo";"ReiseLeistung";"IDReise_FS";"dbo";"Reise";"IDReise"
|
||||||
|
"FK_ReiseLeistungGruppe_Reise";"dbo";"ReiseLeistungGruppe";"IDReise_FS";"dbo";"Reise";"IDReise"
|
||||||
|
"FK_ReiseLeistungGruppeZuweisung_Leistung";"dbo";"ReiseLeistungGruppeZuweisung";"IDLeistung_FS";"dbo";"Leistung";"IDLeistung"
|
||||||
|
"FK_ReiseLeistungGruppeZuweisung_ReiseLeistungGruppe";"dbo";"ReiseLeistungGruppeZuweisung";"IDReiseLeistungGruppe_FS";"dbo";"ReiseLeistungGruppe";"IDReiseLeistungGruppe"
|
||||||
|
"FK_ReiseleiterAbrechnung_Adresse";"dbo";"ReiseleiterAbrechnung";"IDAdresse_FS_Personal";"dbo";"Adresse";"IDAdresse"
|
||||||
|
"FK_ReiseleiterAbrechnung_Reise";"dbo";"ReiseleiterAbrechnung";"IDReise_FS";"dbo";"Reise";"IDReise"
|
||||||
|
"FK_ReiseleiterAbrechnung_ReiseleiterZuordnungStamm";"dbo";"ReiseleiterAbrechnung";"IDReiseleiterZuordnungStamm_FS";"dbo";"ReiseleiterZuordnungStamm";"IDReiseleiterZuordnungStamm"
|
||||||
|
"FK_ReiseleiterAbrechnungPosten_ReiseleiterAbrechnung";"dbo";"ReiseleiterAbrechnungPosten";"IDReiseleiterAbrechnung_FS";"dbo";"ReiseleiterAbrechnung";"IDReiseleiterAbrechnung"
|
||||||
|
"FK_ReiseleiterAbrechnungPosten_ReiseleiterPosten";"dbo";"ReiseleiterAbrechnungPosten";"IDReiseleiterPosten_FS";"dbo";"ReiseleiterPosten";"IDReiseleiterPosten"
|
||||||
|
"FK_ReiseleiterAbrechnungSpesen_ArtSpesenVerpflegung";"dbo";"ReiseleiterAbrechnungSpesen";"IDArtSpesenVerpflegung_FS";"dbo";"ArtSpesenVerpflegung";"IDArtSpesenVerpflegung"
|
||||||
|
"FK_ReiseleiterAbrechnungSpesen_ReiseleiterAbrechnung";"dbo";"ReiseleiterAbrechnungSpesen";"IDReiseleiterAbrechnung_FS";"dbo";"ReiseleiterAbrechnung";"IDReiseleiterAbrechnung"
|
||||||
|
"FK_ReiseleiterAbrechnungZuAbschlag_ReiseleiterAbrechnung";"dbo";"ReiseleiterAbrechnungZuAbschlag";"IDReiseleiterAbrechnung_FS";"dbo";"ReiseleiterAbrechnung";"IDReiseleiterAbrechnung"
|
||||||
|
"FK_ReiseleiterAbrVergütungStaffel_ReiseleiterAbrVergütungStamm1";"dbo";"ReiseleiterAbrVergütungStaffel";"IDReiseleiterAbrVergütungStamm_FS";"dbo";"ReiseleiterAbrVergütungStamm";"IDReiseleiterAbrVergütungStamm"
|
||||||
|
"FK_ReiseleiterAbrVergütungStaffelAnAbreise_ReiseleiterAbrVergütungStamm";"dbo";"ReiseleiterAbrVergütungStaffelAnAbreise";"IDReiseleiterAbrVergütungStamm_FS";"dbo";"ReiseleiterAbrVergütungStamm";"IDReiseleiterAbrVergütungStamm"
|
||||||
|
"FK_ReiseleiterArbeitszeit_ReiseleiterZuordnungReiseleiter";"dbo";"ReiseleiterArbeitszeit";"IDReiseleiterZuordnungReiseleiter_FS";"dbo";"ReiseleiterZuordnungReiseleiter";"IDReiseleiterZuordnungReiseleiter"
|
||||||
|
"FK_ReiseleiterHonorarStaffel_Adresse";"dbo";"ReiseleiterHonorarStaffel";"IDAdresse_FS_Personal";"dbo";"Adresse";"IDAdresse"
|
||||||
|
"FK_ReiseleiterHonorarStaffel_ArtReiseleiterHonorar";"dbo";"ReiseleiterHonorarStaffel";"IDArtReiseleiterHonorar_FS";"dbo";"ArtReiseleiterHonorar";"IDArtReiseleiterHonorar"
|
||||||
|
"FK_ReiseleiterSelektionen_Adresse";"dbo";"ReiseleiterSelektionen";"IDAdresse_FS_Personal";"dbo";"Adresse";"IDAdresse"
|
||||||
|
"FK_ReiseleiterSelektionen_Selektionsstamm";"dbo";"ReiseleiterSelektionen";"IDSelektionsstamm_FS";"dbo";"Selektionsstamm";"IDSelektionsstamm"
|
||||||
|
"FK_ReiseleiterSpesenBetrag_ArtSpesenLand";"dbo";"ReiseleiterSpesenBetrag";"IDArtSpesenLand_FS";"dbo";"ArtSpesenLand";"IDArtSpesenLand"
|
||||||
|
"FK_ReiseleiterSpesenBetrag_ReiseleiterSpesenStaffel";"dbo";"ReiseleiterSpesenBetrag";"IDReiseleiterSpesenStaffel_FS";"dbo";"ReiseleiterSpesenStaffel";"IDReiseleiterSpesenStaffel"
|
||||||
|
"FK_ReiseleiterStamm_Adresse";"dbo";"ReiseleiterStamm";"IDAdresse_FS";"dbo";"Adresse";"IDAdresse"
|
||||||
|
"FK_ReiseleiterWunschReise_Adresse";"dbo";"ReiseleiterWunschReise";"IDAdresse_FS_Personal";"dbo";"Adresse";"IDAdresse"
|
||||||
|
"FK_ReiseleiterWunschReise_Reise";"dbo";"ReiseleiterWunschReise";"IDReise_FS";"dbo";"Reise";"IDReise"
|
||||||
|
"FK_ReiseleiterZuordnungReiseleiter_Adresse1";"dbo";"ReiseleiterZuordnungReiseleiter";"IDAdresse_FS";"dbo";"Adresse";"IDAdresse"
|
||||||
|
"FK_ReiseleiterZuordnungReiseleiter_ReiseleiterZuordnungStamm";"dbo";"ReiseleiterZuordnungReiseleiter";"IDReiseleiterZuordnungStamm_FS";"dbo";"ReiseleiterZuordnungStamm";"IDReiseleiterZuordnungStamm"
|
||||||
|
"FK_ReiseleiterZuordnungZusatzleistung_Leistung";"dbo";"ReiseleiterZuordnungZusatzleistung";"IDLeistung_FS";"dbo";"Leistung";"IDLeistung"
|
||||||
|
"FK_ReiseleiterZuordnungZusatzleistung_ReiseleiterZuordnungReiseleiter";"dbo";"ReiseleiterZuordnungZusatzleistung";"IDReiseleiterZuordnungReiseleiter_FS";"dbo";"ReiseleiterZuordnungReiseleiter";"IDReiseleiterZuordnungReiseleiter"
|
||||||
|
"FK_ReiseListenVersand_ArtListenart";"dbo";"ReiseListenVersand";"IdArtListenart_FS";"dbo";"ArtListenart";"IDArtListenArt"
|
||||||
|
"FK_ReiseListenVersand_ArtListenart1";"dbo";"ReiseListenVersand";"IdArtListenart_FS";"dbo";"ArtListenart";"IDArtListenArt"
|
||||||
|
"FK_ReiseListenVersand_DruckEinstellungEMail";"dbo";"ReiseListenVersand";"IdDruckeinstellungEmail_FS";"dbo";"DruckEinstellungEMail";"IDDruckEinstellungEMail"
|
||||||
|
"FK_ReiseListenVersand_Reise";"dbo";"ReiseListenVersand";"IdReise_FS";"dbo";"Reise";"IDReise"
|
||||||
|
"FK_ReisePartner_Adresse";"dbo";"ReisePartner";"IDAdresse_FS_Partner";"dbo";"Adresse";"IDAdresse"
|
||||||
|
"FK_ReisePartner_ArtVerpflegung";"dbo";"ReisePartner";"IDArtVerpflegung_FS";"dbo";"ArtVerpflegung";"IDArtVerpflegung"
|
||||||
|
"FK_ReisePartner_Reise";"dbo";"ReisePartner";"IDReise_FS";"dbo";"Reise";"IDReise"
|
||||||
|
"FK_ReisePersonalZimmer_Reise";"dbo";"ReisePersonalZimmer";"IDReise_FS";"dbo";"Reise";"IDReise"
|
||||||
|
"FK_ReisePersonalZimmer_Zimmerart";"dbo";"ReisePersonalZimmer";"IDZimmerart_FS";"dbo";"Zimmerart";"IDZimmerart"
|
||||||
|
"FK_ReiseSelektionen_Reise";"dbo";"ReiseSelektionen";"IDReise_FS";"dbo";"Reise";"IDReise"
|
||||||
|
"FK_ReiseSelektionen_Selektionsstamm";"dbo";"ReiseSelektionen";"IDSelektionsstamm_FS";"dbo";"Selektionsstamm";"IDSelektionsstamm"
|
||||||
|
"FK_ReiseSitzplan_Reise";"dbo";"ReiseSitzplan";"IDReise_FS";"dbo";"Reise";"IDReise"
|
||||||
|
"FK_ReiseSitzplan_Sitzplan";"dbo";"ReiseSitzplan";"IDSitzplan_FS";"dbo";"Sitzplan";"IDSitzplan"
|
||||||
|
"FK_ReiseSitzplatzPreis_ArtSitzplatzKategorie";"dbo";"ReiseSitzplatzPreis";"IDArtSitzplatzKategorie_FS";"dbo";"ArtSitzplatzKategorie";"IDArtSitzplatzKategorie"
|
||||||
|
"FK_ReiseSitzplatzPreis_Reise";"dbo";"ReiseSitzplatzPreis";"IDReise_FS";"dbo";"Reise";"IDReise"
|
||||||
|
"FK_ReiseStatistik_Reise";"dbo";"ReiseStatistik";"IDReise_FS";"dbo";"Reise";"IDReise"
|
||||||
|
"FK_ReiseStatistikVertrieb_ReiseStatistik";"dbo";"ReiseStatistikVertrieb";"IDReiseStatistik_FS";"dbo";"ReiseStatistik";"IDReiseStatistik"
|
||||||
|
"FK_ReiseStatus_Reise";"dbo";"ReiseStatus";"IDReise_FS";"dbo";"Reise";"IDReise"
|
||||||
|
"FK_ReiseStatusBuchhaltung_ArtReiseStatusBuchhaltung";"dbo";"ReiseStatusBuchhaltung";"IDArtReiseStatusBuchhaltung_FS";"dbo";"ArtReiseStatusBuchhaltung";"IDArtReiseStatusBuchhaltung"
|
||||||
|
"FK_ReiseStatusBuchhaltung_Reise";"dbo";"ReiseStatusBuchhaltung";"IDReise_FS";"dbo";"Reise";"IDReise"
|
||||||
|
"FK_Reise_ReiseText";"dbo";"ReiseText";"IDReise_FS";"dbo";"Reise";"IDReise"
|
||||||
|
"FK_ReiseTextbaustein_Reise";"dbo";"ReiseTextbaustein";"IDReise_FS";"dbo";"Reise";"IDReise"
|
||||||
|
"FK_ReiseTextbaustein_Textbaustein";"dbo";"ReiseTextbaustein";"IDTextbaustein_FS";"dbo";"Textbaustein";"IDTextbaustein"
|
||||||
|
"FK_ReiseTextbausteinAbwJeMandant_Mandant";"dbo";"ReiseTextbausteinAbwJeMandant";"IDAdresse_FS_Mandant";"dbo";"Adresse";"IDAdresse"
|
||||||
|
"FK_ReiseTextbausteinAbwJeMandant_Reise";"dbo";"ReiseTextbausteinAbwJeMandant";"IDReise_FS";"dbo";"Reise";"IDReise"
|
||||||
|
"FK_ReiseTextbausteinAbwJeMandant_Textbaustein";"dbo";"ReiseTextbausteinAbwJeMandant";"IDTextbaustein_FS";"dbo";"Textbaustein";"IDTextbaustein"
|
||||||
|
"FK_Reiseunterlage_Reise";"dbo";"Reiseunterlage";"IDReise_FS";"dbo";"Reise";"IDReise"
|
||||||
|
"FK_Reiseunterlage_ReiseunterlagenBaustein";"dbo";"Reiseunterlage";"IDReiseunterlagenBaustein_FS";"dbo";"ReiseunterlagenBaustein";"IDReiseunterlagenBaustein"
|
||||||
|
"FK_ReiseunterlageInhalt_Reiseunterlage";"dbo";"ReiseunterlageInhalt";"IDReiseunterlage_FS";"dbo";"Reiseunterlage";"IDReiseunterlage"
|
||||||
|
"FK_ReiseunterlagenBaustein_ReiseunterlagenBausteinTyp";"dbo";"ReiseunterlagenBaustein";"IDReiseunterlagenBausteinTyp_FS";"dbo";"ReiseunterlagenBausteinTyp";"IDReiseunterlagenBausteinTyp"
|
||||||
|
"FK_ReiseunterlagenBausteinBedingung_ReiseunterlagenBaustein";"dbo";"ReiseunterlagenBausteinBedingung";"IDReiseunterlagenBaustein_FS";"dbo";"ReiseunterlagenBaustein";"IDReiseunterlagenBaustein"
|
||||||
|
"FK_ReiseunterlagenBausteinBedingung_ReiseunterlagenBedingung";"dbo";"ReiseunterlagenBausteinBedingung";"IDReiseunterlagenBedingung_FS";"dbo";"ReiseunterlagenBedingung";"IDReiseunterlagenBedingung"
|
||||||
|
"FK_ReiseunterlagenBausteinInhalt_ReiseunterlagenBaustein";"dbo";"ReiseunterlagenBausteinInhalt";"IDReiseunterlagenBaustein_FS";"dbo";"ReiseunterlagenBaustein";"IDReiseunterlagenBaustein"
|
||||||
|
"FK_ReiseunterlagenVorlageBaustein_ReiseunterlagenBaustein";"dbo";"ReiseunterlagenVorlageBaustein";"IDReiseUnterlagenBaustein_FS";"dbo";"ReiseunterlagenBaustein";"IDReiseunterlagenBaustein"
|
||||||
|
"FK_ReiseunterlagenVorlageBaustein_ReiseunterlagenVorlage";"dbo";"ReiseunterlagenVorlageBaustein";"IDReiseUnterlagenVorlage_FS";"dbo";"ReiseunterlagenVorlage";"IDReiseUnterlagenVorlage"
|
||||||
|
"FK_ReiseunterlagenVorlageInhalt_ReiseunterlagenVorlage";"dbo";"ReiseunterlagenVorlageInhalt";"IDReiseunterlagenVorlage_FS";"dbo";"ReiseunterlagenVorlage";"IDReiseUnterlagenVorlage"
|
||||||
|
"FK_ReiseVersicherungsGruppe_ArtVersicherungsGruppe";"dbo";"ReiseVersicherungsGruppe";"IDArtVersicherungsGruppe_FS";"dbo";"ArtVersicherungsGruppe";"IDArtVersicherungsGruppe"
|
||||||
|
"FK_ReiseVersicherungsGruppe_Reise";"dbo";"ReiseVersicherungsGruppe";"IDReise_FS";"dbo";"Reise";"IDReise"
|
||||||
|
"FK_ReiseVerwendung_Reise";"dbo";"ReiseVerwendung";"IDReise_FS";"dbo";"Reise";"IDReise"
|
||||||
|
"FK_ReiseVplDokument_Dokument";"dbo";"ReiseVplDokument";"IdDokument_FS";"dbo";"Dokument";"IDDokument"
|
||||||
|
"FK_ReiseVplDokument_ReiseVpl";"dbo";"ReiseVplDokument";"IdReiseVpl_FS";"dbo";"ReiseVpl";"IdReiseVpl"
|
||||||
|
"FK_ReiseVplKdVormerkung_ReiseVpl";"dbo";"ReiseVplKdVormerkung";"IdReiseVpl_FS";"dbo";"ReiseVpl";"IdReiseVpl"
|
||||||
|
"FK_ReiseVplPartner_ReiseVpl";"dbo";"ReiseVplPartner";"IdReiseVpl_FS";"dbo";"ReiseVpl";"IdReiseVpl"
|
||||||
|
"FK_ReiseVplPartnerDokument_Dokument";"dbo";"ReiseVplPartnerDokument";"IdDokument_FS";"dbo";"Dokument";"IDDokument"
|
||||||
|
"FK_ReiseVplPartnerDokument_ReiseVplPartner";"dbo";"ReiseVplPartnerDokument";"IdReiseVplPartner_FS";"dbo";"ReiseVplPartner";"IdReiseVplPartner"
|
||||||
|
"FK_ReiseVplPartnerStatus_ArtReiseVplPartnerStatus";"dbo";"ReiseVplPartnerStatus";"IDArtReiseVplPartnerStatus_FS";"dbo";"ArtReiseVplPartnerStatus";"IDArtReiseVplPartnerStatus"
|
||||||
|
"FK_ReiseVplPartnerStatus_ReiseVplPartner";"dbo";"ReiseVplPartnerStatus";"IDReiseVplPartner_FS";"dbo";"ReiseVplPartner";"IdReiseVplPartner"
|
||||||
|
"FK_ReiseVplStatus_ArtReiseVplStatus";"dbo";"ReiseVplStatus";"IDArtReiseVplStatus_FS";"dbo";"ArtReiseVplStatus";"IDArtReiseVplStatus"
|
||||||
|
"FK_ReiseVplStatus_ReiseVpl";"dbo";"ReiseVplStatus";"IDReiseVpl_FS";"dbo";"ReiseVpl";"IdReiseVpl"
|
||||||
|
"FK_ReiseVplVerwendung_ReiseVpl";"dbo";"ReiseVplVerwendung";"IDReiseVpl_FS";"dbo";"ReiseVpl";"IdReiseVpl"
|
||||||
|
"FK_ReiseWerbeplanung_Reise";"dbo";"ReiseWerbeplanung";"IDReise_FS";"dbo";"Reise";"IDReise"
|
||||||
|
"FK_ReisezielSelektionsstamm_Reiseziel";"dbo";"ReisezielSelektionsstamm";"IDReiseziel_FS";"dbo";"Reiseziel";"IDReiseziel"
|
||||||
|
"FK_ReisezielSelektionsstamm_Selektionsstamm";"dbo";"ReisezielSelektionsstamm";"IDSelektionsstamm_FS";"dbo";"Selektionsstamm";"IDSelektionsstamm"
|
||||||
|
"FK_ReiseZusatz_ArtAgenturPreisgruppe";"dbo";"ReiseZusatz";"IDArtAgenturPreisgruppe_FS";"dbo";"ArtAgenturPreisgruppe";"IDArtAgenturPreisgruppe"
|
||||||
|
"FK_ReiseZusatz_Reise";"dbo";"ReiseZusatz";"IDReise_FS";"dbo";"Reise";"IDReise"
|
||||||
|
"FK_ReiseZusatzAbwJeMandant_Adresse";"dbo";"ReiseZusatzAbwJeMandant";"IDAdresse_FS_Mandant";"dbo";"Adresse";"IDAdresse"
|
||||||
|
"FK_ReiseZusatzAbwJeMandant_Reise";"dbo";"ReiseZusatzAbwJeMandant";"IDReise_FS";"dbo";"Reise";"IDReise"
|
||||||
|
"FK_ReparaturAuftragZusatz_ReparaturAuftrag";"dbo";"ReparaturAuftragZusatz";"IDReparaturAuftrag_FS";"dbo";"Reparaturauftrag";"IDReparaturauftrag"
|
||||||
|
"FK_Rollsystem_ArtFahrplanVersion";"dbo";"Rollsystem";"IDArtFahrplanversion_FS";"dbo";"ArtFahrplanVersion";"IDArtFahrplanVersion"
|
||||||
|
"FK_RollsystemBlock_Block";"dbo";"RollsystemBlock";"IDBlock_FS";"dbo";"Block";"IDBlock"
|
||||||
|
"FK_RollsystemBlock_RollsystemFahrerFahrzeug";"dbo";"RollsystemBlock";"IDRollsystemFahrerFahrzeug_FS";"dbo";"RollsystemFahrerFahrzeug";"IDRollsystemFahrerFahrzeug"
|
||||||
|
"FK_RollsystemFahrerFahrzeug_Rollsystem";"dbo";"RollsystemFahrerFahrzeug";"IDRollsystem_FS";"dbo";"Rollsystem";"IDRollsystem"
|
||||||
|
"FK_RollsystemFerien_Rollsystem";"dbo";"RollsystemFerien";"IDRollsystem_FS";"dbo";"Rollsystem";"IDRollsystem"
|
||||||
|
"FK_RollsystemPerkap_ArtPersonalkapazitaet";"dbo";"RollsystemPerkap";"IDArtPersonalkapazitaet_FS";"dbo";"ArtPersonalkapazitaet";"IDArtPersonalkapazitaet"
|
||||||
|
"FK_RollsystemPerkap_RollsystemFahrerFahrzeug";"dbo";"RollsystemPerkap";"IDRollsystemFahrerFahrzeug_FS";"dbo";"RollsystemFahrerFahrzeug";"IDRollsystemFahrerFahrzeug"
|
||||||
|
"FK_RsbVeransAnzahlung_RsbVerans";"dbo";"RsbVeransAnzahlung";"IDRsbVerans_FS";"dbo";"RsbVerans";"IDRsbVeranstalter"
|
||||||
|
"FK_RsbVeransZusatz_RsbVerans";"dbo";"RsbVeransZusatz";"IDRsbVerans_FS";"dbo";"RsbVerans";"IDRsbVeranstalter"
|
||||||
|
"FK_Rufbus_FPLinieFahrt";"dbo";"Rufbus";"IDFPLinieFahrt_FS";"dbo";"FPLinieFahrt";"IDFPLinieFahrt"
|
||||||
|
"FK_Rufbus_FPLinieHaltestelleZeitartNach";"dbo";"Rufbus";"FPLinieHaltestelleZeitart_FS_Nach";"dbo";"FPLinieHaltestelleZeitart";"IDFPLinieHaltestelleZeitart"
|
||||||
|
"FK_Rufbus_FPLinieHaltestelleZeitartVon";"dbo";"Rufbus";"FPLinieHaltestelleZeitart_FS_Von";"dbo";"FPLinieHaltestelleZeitart";"IDFPLinieHaltestelleZeitart"
|
||||||
|
"FK_Rufbus_Haltepunkt_Nach";"dbo";"Rufbus";"IDHaltepunkt_FS_Nach";"dbo";"Haltepunkt";"IDHaltepunkt"
|
||||||
|
"FK_Rufbus_Haltepunkt_Von";"dbo";"Rufbus";"IDHaltepunkt_FS_Von";"dbo";"Haltepunkt";"IDHaltepunkt"
|
||||||
|
"FK_Rufbus_Haltestelle_Nach";"dbo";"Rufbus";"IDHaltestelle_FS_Nach";"dbo";"Haltestelle";"IDHaltestelle"
|
||||||
|
"FK_Rufbus_Haltestelle_Von";"dbo";"Rufbus";"IDHaltestelle_FS_Von";"dbo";"Haltestelle";"IDHaltestelle"
|
||||||
|
"FK_Rufbus_Linie";"dbo";"Rufbus";"IDFPLinie_FS";"dbo";"FPLinie";"IDFPLinie"
|
||||||
|
"FK_SaisonZeit_SaisonBezeichnung";"dbo";"SaisonZeit";"IDSaisonBezeichnung_FS";"dbo";"SaisonBezeichnung";"IDSaisonBezeichnung"
|
||||||
|
"FK_SchiffsDeck_Schiff";"dbo";"SchiffsDeck";"IDSchiff_FS";"dbo";"Schiff";"IDSchiff"
|
||||||
|
"FK_SchiffsKabine_SchiffsDeck";"dbo";"SchiffsKabine";"IDSchiffsDeck_FS";"dbo";"SchiffsDeck";"IDSchiffsDeck"
|
||||||
|
"FK_Schule_Schulamt";"dbo";"Schule";"IDSchulamt_FS";"dbo";"Schulamt";"IDSchulamt"
|
||||||
|
"FK_Adresse_Selektion";"dbo";"Selektionen";"IDAdresse_FS";"dbo";"Adresse";"IDAdresse"
|
||||||
|
"FK_Selektionsstamm_Selektion";"dbo";"Selektionen";"IDSelektionsstamm_FS";"dbo";"Selektionsstamm";"IDSelektionsstamm"
|
||||||
|
"FK_Selektionsgruppenstamm_Selektionsgruppe";"dbo";"Selektionsgruppe";"IDSelektionsgruppenstamm_FS";"dbo";"Selektionsgruppenstamm";"IDSelektionsgruppenstamm"
|
||||||
|
"FK_Selektionsstamm_Selektionsgruppe";"dbo";"Selektionsgruppe";"IDSelektionsstamm_FS";"dbo";"Selektionsstamm";"IDSelektionsstamm"
|
||||||
|
"FK_Sitzplan_Sitzplanobjekt";"dbo";"Sitzplanobjekt";"IDSitzplan_FS";"dbo";"Sitzplan";"IDSitzplan"
|
||||||
|
"FK_Sperrung_Adresse";"dbo";"Sperrung";"IDAdresse_FS";"dbo";"Adresse";"IDAdresse"
|
||||||
|
"FK_Sperrung_ArtSperrartFahrer";"dbo";"Sperrung";"IDArtSperrartFahrer_FS";"dbo";"ArtSperrartFahrer";"IDArtSperrartFahrer"
|
||||||
|
"FK_Sperrung_ArtSperrartFahrzeug";"dbo";"Sperrung";"IDArtSperrartFahrzeug_FS";"dbo";"ArtSperrartFahrzeug";"IDArtSperrartFahrzeug"
|
||||||
|
"FK_Sperrung_ArtSperrKategorie";"dbo";"Sperrung";"IDArtSperrKategorie_FS";"dbo";"ArtSperrKategorie";"IDArtSperrKategorie"
|
||||||
|
"FK_Sperrung_Fahrzeug";"dbo";"Sperrung";"IDFahrzeug_FS";"dbo";"Fahrzeug";"IDFahrzeug"
|
||||||
|
"FK_SperrungSperrStatus_ArtSperrStatus";"dbo";"SperrungSperrStatus";"IDArtSperrStatus_FS";"dbo";"ArtSperrStatus";"IDArtSperrStatus"
|
||||||
|
"FK_SperrungSperrStatus_Sperrung";"dbo";"SperrungSperrStatus";"IDSperrung_FS";"dbo";"Sperrung";"IDSperrung"
|
||||||
|
"FK_Spesen_Adresse";"dbo";"Spesen";"IDAdresse_FS_Personal";"dbo";"Adresse";"IDAdresse"
|
||||||
|
"FK_Spesen_ArtSpesen";"dbo";"Spesen";"IDArtSpesen_FS";"dbo";"ArtSpesen";"IDArtSpesen"
|
||||||
|
"FK_SpracheMaskeModul_Programmmodul";"dbo";"SpracheMaskeModul";"IDProgrammmodul_FS";"dbo";"Programmmodul";"IDProgrammmodul"
|
||||||
|
"FK_SpracheMaskeText_SpracheMaske";"dbo";"SpracheMaskeText";"IDSpracheMaske_FS";"dbo";"SpracheMaske";"IDSpracheMaske"
|
||||||
|
"FK_SteueraufteilungDetail_Land";"dbo";"SteueraufteilungDetail";"IDLand_FS";"dbo";"Land";"IDLand"
|
||||||
|
"FK_SteueraufteilungDetail_SteueraufteilungArt";"dbo";"SteueraufteilungDetail";"IDSteueraufteilungArt_FS";"dbo";"SteueraufteilungArt";"IDSteueraufteilungArt"
|
||||||
|
"FK_SteueraufteilungDetail_SteueraufteilungUnterart";"dbo";"SteueraufteilungDetail";"IDSteueraufteilungUnterart_FS";"dbo";"SteueraufteilungUnterart";"IDSteueraufteilungUnterart"
|
||||||
|
"FK_SteueraufteilungDetailArtVerpflegung_ArtVerpflegung";"dbo";"SteueraufteilungDetailArtVerpflegung";"IDArtVerpflegung_FS";"dbo";"ArtVerpflegung";"IDArtVerpflegung"
|
||||||
|
"FK_SteueraufteilungDetailArtVerpflegung_SteueraufteilungDetail";"dbo";"SteueraufteilungDetailArtVerpflegung";"IDSteueraufteilungDetail_FS";"dbo";"SteueraufteilungDetail";"IDSteueraufteilungDetail"
|
||||||
|
"FK_SteueraufteilungUnterart_SteueraufteilungArt";"dbo";"SteueraufteilungUnterart";"IDSteueraufteilungArt_FS";"dbo";"SteueraufteilungArt";"IDSteueraufteilungArt"
|
||||||
|
"FK_Tachostand_Fahrzeug";"dbo";"Tachostand";"IDFahrzeug_FS";"dbo";"Fahrzeug";"IDFahrzeug"
|
||||||
|
"FK_Tachostand_TachostandImportEinstellung";"dbo";"Tachostand";"IDTachostandImportEinstellung_FS";"dbo";"TachostandImportEinstellung";"IDTachostandImportEinstellung"
|
||||||
|
"FK_Tankerfassung_ArtBetankung";"dbo";"Tankerfassung";"IDArtBetankung_FS";"dbo";"ArtBetankung";"IDArtBetankung"
|
||||||
|
"FK_Tankerfassung_ArtKarftstoffart";"dbo";"Tankerfassung";"IDArtKraftstoffart_FS";"dbo";"ArtKraftstoffart";"IDArtKraftstoffart"
|
||||||
|
"FK_Tankerfassung_Fahrzeug";"dbo";"Tankerfassung";"IDFahrzeug_FS";"dbo";"Fahrzeug";"IDFahrzeug"
|
||||||
|
"FK_Tankerfassung_TankimportEinstellung";"dbo";"Tankerfassung";"IDTankimportEinstellung_FS";"dbo";"TankimportEinstellung";"IDTankimportEinstellung"
|
||||||
|
"FK_TankimportEinstellung_ArtBetankung";"dbo";"TankimportEinstellung";"IDArtBetankung_FS";"dbo";"ArtBetankung";"IDArtBetankung"
|
||||||
|
"FK_TankimportEinstellungArtBetankung_ArtBetankung";"dbo";"TankimportEinstellungArtBetankung";"IDArtBetankung_FS";"dbo";"ArtBetankung";"IDArtBetankung"
|
||||||
|
"FK_TankimportEinstellungArtBetankung_TankimportEinstellung";"dbo";"TankimportEinstellungArtBetankung";"IDTankimportEinstellung_FS";"dbo";"TankimportEinstellung";"IDTankimportEinstellung"
|
||||||
|
"FK_TankimportEinstellungKraftstoff_ArtKraftstoffart";"dbo";"TankimportEinstellungKraftstoff";"IDArtKraftstoffart_FS";"dbo";"ArtKraftstoffart";"IDArtKraftstoffart"
|
||||||
|
"FK_TankimportEinstellungKraftstoff_TankimportEinstellung";"dbo";"TankimportEinstellungKraftstoff";"IDTankimportEinstellung_FS";"dbo";"TankimportEinstellung";"IDTankimportEinstellung"
|
||||||
|
"FK_TaxiPartner_Adresse";"dbo";"TaxiPartner";"IDAdresse_FS";"dbo";"Adresse";"IDAdresse"
|
||||||
|
"FK_TaxiPartnerKosten_TaxiPartner";"dbo";"TaxiPartnerKosten";"IDTaxiPartner_FS";"dbo";"TaxiPartner";"IDTaxiPartner"
|
||||||
|
"FK_TaxiPartnerMapGuide_TaxiPartner";"dbo";"TaxiPartnerMapGuide";"IDTaxiPartner_FS";"dbo";"TaxiPartner";"IDTaxiPartner"
|
||||||
|
"FK_TaxiPartnerZustieg_Adresse";"dbo";"TaxiPartnerZustieg";"IDAdresse_FS";"dbo";"Adresse";"IDAdresse"
|
||||||
|
"FK_TaxiPartnerZustieg_Zustieg";"dbo";"TaxiPartnerZustieg";"IDZustieg_FS";"dbo";"Zustieg";"IDZustieg"
|
||||||
|
"FK_TerminalFreigabe_ArtTerminalFreigabe";"dbo";"TerminalFreigabe";"IDArtTerminalFreigabe_FS";"dbo";"ArtTerminalFreigabe";"IDArtTerminalFreigabe"
|
||||||
|
"FK_TerminalFreigabeArtBetriebshof_ArtBetriebshof";"dbo";"TerminalFreigabeArtBetriebshof";"IDArtBetriebshof_FS";"dbo";"ArtBetriebshof";"IDArtBetriebshof"
|
||||||
|
"FK_TerminalProtokoll_Adresse";"dbo";"TerminalProtokoll";"IDAdresse_FS_Sachbearbeiter";"dbo";"Adresse";"IDAdresse"
|
||||||
|
"FK_TerminArtSachbearbeiter_Adresse";"dbo";"TerminArtSachbearbeiter";"IDAdresse_FS_Personal";"dbo";"Adresse";"IDAdresse"
|
||||||
|
"FK_TerminArtSachbearbeiter_TerminArt";"dbo";"TerminArtSachbearbeiter";"IDTerminArt_FS";"dbo";"TerminArt";"IDTerminArt"
|
||||||
|
"FK_TerminKetteAbfolge_TerminKette";"dbo";"TerminKetteAbfolge";"IDTerminArt_FS";"dbo";"TerminArt";"IDTerminArt"
|
||||||
|
"FK_TerminKetteAbfolge_TerminKette1";"dbo";"TerminKetteAbfolge";"IDTerminKette_FS";"dbo";"TerminKette";"IDTerminKette"
|
||||||
|
"FK_TerminSachbearbeiter_Termin";"dbo";"TerminSachbearbeiter";"IDTermin_FS";"dbo";"Termin";"IDTermin"
|
||||||
|
"FK_Tour_ArtFahrplanVersion";"dbo";"Tour";"IDArtFahrplanVersion_FS";"dbo";"ArtFahrplanVersion";"IDArtFahrplanVersion"
|
||||||
|
"FK_Tour_ArtStatistikGruppe";"dbo";"Tour";"IDArtStatistikgruppe_FS_Haupt";"dbo";"ArtStatistikGruppe";"IDArtStatistikGruppe"
|
||||||
|
"FK_Tour_FPLinieFahrt";"dbo";"Tour";"IDFPLinieFahrt_FS";"dbo";"FPLinieFahrt";"IDFPLinieFahrt"
|
||||||
|
"FK_Tour_Haltepunkt_Anfang";"dbo";"Tour";"IDHaltepunkt_FS_Anfang";"dbo";"Haltepunkt";"IDHaltepunkt"
|
||||||
|
"FK_Tour_Haltepunkt_Ende";"dbo";"Tour";"IDHaltepunkt_FS_Ende";"dbo";"Haltepunkt";"IDHaltepunkt"
|
||||||
|
"FK_Tour_Haltestelle_Anfang";"dbo";"Tour";"IDHaltestelle_FS_Anfang";"dbo";"Haltestelle";"IDHaltestelle"
|
||||||
|
"FK_Tour_Haltestelle_Ende";"dbo";"Tour";"IDHaltestelle_FS_Ende";"dbo";"Haltestelle";"IDHaltestelle"
|
||||||
|
"FK_Tour_Ort_Anfang";"dbo";"Tour";"IDOrt_FS_Anfang";"dbo";"Ort";"IDOrt"
|
||||||
|
"FK_Tour_Ort_Ende";"dbo";"Tour";"IDOrt_FS_Ende";"dbo";"Ort";"IDOrt"
|
||||||
|
"FK_TourFahrzeugtyp_ArtFahrzeugTypen";"dbo";"TourFahrzeugtyp";"IDArtFahrzeugTypen_FS";"dbo";"ArtFahrzeugTypen";"IDArtFahrzeugTypen"
|
||||||
|
"FK_TourFahrzeugtyp_Tour";"dbo";"TourFahrzeugtyp";"IDTour_FS";"dbo";"Tour";"IDTour"
|
||||||
|
"FK_TourFerienFeier_Tour";"dbo";"TourFerienFeier";"IDTour_FS";"dbo";"Tour";"IDTour"
|
||||||
|
"FK_TourHaltestelleHaltepunkt_Haltepunkt";"dbo";"TourHaltestelleHaltepunkt";"IDHaltepunkt_FS";"dbo";"Haltepunkt";"IDHaltepunkt"
|
||||||
|
"FK_TourHaltestelleHaltepunkt_Haltestelle";"dbo";"TourHaltestelleHaltepunkt";"IDHaltestelle_FS";"dbo";"Haltestelle";"IDHaltestelle"
|
||||||
|
"FK_TourHaltestelleHaltepunkt_Tour";"dbo";"TourHaltestelleHaltepunkt";"IDTour_FS";"dbo";"Tour";"IDTour"
|
||||||
|
"FK_TourKreisGebiet_ArtKreisGebiet";"dbo";"TourKreisGebiet";"IDArtKreisGebiet_FS";"dbo";"ArtKreisGebiet";"IDArtKreisGebiet"
|
||||||
|
"FK_TourKreisGebiet_Tour";"dbo";"TourKreisGebiet";"IDTour_FS";"dbo";"Tour";"IDTour"
|
||||||
|
"FK_TourLaufzeit_TourLaufzeit";"dbo";"TourLaufzeit";"IDTour_FS";"dbo";"Tour";"IDTour"
|
||||||
|
"FK_TourPlanung_Adresse";"dbo";"TourPlanung";"IDAdresse_FS_Fahrer";"dbo";"Adresse";"IDAdresse"
|
||||||
|
"FK_TourPlanung_Adresse2";"dbo";"TourPlanung";"LoeschenManuellIDAdresse_FS_SB";"dbo";"Adresse";"IDAdresse"
|
||||||
|
"FK_TourPlanung_ArtFahrplanVersion";"dbo";"TourPlanung";"IDArtFahrplanVersion_FS";"dbo";"ArtFahrplanVersion";"IDArtFahrplanVersion"
|
||||||
|
"FK_TourPlanung_ArtStatistikGruppe";"dbo";"TourPlanung";"IDArtStatistikgruppe_FS_Haupt";"dbo";"ArtStatistikGruppe";"IDArtStatistikGruppe"
|
||||||
|
"FK_TourPlanung_BlockPlanung";"dbo";"TourPlanung";"IDBlockPlanung_FS";"dbo";"BlockPlanung";"IDBlockPlanung"
|
||||||
|
"FK_TourPlanung_Fahrzeug";"dbo";"TourPlanung";"IDFahrzeug_FS";"dbo";"Fahrzeug";"IDFahrzeug"
|
||||||
|
"FK_Tourplanung_Haltepunkt_Anfang";"dbo";"TourPlanung";"IDHaltepunkt_FS_Anfang";"dbo";"Haltepunkt";"IDHaltepunkt"
|
||||||
|
"FK_Tourplanung_Haltepunkt_Ende";"dbo";"TourPlanung";"IDHaltepunkt_FS_Ende";"dbo";"Haltepunkt";"IDHaltepunkt"
|
||||||
|
"FK_Tourplanung_Haltestelle_Anfang";"dbo";"TourPlanung";"IDHaltestelle_FS_Anfang";"dbo";"Haltestelle";"IDHaltestelle"
|
||||||
|
"FK_Tourplanung_Haltestelle_Ende";"dbo";"TourPlanung";"IDHaltestelle_FS_Ende";"dbo";"Haltestelle";"IDHaltestelle"
|
||||||
|
"FK_TourPlanung_Ort_Anfang";"dbo";"TourPlanung";"IDOrt_FS_Anfang";"dbo";"Ort";"IDOrt"
|
||||||
|
"FK_TourPlanung_Ort_Ende";"dbo";"TourPlanung";"IDOrt_FS_Ende";"dbo";"Ort";"IDOrt"
|
||||||
|
"FK_TourPlanung_Tour";"dbo";"TourPlanung";"IDTour_FS_Basis";"dbo";"Tour";"IDTour"
|
||||||
|
"FK_TourPlanungFahrzeugtyp_ArtFahrzeugTypen";"dbo";"TourPlanungFahrzeugtyp";"IDArtFahrzeugTypen_FS";"dbo";"ArtFahrzeugTypen";"IDArtFahrzeugTypen"
|
||||||
|
"FK_TourPlanungFahrzeugtyp_TourPlanung";"dbo";"TourPlanungFahrzeugtyp";"IDTourPlanung_FS";"dbo";"TourPlanung";"IDTourPlanung"
|
||||||
|
"FK_TourPlanungKreisGebiet_ArtKreisGebiet";"dbo";"TourPlanungKreisGebiet";"IDArtKreisGebiet_FS";"dbo";"ArtKreisGebiet";"IDArtKreisGebiet"
|
||||||
|
"FK_TourPlanungKreisGebiet_TourPlanung";"dbo";"TourPlanungKreisGebiet";"IDTourPlanung_FS";"dbo";"TourPlanung";"IDTourPlanung"
|
||||||
|
"FK_TourPlanungStatistik_ArtStatistikGruppe";"dbo";"TourPlanungStatistik";"IDArtStatistikGruppe_FS";"dbo";"ArtStatistikGruppe";"IDArtStatistikGruppe"
|
||||||
|
"FK_TourPlanungStatistik_TourPlanung";"dbo";"TourPlanungStatistik";"IDTourPlanung_FS";"dbo";"TourPlanung";"IDTourPlanung"
|
||||||
|
"FK_TourPlanungZusatz_TourPlanung";"dbo";"TourPlanungZusatz";"IDTourPlanung_FS";"dbo";"TourPlanung";"IDTourPlanung"
|
||||||
|
"FK_TourStatistik_ArtStatistikGruppe";"dbo";"TourStatistik";"IDArtStatistikGruppe_FS";"dbo";"ArtStatistikGruppe";"IDArtStatistikGruppe"
|
||||||
|
"FK_TourStatistik_Tour";"dbo";"TourStatistik";"IDTour_FS";"dbo";"Tour";"IDTour"
|
||||||
|
"FK_TourWochentyp_ArtWochentyp";"dbo";"TourWochentyp";"IDArtWochentyp_FS";"dbo";"ArtWochentyp";"IDArtWochentyp"
|
||||||
|
"FK_TourWochentyp_Tour";"dbo";"TourWochentyp";"IDTour_FS";"dbo";"Tour";"IDTour"
|
||||||
|
"FK_TourZeitraum_ArtLaufzeitschema";"dbo";"TourZeitraum";"IDArtLaufzeitschema_FS";"dbo";"ArtLaufzeitschema";"IDArtLaufzeitschema"
|
||||||
|
"FK_TourZeitraum_Tour";"dbo";"TourZeitraum";"IDTour_FS";"dbo";"Tour";"IDTour"
|
||||||
|
"FK_TourZusatz_Tour";"dbo";"TourZusatz";"IDTour_FS";"dbo";"Tour";"IDTour"
|
||||||
|
"FK_UserStartmenue_Adresse";"dbo";"UserStartmenue";"IDAdresse_FS";"dbo";"Adresse";"IDAdresse"
|
||||||
|
"FK_UserStartmenue_Programmmodul";"dbo";"UserStartmenue";"IDProgrammmodul_FS";"dbo";"Programmmodul";"IDProgrammmodul"
|
||||||
|
"FK_VorplanungRasterAblauf_VorplanungRaster";"dbo";"VorplanungRasterAblauf";"IDVorplanungRaster_FS";"dbo";"VorplanungRaster";"IDVorplanungRaster"
|
||||||
|
"FK_VorplanungRasterAblaufAbwPartner_Adresse";"dbo";"VorplanungRasterAblaufAbwPartner";"IDAdresse_FS_Partner";"dbo";"Adresse";"IDAdresse"
|
||||||
|
"FK_VorplanungRasterAblaufAbwPartner_VorplanungRasterAblauf";"dbo";"VorplanungRasterAblaufAbwPartner";"IDVorplanungRasterAblauf_FS";"dbo";"VorplanungRasterAblauf";"IDVorplanungRasterAblauf"
|
||||||
|
"FK_VorplanungRasterAblaufAbwPartner_VorplanungRasterTermin";"dbo";"VorplanungRasterAblaufAbwPartner";"IDVorplanungRasterTermin_FS";"dbo";"VorplanungRasterTermin";"IDVorplanungRasterTermin"
|
||||||
|
"FK_VorplanungRasterAblaufStatus_Adresse";"dbo";"VorplanungRasterAblaufStatus";"IDAdresse_FS_Sachbearbeiter";"dbo";"Adresse";"IDAdresse"
|
||||||
|
"FK_VorplanungRasterAblaufStatus_ArtReiseVplPartnerStatus";"dbo";"VorplanungRasterAblaufStatus";"IDArtReiseVplPartnerStatus_FS";"dbo";"ArtReiseVplPartnerStatus";"IDArtReiseVplPartnerStatus"
|
||||||
|
"FK_VorplanungRasterAblaufStatus_VorplanungRasterAblauf";"dbo";"VorplanungRasterAblaufStatus";"IDVorplanungRasterAblauf_FS";"dbo";"VorplanungRasterAblauf";"IDVorplanungRasterAblauf"
|
||||||
|
"FK_VorplanungRasterAblaufStatus_VorplanungRasterTermin";"dbo";"VorplanungRasterAblaufStatus";"IDVorplanungRasterTermin_FS";"dbo";"VorplanungRasterTermin";"IDVorplanungRasterTermin"
|
||||||
|
"FK_VorplanungRasterAblaufZusatz_VorplanungRasterAblauf";"dbo";"VorplanungRasterAblaufZusatz";"IDVorplanungRasterAblauf_FS";"dbo";"VorplanungRasterAblauf";"IDVorplanungRasterAblauf"
|
||||||
|
"FK_VorplanungRasterBemerkung_VorplanungRaster";"dbo";"VorplanungRasterBemerkung";"IDVorplanungRaster_FS";"dbo";"VorplanungRaster";"IDVorplanungRaster"
|
||||||
|
"FK_VorplanungRasterDokument_Adresse";"dbo";"VorplanungRasterDokument";"IDAdresse_FS_Sachbearbeiter";"dbo";"Adresse";"IDAdresse"
|
||||||
|
"FK_VorplanungRasterDokument_ArtDokument";"dbo";"VorplanungRasterDokument";"IDArtDokument_FS";"dbo";"ArtDokument";"IDArtDokument"
|
||||||
|
"FK_VorplanungRasterDokument_VorplanungRaster";"dbo";"VorplanungRasterDokument";"IDVorplanungRaster_FS";"dbo";"VorplanungRaster";"IDVorplanungRaster"
|
||||||
|
"FK_VorplanungRasterKalkulationÜbernahme_VorplanungRasterKalkulation";"dbo";"VorplanungRasterKalkulationÜbernahme";"IDVorplanungRasterKalkulation_FS";"dbo";"VorplanungRasterKalkulation";"IDVorplanungRasterKalkulation"
|
||||||
|
"FK_VorplanungRasterTermin_VorplanungRaster";"dbo";"VorplanungRasterTermin";"IDVorplanungRaster_FS";"dbo";"VorplanungRaster";"IDVorplanungRaster"
|
||||||
|
"FK_WaehrungsKurse_ArtWaehrung";"dbo";"WaehrungsKurse";"IDArtWaehrung_FS";"dbo";"ArtWaehrung";"IDArtWaehrung"
|
||||||
|
"FK_WerbeplanungPunkte_ArtWerbeplanungReiseart";"dbo";"WerbeplanungPunkte";"IDArtWerbeplanungReiseart_FS";"dbo";"ArtWerbeplanungReiseart";"IDArtWerbeplanungReiseart"
|
||||||
|
"FK_WWKategorieEintrag_WWSuchKategorie";"dbo";"WWSuchKategorieEintrag";"IDWWSuchKategorie_FS";"dbo";"WWSuchKategorie";"IDWWSuchKategorie"
|
||||||
|
"FK_Zahlung_Adresse";"dbo";"Zahlung";"IDAdresse_FS_Sachbearbeiter";"dbo";"Adresse";"IDAdresse"
|
||||||
|
"FK_Zahlung_ArtWaehrung";"dbo";"Zahlung";"IDWaehrung_FS";"dbo";"ArtWaehrung";"IDArtWaehrung"
|
||||||
|
"FK_Zahlung_ArtZahlungsart";"dbo";"Zahlung";"IDArtZahlungart_FS";"dbo";"ArtZahlungsart";"IDArtZahlungsart"
|
||||||
|
"FK_Zahlung_ZahlungCode";"dbo";"Zahlung";"IDKontenplan_FS";"dbo";"Kontenplan";"IDKontenplan"
|
||||||
|
"FK_Zahlung_ZahlungStamm";"dbo";"Zahlung";"IDZahlungStamm_FS";"dbo";"ZahlungStamm";"IDZahlungStamm"
|
||||||
|
"FK_ZahlungDokument_Adresse";"dbo";"ZahlungDokument";"IDAdresse_FS_Sachbearbeiter";"dbo";"Adresse";"IDAdresse"
|
||||||
|
"FK_ZahlungDokument_ArtDokument";"dbo";"ZahlungDokument";"IDArtDokument_FS";"dbo";"ArtDokument";"IDArtDokument"
|
||||||
|
"FK_ZahlungDokument_Zahlung";"dbo";"ZahlungDokument";"IDZahlung_FS";"dbo";"Zahlung";"IDZahlung"
|
||||||
|
"FK_ZahlungStamm_Adresse";"dbo";"ZahlungStamm";"IDAdresse_FS_Mandant";"dbo";"Adresse";"IDAdresse"
|
||||||
|
"FK_ZahlungStamm_ArtWaehrung";"dbo";"ZahlungStamm";"IDWaehrung_FS";"dbo";"ArtWaehrung";"IDArtWaehrung"
|
||||||
|
"FK_ZahlungStamm_Nummernkreis";"dbo";"ZahlungStamm";"IDNummernkreis_FS";"dbo";"Nummernkreis";"IDNummernkreis"
|
||||||
|
"FK_ZiellandRoute_Land";"dbo";"ZiellandRoute";"IDLand_FS_Route";"dbo";"Land";"IDLand"
|
||||||
|
"FK_ZiellandRoute_Land1";"dbo";"ZiellandRoute";"IDLand_FS_Zielland";"dbo";"Land";"IDLand"
|
||||||
|
"FK_Zusatzinformation_Adresse";"dbo";"Zusatzinformation";"IDAdresse_FS_Partner";"dbo";"Adresse";"IDAdresse"
|
||||||
|
"FK_Zusatzinformation_ArtZusatzinfoStamm";"dbo";"Zusatzinformation";"IDArtZusatzinfoStamm_FS";"dbo";"ArtZusatzinfoStamm";"IDArtZusatzinfoStamm"
|
||||||
|
"FK_Zusatzinformation_Reise";"dbo";"Zusatzinformation";"IDReise_FS";"dbo";"Reise";"IDReise"
|
||||||
|
"FK_ZusatzZimmer_ArtBuchungsStatus";"dbo";"ZusatzZimmer";"IDArtBuchungsstatus_FS";"dbo";"ArtBuchungsStatus";"IDArtBuchungsStatus"
|
||||||
|
"FK_ZusatzZimmer_Reise";"dbo";"ZusatzZimmer";"IDReise_FS";"dbo";"Reise";"IDReise"
|
||||||
|
"FK_ZustiegHinweis_Zustieg";"dbo";"ZustiegHinweis";"IDZustieg_FS";"dbo";"Zustieg";"IDZustieg"
|
||||||
|
"FK_Zustiegkoordinate_Zustieg";"dbo";"Zustiegkoordinate";"IDZustieg_FS";"dbo";"Zustieg";"IDZustieg"
|
||||||
|
"FK_ZustiegKoordinate_ZustiegKoordinatenArt";"dbo";"Zustiegkoordinate";"IDArtKoordinaten_FS";"dbo";"ArtZustiegKoordinaten";"IDArtZustiegKoordinaten"
|
||||||
|
"FK_ZustiegPLZ_Zustieg1";"dbo";"ZustiegPLZ";"IDZustieg_FS";"dbo";"Zustieg";"IDZustieg"
|
||||||
|
"FK_ZustiegPreis_ArtZustiegPreis1";"dbo";"ZustiegPreis";"IDArtZustiegPreis_FS";"dbo";"ArtZustiegPreis";"IDArtZustiegPreis"
|
||||||
|
"FK_ZustiegPreis_Zustieg1";"dbo";"ZustiegPreis";"IDZustieg_FS";"dbo";"Zustieg";"IDZustieg"
|
||||||
|
"FK_ZustiegRoute_ArtZustiegRoutenbeschreibung";"dbo";"ZustiegRoute";"IDArtZustiegRoutenbeschreibung_FS";"dbo";"ArtZustiegRoutenbeschreibung";"IDArtZustiegRoutenbeschreibung"
|
||||||
|
"FK_ZustiegRoute_Zustieg";"dbo";"ZustiegRoute";"IDZustieg_FS";"dbo";"Zustieg";"IDZustieg"
|
||||||
|
"FK_ZustiegsPlanungBesonders_ZustiegsPlanungPerson";"dbo";"ZustiegsPlanungBesonders";"IDZustiegsPlanungPerson_FS";"dbo";"ZustiegsPlanungPerson";"IDZustiegsPlanungPerson"
|
||||||
|
"FK_ZustiegsPlanungBus_ZustiegsPlanung";"dbo";"ZustiegsPlanungBus";"IDZustiegsPlanung_FS";"dbo";"ZustiegsPlanung";"IDZustiegsPlanung"
|
||||||
|
"FK_ZustiegsPlanungBusStelle_ZustiegsPlanungBus";"dbo";"ZustiegsPlanungBusStelle";"IDZustiegsPlanungBus_FS";"dbo";"ZustiegsPlanungBus";"IDZustiegsPlanungBus"
|
||||||
|
"FK_ZustiegsPlanungLeistung_ZustiegsPlanung";"dbo";"ZustiegsPlanungLeistung";"IDZustiegsPlanung_FS";"dbo";"ZustiegsPlanung";"IDZustiegsPlanung"
|
||||||
|
"FK_ZustiegsPlanungPerson_BuchungTN";"dbo";"ZustiegsPlanungPerson";"IDBuchungTN_FS";"dbo";"BuchungTN";"IDBuchungTN"
|
||||||
|
"FK_ZustiegsPlanungPerson_Leistung";"dbo";"ZustiegsPlanungPerson";"IDLeistung_FS";"dbo";"Leistung";"IDLeistung"
|
||||||
|
"FK_ZustiegsPlanungPerson_ZustiegsPlanung";"dbo";"ZustiegsPlanungPerson";"IDZustiegsPlanung_FS";"dbo";"ZustiegsPlanung";"IDZustiegsPlanung"
|
||||||
|
"FK_ZustiegsPlanungPersonStelle_ZustiegsPlanungBusStelle";"dbo";"ZustiegsPlanungPersonStelle";"IDZustiegsPlanungBusStelle_FS";"dbo";"ZustiegsPlanungBusStelle";"IDZustiegsPlanungBusStelle"
|
||||||
|
"FK_ZustiegsPlanungPersonStelle_ZustiegsPlanungPerson";"dbo";"ZustiegsPlanungPersonStelle";"IDZustiegsPlanungPerson_FS";"dbo";"ZustiegsPlanungPerson";"IDZustiegsPlanungPerson"
|
||||||
|
"FK_ZustiegZeitplan_ArtZustiegZeitplan";"dbo";"ZustiegZeitplan";"IDArtZustiegZeitplan_FS";"dbo";"ArtZustiegZeitplan";"IDArtZustiegZeitplan"
|
||||||
|
@@ -0,0 +1,94 @@
|
|||||||
|
# Boarding Plan — Table Relations (BusPro schema)
|
||||||
|
|
||||||
|
> **Authority: [`docs/buspro-database-reference.md`](../buspro-database-reference.md) §8.4.**
|
||||||
|
> Retained for the detailed ER diagram of the `ZustiegsPlanung*` subsystem.
|
||||||
|
|
||||||
|
Read-only reference for building the boarding-plan API endpoint (look up a plan
|
||||||
|
by `IDZustiegsPlanung`, returning names, addresses, and times).
|
||||||
|
|
||||||
|
The query walks:
|
||||||
|
**`ZustiegsPlanung` → persons → (name via `BuchungTN`/`AdressePerson`) →
|
||||||
|
`PersonStelle` junction → `BusStelle` (time) → `Zustieg` (address) → `Bus`.**
|
||||||
|
`ZustiegsPlanungPersonStelle` is the pivot that ties a passenger to a timed stop.
|
||||||
|
|
||||||
|
## ER diagram
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
erDiagram
|
||||||
|
ZustiegsPlanung ||--o{ ZustiegsPlanungBus : "IDZustiegsPlanung_FS"
|
||||||
|
ZustiegsPlanung ||--o{ ZustiegsPlanungPerson : "IDZustiegsPlanung_FS"
|
||||||
|
ZustiegsPlanungBus ||--o{ ZustiegsPlanungBusStelle : "IDZustiegsPlanungBus_FS"
|
||||||
|
ZustiegsPlanungPerson ||--o{ ZustiegsPlanungPersonStelle : "IDZustiegsPlanungPerson_FS"
|
||||||
|
ZustiegsPlanungBusStelle ||--o{ ZustiegsPlanungPersonStelle : "IDZustiegsPlanungBusStelle_FS"
|
||||||
|
|
||||||
|
ZustiegsPlanungPerson }o..|| BuchungTN : "IDBuchungTN_FS"
|
||||||
|
BuchungTN }o..|| AdressePerson : "IDAdressePerson_FS (name)"
|
||||||
|
ZustiegsPlanungBusStelle }o..o| Zustieg : "IDZustieg_FS (soft, address)"
|
||||||
|
|
||||||
|
ZustiegsPlanung {
|
||||||
|
bigint IDZustiegsPlanung PK
|
||||||
|
datetime Datum
|
||||||
|
}
|
||||||
|
ZustiegsPlanungBus {
|
||||||
|
bigint IDZustiegsPlanungBus PK
|
||||||
|
string ReiseleiterName
|
||||||
|
}
|
||||||
|
ZustiegsPlanungBusStelle {
|
||||||
|
bigint IDZustiegsPlanungBusStelle PK
|
||||||
|
datetime Zeit "TIME"
|
||||||
|
smallint Sortierung
|
||||||
|
}
|
||||||
|
ZustiegsPlanungPerson {
|
||||||
|
bigint IDZustiegsPlanungPerson PK
|
||||||
|
}
|
||||||
|
ZustiegsPlanungPersonStelle {
|
||||||
|
bigint IDZustiegsPlanungPersonStelle PK
|
||||||
|
string Art "Einstieg/Ausstieg"
|
||||||
|
}
|
||||||
|
AdressePerson {
|
||||||
|
string Name
|
||||||
|
string Vorname
|
||||||
|
}
|
||||||
|
Zustieg {
|
||||||
|
string Strasse
|
||||||
|
string Plz
|
||||||
|
string Ort
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## ASCII fallback
|
||||||
|
|
||||||
|
```
|
||||||
|
ZustiegsPlanung (the planning id)
|
||||||
|
/ \
|
||||||
|
IDZustiegsPlanung_FS IDZustiegsPlanung_FS
|
||||||
|
/ \
|
||||||
|
ZustiegsPlanungBus ZustiegsPlanungPerson ──IDBuchungTN_FS──▶ BuchungTN
|
||||||
|
│ (Reiseleiter) │ │
|
||||||
|
IDZustiegsPlanungBus_FS IDZustiegsPlanungPerson_FS IDAdressePerson_FS
|
||||||
|
│ │ ▼
|
||||||
|
▼ ▼ AdressePerson
|
||||||
|
ZustiegsPlanungBusStelle ◀──┐ ZustiegsPlanungPersonStelle (NAME)
|
||||||
|
• Zeit (TIME) │ • Art (boarding/alighting)
|
||||||
|
• IDZustieg_FS ··soft··▶ Zustieg (ADDRESS)
|
||||||
|
└──IDZustiegsPlanungBusStelle_FS───┘ (junction: passenger ↔ stop)
|
||||||
|
```
|
||||||
|
|
||||||
|
**Legend:** `||--o{` / solid = enforced FK constraint; `}o..` / `··soft··` =
|
||||||
|
convention-only `_FS` reference (no DB constraint — join defensively, expect
|
||||||
|
`NULL`/`0`/orphaned values).
|
||||||
|
|
||||||
|
## Notes for the query
|
||||||
|
|
||||||
|
- **Name** is not stored in the plan; join out live via
|
||||||
|
`ZustiegsPlanungPerson.IDBuchungTN_FS → BuchungTN.IDAdressePerson_FS → AdressePerson`.
|
||||||
|
- **Time** lives on `ZustiegsPlanungBusStelle.Zeit` (per stop), not on the plan
|
||||||
|
header (`ZustiegsPlanung.Datum` is the plan date).
|
||||||
|
- **Address** comes from `Zustieg` (the boarding point). Prefer reaching it via
|
||||||
|
`ZustiegsPlanungBusStelle.IDZustieg_FS` so it never depends on
|
||||||
|
`ZustiegsPlanungPerson.IDZustieg_FS` being populated.
|
||||||
|
- A passenger can have multiple `ZustiegsPlanungPersonStelle` rows (boarding +
|
||||||
|
alighting), distinguished by `Art`. Filter on `Art` for boarding-only.
|
||||||
|
- To verify against real data: the actual `Art` codes (`nvarchar(6)`), and
|
||||||
|
whether `BusStelle.IDZustieg_FS` always matches the passenger's
|
||||||
|
`Person.IDZustieg_FS` on the boarding leg.
|
||||||
@@ -0,0 +1,469 @@
|
|||||||
|
# `SelektionCRM` — how the XML is assembled, and how to debug a missing selection
|
||||||
|
|
||||||
|
> **Authority: [`docs/buspro-database-reference.md`](../buspro-database-reference.md).**
|
||||||
|
> Schema semantics and the falsified-theory record live there and win on any conflict.
|
||||||
|
> This file is retained as the **full investigation record** for the missing-selection /
|
||||||
|
> `aenderbar` problem, including the queries that closed each theory.
|
||||||
|
|
||||||
|
Companion to `travel-queries.md` (static catalog) and `live-api-queries.md` (live
|
||||||
|
socket endpoints). This one covers the `KUNDENKONTO` / `art=SelektionCRM` response —
|
||||||
|
the document that drives the portal's entire authorization model.
|
||||||
|
|
||||||
|
Request side: `ApiClient::getCrmAttributes()` (`src/BusProNet/ApiClient.php`) sends
|
||||||
|
`satz typ="KUNDENKONTO"` + `art=SelektionCRM` + the customer's email/password.
|
||||||
|
Response side: `CrmAttributesResponseParser`
|
||||||
|
(`src/BusProNet/XmlParser/CrmAttributesResponseParser.php`) turns selection ids into
|
||||||
|
Symfony roles:
|
||||||
|
|
||||||
|
| `IDSelektionsstamm` | Role |
|
||||||
|
| --- | --- |
|
||||||
|
| `1070` | `ROLE_TEAMER` |
|
||||||
|
| `1292` | `ROLE_ADMIN` (+ `ROLE_HOUSE_MANAGER`, + hotel code `SSL`) |
|
||||||
|
| `1293` | `ROLE_MANAGER` |
|
||||||
|
| `1477` | `ROLE_GROUPS_MANAGER` |
|
||||||
|
| `1478` | `ROLE_GROUPS_ADMIN` |
|
||||||
|
| label `Hausleitung {CODE}` | `ROLE_HOUSE_MANAGER` + hotel code `{CODE}` |
|
||||||
|
| nothing matched | `ROLE_CUSTOMER` |
|
||||||
|
|
||||||
|
Only selections with `auswahl="True"` count. Every `Admin/*` controller is gated on
|
||||||
|
one of these roles.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## The four tables
|
||||||
|
|
||||||
|
From `BusPronet_20260601-1517.csv` (columns) and `BusPronet_20260601-1518.csv` (FKs):
|
||||||
|
|
||||||
|
| Table | Columns | Role |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| `dbo.Selektionsstamm` | `IDSelektionsstamm`, `Selektion`, `Status` nvarchar(2) null, `System` tinyint | the selection master — that's *all four* columns |
|
||||||
|
| `dbo.Selektionsgruppenstamm` | `IDSelektionsgruppenstamm`, `Selektionsgruppe`, `Status`, `System`, `Ausgrenzung`, `Position` | the group master |
|
||||||
|
| `dbo.Selektionsgruppe` | `IDSelektionsgruppenstamm_FS`, `IDSelektionsstamm_FS`, `Position` | **membership** — which selection sits in which group, and in what order |
|
||||||
|
| `dbo.Selektionen` | `IDAdresse_FS`, `IDSelektionsstamm_FS` | **assignment** — which address holds which selection |
|
||||||
|
|
||||||
|
`<crmaktionen>` comes from a parallel pair: `dbo.CRMAktion` (master: `Code`,
|
||||||
|
`Bezeichnung`, `Aktiv`, `Status`, `AktivDatumVon/Bis`, …) and `dbo.CRMZuweisung`
|
||||||
|
(assignment via `IDAdresse_FS` + `IDCRMAktion_FS`).
|
||||||
|
|
||||||
|
### XML → column mapping
|
||||||
|
|
||||||
|
| XML | Source |
|
||||||
|
| --- | --- |
|
||||||
|
| `<idadresse>` | `Adresse.IDAdresse` (the authenticated account) |
|
||||||
|
| `<idperson>` | `AdressePerson.IDAdressePerson` |
|
||||||
|
| `<selektionsgruppe id>` / `bezeichnung` | `Selektionsgruppenstamm.IDSelektionsgruppenstamm` / `.Selektionsgruppe` |
|
||||||
|
| `<selektion id>` / `bezeichnung` | `Selektionsstamm.IDSelektionsstamm` / `.Selektion` |
|
||||||
|
| `selektion@auswahl` | `EXISTS (Selektionen WHERE IDAdresse_FS = <account> AND IDSelektionsstamm_FS = <id>)` — confirmed |
|
||||||
|
| `selektion@aenderbar` | **computed, not stored** — no such column exists anywhere (see below) |
|
||||||
|
| group order | `Selektionsgruppenstamm.Position`, `<ohne Gruppe>` first |
|
||||||
|
| selection order within a group | `Selektionsgruppe.Position` |
|
||||||
|
| `<crmaktion …>` | `CRMAktion` + `CRMZuweisung` (`auswahl` = assignment exists) |
|
||||||
|
|
||||||
|
### `aenderbar` is not a stored flag
|
||||||
|
|
||||||
|
A case-insensitive search for `aenderbar` / `auswahl` across **every column name in the
|
||||||
|
database** (1023 tables, `ABOBewegungsdaten` … `ZustiegsPlanungPersonStelle`, so the
|
||||||
|
export is complete and untruncated) returns no hit on any `Selektion*` table. The only
|
||||||
|
`*Aenderbar*` column in the entire schema is `AdresseAgenturZusatz.ZahlungsartAenderbar`,
|
||||||
|
which is unrelated. And the three core tables have no spare bit to hide it in:
|
||||||
|
`Selektionsstamm` has exactly four columns, `Selektionsgruppe` three, `Selektionen` two.
|
||||||
|
|
||||||
|
So `aenderbar` is **derived at response time**. Don't go looking for the column again —
|
||||||
|
this is what Query D and Query E are for.
|
||||||
|
|
||||||
|
The `<crmaktionen>` half of the document hints at the intended semantics: `CRMAktion`
|
||||||
|
*does* carry real flags (`Aktiv`, `Anzeige`, `AktivDatumVon`/`Bis`), and in the reference
|
||||||
|
sample the long-expired "Deal Der Woche KW40-2018" is `aenderbar="False"` while the
|
||||||
|
standing "NOMAIL" opt-out is `"True"`. `aenderbar` reads as *"the customer may still
|
||||||
|
toggle this"* — a validity/whitelist question, not a static per-row property.
|
||||||
|
|
||||||
|
Two orderings worth noting, because they rule out the obvious alternatives:
|
||||||
|
|
||||||
|
- Inside `TEAM` the ids run `… 1374, 1375, 1376, 1373, 1377 …` — neither id order nor
|
||||||
|
label order. That is `Selektionsgruppe.Position`.
|
||||||
|
- Within `Interessen` the labels *are* alphabetical, which is consistent with
|
||||||
|
`Position` having been maintained alphabetically there. Don't read it as a
|
||||||
|
different rule.
|
||||||
|
|
||||||
|
### The decisive observation: the catalog is group-driven
|
||||||
|
|
||||||
|
Every `Hausleitung *` row is emitted with `auswahl="False"` for an account that holds
|
||||||
|
none of them. So the endpoint does **not** list "the selections this address has" — it
|
||||||
|
lists **the whole published catalog** and then flags which entries the address holds.
|
||||||
|
|
||||||
|
`<selektionsgruppe id="0" bezeichnung="<ohne Gruppe>">` is the bucket for
|
||||||
|
selections with no (or a `0`) `Selektionsgruppe` membership row.
|
||||||
|
|
||||||
|
The practical consequence: **inserting a row into `dbo.Selektionen` can never make a
|
||||||
|
selection appear.** It can only flip `auswahl` from `False` to `True` on an entry that
|
||||||
|
the catalog already emits. A selection that is absent from the XML is absent from the
|
||||||
|
*catalog*, and the assignment is irrelevant until that is fixed.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Query A — reconstruct the response
|
||||||
|
|
||||||
|
Run this for the account in question and diff its rows against the actual XML. A clean
|
||||||
|
match proves the reconstruction above; any mismatch belongs in the caveats section.
|
||||||
|
|
||||||
|
```sql
|
||||||
|
DECLARE @AddressId bigint = 141747;
|
||||||
|
|
||||||
|
SELECT COALESCE(sg.IDSelektionsgruppenstamm, 0) AS groupId,
|
||||||
|
COALESCE(sg.Selektionsgruppe, '<ohne Gruppe>') AS groupLabel,
|
||||||
|
s.IDSelektionsstamm AS selectionId,
|
||||||
|
s.Selektion AS selectionLabel,
|
||||||
|
CASE WHEN s.System = 0 THEN 'True' ELSE 'False' END AS aenderbar,
|
||||||
|
CASE WHEN sel.IDAdresse_FS IS NULL THEN 'False' ELSE 'True' END AS auswahl
|
||||||
|
FROM dbo.Selektionsstamm s
|
||||||
|
LEFT JOIN dbo.Selektionsgruppe sgm
|
||||||
|
ON sgm.IDSelektionsstamm_FS = s.IDSelektionsstamm
|
||||||
|
LEFT JOIN dbo.Selektionsgruppenstamm sg
|
||||||
|
ON sg.IDSelektionsgruppenstamm = sgm.IDSelektionsgruppenstamm_FS
|
||||||
|
LEFT JOIN dbo.Selektionen sel
|
||||||
|
ON sel.IDSelektionsstamm_FS = s.IDSelektionsstamm
|
||||||
|
AND sel.IDAdresse_FS = @AddressId
|
||||||
|
WHERE COALESCE(s.Status, '') <> 'L'
|
||||||
|
AND COALESCE(sg.Status, '') <> 'L'
|
||||||
|
ORDER BY COALESCE(sg.Position, -1), sgm.Position, s.Selektion;
|
||||||
|
```
|
||||||
|
|
||||||
|
(`Status = 'L'` is this database's soft-delete marker — see
|
||||||
|
`../bpn-connect-query-reference.md`.)
|
||||||
|
|
||||||
|
Note the join fans out: a selection can belong to **several** groups (confirmed —
|
||||||
|
`1292` is in both `10` and `91`), so this query emits one row per membership. The XML
|
||||||
|
shows a selection once per group it is published in.
|
||||||
|
|
||||||
|
`Selektionsgruppenstamm.Ausgrenzung` is *exclusion* semantics (mutually exclusive
|
||||||
|
group), not visibility — don't mistake it for a publish flag.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Query B — diagnose a selection that never appears
|
||||||
|
|
||||||
|
Compares the suspect row against known-good neighbours: `1292`/`1293` (long-standing,
|
||||||
|
emitted, `aenderbar=False`) and `1462` (most recent one that *is* emitted,
|
||||||
|
`aenderbar=True`). Whatever column differs is the answer.
|
||||||
|
|
||||||
|
```sql
|
||||||
|
SELECT s.IDSelektionsstamm,
|
||||||
|
s.Selektion,
|
||||||
|
s.Status,
|
||||||
|
s.System,
|
||||||
|
sgm.IDSelektionsgruppenstamm_FS AS groupId,
|
||||||
|
sgm.Position AS positionInGroup,
|
||||||
|
(SELECT COUNT(*) FROM dbo.Selektionen x
|
||||||
|
WHERE x.IDSelektionsstamm_FS = s.IDSelektionsstamm
|
||||||
|
AND x.IDAdresse_FS = 141747) AS assignedToAddress
|
||||||
|
FROM dbo.Selektionsstamm s
|
||||||
|
LEFT JOIN dbo.Selektionsgruppe sgm
|
||||||
|
ON sgm.IDSelektionsstamm_FS = s.IDSelektionsstamm
|
||||||
|
WHERE s.IDSelektionsstamm IN (1477, 1478, 1292, 1293, 1462)
|
||||||
|
ORDER BY s.IDSelektionsstamm;
|
||||||
|
```
|
||||||
|
|
||||||
|
### What Query B ruled out (address `141747`, 2026-08-04)
|
||||||
|
|
||||||
|
| id | Selektion | Status | System | groupId | posInGroup | assigned |
|
||||||
|
| --- | --- | --- | --- | --- | --- | --- |
|
||||||
|
| 1292 | Admin | *(blank)* | 1 | 10 | 33 | 1 |
|
||||||
|
| 1292 | Admin | *(blank)* | 1 | **91** | 1 | 1 |
|
||||||
|
| 1293 | Manager | *(blank)* | 1 | **92** | 1 | 1 |
|
||||||
|
| 1293 | Manager | *(blank)* | 1 | 10 | 34 | 1 |
|
||||||
|
| 1462 | Hausleitung AGR | *(blank)* | 1 | 10 | 74 | 0 |
|
||||||
|
| 1477 | Preisrechner | *(blank)* | 1 | 10 | 75 | 0 |
|
||||||
|
| 1478 | Preisrechner Admin | *(blank)* | 1 | 10 | 76 | 1 |
|
||||||
|
|
||||||
|
Three conclusions:
|
||||||
|
|
||||||
|
1. **The missing-membership theory is dead.** `1477`/`1478` *are* in group `10` (TEAM),
|
||||||
|
at positions `75`/`76`, and `1478` *is* assigned to the address. On every column
|
||||||
|
available in these three tables, `1478` is indistinguishable from `1462` — which the
|
||||||
|
XML does emit. Whatever excludes them lives **outside**
|
||||||
|
`Selektionsstamm` / `Selektionsgruppe` / `Selektionen`.
|
||||||
|
2. **`aenderbar` is not derived from `System`.** `1292` (`aenderbar="False"`) and `1462`
|
||||||
|
(`aenderbar="True"`) both have `System = 1`. `Selektionsstamm` has no other column,
|
||||||
|
so `aenderbar` comes from somewhere else entirely.
|
||||||
|
3. **A selection can belong to several groups, and some groups are not published.**
|
||||||
|
`1292` is in `10` + `91`, `1293` is in `10` + `92`; groups `91`/`92` appear nowhere in
|
||||||
|
the XML, which only emits `0`, `10`, `83`. So there is a **group-level publish
|
||||||
|
filter** — and, suggestively, the two rows with a second (unpublished) group
|
||||||
|
membership are exactly the two that come back `aenderbar="False"`.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Query D — the agency whitelist (run this first)
|
||||||
|
|
||||||
|
`dbo.AgenturSelektionenKunde` is a bare two-column link table,
|
||||||
|
`(IDAdresse_FS, IDSelektionsstamm_FS)` — literally *"agency's customer selections"*. The
|
||||||
|
portal authenticates against BusPro as an **agency** account (`bpn_username` in
|
||||||
|
`ApiClient`), so a per-agency whitelist of which customer selections that agency may see
|
||||||
|
and/or edit is exactly the right shape. It is the only candidate found so far that could
|
||||||
|
explain the `1478` omission **and** `aenderbar` through one mechanism.
|
||||||
|
|
||||||
|
```sql
|
||||||
|
SELECT ask.IDAdresse_FS AS agencyAddressId,
|
||||||
|
a.SuchName AS agencyName,
|
||||||
|
ask.IDSelektionsstamm_FS AS selectionId,
|
||||||
|
s.Selektion AS selectionLabel
|
||||||
|
FROM dbo.AgenturSelektionenKunde ask
|
||||||
|
JOIN dbo.Selektionsstamm s ON s.IDSelektionsstamm = ask.IDSelektionsstamm_FS
|
||||||
|
LEFT JOIN dbo.Adresse a ON a.IDAdresse = ask.IDAdresse_FS
|
||||||
|
ORDER BY ask.IDAdresse_FS, s.Selektion;
|
||||||
|
|
||||||
|
-- same shape, same question:
|
||||||
|
SELECT * FROM dbo.PartnerSelektionenKunde;
|
||||||
|
```
|
||||||
|
|
||||||
|
Compare the row set for the portal's agency address against a freshly captured response:
|
||||||
|
|
||||||
|
| Result | Meaning |
|
||||||
|
| --- | --- |
|
||||||
|
| set == the 32 emitted entries | **this is the publish gate** — `1477`/`1478` just need rows here |
|
||||||
|
| set == the `aenderbar="True"` subset only | this is the `aenderbar` source |
|
||||||
|
| set is some third thing | note it in this doc and continue to C1 |
|
||||||
|
| table empty | both hypotheses dead — fall through to C1/C2/C3 |
|
||||||
|
|
||||||
|
**Result (2026-08-04): `dbo.AgenturSelektionenKunde` is empty.** The agency-whitelist
|
||||||
|
theory is dead. Do not re-run.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Query E — group-count cross-check (the secondary `aenderbar` theory)
|
||||||
|
|
||||||
|
Query B hinted that the two `aenderbar="False"` rows were the two with a *second*,
|
||||||
|
unpublished group membership (`1292`→{10, 91}, `1293`→{10, 92}) while `aenderbar="True"`
|
||||||
|
`1462` sat in group `10` alone. Two data points is not a rule — this settles it in one run:
|
||||||
|
|
||||||
|
```sql
|
||||||
|
SELECT s.IDSelektionsstamm,
|
||||||
|
s.Selektion,
|
||||||
|
COUNT(*) AS groupCount,
|
||||||
|
STRING_AGG(CAST(sgm.IDSelektionsgruppenstamm_FS AS varchar(10)), ',') AS groupIds
|
||||||
|
FROM dbo.Selektionsstamm s
|
||||||
|
JOIN dbo.Selektionsgruppe sgm ON sgm.IDSelektionsstamm_FS = s.IDSelektionsstamm
|
||||||
|
WHERE s.IDSelektionsstamm IN (1064,1065,1066,1067,1068,1069,1070,1156,1292,1293,
|
||||||
|
1299,1304,1377,1459,1461,1462,1477,1478)
|
||||||
|
GROUP BY s.IDSelektionsstamm, s.Selektion
|
||||||
|
ORDER BY s.IDSelektionsstamm;
|
||||||
|
```
|
||||||
|
|
||||||
|
Read against the known `aenderbar` values from the reference response:
|
||||||
|
|
||||||
|
- `aenderbar="False"`: `1070`, `1156`, `1292`, `1293`, `1299`, `1304`, `1377`
|
||||||
|
- `aenderbar="True"`: `1064`–`1069`, `1459`, `1461`, `1462`
|
||||||
|
|
||||||
|
If every `False` row has `groupCount > 1` and every `True` row has `groupCount = 1`, the
|
||||||
|
theory holds. Note it still would not explain `1478` (group `10` only, yet omitted), so
|
||||||
|
Query D remains the priority.
|
||||||
|
|
||||||
|
**Result (2026-08-04): the theory is dead.** Group membership does not correlate with
|
||||||
|
`aenderbar` at all:
|
||||||
|
|
||||||
|
| id | Selektion | groupCount | groupIds | `aenderbar` |
|
||||||
|
| --- | --- | --- | --- | --- |
|
||||||
|
| 1064–1069 | *Interessen* | 1 | 83 | **True** |
|
||||||
|
| 1070 | E&P Teamer - allg. Merkmal | 1 | 10 | **False** |
|
||||||
|
| 1292 | Admin | 2 | 91, 10 | **False** |
|
||||||
|
| 1293 | Manager | 2 | 92, 10 | **False** |
|
||||||
|
| 1299 / 1304 / 1377 | Hausleitung SSL / DKS / KHH | 1 | 10 | **False** |
|
||||||
|
| 1459 / 1461 / 1462 | Hausleitung SVS / SHM / AGR | 1 | 10 | **True** |
|
||||||
|
| 1477 / 1478 | Preisrechner, Preisrechner Admin | 1 | 10 | *(not emitted)* |
|
||||||
|
|
||||||
|
`1299`/`1304`/`1377` and `1459`/`1461`/`1462` have **identical** group membership,
|
||||||
|
identical `Status`, identical `System` — and opposite `aenderbar`. The `1292`/`1293`
|
||||||
|
double membership was a coincidence.
|
||||||
|
|
||||||
|
Confirmed as a side effect: `1156` is absent from this result because the inner join
|
||||||
|
found no `Selektionsgruppe` row for it. `<ohne Gruppe>` really does mean "no membership
|
||||||
|
row", as modelled at the top of this document.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Query F — exhaust every remaining link to `Selektionsstamm`
|
||||||
|
|
||||||
|
After D and E, the schema export lists exactly these tables with an FK into
|
||||||
|
`Selektionsstamm`. This counts all of them at once for the rows whose behaviour differs,
|
||||||
|
which is the last thing the database can tell us:
|
||||||
|
|
||||||
|
```sql
|
||||||
|
SELECT s.IDSelektionsstamm, s.Selektion,
|
||||||
|
(SELECT COUNT(*) FROM dbo.Selektionen x WHERE x.IDSelektionsstamm_FS = s.IDSelektionsstamm) AS addressAssignments,
|
||||||
|
(SELECT COUNT(*) FROM dbo.PartnerSelektionenKunde x WHERE x.IDSelektionsstamm_FS = s.IDSelektionsstamm) AS partnerLinks,
|
||||||
|
(SELECT COUNT(*) FROM dbo.LeistungSelektionenKunde x WHERE x.IDSelektionsstamm_FS = s.IDSelektionsstamm) AS serviceLinks,
|
||||||
|
(SELECT COUNT(*) FROM dbo.ReiseleiterSelektionen x WHERE x.IDSelektionsstamm_FS = s.IDSelektionsstamm) AS guideLinks,
|
||||||
|
(SELECT COUNT(*) FROM dbo.ReiseSelektionen x WHERE x.IDSelektionsstamm_FS = s.IDSelektionsstamm) AS travelLinks,
|
||||||
|
(SELECT COUNT(*) FROM dbo.ReisezielSelektionsstamm x WHERE x.IDSelektionsstamm_FS = s.IDSelektionsstamm) AS destinationLinks
|
||||||
|
FROM dbo.Selektionsstamm s
|
||||||
|
WHERE s.IDSelektionsstamm IN (1070,1156,1292,1293,1299,1304,1377,1459,1461,1462,1477,1478,1064)
|
||||||
|
ORDER BY s.IDSelektionsstamm;
|
||||||
|
```
|
||||||
|
|
||||||
|
The decisive comparison is `1377` (`aenderbar="False"`) vs `1462` (`"True"`) vs `1478`
|
||||||
|
(omitted). If all three rows are identical here too, then **no per-selection property in
|
||||||
|
this database distinguishes them**, and the rule is not in the schema at all — go to
|
||||||
|
"Where this leaves the investigation" below.
|
||||||
|
|
||||||
|
**Result (2026-08-04): all link counts are zero** for every row queried, except
|
||||||
|
`travelLinks` on `1070` (11) and `1156` (3) via `ReiseSelektionen` — neither of which
|
||||||
|
correlates with `aenderbar` or with being emitted. Assignment counts don't explain
|
||||||
|
anything either:
|
||||||
|
|
||||||
|
| id | assignments | emitted? | `aenderbar` |
|
||||||
|
| --- | --- | --- | --- |
|
||||||
|
| 1377 Hausleitung KHH | **0** | yes | False |
|
||||||
|
| 1462 Hausleitung AGR | 1 | yes | True |
|
||||||
|
| 1478 Preisrechner Admin | **3** | **no** | — |
|
||||||
|
|
||||||
|
`1377` is published with zero assignments; `1478` has three and is not published. This
|
||||||
|
exhausts every FK path into `Selektionsstamm` in the schema. **Stop querying the
|
||||||
|
database** — the answer is not in it.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Query C — locate the publish gate
|
||||||
|
|
||||||
|
Point (1) means some table or config outside the three core tables decides what gets
|
||||||
|
emitted. Run these in order; the first hit explains everything.
|
||||||
|
|
||||||
|
**C1 — what distinguishes a published group from an unpublished one.** Groups `0`, `10`,
|
||||||
|
`83` are emitted; `91`, `92` are not:
|
||||||
|
|
||||||
|
```sql
|
||||||
|
SELECT IDSelektionsgruppenstamm, Selektionsgruppe, Status, System, Ausgrenzung, Position
|
||||||
|
FROM dbo.Selektionsgruppenstamm
|
||||||
|
ORDER BY Position;
|
||||||
|
```
|
||||||
|
|
||||||
|
If exactly the emitted groups share a `Status`/`System`/`Position` value that `91`/`92`
|
||||||
|
lack, that's the group gate. It still won't explain `1478` (same group as `1462`), but
|
||||||
|
it pins down half the rule — and tells you whether `aenderbar` tracks membership in one
|
||||||
|
of these system groups.
|
||||||
|
|
||||||
|
**C2 — hunt for a published-selection whitelist in the config stores.** This is the
|
||||||
|
leading theory for `1478`: a config value enumerating exposed selection ids that was
|
||||||
|
maintained up to `1462` and never extended. This database does store id lists in
|
||||||
|
delimited string columns (`CRMAktion.IDsAgenturEingrenzung`,
|
||||||
|
`ImportAdressen.ZuweisungSelektionIDs`, `AdresseHistorie.SelektionsIDs`), so the pattern
|
||||||
|
exists. Search for a known-published id:
|
||||||
|
|
||||||
|
```sql
|
||||||
|
SELECT * FROM dbo.Einstellung
|
||||||
|
WHERE Wert LIKE '%1462%' OR Wert LIKE '%1292%'
|
||||||
|
OR Bezeichnung LIKE '%elektion%' OR Beschreibung LIKE '%elektion%';
|
||||||
|
|
||||||
|
SELECT * FROM dbo.ProgrammEinstellung
|
||||||
|
WHERE Wert LIKE '%1462%' OR Wert LIKE '%1292%' OR Variable LIKE '%elektion%';
|
||||||
|
|
||||||
|
SELECT * FROM dbo.ConnectEinstellung
|
||||||
|
WHERE WertString LIKE '%1462%' OR WertString LIKE '%1292%';
|
||||||
|
```
|
||||||
|
|
||||||
|
**C3 — brute-force the whole schema** if C1/C2 come up empty. Find every wide text
|
||||||
|
column that mentions a published selection id:
|
||||||
|
|
||||||
|
```sql
|
||||||
|
DECLARE @needle nvarchar(20) = '1462';
|
||||||
|
DECLARE @sql nvarchar(max) = '';
|
||||||
|
|
||||||
|
SELECT @sql = @sql + 'SELECT ''' + QUOTENAME(t.name) + ''' AS tbl, ''' + QUOTENAME(c.name)
|
||||||
|
+ ''' AS col, COUNT(*) AS hits FROM dbo.' + QUOTENAME(t.name)
|
||||||
|
+ ' WHERE CAST(' + QUOTENAME(c.name) + ' AS nvarchar(max)) LIKE ''%'
|
||||||
|
+ @needle + '%'' HAVING COUNT(*) > 0;' + CHAR(10)
|
||||||
|
FROM sys.tables t
|
||||||
|
JOIN sys.columns c ON c.object_id = t.object_id
|
||||||
|
JOIN sys.types ty ON ty.user_type_id = c.user_type_id
|
||||||
|
WHERE ty.name IN ('nvarchar', 'varchar', 'nchar', 'char')
|
||||||
|
AND (c.max_length = -1 OR c.max_length >= 100)
|
||||||
|
AND t.name NOT LIKE 'Selektion%';
|
||||||
|
|
||||||
|
EXEC sp_executesql @sql; -- read-only; slow, run off-peak
|
||||||
|
```
|
||||||
|
|
||||||
|
**C4 — rule out staleness/caching first, it's free.** `1478` is structurally identical
|
||||||
|
to an emitted row, which is also what a cached catalog looks like. Re-fetch the XML now
|
||||||
|
and confirm the sample postdates the insert:
|
||||||
|
|
||||||
|
```php
|
||||||
|
// bin/console or a scratch script
|
||||||
|
$client->getCrmAttributes($email, $password);
|
||||||
|
```
|
||||||
|
|
||||||
|
If BusPro caches the catalog in-process, an application-pool/service restart on the
|
||||||
|
BusProNet host is the fix, and no schema change is needed.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Portal side: a correct XML is not enough
|
||||||
|
|
||||||
|
`BpnAuthenticator::createOrUpdateLocalUser()` snapshots the roles onto the local `User`
|
||||||
|
entity at login (`setRoles($crmAttributes->roles)` /
|
||||||
|
`setHotelCodes($crmAttributes->hotelCodes)`). Roles are **not** re-read per request. So
|
||||||
|
after fixing BusPro the affected user must **log out and log in again** before
|
||||||
|
`ROLE_GROUPS_ADMIN` takes effect — an active session keeps the stale role set.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Where this leaves the investigation
|
||||||
|
|
||||||
|
**Conclusion as of 2026-08-04, after Queries A–F: the schema search is exhausted.**
|
||||||
|
|
||||||
|
- `1478` and `1462` are identical on every column and every link the schema exposes —
|
||||||
|
same blank `Status`, same `System = 1`, same single membership in group `10`, adjacent
|
||||||
|
positions (76 vs 74), zero links in all five side tables. `1462` is emitted, `1478` is
|
||||||
|
not.
|
||||||
|
- `1377` (`aenderbar="False"`) and `1462` (`"True"`) are identical by the same measure.
|
||||||
|
Opposite flag.
|
||||||
|
- Assignment count is not it either: `1377` is published with zero assignments, `1478`
|
||||||
|
has three and is not published.
|
||||||
|
|
||||||
|
Rows that are indistinguishable in the database behave differently in the response. Every
|
||||||
|
column of the three core tables, every FK path into `Selektionsstamm`, and a
|
||||||
|
whole-schema column-name search have now been checked. So **the publish set and the
|
||||||
|
`aenderbar` flag are not derived from this database** — they live in the BusProNet
|
||||||
|
service layer: its own configuration, or an in-process cache of the catalog.
|
||||||
|
|
||||||
|
Only C2/C3 (a text search of the config stores, then of every wide text column) remain,
|
||||||
|
and they are long shots. Prefer the escalation path below.
|
||||||
|
|
||||||
|
Escalation path, cheapest first:
|
||||||
|
|
||||||
|
1. **Re-fetch and confirm staleness.** Our side does not cache this call — the
|
||||||
|
`xml-sync` cache tag covers the XML *export* sync, and `ApiClient::getCrmAttributes()`
|
||||||
|
has no cache layer — so a fresh login hits BusPro directly. If `1478` is still absent
|
||||||
|
from a response captured after the insert, the staleness is on the BusProNet host and
|
||||||
|
an application-pool/service restart there is the test.
|
||||||
|
2. **The UI experiment.** Create a throwaway selection in the TEAM group *through the
|
||||||
|
BusPro UI*, then diff its rows against `1478` across `Selektionsstamm` /
|
||||||
|
`Selektionsgruppe` / `Selektionen`. If it appears in the XML, the diff names exactly
|
||||||
|
what a manual `INSERT` misses. If it does not, the gate is provably config/cache and
|
||||||
|
not per-row data.
|
||||||
|
3. **Ask the vendor.** "What determines which `Selektionsstamm` entries `SelektionCRM`
|
||||||
|
publishes, given group membership is not sufficient — and what drives `aenderbar`?"
|
||||||
|
Both are one-sentence answers for them and may not be discoverable from the schema at
|
||||||
|
all. Worth bundling into the open BPN thread.
|
||||||
|
|
||||||
|
## Caveats
|
||||||
|
|
||||||
|
- **`aenderbar` has no known source.** No such column exists in any of the 1023 tables;
|
||||||
|
`Selektionsstamm.System` (Query B), the agency whitelist (Query D) and group membership
|
||||||
|
(Query E) are all falsified. Treat it as unmodellable in a `bpn-connect` endpoint until
|
||||||
|
the vendor explains it — if `bpn-connect` must serve this response, the safe move is to
|
||||||
|
keep `SelektionCRM` on the socket API rather than guess, exactly as
|
||||||
|
`live-api-queries.md` recommends for `getMutableData()`.
|
||||||
|
- Groups `91` and `92` are known to exist and are never emitted; what they are is still
|
||||||
|
unexplained (Query C1). Record the answer here when you have it.
|
||||||
|
- **The publish gate is not identified.** Group membership is necessary but not
|
||||||
|
sufficient: `1478` sits in the published TEAM group with an assignment and is still
|
||||||
|
omitted. Query C is the open investigation.
|
||||||
|
- Consequently Query A **over-reports**: it will return `1477`/`1478` (and anything in
|
||||||
|
groups `91`/`92`) that the real XML omits. It reconstructs the shape of the response,
|
||||||
|
not yet its exact membership.
|
||||||
|
- `dbo.Selektionen` has no status column and no exported primary key, so a duplicate
|
||||||
|
assignment row may well be insertable. Check before inserting.
|
||||||
|
- The schema exports carry no PK/index catalog (noted in
|
||||||
|
`../bpn-connect-query-reference.md`); none of the queries here are
|
||||||
|
performance-sensitive, but a `bpn-connect` endpoint built on them would want indexes
|
||||||
|
on `Selektionen.IDAdresse_FS` and `Selektionsgruppe.IDSelektionsstamm_FS` confirmed.
|
||||||
|
- `Adresse` vs. `AdressePerson`: assignments hang off `IDAdresse`, not `IDPerson`.
|
||||||
@@ -0,0 +1,165 @@
|
|||||||
|
# Live socket-API endpoints — direct-MSSQL feasibility & queries
|
||||||
|
|
||||||
|
> **Authority: [`docs/buspro-database-reference.md`](../buspro-database-reference.md).**
|
||||||
|
> Schema semantics live there and win on any conflict. This file is retained for the
|
||||||
|
> per-endpoint migration verdicts and the `frei` discovery SQL.
|
||||||
|
|
||||||
|
This complements `travel-queries.md`. That doc replaced the **XML export** (static
|
||||||
|
catalog). This one covers the **live socket API** methods on
|
||||||
|
`src/BusProNet/ApiClient.php` and classifies how replicable each is by direct MSSQL
|
||||||
|
query in the Go proxy.
|
||||||
|
|
||||||
|
**Verdict in one line:** the *structural* parts replicate cleanly; the *live "free"
|
||||||
|
counts* are computed by BusPro's allocation logic (not a flat column) and should either
|
||||||
|
stay on the socket API or be reproduced with an explicitly-approximated query;
|
||||||
|
`getMutableData()` is pure business-rule logic — keep it on the socket API.
|
||||||
|
|
||||||
|
| Endpoint (type) | Tier | Replicable in SQL? |
|
||||||
|
|---|---|---|
|
||||||
|
| `getProducts()` (`PRODUKTE`) | 1 | ✅ trivial |
|
||||||
|
| `getAgencies()` (`AGENTUREN`) | 1 | ✅ structural (confirm agency filter + address joins) |
|
||||||
|
| `getTravelData()` (`PRODUKTDATEN`) | 1 | ✅ = `travel-queries.md` Query B |
|
||||||
|
| `getAvailabilities()` (`VERFUEGBARKEIT`) | 2 | ⚠ structure yes; `frei` count is computed |
|
||||||
|
| `getAvailabilitiesExtended()` (`VERFUEGBARKEIT2`) | 2 | ⚠ structure yes (we have the extra fields); `frei` computed |
|
||||||
|
| `getHotelAvailability()` (`VERFUEGBARKEITHOTEL`) | 2 | ⚠ `frei` = contingent − active bookings |
|
||||||
|
| `getMutableData()` (`MOEGLICHEAENDERUNGEN`) | 3 | ✋ business rules — keep on socket API |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Tier 1 — structural, replicate as-is
|
||||||
|
|
||||||
|
### `getProducts()` → `Product{id, code, name}`
|
||||||
|
Parser keeps only rows with a non-empty `code` (`ProductsParser`).
|
||||||
|
```sql
|
||||||
|
SELECT IDProdukt AS id, Code AS code, Bezeichnung AS name
|
||||||
|
FROM dbo.Produkt
|
||||||
|
WHERE Code IS NOT NULL AND Code <> ''
|
||||||
|
ORDER BY Bezeichnung;
|
||||||
|
```
|
||||||
|
|
||||||
|
### `getTravelData(idprodukt[, hotelId])` → `Travel`
|
||||||
|
This is the same payload as `travel-queries.md` **Query B** (header + services +
|
||||||
|
pickups + hotels/rooms + tags). The *static* structure is fully covered there. Its
|
||||||
|
embedded live `preis`/`frei` values overlap Tier 2 — source those the same way you
|
||||||
|
decide to handle availability below. No new SQL needed; reuse Query B.
|
||||||
|
|
||||||
|
### `getAgencies()` → `Agency{id, name, code, street, postCode, city, phone}`
|
||||||
|
`name/code` map to `Adresse.SuchName` + a code column; `street/postCode/city` live in
|
||||||
|
`AdresseAnschrift`, `phone` in `AdresseKommunikation` (1-to-N → pick the primary row).
|
||||||
|
Two things to pin with the discovery queries below: (1) **which `Adresse` rows are
|
||||||
|
agencies**, and (2) the exact `AdresseAnschrift`/`AdresseKommunikation` column + primary-row flag.
|
||||||
|
```sql
|
||||||
|
-- skeleton (fill the agency filter + verified column names from discovery):
|
||||||
|
SELECT a.IDAdresse AS id,
|
||||||
|
a.SuchName AS name,
|
||||||
|
a.Code AS code, -- ⚠ confirm code column on Adresse
|
||||||
|
an.Strasse AS street, -- ⚠ from AdresseAnschrift
|
||||||
|
an.Plz AS postCode,
|
||||||
|
an.Ort AS city,
|
||||||
|
ak.Wert AS phone -- ⚠ from AdresseKommunikation (primary tel)
|
||||||
|
FROM dbo.Adresse a
|
||||||
|
LEFT JOIN dbo.AdresseAnschrift an ON an.IDAdresse_FS = a.IDAdresse /* AND an.IsPrimary */
|
||||||
|
LEFT JOIN dbo.AdresseKommunikation ak ON ak.IDAdresse_FS = a.IDAdresse /* AND ak.Art = 'TEL' */
|
||||||
|
WHERE /* a is an agency — see discovery */ 1 = 0;
|
||||||
|
```
|
||||||
|
Discovery:
|
||||||
|
```sql
|
||||||
|
-- (1) how agencies are flagged (inspect the org/role tables):
|
||||||
|
SELECT TOP 20 * FROM dbo.AdresseAgenturOrganisation;
|
||||||
|
SELECT IDArtAgenturOrganisation, * FROM dbo.ArtAgenturOrganisation; -- the agency "types"
|
||||||
|
-- (2) the address + comm column names / primary-row flags:
|
||||||
|
SELECT TOP 5 * FROM dbo.AdresseAnschrift;
|
||||||
|
SELECT TOP 5 * FROM dbo.AdresseKommunikation;
|
||||||
|
SELECT TOP 5 * FROM dbo.Adresse; -- find the 'code' column
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Tier 2 — availability: structure is flat, the **`frei` count is computed**
|
||||||
|
|
||||||
|
The response models (`Availability`, `ExtendedAvailability`, `Room`) carry per-item
|
||||||
|
`status`, `preis`, structural attrs (dates/ages/mandatory/board) **and** `frei`. The
|
||||||
|
first set is a flat read; **`frei` is not stored**.
|
||||||
|
|
||||||
|
**Why `frei` is computed (validated):** `Leistung.Kontingent` is a fixed planning
|
||||||
|
allotment, not the remaining free count — e.g. service `155234` has `Kontingent=2500`
|
||||||
|
but `2945` booking rows (bookings *exceed* the allotment). So:
|
||||||
|
```
|
||||||
|
frei = Kontingent − (active, non-cancelled, non-expired bookings) [± pooled contingent]
|
||||||
|
```
|
||||||
|
with three real complications:
|
||||||
|
- **Cancellations**: `BuchungTNLeistung` has no own status; join up via `IDBuchungTN_FS`
|
||||||
|
→ `BuchungTN` → `Buchung` and exclude Storno (the `BuchungStatus*` flags / Storno date).
|
||||||
|
- **Option expiry**: `BuchungTNLeistung.OptionsDatum` + `Leistung.KontingentVerfallTage`
|
||||||
|
— expired options free their slots back.
|
||||||
|
- **Pooled contingents**: `Leistung.IDLeistung_FS_KontingentAUS` / `KontingentAusPartner`
|
||||||
|
— a service may draw from another service's pool (or a `PartnerKontingent`), so its
|
||||||
|
`frei` depends on a sibling, not just its own bookings.
|
||||||
|
|
||||||
|
> **Recommendation:** keep the *authoritative* `frei` on the socket API
|
||||||
|
> (`getAvailabilities`/`getHotelAvailability`). If you want it in SQL, treat it as a
|
||||||
|
> documented **approximation** and validate row-by-row against the socket API before
|
||||||
|
> trusting it for booking decisions. The structural fields below are safe to serve from SQL.
|
||||||
|
|
||||||
|
### `getAvailabilities()` / `getAvailabilitiesExtended()` — structural part
|
||||||
|
```sql
|
||||||
|
SELECT
|
||||||
|
l.IDLeistung AS serviceId,
|
||||||
|
l.Status AS status,
|
||||||
|
lp.Preis AS price,
|
||||||
|
l.Kontingent AS allotment, -- NOT 'frei' (see calc above)
|
||||||
|
-- extended-only fields (VERFUEGBARKEIT2):
|
||||||
|
l.Termin_VON AS dateFrom, l.Termin_BIS AS dateTo,
|
||||||
|
l.Alter_VON AS ageFrom, l.Alter_BIS AS ageTo,
|
||||||
|
l.Pflichtmerkmal AS mandatory
|
||||||
|
FROM dbo.ReiseLeistung rl
|
||||||
|
JOIN dbo.Leistung l ON l.IDLeistung = rl.IDLeistung_FS
|
||||||
|
LEFT JOIN dbo.LeistungPreis lp ON lp.IDLeistung_FS = l.IDLeistung AND lp.IDArtPreisSchema_FS = 1
|
||||||
|
WHERE rl.IDReise_FS = @DateId
|
||||||
|
ORDER BY l.Art, l.Unterart;
|
||||||
|
-- travel-level 'buchungstatusmoeglich' / 'status' come from the Reise + the allowed
|
||||||
|
-- ArtBuchungsStatus set; the extended 'uhrzeit_von'/'hinweis' come from the pickup
|
||||||
|
-- time plan (ZustiegZeitplan) and a Leistung text — see travel-queries.md B2/B2b.
|
||||||
|
```
|
||||||
|
The live `frei` per `serviceId` = the calc above (see recommendation).
|
||||||
|
|
||||||
|
### `getHotelAvailability(idreise, idpartner, terminbis)` → `Room{frei, status, preis, …}`
|
||||||
|
Rooms/price/`status` are the `travel-queries.md` **B3** chain;
|
||||||
|
`status` = `PartnerKontingent.BuchungsStatus` (`''`/`S`/`A`). `frei` = `PartnerKontingent.Anzahl`
|
||||||
|
**minus active hotel bookings** for that `(IDAdresse, IDZimmer, date-span)` — same
|
||||||
|
cancellation/expiry caveats as above.
|
||||||
|
|
||||||
|
### Discovery — quantify the `frei` calc against the socket API
|
||||||
|
```sql
|
||||||
|
-- active (non-storno) booking rows for a service, with option dates:
|
||||||
|
SELECT btl.IDLeistung_FS, COUNT(*) AS rows_total,
|
||||||
|
SUM(CASE WHEN btl.OptionsDatum IS NULL OR btl.OptionsDatum >= GETDATE() THEN 1 ELSE 0 END) AS rows_live
|
||||||
|
FROM dbo.BuchungTNLeistung btl
|
||||||
|
JOIN dbo.BuchungTN bt ON bt.IDBuchungTN = btl.IDBuchungTN_FS
|
||||||
|
JOIN dbo.Buchung b ON b.IDBuchung = bt.IDBuchung_FS -- ⚠ confirm FK name
|
||||||
|
WHERE btl.IDLeistung_FS = @ServiceId
|
||||||
|
/* AND b.<storno flag> = 0 */ -- ⚠ confirm Storno column
|
||||||
|
GROUP BY btl.IDLeistung_FS;
|
||||||
|
-- then compare Leistung.Kontingent − rows_live vs the socket-API 'frei' for the same service.
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Tier 3 — `getMutableData()` — keep on the socket API
|
||||||
|
|
||||||
|
Returns per-aspect `möglich` (bool) + `möglichbiszum` (deadline) for: participant
|
||||||
|
count, transportation, pickup, accommodation, additional services, participant data.
|
||||||
|
These are **derived from booking rules / change-cutoff config / departure timing**
|
||||||
|
(not a flat table). Reproducing them in SQL would mean re-implementing BusPro's
|
||||||
|
change-deadline logic and risks silent divergence. Recommendation: leave this on the
|
||||||
|
socket API; don't migrate it.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Summary for the Go proxy
|
||||||
|
- **Migrate now (SQL):** `getProducts`, `getAgencies` (after the agency-filter discovery),
|
||||||
|
`getTravelData` (reuse Query B), and the **structural** fields of the two availability
|
||||||
|
endpoints.
|
||||||
|
- **Keep computed:** the live `frei` counts — socket API, or an explicitly-validated
|
||||||
|
approximation.
|
||||||
|
- **Keep on socket:** `getMutableData`.
|
||||||
@@ -0,0 +1,247 @@
|
|||||||
|
# Schema refresh & Zustieg-pricing verification queries
|
||||||
|
|
||||||
|
> **Superseded by [`docs/buspro-database-reference.md`](../buspro-database-reference.md) §12**,
|
||||||
|
> which carries the refresh queries and the verification log. Retained only for the
|
||||||
|
> 2026-08-04 run detail; safe to delete once that is no longer of interest.
|
||||||
|
|
||||||
|
Read-only queries to (a) check whether the June schema dump still matches
|
||||||
|
production after a BusPro update, (b) regenerate it if not, and (c) resolve the
|
||||||
|
open `Abfahrtsortzuschlag (Rückfahrt)` question from the database side.
|
||||||
|
|
||||||
|
Current dump: `BusPronet_20260601-1517.csv` (columns),
|
||||||
|
`BusPronet_20260601-1518.csv` (foreign keys), exported 2026-06-01.
|
||||||
|
|
||||||
|
**All queries are `SELECT`-only.** Run in order — Query 1 decides whether 2–4 are
|
||||||
|
needed at all.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 1. Drift check — run this first
|
||||||
|
|
||||||
|
Cheapest, highest signal. If it returns nothing, the June dump is still accurate
|
||||||
|
and the re-export can be skipped.
|
||||||
|
|
||||||
|
```sql
|
||||||
|
SELECT s.name AS schema_name, o.name AS object_name, o.type_desc,
|
||||||
|
o.create_date, o.modify_date
|
||||||
|
FROM sys.objects o
|
||||||
|
JOIN sys.schemas s ON s.schema_id = o.schema_id
|
||||||
|
WHERE o.is_ms_shipped = 0
|
||||||
|
AND (o.create_date > '2026-06-01' OR o.modify_date > '2026-06-01')
|
||||||
|
ORDER BY o.modify_date DESC;
|
||||||
|
```
|
||||||
|
|
||||||
|
Note: `modify_date` moves on metadata changes, so a long list is expected after a
|
||||||
|
version upgrade. What matters is whether anything under `Zustieg*`, `Leistung*`,
|
||||||
|
`Buchung*` appears.
|
||||||
|
|
||||||
|
**Result 2026-08-04.** Every object reports `create_date` **2026-06-03** — the
|
||||||
|
database was restored/rebuilt that day, so `create_date` is a restore artifact and
|
||||||
|
the `> '2026-06-01'` filter matches everything. Use `modify_date` after the restore
|
||||||
|
instead. Only two genuine clusters exist:
|
||||||
|
|
||||||
|
- **2026-06-11** — six new tables, all absent from `…-1517.csv`: `Reichweite`,
|
||||||
|
`ReichweiteZeitraum`, `ReichweiteZeitraumVonBis`, `ReichweiteRestFarbe`,
|
||||||
|
`LadungTankungBetriebshof`, `ConnectViafintechSlip`.
|
||||||
|
- **2026-07-02** — modified: `Tachostand`, `GutscheinAktion`,
|
||||||
|
`AdressePersonalZusatz`, `BlockPlanung`, `Block`, `LeistungZusatz`,
|
||||||
|
`ConnectViafintechSlip`, `TourPlanung`.
|
||||||
|
|
||||||
|
**Nothing under `Zustieg*`, `ZustiegPreis`, `ArtZustiegPreis`,
|
||||||
|
`LeistungBefoerderung` or `BuchungTNZuschlag` changed after the restore.** The June
|
||||||
|
dump is accurate for the booking and boarding areas; the only staleness is the six
|
||||||
|
fleet/payment tables above. For future runs, filter on `o.modify_date > '2026-06-03'`
|
||||||
|
to skip the restore baseline.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 2. Columns — regenerates `…-1517.csv`
|
||||||
|
|
||||||
|
Column order and names match the existing header exactly, so the output is a
|
||||||
|
drop-in replacement. Export semicolon-separated with quoted values, same settings
|
||||||
|
as the June file.
|
||||||
|
|
||||||
|
```sql
|
||||||
|
SELECT s.name AS schema_name,
|
||||||
|
t.name AS table_name,
|
||||||
|
c.name AS column_name,
|
||||||
|
ty.name AS data_type,
|
||||||
|
c.max_length,
|
||||||
|
c.precision,
|
||||||
|
c.scale,
|
||||||
|
c.is_nullable,
|
||||||
|
c.is_identity,
|
||||||
|
dc.definition AS default_definition
|
||||||
|
FROM sys.tables t
|
||||||
|
JOIN sys.schemas s ON s.schema_id = t.schema_id
|
||||||
|
JOIN sys.columns c ON c.object_id = t.object_id
|
||||||
|
JOIN sys.types ty ON ty.user_type_id = c.user_type_id
|
||||||
|
LEFT JOIN sys.default_constraints dc ON dc.object_id = c.default_object_id
|
||||||
|
ORDER BY t.name, c.column_id;
|
||||||
|
```
|
||||||
|
|
||||||
|
## 3. Foreign keys — regenerates `…-1518.csv`
|
||||||
|
|
||||||
|
```sql
|
||||||
|
SELECT fk.name AS foreign_key_name,
|
||||||
|
cs.name AS child_schema, ct.name AS child_table, cc.name AS child_column,
|
||||||
|
ps.name AS parent_schema, pt.name AS parent_table, pc.name AS parent_column
|
||||||
|
FROM sys.foreign_keys fk
|
||||||
|
JOIN sys.foreign_key_columns fkc ON fkc.constraint_object_id = fk.object_id
|
||||||
|
JOIN sys.tables ct ON ct.object_id = fkc.parent_object_id
|
||||||
|
JOIN sys.schemas cs ON cs.schema_id = ct.schema_id
|
||||||
|
JOIN sys.columns cc ON cc.object_id = fkc.parent_object_id
|
||||||
|
AND cc.column_id = fkc.parent_column_id
|
||||||
|
JOIN sys.tables pt ON pt.object_id = fkc.referenced_object_id
|
||||||
|
JOIN sys.schemas ps ON ps.schema_id = pt.schema_id
|
||||||
|
JOIN sys.columns pc ON pc.object_id = fkc.referenced_object_id
|
||||||
|
AND pc.column_id = fkc.referenced_column_id
|
||||||
|
ORDER BY ct.name, fk.name, fkc.constraint_column_id;
|
||||||
|
```
|
||||||
|
|
||||||
|
## 4. Primary keys & indexes — the documented gap
|
||||||
|
|
||||||
|
`bpn-connect-query-reference.md` records that PK/index data was expected but
|
||||||
|
missing, and that identity flags are not a reliable PK substitute here. This closes
|
||||||
|
it. Suggested filename: `BusPronet_<date>-pk-index.csv`.
|
||||||
|
|
||||||
|
```sql
|
||||||
|
SELECT s.name AS schema_name,
|
||||||
|
t.name AS table_name,
|
||||||
|
i.name AS index_name,
|
||||||
|
i.type_desc,
|
||||||
|
i.is_primary_key,
|
||||||
|
i.is_unique,
|
||||||
|
i.is_unique_constraint,
|
||||||
|
ic.key_ordinal,
|
||||||
|
c.name AS column_name,
|
||||||
|
ic.is_included_column,
|
||||||
|
ic.is_descending_key
|
||||||
|
FROM sys.indexes i
|
||||||
|
JOIN sys.tables t ON t.object_id = i.object_id
|
||||||
|
JOIN sys.schemas s ON s.schema_id = t.schema_id
|
||||||
|
JOIN sys.index_columns ic ON ic.object_id = i.object_id AND ic.index_id = i.index_id
|
||||||
|
JOIN sys.columns c ON c.object_id = ic.object_id AND c.column_id = ic.column_id
|
||||||
|
WHERE i.type > 0 -- exclude heaps
|
||||||
|
ORDER BY t.name, i.is_primary_key DESC, i.name, ic.key_ordinal;
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 5. Boarding-price types — `ArtZustiegPreis`
|
||||||
|
|
||||||
|
**Answered 2026-08-04:** this is a **tariff-scheme** lookup, *not* a direction
|
||||||
|
lookup. Active schemes are 36 `Woche26/27`, 37 `WE26/27`, 38 `Event26/27`,
|
||||||
|
39 `SER26/27` (plus legacy A–T at `Status = 'L'`). There is no Hinfahrt/Rückfahrt
|
||||||
|
concept in this table.
|
||||||
|
|
||||||
|
```sql
|
||||||
|
SELECT IDArtZustiegPreis, Code, Kurztext, Langtext, Status, Hierarchie
|
||||||
|
FROM dbo.ArtZustiegPreis
|
||||||
|
ORDER BY Hierarchie, IDArtZustiegPreis;
|
||||||
|
```
|
||||||
|
|
||||||
|
## 6. Configured prices for boarding point 18
|
||||||
|
|
||||||
|
```sql
|
||||||
|
SELECT zp.IDZustiegPreis,
|
||||||
|
zp.IDZustieg_FS,
|
||||||
|
z.Zustiegcode, z.Ort, z.Plz,
|
||||||
|
zp.IDArtZustiegPreis_FS,
|
||||||
|
ap.Code AS PreisArtCode, ap.Kurztext AS PreisArt,
|
||||||
|
zp.Preis, zp.PreisProvisionPflichtig,
|
||||||
|
zp.Sockelbetrag, zp.SockelbetragProvisionPflichtig
|
||||||
|
FROM dbo.ZustiegPreis zp
|
||||||
|
JOIN dbo.Zustieg z ON z.IDZustieg = zp.IDZustieg_FS
|
||||||
|
LEFT JOIN dbo.ArtZustiegPreis ap ON ap.IDArtZustiegPreis = zp.IDArtZustiegPreis_FS
|
||||||
|
WHERE zp.IDZustieg_FS = 18
|
||||||
|
ORDER BY zp.IDArtZustiegPreis_FS;
|
||||||
|
```
|
||||||
|
|
||||||
|
**Answered 2026-08-04:** three rows for point 18 (`ESS-Route`, Essen), one per
|
||||||
|
active tariff scheme — 36 → **17,90**, 37 → 12,90, 38 → 19,90. Prices are keyed by
|
||||||
|
(point, tariff scheme), **not** by direction. The export's
|
||||||
|
`<zustiege_rueck preis="17,90">` is therefore the same row surfaced through the
|
||||||
|
return service, not a separately configured return price.
|
||||||
|
|
||||||
|
## 7. How the two bus services resolve their boarding price — the mechanism
|
||||||
|
|
||||||
|
`LeistungBefoerderung` carries **`IDArtZustiegPreis_FS`** and
|
||||||
|
**`Richtung_Hin_Rueck`**, so each transport service selects which price type
|
||||||
|
applies. This query shows what outbound service 194779 and return service 194776
|
||||||
|
are configured to use.
|
||||||
|
|
||||||
|
```sql
|
||||||
|
SELECT l.IDLeistung, l.Bezeichnung, l.Art, l.Unterart,
|
||||||
|
lb.Richtung_Hin_Rueck,
|
||||||
|
lb.IDArtZustiegPreis_FS,
|
||||||
|
ap.Code AS PreisArtCode, ap.Kurztext AS PreisArt,
|
||||||
|
lb.IDArtZustiegZeitplan_FS,
|
||||||
|
lb.ZustiegeGesperrt,
|
||||||
|
lb.IDZustieg_FS_Basisstelle,
|
||||||
|
lb.ZustiegIDs
|
||||||
|
FROM dbo.LeistungBefoerderung lb
|
||||||
|
JOIN dbo.Leistung l ON l.IDLeistung = lb.IDLeistung_FS
|
||||||
|
LEFT JOIN dbo.ArtZustiegPreis ap ON ap.IDArtZustiegPreis = lb.IDArtZustiegPreis_FS
|
||||||
|
WHERE l.IDLeistung IN (194779, 194776);
|
||||||
|
```
|
||||||
|
|
||||||
|
**Answered 2026-08-04 — configuration is symmetric, config cause excluded:**
|
||||||
|
|
||||||
|
| Leistung | Richtung | `IDArtZustiegPreis_FS` | `ZustiegeGesperrt` | `ZustiegIDs` |
|
||||||
|
|---|---|---|---|---|
|
||||||
|
| 194779 Bus-Hinfahrt | H | 36 (Woche26/27) | 0 | 3,4,18,86,320,470,473 |
|
||||||
|
| 194776 Bus-Rückfahrt | R | 36 (Woche26/27) | 0 | 3,4,18,86,320,470,473 |
|
||||||
|
|
||||||
|
Both legs resolve to the same 17,90 and both have point 18 enabled. The differing
|
||||||
|
BusPro behaviour is therefore not explained by product configuration.
|
||||||
|
|
||||||
|
## 8. Surcharge types — `ArtZuschlag`
|
||||||
|
|
||||||
|
**Answered 2026-08-04:** a discounts/fees lookup (Zwei-Wochen-Rabatt,
|
||||||
|
Kinderermäßigung, Bearbeitungsgebühr, Preiskorrektur, …). No direction concept and
|
||||||
|
**no `Abfahrtsortzuschlag` entry** — so the `SON`/`TRA` positions in the booking
|
||||||
|
response are computed transport surcharges, not `BuchungTNZuschlag` rows. Query 9
|
||||||
|
below is aimed at the wrong table and can be skipped.
|
||||||
|
|
||||||
|
```sql
|
||||||
|
SELECT IDArtZuschlag, Code, Kurztext, Langtext, Status, Hierarchie
|
||||||
|
FROM dbo.ArtZuschlag
|
||||||
|
ORDER BY Hierarchie, IDArtZuschlag;
|
||||||
|
```
|
||||||
|
|
||||||
|
## 9. Booked surcharge rows for an affected booking
|
||||||
|
|
||||||
|
The decisive one *if* a completed booking exhibiting the fault is available: does
|
||||||
|
the working booking persist two `BuchungTNZuschlag` rows and the failing one only
|
||||||
|
one?
|
||||||
|
|
||||||
|
```sql
|
||||||
|
SELECT b.Vorgang,
|
||||||
|
tn.IDBuchungTN,
|
||||||
|
z.IDBuchungTNZuschlag,
|
||||||
|
z.BZText, z.Text,
|
||||||
|
z.Art,
|
||||||
|
z.IDZustieg_FS,
|
||||||
|
az.Code AS ZuschlagArtCode, az.Kurztext AS ZuschlagArt,
|
||||||
|
z.BZPreisMitProvision, z.BZPreisOhneProvision
|
||||||
|
FROM dbo.BuchungTNZuschlag z
|
||||||
|
JOIN dbo.BuchungTN tn ON tn.IDBuchungTN = z.IDBuchungTN_FS
|
||||||
|
JOIN dbo.Buchung b ON b.IDBuchung = tn.IDBuchung_FS
|
||||||
|
LEFT JOIN dbo.ArtZuschlag az ON az.IDArtZuschlag = z.IDArtZuschlag_FS
|
||||||
|
WHERE b.Vorgang IN ('<Vorgang-1>', '<Vorgang-2>')
|
||||||
|
ORDER BY b.Vorgang, tn.IDBuchungTN, z.IDBuchungTNZuschlag;
|
||||||
|
```
|
||||||
|
|
||||||
|
**Caveat:** both captured cases were `<buchungsart>Anfrage</buchungsart>` inquiries,
|
||||||
|
and our flow only commits at step 4 — so these rows may not exist for them. Use the
|
||||||
|
`Vorgang` of an actually completed booking that showed the short total. If none
|
||||||
|
exists, skip this query; queries 5–7 carry the argument on their own.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## What to send back
|
||||||
|
|
||||||
|
Query 1's result, plus 5, 6, 7 and 8 as plain result sets — those four are small and
|
||||||
|
answer the pricing question directly. Queries 2–4 only if query 1 shows drift, as
|
||||||
|
CSV files replacing the ones in this directory.
|
||||||
@@ -0,0 +1,305 @@
|
|||||||
|
# Travel catalog — direct MSSQL queries (to replace the XML export)
|
||||||
|
|
||||||
|
> **Authority: [`docs/buspro-database-reference.md`](../buspro-database-reference.md).**
|
||||||
|
> Schema semantics, conventions and confidence marks live there and win on any conflict.
|
||||||
|
> This file is retained as a **query cookbook** — it holds worked SQL (included-services
|
||||||
|
> A2a/A2b, the full room-pricing chain B3) not reproduced in the reference.
|
||||||
|
|
||||||
|
Purpose: reproduce, straight from the BusPro MSSQL tables, the data the Symfony app
|
||||||
|
currently parses from the `Ziel_*.xml` exports, so the Go proxy can serve it without
|
||||||
|
the SFTP/XML round-trip. Two read paths:
|
||||||
|
|
||||||
|
- **Query A — travel list:** every bookable departure + product + dates (+ hotels,
|
||||||
|
+ a minimal bookable-services list).
|
||||||
|
- **Query B — detail:** everything for one selected `(date, hotel)` combination.
|
||||||
|
|
||||||
|
Validated against the live DB using the sample `var/xmlexport/Ziel_1121.xml`
|
||||||
|
(Produkt `1121`, departure `Reise.IDReise=12665`, hotel `Adresse.IDAdresse=224923`,
|
||||||
|
room-type `Zimmerart 1413`, pickup `Zustieg 494`). Columns verified in
|
||||||
|
`docs/buspronet-schema/*.csv`. Header, services, pickups, hotels, room pricing,
|
||||||
|
availability and tags are all confirmed against live data; the "included services"
|
||||||
|
list for Query A (§A2) is defined as price-`0.00` services + the 10 hardcoded
|
||||||
|
"Leistungen" selection groups (ids baked in). Nothing left to resolve.
|
||||||
|
|
||||||
|
## The naming trap (read first)
|
||||||
|
|
||||||
|
The XML export **renames** the core entities — do not map by name:
|
||||||
|
|
||||||
|
| XML term | Real table | Notes |
|
||||||
|
|---|---|---|
|
||||||
|
| `<reise idbuspro=1121>` | **`Produkt`** | the travel *product*: `IDProdukt`, `Code`, `Bezeichnung` |
|
||||||
|
| `<termin idprodukt=1121 idbuspro=12665>` | **`Reise`** | the **dated departure**: `IDReise=12665`, `IDProdukt_FS=1121`, `Code`, `TerminVon/Bis`, `ReiseArt`, `Status`, `StornoDatum` |
|
||||||
|
| DB `Termin` table | — | **ignore**: generic appointments (odometer/repairs) |
|
||||||
|
| `<leistung>` (lei_befoerderung / lei_sonstiges) | `ReiseLeistung → Leistung` | `Leistung.Art` = `BEF` / `SON`; price via `LeistungPreis` |
|
||||||
|
| `<hotel idbuspro=224923>` + rooms | `ReisePartner` (+ `Partner*` subsystem) | **not** `ReiseLeistung`; keyed by the hotel `Adresse` |
|
||||||
|
| `<zustieg>` | `LeistungBefoerderung.ZustiegIDs` → `Zustieg` (+ `ZustiegZeitplan` for the time) | |
|
||||||
|
| `<selektion>` / `<selektiongruppe>` | `ReiseSelektionen → Selektionsstamm` (+ `Selektionsgruppe → Selektionsgruppenstamm`) | |
|
||||||
|
|
||||||
|
`Produkt 1—N Reise`. **`Reise.IDReise` is the "date id"** and the anchor for all
|
||||||
|
per-departure data.
|
||||||
|
|
||||||
|
**Two distinct status axes** — don't conflate them:
|
||||||
|
1. **Departure lifecycle** — `Reise.Status` (`nvarchar(2)`), observed `''` ≈ 9767,
|
||||||
|
`S` ≈ 945, `L` ≈ 845. Confirmed against the live DB:
|
||||||
|
- `''` = active/bookable.
|
||||||
|
- `S` = **Storno** (cancelled): every `S` row has `StornoDatum` set.
|
||||||
|
- `L` = **template / future master** (not a real sellable departure): every `L`
|
||||||
|
row has `StornoDatum NULL`, far-future `TerminVon` (2029–2035) and template-style
|
||||||
|
`Code`s (`MRAGRMP`, no date suffix). `Leistung.Status` mirrors this (`''` = 196 504,
|
||||||
|
`L` = 1 672 — the leistungen attached to those template departures).
|
||||||
|
2. **Availability / booking status** — booking-state codes, **not** `Leistung.Status`
|
||||||
|
(which only holds `''`/`L`). Canonical dictionary = **`dbo.ArtBuchungsStatus`**
|
||||||
|
(`Code`), confirmed values:
|
||||||
|
|
||||||
|
| Code | Kurztext | meaning |
|
||||||
|
|---|---|---|
|
||||||
|
| `F` | Fest | firm/final booking (available) |
|
||||||
|
| `O` | Option | held option |
|
||||||
|
| `A` | Anfrage | on request / inquiry-only (groups-inquiry path) |
|
||||||
|
| `W` | Warteliste | waitlist |
|
||||||
|
| `S` | Storno | cancelled |
|
||||||
|
| `U` | Umbuchung | rebooking |
|
||||||
|
|
||||||
|
The **working column** for hotel availability is **`PartnerKontingent.BuchungsStatus`**
|
||||||
|
(`nvarchar(2)`) — confirmed to carry these: observed `''` ≈ 19 664 (free/Fest),
|
||||||
|
`S` ≈ 12 215 (stop), `A` ≈ 2 060 (on request). So per room/date: `''` = bookable,
|
||||||
|
`S` = not bookable, `A` = inquiry-only. (The same codes also appear via
|
||||||
|
`…IDArtBuchungsstatus_FS` on individual bookings such as `ZusatzZimmer`.) Transport
|
||||||
|
`<status_hin>`/`<status_rueck>` is not in `Leistung.Status`; treat it as derived from
|
||||||
|
the transport `Kontingent` count.
|
||||||
|
|
||||||
|
Bookable filter (departure-level): `Reise.Status = '' AND Reise.StornoDatum IS NULL`
|
||||||
|
(excludes both `S` Storno and `L` templates), then apply `PartnerKontingent.BuchungsStatus`
|
||||||
|
per room/date (exclude `S`, treat `A` as inquiry-only).
|
||||||
|
|
||||||
|
Note the XML repeats `lei_sonstiges` under each hotel; in the DB the services exist
|
||||||
|
**once** on the departure (`ReiseLeistung`).
|
||||||
|
|
||||||
|
Conventions: ids `bigint`→`int64`; prices `decimal(18,2)`; `_FS` = foreign key (many
|
||||||
|
soft/unenforced — join defensively); bracket non-ASCII columns (`[Reisebüro]`).
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Query A — travel list
|
||||||
|
|
||||||
|
### A1. Departures + product + dates (header)
|
||||||
|
```sql
|
||||||
|
SELECT
|
||||||
|
p.IDProdukt AS ProductId, p.Code AS ProductCode, p.Bezeichnung AS ProductLabel,
|
||||||
|
r.IDReise AS DateId, r.Code AS DateCode,
|
||||||
|
r.ReiseArt AS TravelType, -- XML reiseart, e.g. 'F'
|
||||||
|
r.Bezeichnung AS DateLabel,
|
||||||
|
r.TerminVon AS DateFrom, r.TerminBis AS DateTo
|
||||||
|
FROM dbo.Reise AS r
|
||||||
|
JOIN dbo.Produkt AS p ON p.IDProdukt = r.IDProdukt_FS
|
||||||
|
WHERE r.Status = '' AND r.StornoDatum IS NULL -- bookable (confirm status codes)
|
||||||
|
ORDER BY r.TerminVon, p.Code;
|
||||||
|
```
|
||||||
|
Customer description (XML `<text>`) = `dbo.ReiseText.ExternText` (`IDReise_FS`) — join if wanted.
|
||||||
|
|
||||||
|
### A2. Included-services list per departure
|
||||||
|
"Minimum services" = the **included** services (no surcharge), from two sources that
|
||||||
|
get merged into one plain list per departure.
|
||||||
|
|
||||||
|
**A2a — included `Leistung`s (sales price = 0.00).** Priced services are optional
|
||||||
|
add-ons; the package-included ones have a `0.00` sales price (schema 1).
|
||||||
|
```sql
|
||||||
|
SELECT
|
||||||
|
rl.IDReise_FS AS DateId,
|
||||||
|
l.IDLeistung AS ServiceId,
|
||||||
|
l.Art AS Type, -- 'BEF' (transport) | 'SON' (other)
|
||||||
|
l.Unterart AS SubType, -- BUS/PKW/SPA/VER/SON/LVS/...
|
||||||
|
l.Bezeichnung AS Label
|
||||||
|
FROM dbo.ReiseLeistung rl
|
||||||
|
JOIN dbo.Leistung l ON l.IDLeistung = rl.IDLeistung_FS
|
||||||
|
JOIN dbo.LeistungPreis lp ON lp.IDLeistung_FS = l.IDLeistung
|
||||||
|
AND lp.IDArtPreisSchema_FS = 1 -- standard sales price (confirmed)
|
||||||
|
WHERE rl.IDReise_FS IN (@DateIds)
|
||||||
|
AND lp.Preis = 0.00 -- included = no surcharge
|
||||||
|
ORDER BY rl.IDReise_FS, l.Art, l.Unterart;
|
||||||
|
```
|
||||||
|
> Note: a `LEFT JOIN` would also surface services with **no** price row (NULL). Those
|
||||||
|
> are *not* the same as priced-at-zero — keep the inner join so "included" means an
|
||||||
|
> explicit `0.00`. (If BusPro models some included items as price-less rows, widen to
|
||||||
|
> `lp.Preis = 0.00 OR lp.IDLeistungPreis IS NULL` — confirm with the discovery query.)
|
||||||
|
|
||||||
|
**A2b — "Leistungen…" selection groups (plain list).** The catalog also lists included
|
||||||
|
services as selection tags under the "Leistungen" groups. Filter by a **hardcoded list
|
||||||
|
of `Selektionsgruppenstamm` ids** (configured in the proxy) rather than a label match —
|
||||||
|
the labels can be renamed, the ids are stable. Same join as B4; emit `Selektion` as the
|
||||||
|
plain text item.
|
||||||
|
```sql
|
||||||
|
SELECT rs.IDReise_FS AS DateId,
|
||||||
|
gs.IDSelektionsgruppenstamm AS GroupId,
|
||||||
|
gs.Selektionsgruppe AS GroupLabel, -- e.g. 'Leistungen inklusive'
|
||||||
|
s.Selektion AS Item
|
||||||
|
FROM dbo.ReiseSelektionen rs
|
||||||
|
JOIN dbo.Selektionsstamm s ON s.IDSelektionsstamm = rs.IDSelektionsstamm_FS
|
||||||
|
JOIN dbo.Selektionsgruppe sg ON sg.IDSelektionsstamm_FS = s.IDSelektionsstamm
|
||||||
|
JOIN dbo.Selektionsgruppenstamm gs ON gs.IDSelektionsgruppenstamm = sg.IDSelektionsgruppenstamm_FS
|
||||||
|
WHERE rs.IDReise_FS IN (@DateIds)
|
||||||
|
AND gs.IDSelektionsgruppenstamm IN (70, 89, 87, 88, 86, 7, 8, 90, 85, 71)
|
||||||
|
ORDER BY rs.IDReise_FS, gs.Position, sg.Position;
|
||||||
|
```
|
||||||
|
> The "Leistungen" `Selektionsgruppenstamm` ids (captured from the live DB — hardcode in
|
||||||
|
> the proxy; re-check if groups are added/renamed):
|
||||||
|
>
|
||||||
|
> | id | group | id | group |
|
||||||
|
> |---|---|---|---|
|
||||||
|
> | 70 | Leistungen | 86 | Leistungen Programm |
|
||||||
|
> | 89 | Leistungen Events | 7 | Leistungen Skipass |
|
||||||
|
> | 87 | Leistungen Kurse | 8 | Leistungen Sonstige |
|
||||||
|
> | 88 | Leistungen Personal | 90 | Leistungen Transport |
|
||||||
|
> | 85 | Leistungen Übernachtung | 71 | Leistungen Verpflegung |
|
||||||
|
> `LeistungPreis` has one row per `(Leistung, IDArtPreisSchema_FS)`; schema `1` is the
|
||||||
|
> standard sales price and reproduced the XML service prices exactly (13.90, 50.00, …).
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Query B — detail for one `(@DateId [, @HotelId])`
|
||||||
|
|
||||||
|
Run a header query + one query per child collection; assemble in Go.
|
||||||
|
|
||||||
|
### B1. Header — A1 with `WHERE r.IDReise = @DateId` (+ `ReiseText.ExternText`).
|
||||||
|
|
||||||
|
### B2. Services (transport + other, with direction & pickups) — **confirmed**
|
||||||
|
```sql
|
||||||
|
SELECT
|
||||||
|
l.IDLeistung AS ServiceId,
|
||||||
|
l.Art AS Type, -- BEF | SON
|
||||||
|
l.Unterart AS SubType,
|
||||||
|
l.Bezeichnung AS Label,
|
||||||
|
l.Pflichtmerkmal AS Mandatory,
|
||||||
|
l.Kontingent AS Available,
|
||||||
|
l.Alter_VON AS AgeFrom, l.Alter_BIS AS AgeTo,
|
||||||
|
l.Termin_VON AS DateFrom, l.Termin_BIS AS DateTo,
|
||||||
|
lb.Richtung_Hin_Rueck AS Direction, -- 'H' | 'R' (transport only)
|
||||||
|
lb.ZustiegIDs AS PickupIds, -- delimited list of dbo.Zustieg ids
|
||||||
|
lb.IDArtZustiegZeitplan_FS AS PickupTimePlanId,
|
||||||
|
lp.Preis AS Price
|
||||||
|
FROM dbo.ReiseLeistung rl
|
||||||
|
JOIN dbo.Leistung l ON l.IDLeistung = rl.IDLeistung_FS
|
||||||
|
LEFT JOIN dbo.LeistungBefoerderung lb ON lb.IDLeistung_FS = l.IDLeistung
|
||||||
|
LEFT JOIN dbo.LeistungPreis lp ON lp.IDLeistung_FS = l.IDLeistung
|
||||||
|
AND lp.IDArtPreisSchema_FS = 1
|
||||||
|
WHERE rl.IDReise_FS = @DateId
|
||||||
|
ORDER BY l.Art, l.Unterart, l.Bezeichnung;
|
||||||
|
```
|
||||||
|
`LeistungBefoerderung` present ⇒ transport (`lei_befoerderung`), else `lei_sonstiges`.
|
||||||
|
English texts (`<fremdsprache>`) = `dbo.LeistungText.ExternText` (validate).
|
||||||
|
|
||||||
|
### B2b. Pickup detail (resolve the `ZustiegIDs` list + time) — **confirmed**
|
||||||
|
For each id parsed from `lb.ZustiegIDs`:
|
||||||
|
```sql
|
||||||
|
SELECT z.IDZustieg AS PickupId, z.Zustiegcode AS Code,
|
||||||
|
z.Plz AS PostalCode, z.Ort AS City, z.Strasse AS Street,
|
||||||
|
CONVERT(time, zp.Uhrzeit) AS PickupTime
|
||||||
|
FROM dbo.Zustieg z
|
||||||
|
LEFT JOIN dbo.ZustiegZeitplan zp
|
||||||
|
ON zp.IDZustieg_FS = z.IDZustieg
|
||||||
|
AND zp.IDArtZustiegZeitplan_FS = @PickupTimePlanId -- from B2 (0 ⇒ no time)
|
||||||
|
WHERE z.IDZustieg = @PickupId;
|
||||||
|
```
|
||||||
|
Only the **time-of-day** of `Uhrzeit` is meaningful (the date part is a placeholder).
|
||||||
|
Verified: zustieg `494`, plan `2546` → `05:15`.
|
||||||
|
|
||||||
|
### B3. Hotels + rooms + board — **Partner subsystem**
|
||||||
|
The XML `<hotel idbuspro=224923>` is a hotel **`Adresse.IDAdresse`** (224923 =
|
||||||
|
"NEU Sportclub Waldschlössli – Gruppen 2"), **not** a `ReisePartner`. Hotels are
|
||||||
|
assigned at the **product** level via the join table `PartnerProdukt
|
||||||
|
(IDProdukt_FS, IDAdresse_FS)` — that's why a departure (`IDReise`) has no `ReisePartner`
|
||||||
|
row. (`ReisePartner`/`IDArtVerpflegung_FS` is the booking-side hotel; for the *catalog*
|
||||||
|
use `PartnerProdukt`. `ProduktBeschreibung.IDAdresse_FS_Hotel` = the single featured hotel.)
|
||||||
|
```sql
|
||||||
|
-- hotels of the product (each IDAdresse_FS = an XML <hotel idbuspro>)
|
||||||
|
SELECT pp.IDAdresse_FS AS HotelAddressId, a.SuchName AS HotelName
|
||||||
|
FROM dbo.PartnerProdukt pp
|
||||||
|
JOIN dbo.Adresse a ON a.IDAdresse = pp.IDAdresse_FS
|
||||||
|
WHERE pp.IDProdukt_FS = @ProductId -- e.g. 1121
|
||||||
|
-- AND pp.IDAdresse_FS = @HotelAddressId
|
||||||
|
ORDER BY a.SuchName;
|
||||||
|
```
|
||||||
|
Board (`IDArtVerpflegung`) and stay dates aren't on `PartnerProdukt`; board comes from
|
||||||
|
the `PartnerPreisKategorie` rows below, and the stay span = the departure dates
|
||||||
|
(`Reise.TerminVon/TerminBis`, here `11.–13.12.2026` ⇒ `Naechte = 2`).
|
||||||
|
Rooms / price / availability for a hotel address. The pricing fans out over
|
||||||
|
`room → price-category → season tafel → nights`; **validated** against the live DB
|
||||||
|
for hotel `224923`, room-type `Zimmerart 1413` (Code `MBZ`) → `IDArtPartnerPreisCode 38`
|
||||||
|
→ category `9478`, season `15420` (covers `2026-12-11`), `Naechte=2`, `EK_VK='VK'`,
|
||||||
|
`IDArtPreisSchema_FS=1` → **`269,00`** (single clean row; same schema id `1` as the
|
||||||
|
`LeistungPreis` side). Map a room to its price category via `IDArtPartnerPreisCode_FS`.
|
||||||
|
(The XML headline `abpreis` of `289,00` = this room price + mandatory services, i.e.
|
||||||
|
computed — see note below; the flat per-room price is `269,00`.)
|
||||||
|
|
||||||
|
```sql
|
||||||
|
-- 1) rooms the hotel offers
|
||||||
|
-- PartnerZimmer ⋈ PartnerPreisKategorie on (IDAdresse_FS, IDArtPartnerPreisCode_FS)
|
||||||
|
SELECT pz.IDPartnerZimmer AS RoomId, za.Code AS RoomCode, za.Bezeichnung AS RoomLabel,
|
||||||
|
za.PaxMin, za.PaxMax, pz.IDArtPartnerPreisCode_FS AS PriceCode
|
||||||
|
FROM dbo.PartnerZimmer pz
|
||||||
|
JOIN dbo.Zimmerart za ON za.IDZimmerart = pz.IDZimmerart_FS
|
||||||
|
WHERE pz.IDAdresse_FS = @HotelAddressId;
|
||||||
|
|
||||||
|
-- 2) which season tafel covers the arrival date
|
||||||
|
SELECT IDPartnerSaisonTafel_FS FROM dbo.PartnerSaisonzeit
|
||||||
|
WHERE IDAdresse_FS = @HotelAddressId
|
||||||
|
AND TerminVon <= @Anreise AND TerminBis >= @Anreise
|
||||||
|
AND EK_VK = 'VK'; -- sale side
|
||||||
|
|
||||||
|
-- 3) price for the room's category × that season × nights
|
||||||
|
SELECT pp.Preis AS RoomPrice, pp.Naechte, pp.Verlaengerung
|
||||||
|
FROM dbo.PartnerPreisKategorie pk
|
||||||
|
JOIN dbo.PartnerPreis pp ON pp.IDPartnerPreisKategorie_FS = pk.IDPartnerPreisKategorie
|
||||||
|
WHERE pk.IDAdresse_FS = @HotelAddressId
|
||||||
|
AND pk.IDArtPartnerPreisCode_FS = @PriceCode -- from step 1 (room → category)
|
||||||
|
AND pk.IDArtVerpflegung_FS = @BoardId -- ReisePartner.IDArtVerpflegung_FS
|
||||||
|
AND pk.EK_VK = 'VK'
|
||||||
|
AND pp.IDPartnerSaisonTafel_FS = @SaisonTafelId -- from step 2
|
||||||
|
AND pp.Naechte = @Nights; -- nights of the stay
|
||||||
|
```
|
||||||
|
> `EK_VK` distinguishes purchase (`EK`) from sale (`VK`) — always filter `VK` for the
|
||||||
|
> customer price. `PartnerZimmer.PreisJeZimmer` flags per-room vs. per-person pricing.
|
||||||
|
|
||||||
|
```sql
|
||||||
|
-- availability (XML 'verfuegbar') — VALIDATED: = PartnerKontingent.Anzahl for the
|
||||||
|
-- (hotel, room-type, date-span). IDZimmer_FS = the XML idbuspro_zimmer (a Zimmerart).
|
||||||
|
-- Sample: IDAdresse_FS=224923, IDZimmer_FS=1413, 2026-12-11 → Anzahl=25 = XML verfuegbar.
|
||||||
|
SELECT IDZimmer_FS, Anzahl, BuchungsStatus FROM dbo.PartnerKontingent
|
||||||
|
WHERE IDAdresse_FS = @HotelAddressId
|
||||||
|
AND IDZimmer_FS = @ZimmerartId -- the room type (XML idbuspro_zimmer)
|
||||||
|
AND TerminVon <= @Abreise AND TerminBis >= @Anreise;
|
||||||
|
```
|
||||||
|
> `verfuegbar` is a **flat column** (`PartnerKontingent.Anzahl`) — reproducible by SQL.
|
||||||
|
> Gate it with `BuchungsStatus` (`''` bookable, `S` stop, `A` on-request).
|
||||||
|
> `<abpreis>` (the headline "from" price) is still **computed** (cheapest valid room +
|
||||||
|
> mandatory services) — recompute in the proxy from the per-room prices above.
|
||||||
|
|
||||||
|
### B4. Selection tags + groups — **confirmed**
|
||||||
|
```sql
|
||||||
|
SELECT gs.Selektionsgruppe AS GroupLabel, gs.Position AS GroupPos,
|
||||||
|
s.IDSelektionsstamm AS SelectionId, s.Selektion AS SelectionLabel
|
||||||
|
FROM dbo.ReiseSelektionen rs
|
||||||
|
JOIN dbo.Selektionsstamm s ON s.IDSelektionsstamm = rs.IDSelektionsstamm_FS
|
||||||
|
JOIN dbo.Selektionsgruppe sg ON sg.IDSelektionsstamm_FS = s.IDSelektionsstamm
|
||||||
|
JOIN dbo.Selektionsgruppenstamm gs ON gs.IDSelektionsgruppenstamm = sg.IDSelektionsgruppenstamm_FS
|
||||||
|
WHERE rs.IDReise_FS = @DateId
|
||||||
|
ORDER BY gs.Position, sg.Position;
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Status / open decisions
|
||||||
|
1. ~~**Status codes** (A1)~~ — ✅ confirmed: `Reise.Status` `''` = bookable, `S` = Storno
|
||||||
|
(cancelled, `StornoDatum` set), `L` = template/future master (exclude both).
|
||||||
|
2. ~~**F/A/O/S column**~~ — ✅ codes in `dbo.ArtBuchungsStatus` (F/O/A/W/S/U); the
|
||||||
|
working hotel-availability column is `PartnerKontingent.BuchungsStatus` (`''`/`S`/`A`).
|
||||||
|
3. ~~**Hotel link**~~ — ✅ XML `<hotel idbuspro>` = `Adresse.IDAdresse`; departure→hotel
|
||||||
|
via `PartnerProdukt(IDProdukt_FS, IDAdresse_FS)` at product level (not `ReisePartner`).
|
||||||
|
4. ~~**Partner room pricing**~~ — ✅ fully validated end-to-end: room `1413` (MBZ) →
|
||||||
|
code `38` → category `9478` → season `15420` × `Naechte=2` × `VK` × schema `1` =
|
||||||
|
**`269,00`**. (XML `abpreis 289,00` = room + mandatory services = computed.)
|
||||||
|
5. ~~**`verfuegbar`**~~ — ✅ flat: `PartnerKontingent.Anzahl` for `(IDAdresse_FS, IDZimmer_FS,
|
||||||
|
date-span)`; `1413 / 2026-12-11 → 25`. `<abpreis>` remains computed (recompute in proxy).
|
||||||
|
6. ~~**Minimum-services filter**~~ — ✅ defined: "included services" =
|
||||||
|
(A2a) `Leistung`s with sales price `0.00` (schema 1) **+** (A2b) selection items from
|
||||||
|
the hardcoded "Leistungen" `Selektionsgruppenstamm` ids, merged into one plain list.
|
||||||
@@ -0,0 +1,380 @@
|
|||||||
|
# EP Reisen Mobile App — React Native Plan
|
||||||
|
|
||||||
|
**Copy this file into the React Native repository** (suggested: `docs/plan.md`). It is
|
||||||
|
written to be self-contained: you do not need access to the backend codebase to work from
|
||||||
|
it. Where it says "the contract", it means the API guide and fixtures shipped by the
|
||||||
|
backend team — see §3.
|
||||||
|
|
||||||
|
**Companion (backend side, not needed here):** `docs/mobile-app/backend-plan.md` in the
|
||||||
|
`myep` Symfony repository.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 1. What this app is
|
||||||
|
|
||||||
|
EP Reisen sells group travel — primarily ski and coach trips. A booking is not "one person
|
||||||
|
buys one thing": it is **one applicant booking a set of rooms for a group of participants**,
|
||||||
|
where each participant independently selects ski passes, equipment rental, board, courses,
|
||||||
|
transport, insurance and more, with prices and eligibility varying per person (notably by
|
||||||
|
age).
|
||||||
|
|
||||||
|
The existing web product is a server-rendered Symfony application. This app covers its
|
||||||
|
**public** surface. The admin area is explicitly out of scope and will remain web-only.
|
||||||
|
|
||||||
|
The app is being built for App Store presence and a native-feeling booking flow. Push
|
||||||
|
notifications are **not** currently a requirement — do not build infrastructure for them
|
||||||
|
without asking.
|
||||||
|
|
||||||
|
### The two systems behind the API
|
||||||
|
|
||||||
|
You will see this distinction leak into behaviour, so it is worth knowing:
|
||||||
|
|
||||||
|
- **BusProNet (BPN)** — an external, third-party XML system that is the system of record
|
||||||
|
for individual travel bookings. It is slow, occasionally unavailable, and its rules are
|
||||||
|
not ours to change. Endpoints backed by it can fail in ways local data cannot.
|
||||||
|
- **Local database** — system of record for group/accommodation bookings, user accounts,
|
||||||
|
newsletter consent, and booking drafts. Fast and reliable.
|
||||||
|
|
||||||
|
Increments are deliberately ordered local-data-first so you are not fighting BPN latency
|
||||||
|
while also debugging your own foundations.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 2. The one architectural rule
|
||||||
|
|
||||||
|
> **Business rules live on the server. The app renders what it is told.**
|
||||||
|
|
||||||
|
This is not a stylistic preference; it is the reason the project is viable. The backend
|
||||||
|
already contains, in one place, 27 condition classes and 25 field handlers that decide —
|
||||||
|
per participant, per field — whether a field is visible, editable, required, or shown as
|
||||||
|
read-only text, and which choices it offers. Reimplementing any of that in TypeScript
|
||||||
|
creates two sources of truth that will silently diverge.
|
||||||
|
|
||||||
|
**Concretely, never write code in this repo that:**
|
||||||
|
|
||||||
|
- decides whether a field is shown, e.g. inferring that a licence-plate input appears
|
||||||
|
because transport is by car;
|
||||||
|
- computes or re-computes a price, total, discount or voucher deduction from line items;
|
||||||
|
- decides whether a participant is eligible for a service, especially by age;
|
||||||
|
- validates a business constraint (as opposed to a formatting constraint like "this looks
|
||||||
|
like an email").
|
||||||
|
|
||||||
|
**If the app appears to need one of those, the schema is missing information. That is a
|
||||||
|
backend bug.** Report it; do not patch around it. This single discipline is what the whole
|
||||||
|
architecture buys, and it is lost the first time it is violated.
|
||||||
|
|
||||||
|
Client-side validation is limited to immediate input affordances — keyboard type, max
|
||||||
|
length, obviously-malformed email — purely for responsiveness. The server's verdict is
|
||||||
|
always authoritative and always re-checked on submit.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 3. The contract
|
||||||
|
|
||||||
|
The backend ships two artifacts. Together they are your ground truth.
|
||||||
|
|
||||||
|
1. **The API guide** — a self-contained markdown document describing every endpoint:
|
||||||
|
method, path, auth scope, request shape, response shape, error shapes. The backend
|
||||||
|
team updates it in the same commit as the endpoint.
|
||||||
|
2. **Fixtures** — real JSON responses, written out by the backend's own tests. Because
|
||||||
|
they are test *output*, they cannot silently go stale.
|
||||||
|
|
||||||
|
### How to work with them
|
||||||
|
|
||||||
|
- **Build against fixtures first**, then point at a live backend. This means app work
|
||||||
|
never blocks on a deployed endpoint.
|
||||||
|
- **Generate your TypeScript types from the contract** rather than hand-writing them, so
|
||||||
|
a schema change surfaces as a compile error instead of a runtime surprise.
|
||||||
|
- **When the guide is ambiguous, ask — do not guess.** A guess that happens to work
|
||||||
|
becomes an undocumented dependency on an accident.
|
||||||
|
|
||||||
|
### Error shapes to expect
|
||||||
|
|
||||||
|
The existing API does not have one universal error envelope. Handle all of these:
|
||||||
|
|
||||||
|
- `{"message": "..."}` — typically with 404 or 400.
|
||||||
|
- `{"error": "...", "type": "api_error"}` — upstream (BPN) failure. **Some endpoints
|
||||||
|
return this with HTTP 200.** Check for the presence of an `error` key, not only the
|
||||||
|
status code.
|
||||||
|
- `{"success": false, "message": "..."}` — some write endpoints.
|
||||||
|
- **400 with a constraint-violation body** — validation failures. These are the ones you
|
||||||
|
map back onto form fields; see §5.
|
||||||
|
|
||||||
|
`401` means the token is missing or invalid (refresh, then retry once). `403` means
|
||||||
|
insufficient scope — a bug, not a user-recoverable state.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 4. Authentication
|
||||||
|
|
||||||
|
OAuth2 **authorization_code with PKCE**, against the backend's `/token` endpoint. The
|
||||||
|
password and implicit grants are disabled server-side and are not available to you.
|
||||||
|
|
||||||
|
Requirements:
|
||||||
|
|
||||||
|
- Use the system browser / `ASWebAuthenticationSession` / Custom Tabs — **not** a
|
||||||
|
`WebView`. App Store review and OAuth best practice both require this.
|
||||||
|
- Store tokens in the platform secure store (Keychain / Keystore), never in
|
||||||
|
`AsyncStorage`.
|
||||||
|
- **Access tokens are short-lived** — 10 minutes today, likely 1 hour by the time you
|
||||||
|
build. Confirm with the backend team in Increment 0. Either way the refresh-token grant
|
||||||
|
is enabled and you must use it.
|
||||||
|
- **Refresh-token rotation is ON.** Each refresh returns a *new* refresh token and revokes
|
||||||
|
the one you just used. This has two consequences you must design for, not discover:
|
||||||
|
- **Single-flight refresh is mandatory.** If two requests 401 at the same time and both
|
||||||
|
try to refresh, one wins and the other presents an already-revoked token — logging the
|
||||||
|
user out mid-booking. Put a mutex around refresh and queue every other 401 behind it,
|
||||||
|
then replay them with the new token. This is the most common OAuth bug in mobile apps
|
||||||
|
and the booking flow's per-field schema refreshes will find it immediately.
|
||||||
|
- **Persist the rotated token atomically before using it.** A crash between receiving a
|
||||||
|
new refresh token and storing it logs the user out permanently.
|
||||||
|
- The refresh TTL is a sliding window (currently ~1 month, likely 3), so an active user
|
||||||
|
should never be forced to re-authenticate. If yours are, the refresh path is broken —
|
||||||
|
treat it as a bug, not as expected behaviour.
|
||||||
|
- The redirect URI must be registered server-side against the exact host the app calls.
|
||||||
|
This bites during local development — see §8.
|
||||||
|
|
||||||
|
**You will never handle credentials for the upstream BPN system.** The server resolves
|
||||||
|
those internally. If any task seems to require the app to send a BPN password, stop and
|
||||||
|
ask; the answer is no.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 5. Server-driven UI
|
||||||
|
|
||||||
|
The dynamic parts of the booking flow are rendered from a schema the server computes. You
|
||||||
|
build **one generic renderer**, not per-screen field logic.
|
||||||
|
|
||||||
|
### Expected schema shape
|
||||||
|
|
||||||
|
Confirm against the fixtures — they are authoritative — but the agreed shape is:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"fields": [
|
||||||
|
{
|
||||||
|
"name": "skiPass",
|
||||||
|
"type": "choice",
|
||||||
|
"label": "Skipass",
|
||||||
|
"required": true,
|
||||||
|
"value": 881,
|
||||||
|
"choices": [
|
||||||
|
{"id": 881, "label": "6 Tage", "price": 249.0}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{"name": "licensePlate", "type": "text", "hidden": true},
|
||||||
|
{"name": "pickup", "type": "choice", "readonly": true, "value": 12, "choices": []},
|
||||||
|
{"name": "firstName", "type": "text", "staticText": true, "value": "Anna"}
|
||||||
|
],
|
||||||
|
"dependsOn": {
|
||||||
|
"licensePlate": ["transportationOutbound"],
|
||||||
|
"pickup": ["transportationOutbound"]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Field states — all four are distinct
|
||||||
|
|
||||||
|
| State | Meaning | Render as |
|
||||||
|
|---|---|---|
|
||||||
|
| `hidden` | Not applicable at all | Nothing |
|
||||||
|
| `staticText` | Value matters, user may not change it | Read-only text, no input affordance |
|
||||||
|
| `readonly` | Input shown but not editable | Disabled-looking input |
|
||||||
|
| `disabled` | Temporarily not interactive | Greyed input |
|
||||||
|
|
||||||
|
`hidden` and `staticText` are genuinely different and the backend treats them
|
||||||
|
differently — `staticText` is used, for example, when personal data is locked because
|
||||||
|
changing it would create a duplicate customer record upstream. Collapsing the two will
|
||||||
|
produce wrong screens.
|
||||||
|
|
||||||
|
### `dependsOn`
|
||||||
|
|
||||||
|
Maps a field to the fields whose changes invalidate it. When the user changes field *X*,
|
||||||
|
any field listing *X* in its `dependsOn` may now have different visibility, state, or
|
||||||
|
choices. **Re-fetch the schema from the server** — do not attempt to recompute locally.
|
||||||
|
This is the mechanism that keeps rule evaluation server-side.
|
||||||
|
|
||||||
|
Debounce these refreshes and keep the UI responsive during them, but never predict the
|
||||||
|
result optimistically for anything that affects price or eligibility.
|
||||||
|
|
||||||
|
### Field types you must support
|
||||||
|
|
||||||
|
`text`, `email`, `tel`, `date`, `choice` (single), `multichoice`, `checkbox`, `address`
|
||||||
|
(composite), plus a `static` presentation mode. Confirm the final list against the
|
||||||
|
contract before building.
|
||||||
|
|
||||||
|
### Mapping validation errors back
|
||||||
|
|
||||||
|
The server returns violations keyed by a property path (e.g.
|
||||||
|
`participants[2].dateOfBirth`). Your renderer must resolve those onto the right field on
|
||||||
|
the right participant. Design for this from the start — retrofitting it is painful.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 6. Domain glossary
|
||||||
|
|
||||||
|
Enough to read the API without guessing.
|
||||||
|
|
||||||
|
- **Travel** — a dated departure of a product, at a specific hotel. Identified by a
|
||||||
|
numeric `dateId` + `hotelId`, or by string codes. Carries the available rooms, services,
|
||||||
|
pickups, insurances.
|
||||||
|
- **Applicant** — participant index 0. The person who books and is billed. Subject to
|
||||||
|
extra rules the others are not; their personal data is frequently locked (`staticText`).
|
||||||
|
- **Participant** — one traveller. Most selections live per participant, not per booking.
|
||||||
|
- **Room selection** — how many of which room type. This determines the participant count,
|
||||||
|
which is why step 1 precedes step 2.
|
||||||
|
- **Service** — anything bookable alongside: ski pass, equipment rental, board, courses,
|
||||||
|
transport, parking, additional services. Some are mandatory, some auto-booked with
|
||||||
|
opt-out, some age-restricted.
|
||||||
|
- **Booking status** — `F` firm booking, `O` option (held), `A` inquiry. Determined by
|
||||||
|
server rules, not user choice.
|
||||||
|
- **Payment method** — `transfer` or `debit`. Debit requires bank account details.
|
||||||
|
- **Voucher** — purchase vouchers (a balance), goodwill vouchers, and promo vouchers
|
||||||
|
(fixed or percentage, per-participant or per-booking). **Always** server-validated;
|
||||||
|
never compute a discount locally.
|
||||||
|
- **Baby** — participants aged 0–2 are a real special case in eligibility and pricing.
|
||||||
|
- **Mutability** — for existing bookings, BPN decides per field whether a change is still
|
||||||
|
permitted. Surfaces as `staticText`/`readonly`. Never override it.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 7. Increments
|
||||||
|
|
||||||
|
Each increment is a working loop with the backend session; see §9. Do not start an
|
||||||
|
increment before its backend endpoints and fixtures exist.
|
||||||
|
|
||||||
|
### Increment 0 — Foundations
|
||||||
|
|
||||||
|
- RN app skeleton, navigation, theming, error boundary.
|
||||||
|
- OAuth2 authorization_code + PKCE, secure token storage, silent refresh with request
|
||||||
|
queuing.
|
||||||
|
- API client: auth injection, 401-refresh-retry, the error shapes in §3, and a fixture
|
||||||
|
mock mode toggled by env.
|
||||||
|
- **The generic SDUI renderer** — consumes `{fields, dependsOn}`, renders every field type,
|
||||||
|
emits changes, maps server violations onto fields.
|
||||||
|
- Type generation from the contract wired into the build.
|
||||||
|
- **Done when:** Increment 1 renders entirely through the generic renderer.
|
||||||
|
|
||||||
|
### Increment 1 — Accommodation & group offers (pilot)
|
||||||
|
|
||||||
|
Local data, fast, low risk. Deliberately first so the foundations are exercised end-to-end
|
||||||
|
before anything hard.
|
||||||
|
|
||||||
|
- Offer list for the signed-in user, offer detail, accept an offer.
|
||||||
|
- **Validates:** auth, error handling, navigation, the fixture pipeline.
|
||||||
|
|
||||||
|
### Increment 2 — Account, personal data, newsletter, registration
|
||||||
|
|
||||||
|
- Sign-up, password reset, profile view/edit, newsletter preferences.
|
||||||
|
- **First real use of SDUI** on a small form, before betting the booking flow on it. Expect
|
||||||
|
to find gaps in the renderer here — that is the point of doing it now.
|
||||||
|
|
||||||
|
### Increment 3 — Booking read
|
||||||
|
|
||||||
|
- "My travels": booking list, booking detail with participants, services and price
|
||||||
|
breakdown, document/invoice download.
|
||||||
|
- First BPN-backed screens. Expect slower responses and genuine upstream failures — build
|
||||||
|
proper loading and error states here, and reuse them everywhere after.
|
||||||
|
|
||||||
|
### Increment 4 — *(backend only)*
|
||||||
|
|
||||||
|
An internal backend refactor that produces the participant field schema. No app work.
|
||||||
|
Good moment to pay down debt or firm up the renderer.
|
||||||
|
|
||||||
|
### Increment 5 — Booking edit
|
||||||
|
|
||||||
|
- Edit an existing booking through a server-persisted draft: load draft, edit participants
|
||||||
|
via SDUI, review changes, submit.
|
||||||
|
- Honour mutability strictly — many fields will be `staticText`, and that is correct.
|
||||||
|
- Drafts are server-side, so edits survive app restarts. Design the UX around that.
|
||||||
|
|
||||||
|
### Increment 6 — Booking create
|
||||||
|
|
||||||
|
The full four-step flow, last, once everything above is proven.
|
||||||
|
|
||||||
|
1. **Rooms** — select room types and quantities. Determines participant count.
|
||||||
|
2. **Participants** — one card per participant, each opening an SDUI form. Groups can be
|
||||||
|
large (50+); the web version lazy-loads per participant and you should too.
|
||||||
|
3. **Payment** — method, and bank details when debit.
|
||||||
|
4. **Confirmation** — full summary, terms, submit.
|
||||||
|
|
||||||
|
Notes:
|
||||||
|
|
||||||
|
- State lives in a **server-side draft keyed by UUID**, not on the device. The app holds
|
||||||
|
the draft id and renders server state.
|
||||||
|
- Price refreshes are server calls. Never compute totals locally, not even for a
|
||||||
|
"preview".
|
||||||
|
- Submission goes to BPN and can fail or partially succeed. Treat the submit step as
|
||||||
|
genuinely fallible and make retry safe.
|
||||||
|
|
||||||
|
### Increment 7 — Discovery *(not yet scoped)*
|
||||||
|
|
||||||
|
Browsing travels and hotels currently lives in a separate CMS website, not in the backend
|
||||||
|
this app talks to. If the app must be a standalone entry point rather than something users
|
||||||
|
deep-link into, that is a second integration project. Do not assume it is in scope.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 8. Local development
|
||||||
|
|
||||||
|
- The backend runs in DDEV. A **simulator** can reach it via the host; a **physical
|
||||||
|
device** cannot resolve `*.ddev.site`. The backend team will expose a shareable URL
|
||||||
|
(`ddev share` / ngrok).
|
||||||
|
- OAuth2 redirect URIs are registered per host, so switching between simulator and device
|
||||||
|
URLs needs a backend-side change. Agree the setup in Increment 0 rather than discovering
|
||||||
|
it mid-increment.
|
||||||
|
- Keep fixture-mock mode working permanently, not just as scaffolding — it is how you stay
|
||||||
|
unblocked and how you write deterministic tests.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 9. Working agreement with the backend session
|
||||||
|
|
||||||
|
The backend lives in a separate repository and a separate sandboxed session. Neither side
|
||||||
|
can see the other's code. The contract is the only coupling point, and keeping it that way
|
||||||
|
is a shared discipline.
|
||||||
|
|
||||||
|
**Per-increment loop:**
|
||||||
|
|
||||||
|
1. Backend ships: endpoints + tests + fixtures + updated guide.
|
||||||
|
2. Handoff brief: what is live, which fixtures to mock, what changed in the guide.
|
||||||
|
3. App builds against fixtures, then against a live backend.
|
||||||
|
4. Joint end-to-end verification.
|
||||||
|
|
||||||
|
The two sessions do not work the same increment concurrently — they overlap by one stage,
|
||||||
|
so the backend starts *N+1* while the app builds *N*.
|
||||||
|
|
||||||
|
**Escalate to the backend rather than solving locally when:**
|
||||||
|
|
||||||
|
- a rule seems missing from the schema;
|
||||||
|
- a response shape is undocumented or contradicts the guide;
|
||||||
|
- you need a field the API does not expose;
|
||||||
|
- you are tempted to hardcode a business constant.
|
||||||
|
|
||||||
|
Each of those is a contract gap. Fixing it in the app is the failure mode this entire
|
||||||
|
architecture exists to prevent.
|
||||||
|
|
||||||
|
**Suggested `AGENTS.md` for this repo**, so future sessions inherit the rule:
|
||||||
|
|
||||||
|
> Business rules live server-side. This app renders a server-provided schema and never
|
||||||
|
> decides field visibility, eligibility, or pricing. If a rule appears to be missing,
|
||||||
|
> that is a backend bug — report it, do not implement it here. Never recompute prices
|
||||||
|
> from line items or infer field visibility from other field values.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 10. Verification
|
||||||
|
|
||||||
|
- **Unit:** the SDUI renderer against every field type and state combination, including
|
||||||
|
`hidden` vs `staticText`, and violation-path mapping onto nested participant fields.
|
||||||
|
- **Auth:** an explicit test that fires several concurrent requests against an expired
|
||||||
|
access token and asserts *exactly one* refresh call is made, all requests succeed, and
|
||||||
|
the rotated refresh token is persisted. Rotation makes this a correctness test, not a
|
||||||
|
performance one.
|
||||||
|
- **Integration:** screens against committed fixtures — deterministic, no backend needed.
|
||||||
|
- **Contract:** types regenerate cleanly and compile against current fixtures. A failure
|
||||||
|
here is an early warning of drift; treat it as urgent.
|
||||||
|
- **End-to-end:** at the close of Increment 6, complete one booking through the app
|
||||||
|
against a real backend. The backend team verifies the resulting upstream payload is
|
||||||
|
**identical** to the same booking made through the web flow. That equivalence is the
|
||||||
|
project's actual acceptance criterion — everything else is a proxy for it.
|
||||||
@@ -0,0 +1,354 @@
|
|||||||
|
# Mobile App — Backend Plan (myep / Symfony)
|
||||||
|
|
||||||
|
**Audience:** sessions working in *this* repository (`myep`, Symfony 6.4).
|
||||||
|
**Companion:** `docs/mobile-app/app-plan.md` — the React Native side. That document is
|
||||||
|
written to be self-contained and is meant to be **copied into the RN repository**, whose
|
||||||
|
sessions have no access to this codebase.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 1. Context
|
||||||
|
|
||||||
|
`myep` is the booking engine behind the separate CMS marketing site (`ep-reisen.de`;
|
||||||
|
see `BookingSessionManager::DEFAULT_RETURN_URL` and `CmsDataProvider`). It serves:
|
||||||
|
|
||||||
|
- **Individual travel bookings** — system of record is **BusProNet** (BPN), an external
|
||||||
|
XML service reached through `src/BusProNet/ApiClient.php`.
|
||||||
|
- **Groups / accommodation bookings** — system of record is local Doctrine entities under
|
||||||
|
`src/Entity/Groups/`.
|
||||||
|
|
||||||
|
The public UI is Twig + HTMX + Tailwind. The admin UI under `/admin` is **out of scope**
|
||||||
|
for the mobile app and stays web-only.
|
||||||
|
|
||||||
|
### What we are building and why
|
||||||
|
|
||||||
|
A React Native app covering the **full public surface, including the booking create
|
||||||
|
flow**. Drivers: App Store presence/brand and a native-feeling booking experience. A PWA
|
||||||
|
was explicitly ruled out. Push notifications were *not* named as a driver — worth
|
||||||
|
remembering, since push is normally what makes native unarguable; the payoff here rests
|
||||||
|
on brand and UX.
|
||||||
|
|
||||||
|
### The decision that shapes everything
|
||||||
|
|
||||||
|
**The sibling project is the React Native app only. The API stays in this repository.**
|
||||||
|
|
||||||
|
A second backend would recreate exactly the duplication of validation and business rules
|
||||||
|
this plan exists to prevent. The API is a new `src/Controller/Api/App/` namespace reusing
|
||||||
|
the existing services and DTOs.
|
||||||
|
|
||||||
|
**Client strategy: server-driven UI (SDUI).** The server emits a JSON field schema per
|
||||||
|
participant/step; RN renders it generically. Business rules never leave PHP.
|
||||||
|
|
||||||
|
### Why this codebase can actually support that
|
||||||
|
|
||||||
|
The rules are already headless:
|
||||||
|
|
||||||
|
- **Validation lives on DTOs, not form types.** `src/Form/Model/ParticipantDto.php` (21
|
||||||
|
constraints), `BookingDto.php`, `BankAccountDto.php`, `RegistrationDto.php` carry
|
||||||
|
`Assert\*` plus custom `App\Validator\Constraints\Participant`, with validation groups
|
||||||
|
(`booking_create`, `booking_edit`, `strict_required`, `applicant_address`). An API
|
||||||
|
endpoint can denormalize → `validate($dto, groups: [...])` and get identical results.
|
||||||
|
- **Dynamic field logic is a rules engine.** `src/Form/Service/` holds
|
||||||
|
`Contract/FieldStateProviderInterface` (hidden / readonly / disabled / required /
|
||||||
|
static_text), `Contract/FieldOptionsProviderInterface` (labels + choices),
|
||||||
|
`ParticipantFieldHandlerRegistry` (25 handlers) and 27 reusable `Condition/` classes.
|
||||||
|
- **Orchestration is in services, not controllers.** `BookingConfigurator` (652 lines),
|
||||||
|
`RoomAssigner`, `BookingPricingAssembler`, `BookingSummaryAssembler`,
|
||||||
|
`VoucherValidator`, `BookingEditSubmitGuard`, `BookingEditSubmitter`. Controllers are
|
||||||
|
thin — `Step2Controller` is 147 lines, mostly session handling and redirects.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 2. The four real obstacles
|
||||||
|
|
||||||
|
Everything else is mechanical. These need design work before the increments that depend
|
||||||
|
on them.
|
||||||
|
|
||||||
|
### Obstacle 1 — The create flow is session-bound
|
||||||
|
|
||||||
|
`src/Service/BookingSessionManager.php` keys the entire create flow off
|
||||||
|
`$request->getSession()` (`booking_create`, `booking_create_baseline_snapshot`,
|
||||||
|
`booking_return_url`). Stateless OAuth2 clients have no session.
|
||||||
|
|
||||||
|
**Fix:** a server-persisted draft addressed by UUID. The pattern already exists for edit —
|
||||||
|
`src/Entity/BookingEditDraft.php` plus `BookingEditDraftManager` / `BookingEditDraftMerger`.
|
||||||
|
Generalise into a `BookingDraft` store and put `BookingStateStoreInterface` in front, with
|
||||||
|
two backends: session (web, unchanged) and draft (app). Do **not** fork the flow logic.
|
||||||
|
|
||||||
|
### Obstacle 2 — `FieldStateProviderInterface` leaks Symfony Form
|
||||||
|
|
||||||
|
Two leaks:
|
||||||
|
|
||||||
|
- `getBookingDtoFromForm(FormInterface $form)` is pure Form coupling and belongs in a
|
||||||
|
form-side adapter, not the interface.
|
||||||
|
- `getFieldState()` returns **Symfony form options** (`disabled`, `required`,
|
||||||
|
`attr => ['readonly' => true]`), and `ParticipantFieldOptionsProvider` returns `choices`
|
||||||
|
as domain objects (`Service`, `Pickup`, `Insurance`) plus occasional `choice_loader`.
|
||||||
|
|
||||||
|
**Fix:** a neutral `FieldDescriptor` value object — name, type, label, required, readonly,
|
||||||
|
disabled, hidden, staticText, choices, value. Both `BookingParticipantType` and the new
|
||||||
|
JSON serializer consume it. Conditions and handlers are untouched.
|
||||||
|
|
||||||
|
Note the `hidden` vs `static_text` distinction documented in `AbstractFieldStateProvider`:
|
||||||
|
`hidden` means excluded entirely; `static_text` means "show the value, don't let them edit
|
||||||
|
it". The app must honour both, so `FieldDescriptor` has to carry them separately.
|
||||||
|
|
||||||
|
### Obstacle 3 — Token lifetimes and refresh-token rotation
|
||||||
|
|
||||||
|
`config/packages/league_oauth2_server.yaml` sets `access_token_ttl: PT10M` — deliberately,
|
||||||
|
since the bundle's own default is `PT1H`. Find out why before changing it.
|
||||||
|
|
||||||
|
**TTLs are global.** They live under `authorization_server`; the bundle has no per-client
|
||||||
|
TTL. Any change affects the CMS and M2M clients too. "Raise it just for the app" is not
|
||||||
|
available without a custom grant or response type.
|
||||||
|
|
||||||
|
Two values are unset and defaulted, and both matter:
|
||||||
|
|
||||||
|
- `refresh_token_ttl` → **`P1M`** (1 month)
|
||||||
|
- `revoke_refresh_tokens` → **`true`**, so **refresh-token rotation is on**
|
||||||
|
|
||||||
|
Rotation is correct security, and it is also the main source of mobile auth bugs: two
|
||||||
|
requests 401 concurrently, both refresh, one rotates, the second presents a revoked
|
||||||
|
refresh token and the user is logged out mid-booking. At a 10-minute TTL with step 2
|
||||||
|
firing schema refreshes per field change, this *will* happen. The mitigation is client-side
|
||||||
|
— single-flight refresh — and it is a hard requirement in `app-plan.md` §4.
|
||||||
|
|
||||||
|
A longer access-token TTL does **not** create an unrevocable window here:
|
||||||
|
`persist_access_token` defaults to true and `BearerTokenValidator` checks
|
||||||
|
`isAccessTokenRevoked()` on every request, so tokens can be killed immediately. The usual
|
||||||
|
argument for a very short TTL does not apply.
|
||||||
|
|
||||||
|
**Recommendation:** `access_token_ttl: PT1H`, `refresh_token_ttl: P3M` set explicitly,
|
||||||
|
rotation left on. Rotation issues a fresh refresh token each time, so the refresh TTL is a
|
||||||
|
sliding window — active users never re-auth, only ~3 months of true inactivity forces it.
|
||||||
|
M2M clients get fewer token round-trips. Extra token rows are already handled by
|
||||||
|
`league:oauth2-server:clear-expired-tokens`, scheduled in `config/packages/zenstruck_schedule.yaml`.
|
||||||
|
|
||||||
|
**Settle this before the RN auth layer is written, not after.**
|
||||||
|
|
||||||
|
Otherwise auth is ready: `enable_auth_code_grant: true` with
|
||||||
|
`require_code_challenge_for_public_clients: true` (PKCE), and
|
||||||
|
`enable_password_grant: false` / `enable_implicit_grant: false` — correct for a native app.
|
||||||
|
|
||||||
|
### Obstacle 4 — BPN per-user calls need the user's plaintext password
|
||||||
|
|
||||||
|
`ApiClient::getBookings()`, `getBooking()`, `getPersonalData()`, `updatePersonalData()`,
|
||||||
|
`updateNewsletterRegistration()` all take `(string $email, string $password)`.
|
||||||
|
`src/Controller/Booking/IndexController.php` supplies them via
|
||||||
|
`$this->crypt->decrypt($user->getPassword())` — the local `User` stores the BPN password
|
||||||
|
RSA-encrypted (`src/Security/Crypt.php`).
|
||||||
|
|
||||||
|
Consequences:
|
||||||
|
|
||||||
|
- **The app must never see BPN credentials.** The API layer resolves them server-side from
|
||||||
|
the authenticated `User`, exactly as the web controllers do. This is not a change, but
|
||||||
|
it must be stated so nobody "simplifies" it by proxying credentials.
|
||||||
|
- **BPN-backed user data only works for users with a local `User` record** carrying the
|
||||||
|
encrypted password. Guest flows and app-only accounts cannot read BPN bookings. Confirm
|
||||||
|
how registration-via-app populates this before Increment 3.
|
||||||
|
- The OAuth2 token identifies the user; it does **not** carry BPN authority. Every
|
||||||
|
BPN-backed endpoint needs an explicit ownership check, not just a valid token.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 3. Increments
|
||||||
|
|
||||||
|
Ordered local-data-first, BPN-last, so each stage ships something usable and the riskiest
|
||||||
|
integration lands after the SDUI machinery is proven.
|
||||||
|
|
||||||
|
### Increment 0 — Foundations
|
||||||
|
|
||||||
|
No user-visible feature. Backend side:
|
||||||
|
|
||||||
|
- Register an OAuth2 client for the app (authorization_code + PKCE, native redirect URI).
|
||||||
|
- Resolve Obstacle 3 (TTL).
|
||||||
|
- Resolve device→DDEV access: `.ddev/config.yaml` has `ngrok_args`; `ddev share` is the
|
||||||
|
path. Redirect URIs must be registered against whatever host the app actually calls.
|
||||||
|
- Create `docs/app-api/` with the contract skeleton and the fixtures directory.
|
||||||
|
|
||||||
|
### Increment 1 — Accommodation & group offers (pilot)
|
||||||
|
|
||||||
|
Local Doctrine data, UUID-addressed, and a write endpoint already exists. Zero BPN risk.
|
||||||
|
|
||||||
|
- Reuse `GET /api/accommodation-bookings/{uuid}` and
|
||||||
|
`POST /api/accommodation-bookings/{uuid}/accept`
|
||||||
|
(`src/Controller/Api/AccommodationBookingController.php`).
|
||||||
|
- Add a list endpoint scoped to the authenticated user.
|
||||||
|
- Mirrors `src/Controller/Groups/Offer/IndexController.php`; reuse
|
||||||
|
`AccommodationBookingService`, `AccommodationBookingBreakdownCalculator`,
|
||||||
|
`AccommodationBookingApiResponse`.
|
||||||
|
- **Validates:** auth, serialization conventions, RN navigation, the fixture pipeline.
|
||||||
|
|
||||||
|
### Increment 2 — Account, personal data, newsletter, registration
|
||||||
|
|
||||||
|
- Mirror `src/Controller/Account/`, `RegistrationController`, `ResetPasswordController`,
|
||||||
|
`src/Controller/Newsletter/`.
|
||||||
|
- Reuse `RegistrationDto`, the `PersonalDataType` DTO, `NewsletterManager`,
|
||||||
|
`ProfileCompletenessChecker`, and existing `/api/newsletter-subscriptions`,
|
||||||
|
`/api/userinfo`, `/api/crm-attributes`.
|
||||||
|
- **First real SDUI use**, on a small low-risk form, before betting the booking flow on it.
|
||||||
|
- Registration here is what makes Obstacle 4 tractable — verify the encrypted-password
|
||||||
|
path is populated for app-registered users.
|
||||||
|
|
||||||
|
### Increment 3 — Booking read
|
||||||
|
|
||||||
|
- `GET /api/app/bookings` and `/api/app/bookings/{id}`, mirroring
|
||||||
|
`src/Controller/Booking/IndexController.php` (note its `TravelLoader::patchBookings()`
|
||||||
|
enrichment step).
|
||||||
|
- Documents/invoice, mirroring `src/Controller/Booking/DownloadController.php`.
|
||||||
|
- Reuse `BookingSummaryAssembler`, `BookingPricingAssembler`, `BookingEditDataLoader`.
|
||||||
|
- BPN **reads only, no writes** — the safe way to shake out `BusProNet\Model`
|
||||||
|
normalization (`Travel`, `Booking`, `Service`, `Room`, `Pickup`, `Insurance`), which
|
||||||
|
every later increment depends on.
|
||||||
|
|
||||||
|
### Increment 4 — `FieldDescriptor` refactor
|
||||||
|
|
||||||
|
Pure internal refactor. No new endpoints. Covered by the existing 155 test files.
|
||||||
|
|
||||||
|
- Introduce `FieldDescriptor`; split `getBookingDtoFromForm` out of
|
||||||
|
`FieldStateProviderInterface`.
|
||||||
|
- Adapt `BookingParticipantType::mergeFieldState()` / `addDynamicFields()` to consume it.
|
||||||
|
- Add `ParticipantFieldSchemaSerializer` producing the JSON schema, including the
|
||||||
|
`dependsOn` map derived from `FieldConditionInterface::getDependentFields()` and
|
||||||
|
`ParticipantFieldHandlerInterface::getDependencies()`.
|
||||||
|
- **Ship criterion:** web behaviour byte-identical, Cypress specs green, **no test file
|
||||||
|
changed**. A required test change means a behaviour regression.
|
||||||
|
|
||||||
|
### Increment 5 — Booking edit
|
||||||
|
|
||||||
|
Before create, because drafts already exist here.
|
||||||
|
|
||||||
|
- Endpoints over `BookingEditDraftManager`, `BookingEditPreFlightChecker`,
|
||||||
|
`BookingEditSubmitGuard`, `BookingEditSubmitter`, `BookingChangeTracker`.
|
||||||
|
- Participant schema endpoint from Increment 4.
|
||||||
|
- Honour `BookingMutabilityDto` and BPN's `aenderungmoeglich` mutability rules — these
|
||||||
|
already drive `static_text`, so SDUI inherits them.
|
||||||
|
- **Caution:** the participant[0]/applicant block is on hold pending BPN vendor
|
||||||
|
confirmation about the shared customer id. Do not try to resolve it here.
|
||||||
|
|
||||||
|
### Increment 6 — Booking create
|
||||||
|
|
||||||
|
The full flow, last. Web routes being mirrored:
|
||||||
|
|
||||||
|
| Step | Web route | Controller |
|
||||||
|
|---|---|---|
|
||||||
|
| init | `/bookings/create`, `/bookings/create/init` | `Create/IndexController.php` |
|
||||||
|
| 1 — rooms | `/bookings/create/rooms` (+ `/refresh`) | `Create/Step1Controller.php` |
|
||||||
|
| 2 — participants | `/bookings/create/participants` (+ `/{index}`, `/{index}/refresh`) | `Create/Step2Controller.php`, `Step2ParticipantController.php` |
|
||||||
|
| 3 — payment | `/bookings/create/payment` (+ `/refresh`) | `Create/Step3Controller.php` |
|
||||||
|
| 4 — confirmation | `/bookings/create/confirmation` | `Create/Step4Controller.php` |
|
||||||
|
| success | `/bookings/create/success` | `Create/SuccessController.php` |
|
||||||
|
|
||||||
|
- Generalise draft storage behind `BookingStateStoreInterface` (Obstacle 1).
|
||||||
|
- Reuse `BookingConfigurator` (`startFreshBooking`, `preselectDefaultServices`,
|
||||||
|
`applyCreateBookingStatusRules`, `updateBookingStatusFromRoomSelection`), `RoomAssigner`,
|
||||||
|
`ParticipantDataPrefiller`, `TravelDataProvider`, `VoucherValidator`,
|
||||||
|
`FamilyInsuranceAvailabilityChecker`.
|
||||||
|
- Submit via `BusProNet\ApiClient::createBooking()` / `createBookingInquiry()` with
|
||||||
|
`BookingPayloadBuilder`, exactly as `Step4Controller` does.
|
||||||
|
- Every HTMX refresh route gets a JSON sibling returning recomputed schema + pricing.
|
||||||
|
|
||||||
|
### Increment 7 — Discovery (scoping decision, not yet planned)
|
||||||
|
|
||||||
|
Travel/hotel browsing lives in the **CMS**, not here — this repo only proxies it via
|
||||||
|
`CmsDataProvider` and `/api/hotels`, `/api/products`, `/api/travels`. If the app is to be
|
||||||
|
a standalone entry point rather than a deep-link target, that is a second integration
|
||||||
|
project and should be scoped separately.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 4. Files
|
||||||
|
|
||||||
|
**New (representative):**
|
||||||
|
|
||||||
|
- `src/Controller/Api/App/` — one controller per resource, mirroring the public tree
|
||||||
|
- `src/Form/Service/Model/FieldDescriptor.php`
|
||||||
|
- `src/Form/Service/ParticipantFieldSchemaSerializer.php`
|
||||||
|
- `src/Service/BookingStateStoreInterface.php` + draft-backed implementation
|
||||||
|
- `src/Entity/BookingDraft.php` (generalised from `BookingEditDraft`) + migration
|
||||||
|
- Normalizers for `BusProNet\Model\*` value objects
|
||||||
|
- `tests/Controller/Api/App/`
|
||||||
|
|
||||||
|
**Modified:**
|
||||||
|
|
||||||
|
- `src/Form/Service/Contract/FieldStateProviderInterface.php` — drop the Form-coupled method
|
||||||
|
- `src/Form/Service/Abstract/AbstractFieldStateProvider.php`, `CreateFieldStateProvider.php`,
|
||||||
|
`EditFieldStateProvider.php`
|
||||||
|
- `src/Form/BookingParticipantType.php` — consume `FieldDescriptor`
|
||||||
|
- `src/Service/BookingSessionManager.php` — implement the store interface
|
||||||
|
- `config/packages/league_oauth2_server.yaml` — TTL, app client, scopes
|
||||||
|
- `docs/api-consumer-guide.md` / `docs/app-api/` — the contract
|
||||||
|
|
||||||
|
**Unchanged by design:** every `src/Form/Service/Condition/*`, every
|
||||||
|
`src/Form/Service/Participant*FieldHandler.php`, every `src/Validator/Constraints/*`, and
|
||||||
|
all pricing services. If an increment starts wanting to edit these, the design has drifted
|
||||||
|
— stop and reconsider.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 5. Working across two repos and two sessions
|
||||||
|
|
||||||
|
The RN work happens in a separate repo and a separate sandboxed session. The risk that
|
||||||
|
creates is **contract drift**: the app session guessing at response shapes, or worse,
|
||||||
|
re-deriving business rules in TypeScript because the JSON was ambiguous. That is the
|
||||||
|
original duplication problem arriving through a side door.
|
||||||
|
|
||||||
|
### The contract is an artifact in this repo
|
||||||
|
|
||||||
|
`docs/api-consumer-guide.md` already opens with *"It is self-contained: no access to this
|
||||||
|
codebase is required to use it."* That is the format. Extend it — or split out
|
||||||
|
`docs/app-api/guide.md` once it outgrows one file — **in the same commit as the endpoint**,
|
||||||
|
every time.
|
||||||
|
|
||||||
|
Rule: **the RN session never reads this PHP repo.** Its ground truth is the guide plus
|
||||||
|
fixtures. If it has to ask "what does the server send here?", the guide has a gap — fix
|
||||||
|
the guide, not the app.
|
||||||
|
|
||||||
|
### Fixtures decouple the sessions
|
||||||
|
|
||||||
|
Parity tests in `tests/Controller/Api/App/` write their JSON responses to
|
||||||
|
`docs/app-api/fixtures/*.json` (mirroring the existing `tests/Resources/*.xml`
|
||||||
|
convention). Commit them. The RN session mocks against those files, so app work never
|
||||||
|
waits on a deployed endpoint — and because they are test *output*, they cannot silently
|
||||||
|
go stale.
|
||||||
|
|
||||||
|
### Per-increment rhythm
|
||||||
|
|
||||||
|
1. **Backend session (here):** endpoint + parity test + fixtures + guide update.
|
||||||
|
2. **Handoff:** a short brief — endpoints now live, fixtures to mock, what changed in the
|
||||||
|
guide since last time.
|
||||||
|
3. **App session (RN repo):** build against fixtures first, then against DDEV.
|
||||||
|
4. **Joint verification:** run the increment end-to-end against a real backend.
|
||||||
|
|
||||||
|
Do not run both sessions on the same increment concurrently. Overlap by one stage: while
|
||||||
|
the app session builds increment *N*, start *N+1* here.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 6. Verification
|
||||||
|
|
||||||
|
Per increment:
|
||||||
|
|
||||||
|
1. `vendor/bin/phpunit` — 155 existing test files, notably `tests/Form/`, `tests/Service/`,
|
||||||
|
`tests/BusProNet/`. **Increment 4 must pass with no test changes.**
|
||||||
|
2. `vendor/bin/phpstan analyse` and `vendor/bin/php-cs-fixer fix --dry-run`.
|
||||||
|
3. `npx cypress run` — existing specs cover the web booking flow and guard against SDUI
|
||||||
|
refactors leaking into Twig rendering.
|
||||||
|
4. **Parity tests** under `tests/Controller/Api/App/`, asserting the JSON schema matches
|
||||||
|
what `BookingParticipantType` builds for the same `BookingDto`. This is the single most
|
||||||
|
valuable artifact in the project — it mechanically proves web and app share one rule set.
|
||||||
|
5. Manual: extend the existing `api.http` / `http-client.env.json` collection per increment.
|
||||||
|
6. End-to-end: run one booking through the RN client against a DDEV backend and confirm the
|
||||||
|
BPN payload is identical to a web-flow booking with the same inputs — compare via
|
||||||
|
`src/Controller/Admin/Log/XmlDumpController.php`.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 7. Open questions before Increment 6
|
||||||
|
|
||||||
|
- App-client access token TTL (Obstacle 3).
|
||||||
|
- How app registration populates the encrypted BPN password (Obstacle 4), and whether
|
||||||
|
guest/unauthenticated create is supported in the app as it is on the web via
|
||||||
|
`/bookings/create/init`.
|
||||||
|
- Draft retention and expiry policy.
|
||||||
|
- Whether the app deep-links from the CMS site or must own discovery (Increment 7).
|
||||||
Reference in New Issue
Block a user