@v-office/website-sdk 2.20.4 → 2.22.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -13,7 +13,8 @@ Use this directory as the consumer-facing reference for the package:
13
13
  - `search.md`: `sdk.live.search.search`.
14
14
  - `availability.md`: date-picker availability flows.
15
15
  - `quote.md`: quote booking-card modifiers, additional services, cancellation policy, and insurance flows.
16
- - `booking.md`: booking and payment option submission.
16
+ - `booking.md`: booking, payment option submission, and
17
+ `sdk.static.payment.getBankTransferDetails` (read-only bank details).
17
18
  - `contact.md`: contact submission.
18
19
  - `document-structured-json.md`: `sdk.static.documents.getTermsAndPrivacyPolicy` and structured document JSON rendering rules.
19
20
  - `CHANGELOG.md`: versioned changelog index.
@@ -134,6 +134,11 @@ Sample:
134
134
 
135
135
  `paymentOptions` is present only when the SDK can currently perform that payment. Future or on-site steps remain visible without payment options.
136
136
 
137
+ `lines` is present on a step or alternative only when the backend states a deposit
138
+ included in its amount. It contains the formatted deposit and, when nonzero, the
139
+ amount excluding the deposit. Without a stated deposit there are no `lines`;
140
+ never derive a deposit from `amount` and a percentage.
141
+
137
142
  An optional `insurancePaymentOptions` array is returned only when post-booking insurance payment is available.
138
143
 
139
144
  Sites upgrading from 2.12.0 must replace the former `paymentSchedules` output. See
@@ -141,11 +146,42 @@ Sites upgrading from 2.12.0 must replace the former `paymentSchedules` output. S
141
146
 
142
147
  Payment option variants:
143
148
 
144
- - `bank_transfer`: display-only payment details.
149
+ - `bank_transfer`: display-only payment details. `holder`, `iban`, `swiftOrBic` and
150
+ `institution` are the PMS payment settings' values; `holder`, `swiftOrBic` and
151
+ `institution` are absent when the PMS has none. `holder` is never another name:
152
+ render the row only when present. `remittanceText` is emitted on `v9`.
145
153
  - `redirect`: redirect the browser to the payment URL.
146
154
  - `form_post`: submit a generated HTML form, currently used for PayPal-style flows.
147
155
  - `stripe_checkout`: open Stripe Checkout. Emitted on `v9` only.
148
156
 
157
+ ## Bank Transfer Details
158
+
159
+ The bank details a guest is told to transfer to must be right before a site goes
160
+ live. On `v10`, read them without creating a booking:
161
+
162
+ ```ts
163
+ const accounts = await sdk.static.payment.getBankTransferDetails();
164
+ // [{ holder: "Example GmbH", iban: "DE02120300000000202051", swiftOrBic: "BYLADEM1001", institution: "Example Bank" }]
165
+ ```
166
+
167
+ Returns `Promise<ReadonlyArray<BookingBankTransferDetails>>`: the bank account of
168
+ the PMS's primary document settings, the same single account the booking output
169
+ shows, or an empty array when that account has no IBAN. Never placeholder values. The call runs the same PMS query and mapping the
170
+ booking output uses for its `bank_transfer` payment options, so what it returns
171
+ is exactly what the next booking's confirmation will show. It creates no booking,
172
+ reservation or other PMS write. Compare the result with the PMS payment settings
173
+ before launch, or run the CLI:
174
+
175
+ ```sh
176
+ website-sdk --backend v10 bank-transfer-details
177
+ ```
178
+
179
+ The call is not available on `v9`: the v9 hub exposes bank details only inside
180
+ a booking response. Do not verify them with a test booking against the v9 demo
181
+ hub: the demo hub and the production hub front the same PMS account, so a
182
+ booking through either is a real booking in the PMS. Verify the payment
183
+ settings in the PMS itself instead.
184
+
149
185
  ## Payment Submission
150
186
 
151
187
  Use `sdk.live.booking.submitPaymentOption(option)` or the top-level `submitPaymentOption(option)` export for every option except `bank_transfer`, which is display-only. Submission requires a browser environment and fails outside one.
@@ -374,6 +374,35 @@ requested locale; backend numeric amounts and modifier type keys are not exposed
374
374
  individual modifier lines. Exact-period results are returned in `items`;
375
375
  alternative-period suggestions are returned in root-level `alternatives`.
376
376
 
