@v-office/website-sdk 2.10.0 → 2.12.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.
- package/README.md +7 -3
- package/dist/cli.d.mts +1 -1
- package/dist/cli.mjs +2 -2
- package/dist/{client-DYAHnU5F.mjs → client-Bmxh2SAu.mjs} +54 -30
- package/dist/index.d.mts +590 -291
- package/dist/index.mjs +1 -1
- package/dist/instructions/CHANGELOG.md +2 -0
- package/dist/instructions/MIGRATION.md +2 -0
- package/dist/instructions/README.md +10 -3
- package/dist/instructions/quote.md +95 -3
- package/dist/instructions/search.md +118 -13
- package/dist/instructions/versions/2.11.0/CHANGELOG.md +28 -0
- package/dist/instructions/versions/2.11.0/MIGRATION.md +72 -0
- package/dist/instructions/versions/2.12.0/CHANGELOG.md +56 -0
- package/dist/instructions/versions/2.12.0/MIGRATION.md +194 -0
- package/dist/instructions/versions/2.5.0/MIGRATION.md +6 -0
- package/dist/{quote-Cs6jGoRS.mjs → quote-Qy_affum.mjs} +4 -4
- package/dist/{rentals-CFod9H4m.mjs → rentals-BG1diZoo.mjs} +7 -4
- package/dist/{search-QlZrI7ue.mjs → search-BlL8vSPY.mjs} +39 -19
- package/dist/{to-rental-highlights-B6a_fi0j.mjs → to-rental-highlights-BVikT4Iz.mjs} +4 -2
- package/instructions/CHANGELOG.md +2 -0
- package/instructions/MIGRATION.md +2 -0
- package/instructions/README.md +10 -3
- package/instructions/quote.md +95 -3
- package/instructions/search.md +118 -13
- package/instructions/versions/2.11.0/CHANGELOG.md +28 -0
- package/instructions/versions/2.11.0/MIGRATION.md +72 -0
- package/instructions/versions/2.12.0/CHANGELOG.md +56 -0
- package/instructions/versions/2.12.0/MIGRATION.md +194 -0
- package/instructions/versions/2.5.0/MIGRATION.md +6 -0
- package/package.json +15 -13
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
# Migration: 2.11.0 to 2.12.0
|
|
2
|
+
|
|
3
|
+
2.12.0 adds optional discount information to priced legacy v9 search results,
|
|
4
|
+
normalizes empty quote booking-card lines across v9 and v10, and completes v10
|
|
5
|
+
card-level pre-modifier totals across all modifier presentation paths. It also
|
|
6
|
+
rejects unsupported v9 flexible-period searches before transport and restores
|
|
7
|
+
empty-query inventory browsing on v9. Existing supported calls remain valid
|
|
8
|
+
without changes.
|
|
9
|
+
|
|
10
|
+
## 1. Reuse the Shared Discount Output
|
|
11
|
+
|
|
12
|
+
Legacy v9 now uses the same optional shape introduced for v10 in 2.11.0:
|
|
13
|
+
|
|
14
|
+
```ts
|
|
15
|
+
type SearchDiscount = {
|
|
16
|
+
readonly formattedOriginalTotal: string;
|
|
17
|
+
readonly applied: readonly {
|
|
18
|
+
readonly label: string;
|
|
19
|
+
readonly formattedAmount: string;
|
|
20
|
+
}[];
|
|
21
|
+
};
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
For exact-period results, read `discount` from the item:
|
|
25
|
+
|
|
26
|
+
```ts
|
|
27
|
+
result.items[0]?.discount;
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
For nearby suggestions, read it from the individual alternative period:
|
|
31
|
+
|
|
32
|
+
```ts
|
|
33
|
+
result.alternatives?.[0]?.alternativePeriods[0]?.discount;
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
## 2. Understand the Legacy v9 Mapping
|
|
37
|
+
|
|
38
|
+
For priced v9 results:
|
|
39
|
+
|
|
40
|
+
- `calc.total` remains the final `formattedTotal`.
|
|
41
|
+
- `discount` is present only when `calc.oTotal` is greater than `calc.total`.
|
|
42
|
+
- `discount.formattedOriginalTotal` is formatted from `calc.oTotal`.
|
|
43
|
+
- A non-empty `calc.discountName` becomes the label of the single applied entry.
|
|
44
|
+
- The applied amount is the formatted negative difference
|
|
45
|
+
`calc.total - calc.oTotal`.
|
|
46
|
+
- If the backend supplies no usable discount name, `applied` is empty while the
|
|
47
|
+
formatted original total remains available.
|
|
48
|
+
|
|
49
|
+
The SDK omits `discount` when there is no final total or when the original total is
|
|
50
|
+
not greater than the final total.
|
|
51
|
+
|
|
52
|
+
## 3. Account for Backend Detail Differences
|
|
53
|
+
|
|
54
|
+
v9 exposes one aggregated discount name and therefore returns at most one
|
|
55
|
+
`discount.applied` entry. v10 search can expose multiple `discount.applied`
|
|
56
|
+
entries. Consumers should render the array without assuming a fixed length.
|
|
57
|
+
|
|
58
|
+
Both backends return presentation-ready localized strings. Backend numeric amounts
|
|
59
|
+
and internal modifier keys are not part of the public output.
|
|
60
|
+
|
|
61
|
+
## 4. Account for Booking-Card Cleanup
|
|
62
|
+
|
|
63
|
+
Quote booking cards on both backends now omit numeric zero-value lines without
|
|
64
|
+
subitems from the `other` section, matching the existing handling of included and
|
|
65
|
+
tax sections.
|
|
66
|
+
|
|
67
|
+
- A zero-only `other` section is omitted.
|
|
68
|
+
- A mixed `other` section retains its non-zero lines unchanged.
|
|
69
|
+
- Lines with subitems remain available because they still carry descriptive
|
|
70
|
+
content.
|
|
71
|
+
|
|
72
|
+
No required booking-card property was added and the public schema remains
|
|
73
|
+
source-compatible. Runtime output can contain fewer empty rows. Sites that used a
|
|
74
|
+
zero-value row to represent a declined service should use explicit selection or
|
|
75
|
+
service state instead of inferring that state from the price breakdown.
|
|
76
|
+
|
|
77
|
+
## 5. Render v10 Quote Modifiers
|
|
78
|
+
|
|
79
|
+
On v10, an item at `bookingCardInformation.sections[].lines[].item` can include:
|
|
80
|
+
|
|
81
|
+
```ts
|
|
82
|
+
{
|
|
83
|
+
modifiers?: readonly {
|
|
84
|
+
label: string;
|
|
85
|
+
amount: string;
|
|
86
|
+
}[];
|
|
87
|
+
totalBeforeModifiers?: string;
|
|
88
|
+
}
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
The card can also include `bookingCardInformation.totalBeforeModifiers`.
|
|
92
|
+
`appliedCharge` and `total` are the final amounts after modifiers. The
|
|
93
|
+
corresponding `totalBeforeModifiers` is the formatted amount before modifiers and
|
|
94
|
+
is omitted when there is no non-zero net modifier effect. `modifiers` is omitted
|
|
95
|
+
when the item has none; entries with the same localized label are grouped and
|
|
96
|
+
their amounts are summed before formatting.
|
|
97
|
+
|
|
98
|
+
Included, tax, and other lines attach their adjustments to `item.modifiers`.
|
|
99
|
+
Negative modifiers from backend lines that do not map to those sections may
|
|
100
|
+
instead appear as dedicated booking-card lines. In 2.12.0, card-level
|
|
101
|
+
`totalBeforeModifiers` accounts for both forms. v9 quote cards omit these fields.
|
|
102
|
+
|
|
103
|
+
Example for `de-DE`:
|
|
104
|
+
|
|
105
|
+
```json
|
|
106
|
+
{
|
|
107
|
+
"bookingCardInformation": {
|
|
108
|
+
"sections": [
|
|
109
|
+
{
|
|
110
|
+
"lines": [
|
|
111
|
+
{
|
|
112
|
+
"item": {
|
|
113
|
+
"position": "Inklusivpreis",
|
|
114
|
+
"appliedCharge": "1.554,00 €",
|
|
115
|
+
"modifiers": [
|
|
116
|
+
{
|
|
117
|
+
"label": "Frühbucher/Last-Minute",
|
|
118
|
+
"amount": "-140,00 €"
|
|
119
|
+
}
|
|
120
|
+
],
|
|
121
|
+
"totalBeforeModifiers": "1.694,00 €"
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
]
|
|
125
|
+
}
|
|
126
|
+
],
|
|
127
|
+
"total": "1.596,70 €",
|
|
128
|
+
"totalBeforeModifiers": "1.736,70 €"
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
Do not assume a voucher appears as its own section line. Use
|
|
134
|
+
`quote.voucher.status` for voucher application status and the booking-card fields
|
|
135
|
+
for price presentation. To keep price arithmetic visible, render the pre-modifier
|
|
136
|
+
amount, modifier rows, and final amount separately. Whether to display or strike
|
|
137
|
+
through a reference price remains the consuming site's product and legal
|
|
138
|
+
decision.
|
|
139
|
+
|
|
140
|
+
## 6. Keep Flexible Search Disabled on v9
|
|
141
|
+
|
|
142
|
+
No configuration or supported request migration is required. Legacy v9 now rejects
|
|
143
|
+
the unsupported flexible-period keys `month`, `dates`, `nights`, and `weekend`
|
|
144
|
+
before transport instead of silently returning an unpriced item list. Keep
|
|
145
|
+
flexible search unavailable on v9 sites and use fixed `start`/`end` period
|
|
146
|
+
queries. v10 flexible search is unchanged.
|
|
147
|
+
|
|
148
|
+
The rejection is a `CoreSDKError` with operation `v9.search` and occurs before a
|
|
149
|
+
GraphQL request is sent. The public `SearchSearchInput` type remains unchanged
|
|
150
|
+
because its `query` field is an opaque query string.
|
|
151
|
+
|
|
152
|
+
This release enriches v9 search output when its existing response contains
|
|
153
|
+
sufficient discount data, removes empty quote breakdown rows from both backends,
|
|
154
|
+
and can return the existing optional card-level `totalBeforeModifiers` in
|
|
155
|
+
additional v10 cases.
|
|
156
|
+
|
|
157
|
+
## 7. Remove Dummy Occupancy from Empty v9 Searches
|
|
158
|
+
|
|
159
|
+
Legacy v9 now sends an empty backend-filter set as GraphQL `data: null` instead of
|
|
160
|
+
`data: []`. An empty query can therefore browse the first page of searchable
|
|
161
|
+
inventory under the configured rental scope:
|
|
162
|
+
|
|
163
|
+
```ts
|
|
164
|
+
await sdk.live.search.search({
|
|
165
|
+
locale: "de-DE",
|
|
166
|
+
query: "",
|
|
167
|
+
});
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
Remove workarounds that inject `adults=1` only to make an empty query return
|
|
171
|
+
results. Real occupancy, period, and non-empty backend filters keep their existing
|
|
172
|
+
mapping. Pagination and `limit` still apply, and an undated result does not assert
|
|
173
|
+
availability for a particular stay.
|
|
174
|
+
|
|
175
|
+
## Recommended Verification
|
|
176
|
+
|
|
177
|
+
1. Run a priced v9 exact-period search where the original total exceeds the final
|
|
178
|
+
total and verify the formatted values and label.
|
|
179
|
+
2. Verify discounted v9 alternative periods independently.
|
|
180
|
+
3. Run a v9 search without a discount and confirm existing rendering is unchanged.
|
|
181
|
+
4. Verify a missing v9 discount name produces an empty `applied` array.
|
|
182
|
+
5. Verify v9 rejects `month`, `dates`, `nights`, and `weekend` before transport.
|
|
183
|
+
6. Run an empty v9 query and confirm it returns searchable inventory without a
|
|
184
|
+
dummy occupancy value.
|
|
185
|
+
7. Recheck a discounted v10 search and confirm its existing multi-entry behavior
|
|
186
|
+
remains unchanged.
|
|
187
|
+
8. Quote a v9 and v10 rental with a zero-value `other` service and confirm the
|
|
188
|
+
empty section is absent.
|
|
189
|
+
9. Confirm a mixed `other` section retains only its non-zero lines.
|
|
190
|
+
10. Quote a discounted v10 rental and render `item.modifiers`, item-level
|
|
191
|
+
`totalBeforeModifiers`, and card-level `totalBeforeModifiers`.
|
|
192
|
+
11. Confirm a v9 quote continues to omit the modifier fields.
|
|
193
|
+
12. Verify a v10 modifier rendered as a dedicated line still contributes to the
|
|
194
|
+
card-level `totalBeforeModifiers`.
|
|
@@ -121,6 +121,12 @@ The public output type is unchanged, but v10 search cards now reflect the REST p
|
|
|
121
121
|
- `property` is the minimal `{ id, nameOrLabel }` shape. Hydrate `property.location`, `property.images`, or `property.address` from `sdk.static.rentals.getRentals(...)` when a search card needs them.
|
|
122
122
|
- Exact-period matches are returned in `items` with `formattedTotal`; nearby suggestions are returned in root-level `alternatives`, unchanged.
|
|
123
123
|
|
|
124
|
+
Starting with 2.11.0, priced v10 items and alternative periods may also include
|
|
125
|
+
optional localized `discount` details. See `../../search.md`.
|
|
126
|
+
|
|
127
|
+
Starting with 2.12.0, legacy v9 maps the same optional shape from its aggregated
|
|
128
|
+
original total and discount name when the original total exceeds the final total.
|
|
129
|
+
|
|
124
130
|
## Backend Behavior
|
|
125
131
|
|
|
126
132
|
- Fixed-period and flexible searches are priced by the REST backend; occupancy is required for priced searches.
|
|
@@ -241,12 +241,12 @@ const toSections = ({ input, guestQuoteResult, locale, translations }) => Effect
|
|
|
241
241
|
locale,
|
|
242
242
|
translations
|
|
243
243
|
});
|
|
244
|
-
const
|
|
244
|
+
const sectionsOtherWithContent = (yield* toSectionsOther({
|
|
245
245
|
input,
|
|
246
246
|
guestQuoteResult,
|
|
247
247
|
locale,
|
|
248
248
|
translations
|
|
249
|
-
});
|
|
249
|
+
})).filter(hasSectionLineContent);
|
|
250
250
|
if (hasSectionLineContent(sectionsIncluded)) sections.push({
|
|
251
251
|
lines: [sectionsIncluded],
|
|
252
252
|
displayOrder: GuestQuoteBookingCardDisplayOrder.inclusive
|
|
@@ -255,8 +255,8 @@ const toSections = ({ input, guestQuoteResult, locale, translations }) => Effect
|
|
|
255
255
|
lines: [sectionsTax],
|
|
256
256
|
displayOrder: GuestQuoteBookingCardDisplayOrder.tax
|
|
257
257
|
});
|
|
258
|
-
if (
|
|
259
|
-
lines:
|
|
258
|
+
if (sectionsOtherWithContent.length > 0) sections.push({
|
|
259
|
+
lines: sectionsOtherWithContent,
|
|
260
260
|
displayOrder: GuestQuoteBookingCardDisplayOrder.other
|
|
261
261
|
});
|
|
262
262
|
return sections;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { c as VofficeUnitDataFieldSchemas, d as VofficeUnitDataPropertyMetadata, f as parseVofficeFacilityData, i as toLocalizedString, l as VofficeUnitDataPropertyCategoryLabelKeys, m as parseVofficeUnitData, n as toImages, o as rentalsAllFeedbacksQuery, p as parseVofficeFeedbackData, r as toAddress, s as rentalsAllWithoutFeedbacksQuery, t as toRentalHighlights, u as VofficeUnitDataPropertyCategoryValues } from "./to-rental-highlights-
|
|
1
|
+
import { c as VofficeUnitDataFieldSchemas, d as VofficeUnitDataPropertyMetadata, f as parseVofficeFacilityData, i as toLocalizedString, l as VofficeUnitDataPropertyCategoryLabelKeys, m as parseVofficeUnitData, n as toImages, o as rentalsAllFeedbacksQuery, p as parseVofficeFeedbackData, r as toAddress, s as rentalsAllWithoutFeedbacksQuery, t as toRentalHighlights, u as VofficeUnitDataPropertyCategoryValues } from "./to-rental-highlights-BVikT4Iz.mjs";
|
|
2
2
|
import { makeTranslate, renderLabeledAttributeValue, renderResolvedCustomAttribute, toCustomAttributeList, toResolvedCustomAttributeCategoryTranslationKey } from "@v-office/sdk-core";
|
|
3
3
|
import { Effect } from "effect";
|
|
4
4
|
//#region src/legacy-v9/parser/rentals/to-description.ts
|
|
@@ -91,9 +91,10 @@ const toRentalAttributes = ({ locale, translations, attributes, customAttributes
|
|
|
91
91
|
for (const { key, metadata } of PROPERTY_METADATA_ENTRIES) {
|
|
92
92
|
const value = knownAttributes[key];
|
|
93
93
|
if (!canRenderLabeledAttributeValue$1(value)) continue;
|
|
94
|
+
const label = yield* translate(metadata.labelKey, key);
|
|
94
95
|
const attribute = renderLabeledAttributeValue({
|
|
95
96
|
key,
|
|
96
|
-
label
|
|
97
|
+
label,
|
|
97
98
|
locale,
|
|
98
99
|
value
|
|
99
100
|
});
|
|
@@ -154,9 +155,10 @@ const toRentalVicinity = ({ locale, translations, attributes }) => Effect.gen(fu
|
|
|
154
155
|
for (const { key, metadata } of LOCATION_METADATA_ENTRIES) {
|
|
155
156
|
const value = knownAttributes[key];
|
|
156
157
|
if (!canRenderLabeledAttributeValue(value)) continue;
|
|
158
|
+
const label = yield* translate(metadata.labelKey, key);
|
|
157
159
|
const item = renderLabeledAttributeValue({
|
|
158
160
|
key,
|
|
159
|
-
label
|
|
161
|
+
label,
|
|
160
162
|
locale,
|
|
161
163
|
value
|
|
162
164
|
});
|
|
@@ -200,7 +202,8 @@ const toReviews = ({ locale, translations, rental }) => Effect.gen(function* ()
|
|
|
200
202
|
}];
|
|
201
203
|
}) ?? [];
|
|
202
204
|
if (parsedItems.length === 0) return void 0;
|
|
203
|
-
const
|
|
205
|
+
const averageRating = parsedItems.reduce((ratingSum, item) => ratingSum + item.rating, 0) / parsedItems.length;
|
|
206
|
+
const summaryRating = roundRatingUp(averageRating);
|
|
204
207
|
const summaryRatingTemplate = yield* translations.translate(locale, "reviews.summary.rating");
|
|
205
208
|
const summaryCountTemplate = yield* translations.translate(locale, "reviews.summary.count");
|
|
206
209
|
const classification = toClassification(summaryRating);
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { a as parseQueryParameters, i as collectQueryParameters, n as makeV9CustomAttributeFilterCapabilities, o as toQueryString, r as toBasicQueryInputs, s as applyVofficeFilterDerivedBasicQueryInputs } from "./client-
|
|
2
|
-
import { a as searchQuery, c as VofficeUnitDataFieldSchemas, m as parseVofficeUnitData, n as toImages, r as toAddress, t as toRentalHighlights } from "./to-rental-highlights-
|
|
1
|
+
import { a as parseQueryParameters, i as collectQueryParameters, n as makeV9CustomAttributeFilterCapabilities, o as toQueryString, r as toBasicQueryInputs, s as applyVofficeFilterDerivedBasicQueryInputs } from "./client-Bmxh2SAu.mjs";
|
|
2
|
+
import { a as searchQuery, c as VofficeUnitDataFieldSchemas, m as parseVofficeUnitData, n as toImages, r as toAddress, t as toRentalHighlights } from "./to-rental-highlights-BVikT4Iz.mjs";
|
|
3
3
|
import { CoreSDKError, STABLE_SEARCH_INPUTS, daysBetweenLocalDates, expandCustomAttributeFilterCompositions, parseChildrenAges, parseOccupancyCount, resolveExpandedCompositions, toFormattedSearchPrice, toIsoDateFromPeriodQueryDate, toStableSearchInputBackendQueryKeys, toStableSearchInputParameterValues, toStableSearchInputQueryKeys, toUnusedFilterKeys } from "@v-office/sdk-core";
|
|
4
4
|
import { Effect } from "effect";
|
|
5
5
|
//#region src/legacy-v9/parser/search/input/search-input-error.ts
|
|
@@ -79,9 +79,11 @@ const PERIOD_QUERY_KEYS = toStableSearchInputBackendQueryKeys({
|
|
|
79
79
|
backend: "v9",
|
|
80
80
|
group: STABLE_SEARCH_INPUTS.period
|
|
81
81
|
});
|
|
82
|
+
const UNSUPPORTED_FLEXIBLE_PERIOD_QUERY_KEYS = new Set(STABLE_SEARCH_INPUTS.period.keys.filter((key) => !PERIOD_QUERY_KEYS.has(key)));
|
|
82
83
|
//#endregion
|
|
83
84
|
//#region src/legacy-v9/parser/search/input/period/collect-period-query-parameters.ts
|
|
84
85
|
const hasPeriodInput = (query) => parseQueryParameters(query).some(([key]) => PERIOD_QUERY_KEYS.has(key));
|
|
86
|
+
const hasUnsupportedFlexiblePeriodInput = (query) => parseQueryParameters(query).some(([key]) => UNSUPPORTED_FLEXIBLE_PERIOD_QUERY_KEYS.has(key));
|
|
85
87
|
const collectPeriodQueryParameters = ({ query }) => {
|
|
86
88
|
const { matchingParameters, remainingParameters } = collectQueryParameters({
|
|
87
89
|
query,
|
|
@@ -178,6 +180,7 @@ const toVofficeSorting = (sort) => {
|
|
|
178
180
|
//#endregion
|
|
179
181
|
//#region src/legacy-v9/parser/search/input/to-query-input.ts
|
|
180
182
|
const toQueryInput = ({ query, sort, customAttributeFilterDefinitions, locale, translations }) => Effect.gen(function* () {
|
|
183
|
+
if (hasUnsupportedFlexiblePeriodInput(query)) return yield* failInvalidV9SearchInput("Legacy v9 search does not support flexible period query parameters \"month\", \"dates\", \"nights\", or \"weekend\". Use \"start\" and \"end\" for a fixed period.");
|
|
181
184
|
const compositionResult = expandCustomAttributeFilterCompositions({
|
|
182
185
|
capabilities: makeV9CustomAttributeFilterCapabilities(customAttributeFilterDefinitions),
|
|
183
186
|
customAttributeFilterDefinitions,
|
|
@@ -221,21 +224,41 @@ const toQueryInput = ({ query, sort, customAttributeFilterDefinitions, locale, t
|
|
|
221
224
|
alternatives: true,
|
|
222
225
|
sorting: toVofficeSorting(sort)
|
|
223
226
|
},
|
|
224
|
-
basicQueryInputs
|
|
227
|
+
basicQueryInputs: basicQueryInputs.length > 0 ? basicQueryInputs : null
|
|
225
228
|
},
|
|
226
229
|
unusedFilterKeys: compositionFilters.unusedFilterKeys
|
|
227
230
|
};
|
|
228
231
|
});
|
|
229
232
|
//#endregion
|
|
230
|
-
//#region src/legacy-v9/parser/search/output/to-
|
|
231
|
-
const DEFAULT_V9_SEARCH_CURRENCY
|
|
232
|
-
const
|
|
233
|
-
if (calc?.total == null) return
|
|
234
|
-
|
|
233
|
+
//#region src/legacy-v9/parser/search/output/to-search-price-fields.ts
|
|
234
|
+
const DEFAULT_V9_SEARCH_CURRENCY = "EUR";
|
|
235
|
+
const toSearchPriceFields = ({ locale, calc }) => {
|
|
236
|
+
if (calc?.total == null) return {};
|
|
237
|
+
const formattedTotal = toFormattedSearchPrice({
|
|
235
238
|
amount: calc.total,
|
|
236
|
-
currency: DEFAULT_V9_SEARCH_CURRENCY
|
|
239
|
+
currency: DEFAULT_V9_SEARCH_CURRENCY,
|
|
237
240
|
locale
|
|
238
|
-
})
|
|
241
|
+
});
|
|
242
|
+
if (calc.oTotal == null || calc.oTotal <= calc.total) return { formattedTotal };
|
|
243
|
+
const label = calc.discountName?.trim();
|
|
244
|
+
return {
|
|
245
|
+
formattedTotal,
|
|
246
|
+
discount: {
|
|
247
|
+
formattedOriginalTotal: toFormattedSearchPrice({
|
|
248
|
+
amount: calc.oTotal,
|
|
249
|
+
currency: DEFAULT_V9_SEARCH_CURRENCY,
|
|
250
|
+
locale
|
|
251
|
+
}),
|
|
252
|
+
applied: label == null || label.length === 0 ? [] : [{
|
|
253
|
+
label,
|
|
254
|
+
formattedAmount: toFormattedSearchPrice({
|
|
255
|
+
amount: calc.total - calc.oTotal,
|
|
256
|
+
currency: DEFAULT_V9_SEARCH_CURRENCY,
|
|
257
|
+
locale
|
|
258
|
+
})
|
|
259
|
+
}]
|
|
260
|
+
}
|
|
261
|
+
};
|
|
239
262
|
};
|
|
240
263
|
//#endregion
|
|
241
264
|
//#region src/legacy-v9/parser/search/to-search-output-item.ts
|
|
@@ -258,26 +281,23 @@ const toSearchOutputItem = ({ locale, imageProxyBaseUrl, rentalHighlightPrioriti
|
|
|
258
281
|
attributes: data
|
|
259
282
|
});
|
|
260
283
|
if (highlights != null) item.highlights = highlights;
|
|
261
|
-
|
|
284
|
+
if (includeFormattedTotal) Object.assign(item, toSearchPriceFields({
|
|
262
285
|
locale,
|
|
263
286
|
calc: rental.additional_voffice_data?.calc
|
|
264
|
-
});
|
|
265
|
-
if (includeFormattedTotal && formattedPrice != null) item.formattedTotal = formattedPrice;
|
|
287
|
+
}));
|
|
266
288
|
return item;
|
|
267
289
|
});
|
|
268
290
|
//#endregion
|
|
269
291
|
//#region src/legacy-v9/parser/search/output/to-alternative-periods.ts
|
|
270
|
-
const DEFAULT_V9_SEARCH_CURRENCY = "EUR";
|
|
271
292
|
const toAlternativePeriods = ({ locale, alternatives }) => Effect.succeed((alternatives ?? []).flatMap((alternative) => {
|
|
272
293
|
if (alternative.fromdate == null || alternative.tilldate == null) return [];
|
|
273
294
|
return [{
|
|
274
295
|
start: alternative.fromdate,
|
|
275
296
|
end: alternative.tilldate,
|
|
276
|
-
...
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
}) }
|
|
297
|
+
...toSearchPriceFields({
|
|
298
|
+
locale,
|
|
299
|
+
calc: alternative.calc
|
|
300
|
+
})
|
|
281
301
|
}];
|
|
282
302
|
}));
|
|
283
303
|
//#endregion
|
|
@@ -5900,10 +5900,11 @@ const toRentalHighlights = ({ locale, translations, highlightPrioritization, cus
|
|
|
5900
5900
|
const attribute = customAttributes.byKey[highlightKey];
|
|
5901
5901
|
if (attribute === void 0) continue;
|
|
5902
5902
|
const binding = attribute.v9;
|
|
5903
|
+
const value = binding === void 0 ? void 0 : knownAttributes[binding] ?? attributes.unknown[binding];
|
|
5903
5904
|
const highlight = renderResolvedCustomAttribute({
|
|
5904
5905
|
attribute,
|
|
5905
5906
|
locale,
|
|
5906
|
-
value
|
|
5907
|
+
value
|
|
5907
5908
|
});
|
|
5908
5909
|
if (highlight != null) {
|
|
5909
5910
|
highlights.push(highlight);
|
|
@@ -5914,9 +5915,10 @@ const toRentalHighlights = ({ locale, translations, highlightPrioritization, cus
|
|
|
5914
5915
|
if (seenKeys.has(v9Key)) continue;
|
|
5915
5916
|
seenKeys.add(v9Key);
|
|
5916
5917
|
const metadata = VofficeUnitDataPropertyMetadata[v9Key];
|
|
5918
|
+
const label = yield* translate(metadata.labelKey, v9Key);
|
|
5917
5919
|
const highlight = renderLabeledAttributeValue({
|
|
5918
5920
|
key: v9Key,
|
|
5919
|
-
label
|
|
5921
|
+
label,
|
|
5920
5922
|
locale,
|
|
5921
5923
|
value: knownAttributes[v9Key]
|
|
5922
5924
|
});
|
|
@@ -4,6 +4,8 @@ This file is the versioned changelog index for the website SDK instructions.
|
|
|
4
4
|
|
|
5
5
|
## Versions
|
|
6
6
|
|
|
7
|
+
- `versions/2.12.0/CHANGELOG.md`: `@v-office/website-sdk` 2.12.0 release notes.
|
|
8
|
+
- `versions/2.11.0/CHANGELOG.md`: `@v-office/website-sdk` 2.11.0 release notes.
|
|
7
9
|
- `versions/2.10.0/CHANGELOG.md`: `@v-office/website-sdk` 2.10.0 release notes.
|
|
8
10
|
- `versions/2.9.0/CHANGELOG.md`: `@v-office/website-sdk` 2.9.0 release notes.
|
|
9
11
|
- `versions/2.8.0/CHANGELOG.md`: `@v-office/website-sdk` 2.8.0 release notes.
|
|
@@ -4,6 +4,8 @@ This file is the versioned migration index for the website SDK instructions.
|
|
|
4
4
|
|
|
5
5
|
## Available Guides
|
|
6
6
|
|
|
7
|
+
- `versions/2.12.0/MIGRATION.md`: migrate from `@v-office/website-sdk` 2.11.0 to 2.12.0.
|
|
8
|
+
- `versions/2.11.0/MIGRATION.md`: migrate from `@v-office/website-sdk` 2.10.0 to 2.11.0.
|
|
7
9
|
- `versions/2.10.0/MIGRATION.md`: migrate from `@v-office/website-sdk` 2.9.0 to 2.10.0.
|
|
8
10
|
- `versions/2.9.0/MIGRATION.md`: migrate from `@v-office/website-sdk` 2.8.0 to 2.9.0.
|
|
9
11
|
- `versions/2.8.0/MIGRATION.md`: migrate from `@v-office/website-sdk` 2.7.0 to 2.8.0.
|
package/instructions/README.md
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# Website SDK Instructions
|
|
2
2
|
|
|
3
3
|
These instructions describe the current source targeted for
|
|
4
|
-
`@v-office/website-sdk` 2.
|
|
4
|
+
`@v-office/website-sdk` 2.12.0. Package versions remain unchanged until the release
|
|
5
5
|
workflow performs the coordinated core and website bumps.
|
|
6
6
|
|
|
7
7
|
Use this directory as the consumer-facing reference for the package:
|
|
@@ -12,12 +12,17 @@ Use this directory as the consumer-facing reference for the package:
|
|
|
12
12
|
- `custom-attributes.md`: custom attribute catalog, configuration, per-backend behaviour, and the v9-to-v10 move.
|
|
13
13
|
- `search.md`: `sdk.live.search.search`.
|
|
14
14
|
- `availability.md`: date-picker availability flows.
|
|
15
|
-
- `quote.md`: quote, additional services, cancellation policy, and insurance flows.
|
|
15
|
+
- `quote.md`: quote booking-card modifiers, additional services, cancellation policy, and insurance flows.
|
|
16
16
|
- `booking.md`: booking and payment option submission.
|
|
17
17
|
- `contact.md`: contact submission.
|
|
18
18
|
- `document-structured-json.md`: `sdk.static.documents.getTermsAndPrivacyPolicy` and structured document JSON rendering rules.
|
|
19
19
|
- `CHANGELOG.md`: versioned changelog index.
|
|
20
20
|
- `MIGRATION.md`: versioned migration index.
|
|
21
|
+
- `versions/2.12.0/`: 2.12.0 legacy-v9 search discounts, empty-query browsing,
|
|
22
|
+
and flexible-period rejection; quote booking-card cleanup; and v10 modifier
|
|
23
|
+
guidance, plus the 2.11.0-to-2.12.0 migration guide.
|
|
24
|
+
- `versions/2.11.0/`: 2.11.0 search-discount release notes and
|
|
25
|
+
2.10.0-to-2.11.0 migration guide.
|
|
21
26
|
- `versions/2.10.0/`: 2.10.0 option-booking release notes and 2.9.0-to-2.10.0 migration guide.
|
|
22
27
|
- `versions/2.9.0/`: 2.9.0 highlight-selection release notes and 2.8.0-to-2.9.0 migration guide.
|
|
23
28
|
- `versions/2.8.0/`: 2.8.0 custom-attribute release notes and 2.7.0-to-2.8.0 migration guide.
|
|
@@ -76,4 +81,6 @@ website-sdk --backend v10 search --locale de-DE --query "adults=2"
|
|
|
76
81
|
website-sdk --backend v10 search --locale de-DE --query "adults=2" --sort '{"by":"field","orderBy":{"label":"ASC"}}'
|
|
77
82
|
```
|
|
78
83
|
|
|
79
|
-
Config file examples in these docs use the flat `WebsiteSDKConfig` shape introduced
|
|
84
|
+
Config file examples in these docs use the flat `WebsiteSDKConfig` shape introduced
|
|
85
|
+
in 2.0.0 and kept in 2.12.0. v10 config additionally requires `searchEndpoint` as
|
|
86
|
+
of 2.5.0.
|
package/instructions/quote.md
CHANGED
|
@@ -62,13 +62,13 @@ Sample:
|
|
|
62
62
|
```
|
|
63
63
|
|
|
64
64
|
Dates are local dates formatted as `YYYY-MM-DD`. For `v9`, `rentalId` must be a numeric vOffice unit id.
|
|
65
|
-
Both backends accept `voucher` on quote and booking flows. `v10
|
|
65
|
+
Both backends accept `voucher` on quote and booking flows. On `v10`, applied voucher and non-voucher modifiers can be exposed through the booking-card fields described below. `v9` reflects voucher effects in quoted totals but does not expose booking-card modifier details.
|
|
66
66
|
|
|
67
67
|
## Output
|
|
68
68
|
|
|
69
69
|
Returns `Promise<GuestQuoteResult>`.
|
|
70
70
|
|
|
71
|
-
Available sample:
|
|
71
|
+
Available sample without modifiers:
|
|
72
72
|
|
|
73
73
|
```json
|
|
74
74
|
{
|
|
@@ -139,6 +139,94 @@ Unavailable sample:
|
|
|
139
139
|
|
|
140
140
|
Selection methods return `{ ok: true, quote }` or `{ ok: false, error }`. Possible selection errors include unknown additional service, additional service limit exceeded, unknown cancellation policy, unavailable cancellation policy quote, and unavailable quote combination.
|
|
141
141
|
|
|
142
|
+
## Booking-Card Breakdown
|
|
143
|
+
|
|
144
|
+
Booking-card sections are returned in display order. On both v9 and v10, the SDK
|
|
145
|
+
omits numeric zero-value lines without subitems from the included, tax, and other
|
|
146
|
+
breakdown sections. If no lines remain in a section, the section is omitted.
|
|
147
|
+
Non-zero lines are unchanged, including when they share an `other` section with a
|
|
148
|
+
filtered zero-value line.
|
|
149
|
+
|
|
150
|
+
A zero-total line with subitems can remain because those subitems carry
|
|
151
|
+
descriptive content. Do not use the absence or presence of a zero-value price row
|
|
152
|
+
as service-selection state; use the quote's explicit service or selection data.
|
|
153
|
+
|
|
154
|
+
### Modifiers and Pre-Modifier Totals
|
|
155
|
+
|
|
156
|
+
On `v10`, a booking-card item at
|
|
157
|
+
`bookingCardInformation.sections[].lines[].item` can include these optional
|
|
158
|
+
fields:
|
|
159
|
+
|
|
160
|
+
```ts
|
|
161
|
+
{
|
|
162
|
+
modifiers?: readonly {
|
|
163
|
+
label: string;
|
|
164
|
+
amount: string;
|
|
165
|
+
}[];
|
|
166
|
+
totalBeforeModifiers?: string;
|
|
167
|
+
}
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
`modifiers` contains localized, formatted adjustments applied to that item. A
|
|
171
|
+
negative amount represents a deduction and a positive amount represents a
|
|
172
|
+
surcharge. The SDK groups backend modifiers with the same label and formats their
|
|
173
|
+
summed amount as one entry. The field is omitted when the item has no modifiers.
|
|
174
|
+
|
|
175
|
+
`item.totalBeforeModifiers` is the formatted item amount before its modifiers. It
|
|
176
|
+
is present when the item has a non-zero net modifier effect and the amount can be
|
|
177
|
+
derived; otherwise it is omitted. `item.appliedCharge` remains the final amount
|
|
178
|
+
after modifiers.
|
|
179
|
+
|
|
180
|
+
The booking card itself can also include
|
|
181
|
+
`bookingCardInformation.totalBeforeModifiers`. It is the formatted whole-card
|
|
182
|
+
total before all backend modifiers and is present when those modifiers have a
|
|
183
|
+
non-zero net effect. It is omitted when there are no modifiers or their amounts
|
|
184
|
+
net to zero. The SDK derives quote pre-modifier totals from the final amounts and
|
|
185
|
+
modifier values.
|
|
186
|
+
|
|
187
|
+
Items in the included, tax, and other sections carry their adjustments in
|
|
188
|
+
`item.modifiers`; do not expect those adjustments to be separate section lines.
|
|
189
|
+
Negative modifiers on backend lines that cannot be mapped to those sections may
|
|
190
|
+
instead appear as dedicated booking-card lines. `v9` quote cards omit
|
|
191
|
+
`modifiers` and both `totalBeforeModifiers` fields.
|
|
192
|
+
|
|
193
|
+
Discounted `v10` example for locale `de-DE`:
|
|
194
|
+
|
|
195
|
+
```json
|
|
196
|
+
{
|
|
197
|
+
"bookingCardInformation": {
|
|
198
|
+
"sections": [
|
|
199
|
+
{
|
|
200
|
+
"lines": [
|
|
201
|
+
{
|
|
202
|
+
"item": {
|
|
203
|
+
"position": "Inklusivpreis",
|
|
204
|
+
"appliedCharge": "1.554,00 €",
|
|
205
|
+
"modifiers": [
|
|
206
|
+
{
|
|
207
|
+
"label": "Frühbucher/Last-Minute",
|
|
208
|
+
"amount": "-140,00 €"
|
|
209
|
+
}
|
|
210
|
+
],
|
|
211
|
+
"totalBeforeModifiers": "1.694,00 €"
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
]
|
|
215
|
+
}
|
|
216
|
+
],
|
|
217
|
+
"total": "1.596,70 €",
|
|
218
|
+
"totalBeforeModifiers": "1.736,70 €"
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
```
|
|
222
|
+
|
|
223
|
+
For a price breakdown that keeps its arithmetic visible, render
|
|
224
|
+
`totalBeforeModifiers` as the pre-modifier amount, show each modifier as an
|
|
225
|
+
adjustment row, and use `appliedCharge` or `total` as the resulting final amount.
|
|
226
|
+
The SDK supplies formatted values but does not decide whether a reference price
|
|
227
|
+
should be displayed or struck through; that presentation and its legal
|
|
228
|
+
requirements remain the consuming site's responsibility.
|
|
229
|
+
|
|
142
230
|
## Vouchers
|
|
143
231
|
|
|
144
232
|
When `voucher` is provided in the quote input, an available quote may include `quote.voucher`:
|
|
@@ -153,7 +241,11 @@ When `voucher` is provided in the quote input, an available quote may include `q
|
|
|
153
241
|
|
|
154
242
|
`status` is `"applied"`, `"not_applied"`, or `"unknown"`. `v10` reports `"applied"` when the backend returns a non-zero voucher modifier and `"not_applied"` when no voucher modifier is returned for the requested voucher. `v9` returns `"unknown"` for available voucher quotes because the legacy response does not provide a reliable voucher modifier signal.
|
|
155
243
|
|
|
156
|
-
|
|
244
|
+
Do not assume an applied voucher appears as its own section line. On `v10`, a
|
|
245
|
+
voucher adjustment on an included, tax, or other line appears in that line's
|
|
246
|
+
`item.modifiers`; an unmapped negative modifier can appear as a dedicated line.
|
|
247
|
+
Use `quote.voucher.status` for voucher application status and the booking-card
|
|
248
|
+
fields for price presentation.
|
|
157
249
|
|
|
158
250
|
## Additional Services
|
|
159
251
|
|