377
+ On legacy v9 only, an exact match may include `matchingPeriods` when the backend
378
+ chose the dates itself in a window search (`start`/`end` plus `minNights`/`maxNights`).
379
+ The field exists only on the v9 facade: `sdk.live.search.search` of a
380
+ `WebsiteSDKV9` returns `V9SearchSearchOutput`, whose items are
381
+ `V9SearchSearchOutputItem`. Narrow on `sdk.backend === "v9"` to read it. Each entry has the same shape as an `alternativePeriods` entry: `start`, `end`,
382
+ and the optional `formattedTotal` and `discount` for that period. Entries keep the
383
+ backend order. The item's own `formattedTotal` and `discount` are the price of the
384
+ first entry when that entry has one; otherwise they are the backend's overall price
385
+ for the hit. Show `matchingPeriods[0]` as the dates the card price is for, and open
386
+ the rental page with those dates so card and detail price agree. For a
387
+ fixed-period search without a window, the dates are the requested ones and
388
+ `matchingPeriods` is absent, never an empty array.
389
+
390
+ ```json
391
+ {
392
+ "id": "214950",
393
+ "nameOrLabel": "Ferienhaus Seeblick",
394
+ "timeZone": "Europe/Berlin",
395
+ "formattedTotal": "1.144,10 €",
396
+ "matchingPeriods": [
397
+ {
398
+ "start": "2026-10-01",
399
+ "end": "2026-10-08",
400
+ "formattedTotal": "1.144,10 €"
401
+ }
402
+ ]
403
+ }
404
+ ```
405
+
377
406
  `appliedFilters` reports what the backend actually applied, and is what a "remove
378
407
  this filter" chip should be built from. `label` is localized presentation and can
379
408
  repeat, so it cannot identify a filter; `key` plus `value` can. `value` is the
@@ -421,6 +450,10 @@ projection:
421
450
  and booking flow.
422
451
  - Pagination uses the backend `from`/`size` window behind the same opaque `cursor`,
423
452
  capped at 1,000 results.
453
+ - v10 items have no `matchingPeriods`. A v10 hit counts as exact only when its period
454
+ equals the requested fixed period; a hit the backend priced for other dates,
455
+ including every hit of a `minNights`/`maxNights` window search, is returned in
456
+ `alternatives` with its dates in `alternativePeriods`.
424
457
 
425
458
  ### Legacy v9
426
459
 
@@ -442,6 +475,12 @@ shape:
442
475
  formatted original total.
443
476
  - The same mapping applies to exact-period items and individual alternative
444
477
  periods.
478
+ - For an exact match, every `additional_voffice_data.matchingPeriods` entry with
479
+ both dates becomes a `matchingPeriods` entry (`fromdate`/`tilldate` become
480
+ `start`/`end`, its `calc` becomes the period's price fields); entries without
481
+ dates are dropped. In a window search the guest enters a window and a stay
482
+ length, not the stay itself. The backend returns the bookable stays inside the
483
+ window, earliest first; the SDK keeps that order.
445
484
  - v9 never executes a custom-attribute search filter.
446
485
 
447
486
  The field is omitted when v9 returns no final total or when its original total is
@@ -0,0 +1,46 @@
1
+ # Changelog: 2.21.0
2
+
3
+ Two faults in the v9 bank-transfer confirmation, found on a pilot one step
4
+ before go-live, and a read-only call to verify bank details before launch.
5
+
6
+ Against a v9 hub that sends no account holder, the SDK filled the
7
+ `bank_transfer` option's `holder` with the booking's customer name. Every
8
+ confirmation told the guest to pay an account held by themselves; with EU
9
+ payee-name verification the guest's bank flags that transfer as a name
10
+ mismatch. Separately, when the hub stated neither a booking total nor a deposit,
11
+ the SDK derived a total from the rounded prepayment and its percentage and
12
+ labelled the rounding remainder a deposit: a booking of 486.50 € with a 20 %
13
+ prepayment rounded to 97.00 € showed "486.50 €" with the lines "485.00 €" and a
14
+ deposit of "1.50 €".
15
+
16
+ ## Added
17
+
18
+ - `sdk.static.payment.getBankTransferDetails()` on `v10`: the bank account the
19
+ next booking's `bank_transfer` payment options will show (`holder?`, `iban`,
20
+ `swiftOrBic?`, `institution?`; at most one entry), read from the PMS's primary
21
+ document settings through the same query and mapping the booking output uses. Creates no booking. Empty when
22
+ the account offers no bank transfer. Not available on `v9`: the v9 hub exposes
23
+ bank details only inside a booking response, and its demo hub is not a sandbox
24
+ (see `booking.md`).
25
+ - CLI: `website-sdk --backend v10 bank-transfer-details`.
26
+
27
+ ## Changed
28
+
29
+ - `holder` on a `bank_transfer` payment option is optional. It is the PMS
30
+ payment settings' holder or absent; never the guest's name.
31
+ - `lines` on a payment step or the `full_amount` alternative are emitted only
32
+ when the hub states a deposit amount. They then read the deposit and, when
33
+ nonzero, the amount excluding it. Without a stated deposit there are no
34
+ lines; the step's `amount` stands alone.
35
+
36
+ ## Fixed
37
+
38
+ - `v9`: the `bank_transfer` holder is no longer the booking customer's name.
39
+ - `v9`: no deposit line is invented from a rounded prepayment. Nothing is
40
+ derived from percentages or totals any more.
41
+
42
+ ## Unchanged
43
+
44
+ - `payment.schedule` and `payment.alternatives` structure, amounts, labels,
45
+ `dueOn`, `remittanceText`, and the other payment option variants.
46
+ - The `v10` booking output apart from the optional `holder`.
@@ -0,0 +1,30 @@
1
+ # Migration: 2.20.4 to 2.21.0
2
+
3
+ ## 1. Upgrade
4
+
5
+ ```sh
6
+ pnpm add @v-office/website-sdk@2.21.0
7
+ ```
8
+
9
+ ## 2. Optional `holder`
10
+
11
+ `holder` on a `bank_transfer` payment option is now `string | undefined`.
12
+ Render the holder row only when it is present, as for `swiftOrBic` and
13
+ `institution`. A site that replaced the holder with its own value to work
14
+ around the guest-name fault can remove that workaround.
15
+
16
+ ## 3. Payment lines
17
+
18
+ `lines` on a payment step or alternative are absent unless the hub states a
19
+ deposit. A site that hid the lines to work around the invented deposit can
20
+ show them again.
21
+
22
+ ## 4. Verify bank details before launch (`v10`)
23
+
24
+ ```ts
25
+ const accounts = await sdk.static.payment.getBankTransferDetails();
26
+ ```
27
+
28
+ or `website-sdk --backend v10 bank-transfer-details`. Compare the result with
29
+ the PMS payment settings. On `v9` this call is not available; see the note in
30
+ `booking.md`.
@@ -0,0 +1,30 @@
1
+ # Changelog: 2.22.0
2
+
3
+ On a v9 hub, a search over a date window (`start`/`end` with `minNights`/`maxNights`)
4
+ lets the hub pick the stay itself: the earliest bookable stay in the window. Such a hit came back as an exact result with a price but without the
5
+ dates that price was for. A site could only link the rental page with the
6
+ window the guest typed, and the detail page then showed a different price than
7
+ the card.
8
+
9
+ ## Added
10
+
11
+ - `v9`: exact search results carry `matchingPeriods` when the hub chose the
12
+ dates. Each entry has `start`, `end` and the optional `formattedTotal` and
13
+ `discount` for that period, in the hub's order. The field is absent for a
14
+ fixed-period search, never an empty array.
15
+ - Types `V9SearchSearchOutput` and `V9SearchSearchOutputItem`.
16
+ `sdk.live.search.search` of a `WebsiteSDKV9` now returns
17
+ `V9SearchSearchOutput`; narrow on `sdk.backend === "v9"` to read
18
+ `matchingPeriods`.
19
+
20
+ ## Changed
21
+
22
+ - `v9`: the `formattedTotal` and `discount` of an exact result are the price of
23
+ its first `matchingPeriods` entry when that entry has a price.
24
+
25
+ ## Unchanged
26
+
27
+ - Fixed-period searches on v9: same items, same prices, no new field.
28
+ - Alternatives and their `alternativePeriods`.
29
+ - The v10 backend. v10 items have no `matchingPeriods`; a v10 hit for other
30
+ dates than the requested ones is still returned in `alternatives`.
@@ -0,0 +1,27 @@
1
+ # Migration: 2.21.0 to 2.22.0
2
+
3
+ ## 1. Upgrade
4
+
5
+ ```sh
6
+ pnpm add @v-office/website-sdk@2.22.0
7
+ ```
8
+
9
+ No changes are required. The v9 search result type is a superset of the
10
+ previous one, so existing code compiles and renders as before.
11
+
12
+ ## 2. Show the dates of a window-search hit (`v9`)
13
+
14
+ A v9 site that offers a date window with a night range should show
15
+ `matchingPeriods[0]` on the result card as the dates the price is for, and open
16
+ the rental page with those dates instead of the typed window. Card and detail
17
+ page then show the same price.
18
+
19
+ ```ts
20
+ if (sdk.backend === "v9") {
21
+ const output = await sdk.live.search.search(input);
22
+ for (const item of output.items) {
23
+ const period = item.matchingPeriods?.[0];
24
+ // period?.start, period?.end: dates for the card and the rental link
25
+ }
26
+ }
27
+ ```
@@ -1,4 +1,4 @@
1
- import { Ht as V9_FACILITY_ATTRIBUTE_KEYS } from "./client-BGeG3B_l.mjs";
1
+ import { Ut as V9_FACILITY_ATTRIBUTE_KEYS } from "./client-BtZ30vTP.mjs";
2
2
  import { c as parseVofficeUnitData, i as VofficeUnitDataPropertyMetadata, n as VofficeUnitDataPropertyCategoryLabelKeys, o as parseVofficeFacilityData, r as VofficeUnitDataPropertyCategoryValues, s as parseVofficeFeedbackData, t as VofficeUnitDataFieldSchemas } from "./v9-data-BnYxa2Ek.mjs";
3
3
  import { a as toAddress, c as rentalFacilitiesForObjectGroupRelationQuery, d as rentalsAllFeedbacksQuery, f as rentalsAllWithoutFeedbacksQuery, i as toImages, l as rentalIdsQuery, n as renderVofficePropertyAttribute, o as toLocalizedString, r as toFacilityImages, t as toRentalHighlights, u as rentalsAllByFacilityObjectGroupsWithoutFeedbacksQuery } from "./to-rental-highlights-CN-wpRh3.mjs";
4
4
  import { CoreSDKError, makeTranslate, renderResolvedCustomAttribute, toCustomAttributeList, toResolvedCustomAttributeCategoryTranslationKey } from "@v-office/sdk-core";
@@ -1,4 +1,4 @@
1
- import { a as parseQueryParameters, i as collectQueryParameters, n as makeV9CustomAttributeFilterCapabilities, o as toQueryString, r as toBasicQueryInputs, s as applyVofficeFilterDerivedBasicQueryInputs } from "./client-BGeG3B_l.mjs";
1
+ import { a as parseQueryParameters, i as collectQueryParameters, n as makeV9CustomAttributeFilterCapabilities, o as toQueryString, r as toBasicQueryInputs, s as applyVofficeFilterDerivedBasicQueryInputs } from "./client-BtZ30vTP.mjs";
2
2
  import { c as parseVofficeUnitData, t as VofficeUnitDataFieldSchemas } from "./v9-data-BnYxa2Ek.mjs";
3
3
  import { a as toAddress, i as toImages, s as searchQuery, t as toRentalHighlights } from "./to-rental-highlights-CN-wpRh3.mjs";
4
4
  import { CoreSDKError, STABLE_SEARCH_INPUTS, daysBetweenLocalDates, expandCustomAttributeFilterCompositions, parseChildrenAges, parseOccupancyCount, resolveExpandedCompositions, toFormattedSearchPrice, toIsoDateFromPeriodQueryDate, toStableSearchInputBackendQueryKeys, toStableSearchInputParameterValues, toStableSearchInputQueryKeys, toUnusedFilterKeys } from "@v-office/sdk-core";
@@ -235,12 +235,18 @@ const toQueryInput = ({ query, sort, customAttributeFilterDefinitions, locale, t
235
235
  //#region src/legacy-v9/parser/search/resolve-exact-match.ts
236
236
  const resolveExactMatch = (additionalData) => {
237
237
  const alternatives = additionalData?.alternatives ?? [];
238
- const calc = additionalData?.calc ?? additionalData?.matchingPeriods?.[0]?.calc;
239
- const isExactMatch = additionalData?.foundExactMatch === true || additionalData?.foundExactMatch == null && alternatives.length === 0 && calc != null;
238
+ const matchingPeriods = additionalData?.matchingPeriods ?? [];
239
+ const calcCandidates = [
240
+ matchingPeriods.find((period) => period.fromdate != null && period.tilldate != null)?.calc,
241
+ additionalData?.calc,
242
+ matchingPeriods[0]?.calc
243
+ ];
244
+ const calc = calcCandidates.find((candidate) => candidate?.total != null);
245
+ const isExactMatch = additionalData?.foundExactMatch === true || additionalData?.foundExactMatch == null && alternatives.length === 0 && calcCandidates.some((candidate) => candidate != null);
240
246
  return {
241
247
  isExactMatch,
242
248
  exactMatchCalc: isExactMatch ? calc : void 0,
243
- periods: isExactMatch ? [] : alternatives
249
+ periods: isExactMatch ? matchingPeriods : alternatives
244
250
  };
245
251
  };
246
252
  //#endregion
@@ -302,15 +308,15 @@ const toSearchOutputItem = ({ locale, imageProxyBaseUrl, rentalHighlightPrioriti
302
308
  return item;
303
309
  });
304
310
  //#endregion
305
- //#region src/legacy-v9/parser/search/output/to-alternative-periods.ts
306
- const toAlternativePeriods = ({ locale, alternatives }) => Effect.succeed((alternatives ?? []).flatMap((alternative) => {
307
- if (alternative.fromdate == null || alternative.tilldate == null) return [];
311
+ //#region src/legacy-v9/parser/search/output/to-search-periods.ts
312
+ const toSearchPeriods = ({ locale, periods }) => Effect.succeed((periods ?? []).flatMap((period) => {
313
+ if (period.fromdate == null || period.tilldate == null) return [];
308
314
  return [{
309
- start: alternative.fromdate,
310
- end: alternative.tilldate,
315
+ start: period.fromdate,
316
+ end: period.tilldate,
311
317
  ...toSearchPriceFields({
312
318
  locale,
313
- calc: alternative.calc
319
+ calc: period.calc
314
320
  })
315
321
  }];
316
322
  }));
@@ -318,4 +324,4 @@ const toAlternativePeriods = ({ locale, alternatives }) => Effect.succeed((alter
318
324
  //#region src/legacy-v9/runtime/search.ts
319
325
  const defaultSearchDataAttributes = Object.keys(VofficeUnitDataFieldSchemas);
320
326
  //#endregion
321
- export { defaultSearchDataAttributes, resolveExactMatch, searchQuery, toAlternativePeriods, toQueryInput, toSearchOutputItem };
327
+ export { defaultSearchDataAttributes, resolveExactMatch, searchQuery, toQueryInput, toSearchOutputItem, toSearchPeriods };
@@ -4,6 +4,8 @@
4
4
 
5
5
  Release notes of `@v-office/website-sdk`, newest first. Each version has its own directory.
6
6
 
7
+ - `versions/2.22.0/CHANGELOG.md`: release notes for 2.22.0
8
+ - `versions/2.21.0/CHANGELOG.md`: release notes for 2.21.0
7
9
  - `versions/2.20.4/CHANGELOG.md`: release notes for 2.20.4
8
10
  - `versions/2.20.3/CHANGELOG.md`: release notes for 2.20.3
9
11
  - `versions/2.20.2/CHANGELOG.md`: release notes for 2.20.2
@@ -4,6 +4,8 @@
4
4
 
5
5
  Migration guides of `@v-office/website-sdk`, newest first. Apply them in order when skipping versions.
6
6
 
7
+ - `versions/2.22.0/MIGRATION.md`: Migration: 2.21.0 to 2.22.0
8
+ - `versions/2.21.0/MIGRATION.md`: Migration: 2.20.4 to 2.21.0
7
9
  - `versions/2.20.4/MIGRATION.md`: Migration: 2.20.3 to 2.20.4
8
10
  - `versions/2.20.3/MIGRATION.md`: Migration: 2.20.2 to 2.20.3
9
11
  - `versions/2.20.2/MIGRATION.md`: Migration: 2.20.1 to 2.20.2
@@ -13,7 +13,8 @@ Use this directory as the consumer-facing reference for the package:
13
13
  - `search.md`: `sdk.live.search.search`.
14
14
  - `availability.md`: date-picker availability flows.
15
15
  - `quote.md`: quote booking-card modifiers, additional services, cancellation policy, and insurance flows.
16
- - `booking.md`: booking and payment option submission.
16
+ - `booking.md`: booking, payment option submission, and
17
+ `sdk.static.payment.getBankTransferDetails` (read-only bank details).
17
18
  - `contact.md`: contact submission.
18
19
  - `document-structured-json.md`: `sdk.static.documents.getTermsAndPrivacyPolicy` and structured document JSON rendering rules.
19
20
  - `CHANGELOG.md`: versioned changelog index.
@@ -134,6 +134,11 @@ Sample:
134
134
 
135
135
  `paymentOptions` is present only when the SDK can currently perform that payment. Future or on-site steps remain visible without payment options.
136
136
 
137
+ `lines` is present on a step or alternative only when the backend states a deposit
138
+ included in its amount. It contains the formatted deposit and, when nonzero, the
139
+ amount excluding the deposit. Without a stated deposit there are no `lines`;
140
+ never derive a deposit from `amount` and a percentage.
141
+
137
142
  An optional `insurancePaymentOptions` array is returned only when post-booking insurance payment is available.
138
143
 
139
144
  Sites upgrading from 2.12.0 must replace the former `paymentSchedules` output. See
@@ -141,11 +146,42 @@ Sites upgrading from 2.12.0 must replace the former `paymentSchedules` output. S
141
146
 
142
147
  Payment option variants:
143
148
 
144
- - `bank_transfer`: display-only payment details.
149
+ - `bank_transfer`: display-only payment details. `holder`, `iban`, `swiftOrBic` and
150
+ `institution` are the PMS payment settings' values; `holder`, `swiftOrBic` and
151
+ `institution` are absent when the PMS has none. `holder` is never another name:
152
+ render the row only when present. `remittanceText` is emitted on `v9`.
145
153
  - `redirect`: redirect the browser to the payment URL.
146
154
  - `form_post`: submit a generated HTML form, currently used for PayPal-style flows.
147
155
  - `stripe_checkout`: open Stripe Checkout. Emitted on `v9` only.
148
156
 
157
+ ## Bank Transfer Details
158
+
159
+ The bank details a guest is told to transfer to must be right before a site goes
160
+ live. On `v10`, read them without creating a booking:
161
+
162
+ ```ts
163
+ const accounts = await sdk.static.payment.getBankTransferDetails();
164
+ // [{ holder: "Example GmbH", iban: "DE02120300000000202051", swiftOrBic: "BYLADEM1001", institution: "Example Bank" }]
165
+ ```
166
+
167
+ Returns `Promise<ReadonlyArray<BookingBankTransferDetails>>`: the bank account of
168
+ the PMS's primary document settings, the same single account the booking output
169
+ shows, or an empty array when that account has no IBAN. Never placeholder values. The call runs the same PMS query and mapping the
170
+ booking output uses for its `bank_transfer` payment options, so what it returns
171
+ is exactly what the next booking's confirmation will show. It creates no booking,
172
+ reservation or other PMS write. Compare the result with the PMS payment settings
173
+ before launch, or run the CLI:
174
+
175
+ ```sh
176
+ website-sdk --backend v10 bank-transfer-details
177
+ ```
178
+
179
+ The call is not available on `v9`: the v9 hub exposes bank details only inside
180
+ a booking response. Do not verify them with a test booking against the v9 demo
181
+ hub: the demo hub and the production hub front the same PMS account, so a
182
+ booking through either is a real booking in the PMS. Verify the payment
183
+ settings in the PMS itself instead.
184
+
149
185
  ## Payment Submission
150
186
 
151
187
  Use `sdk.live.booking.submitPaymentOption(option)` or the top-level `submitPaymentOption(option)` export for every option except `bank_transfer`, which is display-only. Submission requires a browser environment and fails outside one.
@@ -374,6 +374,35 @@ requested locale; backend numeric amounts and modifier type keys are not exposed
374
374
  individual modifier lines. Exact-period results are returned in `items`;
375
375
  alternative-period suggestions are returned in root-level `alternatives`.
376
376
 
377
+ On legacy v9 only, an exact match may include `matchingPeriods` when the backend
378
+ chose the dates itself in a window search (`start`/`end` plus `minNights`/`maxNights`).
379
+ The field exists only on the v9 facade: `sdk.live.search.search` of a
380
+ `WebsiteSDKV9` returns `V9SearchSearchOutput`, whose items are
381
+ `V9SearchSearchOutputItem`. Narrow on `sdk.backend === "v9"` to read it. Each entry has the same shape as an `alternativePeriods` entry: `start`, `end`,
382
+ and the optional `formattedTotal` and `discount` for that period. Entries keep the
383
+ backend order. The item's own `formattedTotal` and `discount` are the price of the
384
+ first entry when that entry has one; otherwise they are the backend's overall price
385
+ for the hit. Show `matchingPeriods[0]` as the dates the card price is for, and open
386
+ the rental page with those dates so card and detail price agree. For a
387
+ fixed-period search without a window, the dates are the requested ones and
388
+ `matchingPeriods` is absent, never an empty array.
389
+
390
+ ```json
391
+ {
392
+ "id": "214950",
393
+ "nameOrLabel": "Ferienhaus Seeblick",
394
+ "timeZone": "Europe/Berlin",
395
+ "formattedTotal": "1.144,10 €",
396
+ "matchingPeriods": [
397
+ {
398
+ "start": "2026-10-01",
399
+ "end": "2026-10-08",
400
+ "formattedTotal": "1.144,10 €"
401
+ }
402
+ ]
403
+ }
404
+ ```
405
+
377
406
  `appliedFilters` reports what the backend actually applied, and is what a "remove
378
407
  this filter" chip should be built from. `label` is localized presentation and can
379
408
  repeat, so it cannot identify a filter; `key` plus `value` can. `value` is the
@@ -421,6 +450,10 @@ projection:
421
450
  and booking flow.
422
451
  - Pagination uses the backend `from`/`size` window behind the same opaque `cursor`,
423
452
  capped at 1,000 results.
453
+ - v10 items have no `matchingPeriods`. A v10 hit counts as exact only when its period
454
+ equals the requested fixed period; a hit the backend priced for other dates,
455
+ including every hit of a `minNights`/`maxNights` window search, is returned in
456
+ `alternatives` with its dates in `alternativePeriods`.
424
457
 
425
458
  ### Legacy v9
426
459
 
@@ -442,6 +475,12 @@ shape:
442
475
  formatted original total.
443
476
  - The same mapping applies to exact-period items and individual alternative
444
477
  periods.
478
+ - For an exact match, every `additional_voffice_data.matchingPeriods` entry with
479
+ both dates becomes a `matchingPeriods` entry (`fromdate`/`tilldate` become
480
+ `start`/`end`, its `calc` becomes the period's price fields); entries without
481
+ dates are dropped. In a window search the guest enters a window and a stay
482
+ length, not the stay itself. The backend returns the bookable stays inside the
483
+ window, earliest first; the SDK keeps that order.
445
484
  - v9 never executes a custom-attribute search filter.
446
485
 
447
486
  The field is omitted when v9 returns no final total or when its original total is
@@ -0,0 +1,46 @@
1
+ # Changelog: 2.21.0
2
+
3
+ Two faults in the v9 bank-transfer confirmation, found on a pilot one step
4
+ before go-live, and a read-only call to verify bank details before launch.
5
+
6
+ Against a v9 hub that sends no account holder, the SDK filled the
7
+ `bank_transfer` option's `holder` with the booking's customer name. Every
8
+ confirmation told the guest to pay an account held by themselves; with EU
9
+ payee-name verification the guest's bank flags that transfer as a name
10
+ mismatch. Separately, when the hub stated neither a booking total nor a deposit,
11
+ the SDK derived a total from the rounded prepayment and its percentage and
12
+ labelled the rounding remainder a deposit: a booking of 486.50 € with a 20 %
13
+ prepayment rounded to 97.00 € showed "486.50 €" with the lines "485.00 €" and a
14
+ deposit of "1.50 €".
15
+
16
+ ## Added
17
+
18
+ - `sdk.static.payment.getBankTransferDetails()` on `v10`: the bank account the
19
+ next booking's `bank_transfer` payment options will show (`holder?`, `iban`,
20
+ `swiftOrBic?`, `institution?`; at most one entry), read from the PMS's primary
21
+ document settings through the same query and mapping the booking output uses. Creates no booking. Empty when
22
+ the account offers no bank transfer. Not available on `v9`: the v9 hub exposes
23
+ bank details only inside a booking response, and its demo hub is not a sandbox
24
+ (see `booking.md`).
25
+ - CLI: `website-sdk --backend v10 bank-transfer-details`.
26
+
27
+ ## Changed
28
+
29
+ - `holder` on a `bank_transfer` payment option is optional. It is the PMS
30
+ payment settings' holder or absent; never the guest's name.
31
+ - `lines` on a payment step or the `full_amount` alternative are emitted only
32
+ when the hub states a deposit amount. They then read the deposit and, when
33
+ nonzero, the amount excluding it. Without a stated deposit there are no
34
+ lines; the step's `amount` stands alone.
35
+
36
+ ## Fixed
37
+
38
+ - `v9`: the `bank_transfer` holder is no longer the booking customer's name.
39
+ - `v9`: no deposit line is invented from a rounded prepayment. Nothing is
40
+ derived from percentages or totals any more.
41
+
42
+ ## Unchanged
43
+
44
+ - `payment.schedule` and `payment.alternatives` structure, amounts, labels,
45
+ `dueOn`, `remittanceText`, and the other payment option variants.
46
+ - The `v10` booking output apart from the optional `holder`.
@@ -0,0 +1,30 @@
1
+ # Migration: 2.20.4 to 2.21.0
2
+
3
+ ## 1. Upgrade
4
+
5
+ ```sh
6
+ pnpm add @v-office/website-sdk@2.21.0
7
+ ```
8
+
9
+ ## 2. Optional `holder`
10
+
11
+ `holder` on a `bank_transfer` payment option is now `string | undefined`.
12
+ Render the holder row only when it is present, as for `swiftOrBic` and
13
+ `institution`. A site that replaced the holder with its own value to work
14
+ around the guest-name fault can remove that workaround.
15
+
16
+ ## 3. Payment lines
17
+
18
+ `lines` on a payment step or alternative are absent unless the hub states a
19
+ deposit. A site that hid the lines to work around the invented deposit can
20
+ show them again.
21
+
22
+ ## 4. Verify bank details before launch (`v10`)
23
+
24
+ ```ts
25
+ const accounts = await sdk.static.payment.getBankTransferDetails();
26
+ ```
27
+
28
+ or `website-sdk --backend v10 bank-transfer-details`. Compare the result with
29
+ the PMS payment settings. On `v9` this call is not available; see the note in
30
+ `booking.md`.
@@ -0,0 +1,3 @@
1
+ {
2
+ "componentsAffectedByHeadlessChange": []
3
+ }
@@ -0,0 +1,30 @@
1
+ # Changelog: 2.22.0
2
+
3
+ On a v9 hub, a search over a date window (`start`/`end` with `minNights`/`maxNights`)
4
+ lets the hub pick the stay itself: the earliest bookable stay in the window. Such a hit came back as an exact result with a price but without the
5
+ dates that price was for. A site could only link the rental page with the
6
+ window the guest typed, and the detail page then showed a different price than
7
+ the card.
8
+
9
+ ## Added
10
+
11
+ - `v9`: exact search results carry `matchingPeriods` when the hub chose the
12
+ dates. Each entry has `start`, `end` and the optional `formattedTotal` and
13
+ `discount` for that period, in the hub's order. The field is absent for a
14
+ fixed-period search, never an empty array.
15
+ - Types `V9SearchSearchOutput` and `V9SearchSearchOutputItem`.
16
+ `sdk.live.search.search` of a `WebsiteSDKV9` now returns
17
+ `V9SearchSearchOutput`; narrow on `sdk.backend === "v9"` to read
18
+ `matchingPeriods`.
19
+
20
+ ## Changed
21
+
22
+ - `v9`: the `formattedTotal` and `discount` of an exact result are the price of
23
+ its first `matchingPeriods` entry when that entry has a price.
24
+
25
+ ## Unchanged
26
+
27
+ - Fixed-period searches on v9: same items, same prices, no new field.
28
+ - Alternatives and their `alternativePeriods`.
29
+ - The v10 backend. v10 items have no `matchingPeriods`; a v10 hit for other
30
+ dates than the requested ones is still returned in `alternatives`.
@@ -0,0 +1,27 @@
1
+ # Migration: 2.21.0 to 2.22.0
2
+
3
+ ## 1. Upgrade
4
+
5
+ ```sh
6
+ pnpm add @v-office/website-sdk@2.22.0
7
+ ```
8
+
9
+ No changes are required. The v9 search result type is a superset of the
10
+ previous one, so existing code compiles and renders as before.
11
+
12
+ ## 2. Show the dates of a window-search hit (`v9`)
13
+
14
+ A v9 site that offers a date window with a night range should show
15
+ `matchingPeriods[0]` on the result card as the dates the price is for, and open
16
+ the rental page with those dates instead of the typed window. Card and detail
17
+ page then show the same price.
18
+
19
+ ```ts
20
+ if (sdk.backend === "v9") {
21
+ const output = await sdk.live.search.search(input);
22
+ for (const item of output.items) {
23
+ const period = item.matchingPeriods?.[0];
24
+ // period?.start, period?.end: dates for the card and the rental link
25
+ }
26
+ }
27
+ ```
@@ -0,0 +1,3 @@
1
+ {
2
+ "componentsAffectedByHeadlessChange": ["searchResults"]
3
+ }