@v-office/website-sdk 2.17.1 → 2.18.1
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 +18 -0
- package/dist/cli.mjs +10 -11
- package/dist/{client-yYl7H82t.mjs → client-BnA0oXd_.mjs} +220 -23
- package/dist/index.d.mts +48 -2
- package/dist/index.mjs +2 -2
- package/dist/instructions/CHANGELOG.md +26 -27
- package/dist/instructions/MIGRATION.md +26 -27
- package/dist/instructions/README.md +7 -2
- package/dist/instructions/availability.md +9 -7
- package/dist/instructions/creation.md +46 -1
- package/dist/instructions/custom-attributes.md +7 -0
- package/dist/instructions/quote.md +8 -0
- package/dist/instructions/rentals.md +130 -2
- package/dist/instructions/versions/2.18.0/CHANGELOG.md +133 -0
- package/dist/instructions/versions/2.18.0/MIGRATION.md +364 -0
- package/dist/instructions/versions/2.18.1/CHANGELOG.md +16 -0
- package/dist/instructions/versions/2.18.1/MIGRATION.md +12 -0
- package/dist/{quote-C-Bs3XTE.mjs → quote-cjFdLn0m.mjs} +1 -0
- package/dist/{rentals-BokBV-ze.mjs → rentals-GfJVIv7i.mjs} +205 -12
- package/dist/{search-DkXUHJt8.mjs → search-CR1UjnmR.mjs} +3 -2
- package/dist/to-rental-highlights-CJvDxSLw.mjs +3035 -0
- package/dist/translations/v10/de-DE/core.json +1 -1
- package/dist/translations/v9/de-DE/core.json +7 -1
- package/dist/translations/v9/en-US/core.json +7 -1
- package/dist/{to-rental-highlights-BAsEuxoy.mjs → v9-data-BnYxa2Ek.mjs} +21 -2435
- package/instructions/CHANGELOG.md +26 -27
- package/instructions/MIGRATION.md +26 -27
- package/instructions/README.md +7 -2
- package/instructions/availability.md +9 -7
- package/instructions/creation.md +46 -1
- package/instructions/custom-attributes.md +7 -0
- package/instructions/quote.md +8 -0
- package/instructions/rentals.md +130 -2
- package/instructions/versions/2.18.0/CHANGELOG.md +133 -0
- package/instructions/versions/2.18.0/MIGRATION.md +364 -0
- package/instructions/versions/2.18.0/release.json +3 -0
- package/instructions/versions/2.18.1/CHANGELOG.md +16 -0
- package/instructions/versions/2.18.1/MIGRATION.md +12 -0
- package/instructions/versions/2.18.1/release.json +3 -0
- package/package.json +8 -7
- package/dist/instructions/versions/2.6.0/CHANGELOG.md +0 -6
- package/dist/instructions/versions/2.6.0/MIGRATION.md +0 -6
- package/instructions/versions/2.6.0/CHANGELOG.md +0 -6
- package/instructions/versions/2.6.0/MIGRATION.md +0 -6
|
@@ -0,0 +1,364 @@
|
|
|
1
|
+
# Migration: 2.17.1 to 2.18.0
|
|
2
|
+
|
|
3
|
+
2.18.0 adds an opt-in legacy-v9 facility association for tenants whose
|
|
4
|
+
facilities reference vOffice object groups through a custom `p_*` data
|
|
5
|
+
attribute. It also exposes initial-availability calendar prices on available
|
|
6
|
+
dates that cannot be used as a start date, and combines repeated included
|
|
7
|
+
rent rows when a quoted stay crosses seasonal rates.
|
|
8
|
+
|
|
9
|
+
The default facility association and the public static rental result remain
|
|
10
|
+
unchanged when the new config field is omitted. Public availability and quote
|
|
11
|
+
types are unchanged.
|
|
12
|
+
|
|
13
|
+
## 1. Upgrade
|
|
14
|
+
|
|
15
|
+
```sh
|
|
16
|
+
pnpm add @v-office/website-sdk@2.18.0
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
## 2. Keep the Default Relation When Available
|
|
20
|
+
|
|
21
|
+
No configuration change is required when vOffice units already carry their
|
|
22
|
+
native facility relation:
|
|
23
|
+
|
|
24
|
+
```ts
|
|
25
|
+
const sdk = createWebsiteSDK({
|
|
26
|
+
config: {
|
|
27
|
+
backend: "v9",
|
|
28
|
+
graphqlUrl: "https://example.com/graphql",
|
|
29
|
+
apiKey: "...",
|
|
30
|
+
imageProxyBaseUrl: "https://images.example.com",
|
|
31
|
+
},
|
|
32
|
+
});
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
This continues to load the nested `voffice_facility` for each unit. It does not
|
|
36
|
+
request top-level facilities or object-group memberships.
|
|
37
|
+
|
|
38
|
+
## 3. Enable Object-Group Association When Required
|
|
39
|
+
|
|
40
|
+
Set the numeric suffix of the facility custom attribute that contains the
|
|
41
|
+
related object-group ID or IDs:
|
|
42
|
+
|
|
43
|
+
```ts
|
|
44
|
+
const sdk = createWebsiteSDK({
|
|
45
|
+
config: {
|
|
46
|
+
backend: "v9",
|
|
47
|
+
graphqlUrl: "https://example.com/graphql",
|
|
48
|
+
apiKey: "...",
|
|
49
|
+
imageProxyBaseUrl: "https://images.example.com",
|
|
50
|
+
facilityObjectGroupRelationAttributeId: 18962,
|
|
51
|
+
},
|
|
52
|
+
});
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
The SDK converts `18962` to the GraphQL facility data attribute `p_18962`.
|
|
56
|
+
Do not pass `"p_18962"` or another string; the config value is a positive
|
|
57
|
+
integer.
|
|
58
|
+
|
|
59
|
+
When enabled, `getRentals`:
|
|
60
|
+
|
|
61
|
+
1. Loads all units with `voffice_groups { voffice_group_id }`.
|
|
62
|
+
2. Loads all facilities and requests `p_18962` alongside the normal facility
|
|
63
|
+
attributes.
|
|
64
|
+
3. Associates each unit with the facility whose configured object-group IDs
|
|
65
|
+
contain one of the unit's group memberships.
|
|
66
|
+
4. Exposes the resolved facility through the existing `rental.property`.
|
|
67
|
+
5. Applies static rental scope and then loads feedbacks for retained rentals.
|
|
68
|
+
|
|
69
|
+
### Expanded v9 property fields
|
|
70
|
+
|
|
71
|
+
Both native and object-group v9 facility relations now populate more of the
|
|
72
|
+
existing `rental.property` shape when the Hub provides the source data:
|
|
73
|
+
|
|
74
|
+
- `propertyType` from `type`
|
|
75
|
+
- `location` from the GeoJSON `loc`
|
|
76
|
+
- `address` from `address`, with `regionName` used as `province`
|
|
77
|
+
- all existing description components from their corresponding localized
|
|
78
|
+
facility fields
|
|
79
|
+
- `attributes` for `allergic`, `childrenWelcome`, `pets`, and `youthgroups`
|
|
80
|
+
|
|
81
|
+
`HOUSE_FAC` becomes `HOLIDAY_HOME_COMPLEX` and `FLAT_FAC` becomes
|
|
82
|
+
`APARTMENT_COMPLEX`. `HOTEL`, `HOSTEL`, `FARM`, and `CAMPGROUND` already match
|
|
83
|
+
the shared values. The normalized value is localized through
|
|
84
|
+
`Property.propertyType.option.*` before it is returned. Unknown facility types
|
|
85
|
+
are omitted.
|
|
86
|
+
|
|
87
|
+
This uses the existing core `RentalPropertySchema`; no public property field or
|
|
88
|
+
type was added. Missing, empty, zero-valued, or malformed optional source data
|
|
89
|
+
remains omitted. The release does not synthesize property `vicinity` from
|
|
90
|
+
unrelated facility fields.
|
|
91
|
+
|
|
92
|
+
To select and order v9 property highlights, use the existing website option:
|
|
93
|
+
|
|
94
|
+
```ts
|
|
95
|
+
const sdk = createWebsiteSDK({
|
|
96
|
+
config,
|
|
97
|
+
options: {
|
|
98
|
+
rentalPropertyHighlightPrioritization: ["childrenWelcome", "pets", "youthgroups"],
|
|
99
|
+
},
|
|
100
|
+
});
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
The v9 renderer supports the typed facility attributes `allergic`,
|
|
104
|
+
`childrenWelcome`, `pets`, and `youthgroups`. It preserves the configured order,
|
|
105
|
+
deduplicates keys, and ignores unsupported, missing, or non-renderable values.
|
|
106
|
+
Rental custom attributes are not considered for property highlights.
|
|
107
|
+
|
|
108
|
+
## 4. Add Tenant-Specific Facility Highlight Text
|
|
109
|
+
|
|
110
|
+
Use a v9 property-highlight source when a facility custom field contains
|
|
111
|
+
editor-authored highlight lines, such as `p_18963` ("Anlagen Highlights"):
|
|
112
|
+
|
|
113
|
+
```ts
|
|
114
|
+
import {
|
|
115
|
+
createWebsiteSDK,
|
|
116
|
+
defineV9PropertyHighlightSources,
|
|
117
|
+
defineWebsiteSDKOptions,
|
|
118
|
+
} from "@v-office/website-sdk";
|
|
119
|
+
|
|
120
|
+
const v9PropertyHighlightSources = defineV9PropertyHighlightSources({
|
|
121
|
+
facilityHighlights: {
|
|
122
|
+
v9: "p_18963",
|
|
123
|
+
type: "line-list",
|
|
124
|
+
},
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
const sdk = createWebsiteSDK({
|
|
128
|
+
config,
|
|
129
|
+
options: defineWebsiteSDKOptions({
|
|
130
|
+
v9PropertyHighlightSources,
|
|
131
|
+
rentalPropertyHighlightPrioritization: [
|
|
132
|
+
"childrenWelcome",
|
|
133
|
+
v9PropertyHighlightSources.keys.facilityHighlights,
|
|
134
|
+
"pets",
|
|
135
|
+
],
|
|
136
|
+
}),
|
|
137
|
+
});
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
The registry gives the tenant-specific field a stable public selection key.
|
|
141
|
+
Defining a source alone does not request or emit it; add the generated key to
|
|
142
|
+
`rentalPropertyHighlightPrioritization`. The selected `p_*` field is requested
|
|
143
|
+
for both native and object-group facility relations.
|
|
144
|
+
|
|
145
|
+
Source keys must not reuse the built-in v9 facility keys `allergic`,
|
|
146
|
+
`childrenWelcome`, `pets`, or `youthgroups`; registry creation rejects those
|
|
147
|
+
collisions.
|
|
148
|
+
|
|
149
|
+
`line-list` resolves the localized field value, splits it at Unix or Windows
|
|
150
|
+
newlines, trims each line, drops empty lines, and deduplicates exact visible
|
|
151
|
+
values while preserving order. Each remaining line becomes one
|
|
152
|
+
`property.highlights` item at the source key's position. Missing and `null`
|
|
153
|
+
values emit nothing. Semicolons remain text; use one highlight per line in
|
|
154
|
+
vOffice.
|
|
155
|
+
|
|
156
|
+
For CLI JSON, provide the authored source definitions directly:
|
|
157
|
+
|
|
158
|
+
```json
|
|
159
|
+
{
|
|
160
|
+
"v9PropertyHighlightSources": {
|
|
161
|
+
"facilityHighlights": {
|
|
162
|
+
"v9": "p_18963",
|
|
163
|
+
"type": "line-list"
|
|
164
|
+
}
|
|
165
|
+
},
|
|
166
|
+
"rentalPropertyHighlightPrioritization": ["childrenWelcome", "facilityHighlights", "pets"]
|
|
167
|
+
}
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
The CLI builds and validates the registry. TypeScript consumers should use
|
|
171
|
+
`defineV9PropertyHighlightSources` so `keys.facilityHighlights` is inferred and
|
|
172
|
+
checked.
|
|
173
|
+
|
|
174
|
+
## 5. Prepare the GraphQL Hub
|
|
175
|
+
|
|
176
|
+
Before enabling the config, verify that the same API key can query:
|
|
177
|
+
|
|
178
|
+
```graphql
|
|
179
|
+
query FacilityObjectGroupRelations {
|
|
180
|
+
facilities: voffice_facilities(language: "de") {
|
|
181
|
+
id
|
|
182
|
+
name
|
|
183
|
+
data(attributes: ["p_18962", "p_18963"])
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
all(language: "de") {
|
|
187
|
+
voffice_id
|
|
188
|
+
voffice_groups {
|
|
189
|
+
voffice_group_id
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
The Hub must return:
|
|
196
|
+
|
|
197
|
+
- the required facilities from `voffice_facilities`
|
|
198
|
+
- a usable relation value in the configured `p_*` attribute
|
|
199
|
+
- any selected facility highlight `p_*` values
|
|
200
|
+
- matching `voffice_group_id` values on the intended units
|
|
201
|
+
|
|
202
|
+
Do not enable the mode while those resources are only available through v0 or
|
|
203
|
+
v1 and have not yet synchronized to GraphQL.
|
|
204
|
+
|
|
205
|
+
## 6. Account for Relation Validation
|
|
206
|
+
|
|
207
|
+
The relation attribute can contain positive numeric IDs as numbers, numeric
|
|
208
|
+
strings, localized string records, arrays, or strings separated by whitespace,
|
|
209
|
+
commas, or semicolons.
|
|
210
|
+
|
|
211
|
+
The static request fails rather than selecting an arbitrary property when:
|
|
212
|
+
|
|
213
|
+
- no facility has a usable configured relation value
|
|
214
|
+
- a non-empty relation value cannot be interpreted as positive integer IDs
|
|
215
|
+
- two facilities claim the same object-group ID
|
|
216
|
+
- one unit matches object groups belonging to different facilities
|
|
217
|
+
|
|
218
|
+
One facility may reference several groups. One unit may match several groups
|
|
219
|
+
when all of them resolve to the same facility.
|
|
220
|
+
|
|
221
|
+
Facilities whose relation is empty contribute no association. Rentals with no
|
|
222
|
+
matching relation remain in the result and omit `property`. Compatibility mode
|
|
223
|
+
does not fall back to the native facility relation.
|
|
224
|
+
|
|
225
|
+
## 7. Account for Batched Catalogue Requests
|
|
226
|
+
|
|
227
|
+
Legacy-v9 static rentals now load a small ordered rental-ID list first. Complete
|
|
228
|
+
rental details and feedbacks are then requested sequentially in batches of 128
|
|
229
|
+
IDs. Object-group mode loads the facility list once.
|
|
230
|
+
|
|
231
|
+
The public result and rental order are unchanged. HTTP mocks, request counters,
|
|
232
|
+
and GraphQL tracing that expected one detail query and one feedback query must
|
|
233
|
+
allow multiple requests for catalogues larger than 128 rentals.
|
|
234
|
+
|
|
235
|
+
Do not combine the detail batches into GraphQL aliases in one HTTP request. The
|
|
236
|
+
separate requests are intentional because they bound the amount of data the
|
|
237
|
+
Laravel/PHP Hub must construct and serialize at once.
|
|
238
|
+
|
|
239
|
+
## 8. Keep Other APIs Unchanged
|
|
240
|
+
|
|
241
|
+
The facility-association config only changes legacy-v9 static `getRentals`.
|
|
242
|
+
It does not change:
|
|
243
|
+
|
|
244
|
+
- v9 live search or its `falicityid` rental-scope filter
|
|
245
|
+
- quote inputs, booking, or contact requests
|
|
246
|
+
- start-date-selected availability
|
|
247
|
+
- shared core rental types
|
|
248
|
+
|
|
249
|
+
If an application uses both static rental scope and live search, verify both
|
|
250
|
+
flows separately because object-group association is intentionally limited to
|
|
251
|
+
the static catalogue.
|
|
252
|
+
|
|
253
|
+
## 9. Render Prices on Available Non-Start Dates
|
|
254
|
+
|
|
255
|
+
`getInitialAvailability` can now return a non-null `formattedPrice` on
|
|
256
|
+
available dates whose status is `check_in_not_allowed` or
|
|
257
|
+
`no_valid_check_out_from_start`:
|
|
258
|
+
|
|
259
|
+
```ts
|
|
260
|
+
const availability = await sdk.live.availability.getInitialAvailability(input);
|
|
261
|
+
|
|
262
|
+
for (const [date, day] of Object.entries(availability.calendarDays)) {
|
|
263
|
+
renderCalendarDay({
|
|
264
|
+
date,
|
|
265
|
+
status: day.status,
|
|
266
|
+
price: day.formattedPrice,
|
|
267
|
+
});
|
|
268
|
+
}
|
|
269
|
+
```
|
|
270
|
+
|
|
271
|
+
`formattedPrice` is already localized for the input locale. Render it
|
|
272
|
+
directly when non-null. Do not treat a missing price as the only signal that
|
|
273
|
+
a date is unavailable; use `isAvailableDate` and `status`.
|
|
274
|
+
|
|
275
|
+
The field remains `null` when:
|
|
276
|
+
|
|
277
|
+
- the calendar marks the day unavailable
|
|
278
|
+
- the source supplies no numeric price
|
|
279
|
+
|
|
280
|
+
Start-date-selected availability still has no calendar prices. The v10 change
|
|
281
|
+
is delivered by `@v-office/sdk-core`. Refresh the lockfile when upgrading the
|
|
282
|
+
website SDK so it resolves the coordinated core version shipped for 2.18.0.
|
|
283
|
+
|
|
284
|
+
## 10. Render Combined Seasonal Rent Lines
|
|
285
|
+
|
|
286
|
+
Included booking-card subitems that share the same localized `position` and
|
|
287
|
+
`appliedCharge` are now one row on both v9 and v10. A stay that crosses
|
|
288
|
+
seasonal rental prices therefore shows a single rent line such as `Miete` /
|
|
289
|
+
`Inklusive` instead of repeating that row once per rate period.
|
|
290
|
+
|
|
291
|
+
Cleaning, linen, booking fees, and other distinct included labels remain
|
|
292
|
+
separate. The inclusive total still sums every backend rent period; only the
|
|
293
|
+
repeated display rows are combined. Quote inputs and the booking-card schema
|
|
294
|
+
are unchanged.
|
|
295
|
+
|
|
296
|
+
Render `subItems` as returned. Do not reconstruct a seasonal breakdown from
|
|
297
|
+
duplicate rent labels; those duplicates are no longer emitted. The v10 change
|
|
298
|
+
is delivered by `@v-office/sdk-core`. Refresh the lockfile when upgrading the
|
|
299
|
+
website SDK so it resolves the coordinated core version shipped for 2.18.0.
|
|
300
|
+
|
|
301
|
+
## Required Consumer Work
|
|
302
|
+
|
|
303
|
+
Consumers using the default native facility relation and selected availability
|
|
304
|
+
fields only need to upgrade.
|
|
305
|
+
|
|
306
|
+
Consumers enabling object-group association should:
|
|
307
|
+
|
|
308
|
+
1. Confirm GraphQL synchronization for facilities, relation values, and groups.
|
|
309
|
+
2. Add `facilityObjectGroupRelationAttributeId` to the v9 config.
|
|
310
|
+
3. Confirm expected rentals contain `property`.
|
|
311
|
+
4. Keep unmatched rentals without `property` valid.
|
|
312
|
+
5. Update complete-output snapshots that gain associated properties.
|
|
313
|
+
6. Update v9 property snapshots that gain `propertyType`, `location`, `address`,
|
|
314
|
+
description components, or built-in attributes.
|
|
315
|
+
|
|
316
|
+
Consumers enabling custom v9 property highlight text should:
|
|
317
|
+
|
|
318
|
+
1. Confirm the facility `p_*` field has synchronized to GraphQL.
|
|
319
|
+
2. Define it with `defineV9PropertyHighlightSources`.
|
|
320
|
+
3. Select its stable key in `rentalPropertyHighlightPrioritization`.
|
|
321
|
+
4. Keep missing or `null` source values valid.
|
|
322
|
+
5. Update complete rental snapshots that gain property highlight lines.
|
|
323
|
+
|
|
324
|
+
Consumers that snapshot or hide calendar prices should:
|
|
325
|
+
|
|
326
|
+
1. Render `formattedPrice` directly when non-null, including on available
|
|
327
|
+
dates that cannot be used as a start date.
|
|
328
|
+
2. Keep `formattedPrice: null` valid for unavailable and price-less dates.
|
|
329
|
+
3. Refresh the lockfile so v10 resolves the coordinated core release.
|
|
330
|
+
4. Update complete initial-availability snapshots that expected `null` on
|
|
331
|
+
`check_in_not_allowed` or `no_valid_check_out_from_start`.
|
|
332
|
+
|
|
333
|
+
Consumers that snapshot or expand included quote rows should:
|
|
334
|
+
|
|
335
|
+
1. Keep rendering each included `subItem` as one row.
|
|
336
|
+
2. Update complete quote snapshots that expected one rent row per seasonal
|
|
337
|
+
rate period.
|
|
338
|
+
3. Refresh the lockfile so v10 resolves the coordinated core release.
|
|
339
|
+
|
|
340
|
+
## Recommended Verification
|
|
341
|
+
|
|
342
|
+
1. Run `getRentals` without the config and confirm native facility associations
|
|
343
|
+
remain unchanged.
|
|
344
|
+
2. Run it with the configured attribute ID and count rentals by `property.id`.
|
|
345
|
+
3. Verify a facility that references several groups receives every intended
|
|
346
|
+
rental once.
|
|
347
|
+
4. Verify unmatched rentals remain present without `property`.
|
|
348
|
+
5. Verify the configured `rentalScope.propertyId`, when used, returns only the
|
|
349
|
+
resolved facility's rentals.
|
|
350
|
+
6. Verify populated facility location, address, type, descriptions, and
|
|
351
|
+
attributes are represented in `rental.property`.
|
|
352
|
+
7. Test at least one catalogue larger than 128 rentals so detail and feedback
|
|
353
|
+
batching are exercised.
|
|
354
|
+
8. Select a configured line-list source between two built-in property keys and
|
|
355
|
+
confirm its non-empty lines appear at that exact position without duplicates.
|
|
356
|
+
9. Confirm an unselected source is not requested or emitted.
|
|
357
|
+
10. Load initial availability for a stay-through or closed-on-arrival date that
|
|
358
|
+
has a source price and confirm `formattedPrice` is non-null.
|
|
359
|
+
11. Confirm unavailable and price-less dates retain `formattedPrice: null`.
|
|
360
|
+
12. Confirm start-date-selected availability still has no calendar prices.
|
|
361
|
+
13. Quote a stay that crosses a seasonal rental-price change and confirm the
|
|
362
|
+
included section shows one rent row.
|
|
363
|
+
14. Confirm other included labels still appear as separate rows and that the
|
|
364
|
+
inclusive total is unchanged.
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
# Changelog: 2.18.1
|
|
2
|
+
|
|
3
|
+
Maintenance release. `@v-office/website-sdk` now pins `@v-office/sdk-core`
|
|
4
|
+
exactly, so one website SDK version always resolves one core version. There
|
|
5
|
+
are no functional changes.
|
|
6
|
+
|
|
7
|
+
## Changed
|
|
8
|
+
|
|
9
|
+
- `@v-office/sdk-core` is pinned to exactly `1.20.0` instead of the caret
|
|
10
|
+
range `^1.19.0`. Installs that had already resolved 1.20.0 through the
|
|
11
|
+
range see no change; consumers whose lockfile still held 1.19.x move to
|
|
12
|
+
1.20.0 with this release.
|
|
13
|
+
|
|
14
|
+
## Unchanged
|
|
15
|
+
|
|
16
|
+
- Every public API, type and behavior of 2.18.0.
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
# Migration: 2.18.0 to 2.18.1
|
|
2
|
+
|
|
3
|
+
No changes required.
|
|
4
|
+
|
|
5
|
+
## 1. Upgrade
|
|
6
|
+
|
|
7
|
+
```sh
|
|
8
|
+
pnpm add @v-office/website-sdk@2.18.1
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
Future core updates arrive through a new website SDK version; the lockfile
|
|
12
|
+
no longer needs a separate refresh to pick up a coordinated core release.
|
|
@@ -182,6 +182,7 @@ const toSectionsIncluded = ({ input: _input, guestQuoteResult, locale, translati
|
|
|
182
182
|
locale,
|
|
183
183
|
translations
|
|
184
184
|
});
|
|
185
|
+
if (subItems.some((item) => item.position === position)) continue;
|
|
185
186
|
subItems.push({
|
|
186
187
|
position,
|
|
187
188
|
appliedCharge: yield* translations.translate(locale, "quote.sections.included")
|
|
@@ -1,5 +1,7 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { Ht as V9_FACILITY_ATTRIBUTE_KEYS } from "./client-BnA0oXd_.mjs";
|
|
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
|
+
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-CJvDxSLw.mjs";
|
|
4
|
+
import { CoreSDKError, makeTranslate, renderResolvedCustomAttribute, toCustomAttributeList, toResolvedCustomAttributeCategoryTranslationKey } from "@v-office/sdk-core";
|
|
3
5
|
import { Effect } from "effect";
|
|
4
6
|
//#region src/legacy-v9/parser/rentals/to-description.ts
|
|
5
7
|
const toDescription = (data, locale) => {
|
|
@@ -33,20 +35,128 @@ const toLocation = (location) => {
|
|
|
33
35
|
};
|
|
34
36
|
};
|
|
35
37
|
//#endregion
|
|
38
|
+
//#region src/legacy-v9/parser/rentals/to-property-attributes.ts
|
|
39
|
+
const toPropertyAttributes = ({ attributes, locale, translations }) => Effect.gen(function* () {
|
|
40
|
+
const items = [];
|
|
41
|
+
const translate = makeTranslate(translations, locale);
|
|
42
|
+
for (const key of V9_FACILITY_ATTRIBUTE_KEYS) {
|
|
43
|
+
const item = yield* renderVofficePropertyAttribute({
|
|
44
|
+
key,
|
|
45
|
+
metadata: VofficeUnitDataPropertyMetadata[key],
|
|
46
|
+
locale,
|
|
47
|
+
translate,
|
|
48
|
+
value: attributes.known[key]
|
|
49
|
+
});
|
|
50
|
+
if (item != null) items.push(item);
|
|
51
|
+
}
|
|
52
|
+
if (items.length === 0) return [];
|
|
53
|
+
const label = yield* translate(VofficeUnitDataPropertyCategoryLabelKeys.GENERAL, "GENERAL");
|
|
54
|
+
return [{
|
|
55
|
+
label,
|
|
56
|
+
subCategories: [{
|
|
57
|
+
label,
|
|
58
|
+
items
|
|
59
|
+
}]
|
|
60
|
+
}];
|
|
61
|
+
});
|
|
62
|
+
//#endregion
|
|
63
|
+
//#region src/legacy-v9/parser/rentals/to-line-list.ts
|
|
64
|
+
const toLineList = (value, locale) => {
|
|
65
|
+
const text = toLocalizedString(value, locale);
|
|
66
|
+
if (text == null) return [];
|
|
67
|
+
return [...new Set(text.split(/\r?\n/).map((item) => item.trim()).filter((item) => item.length > 0))];
|
|
68
|
+
};
|
|
69
|
+
//#endregion
|
|
70
|
+
//#region src/legacy-v9/parser/rentals/to-property-highlights.ts
|
|
71
|
+
const facilityAttributeKeys = new Set(V9_FACILITY_ATTRIBUTE_KEYS);
|
|
72
|
+
const isFacilityAttributeKey = (key) => facilityAttributeKeys.has(key);
|
|
73
|
+
const toPropertyHighlights = ({ attributes, highlightPrioritization, highlightSources, locale, translations }) => Effect.gen(function* () {
|
|
74
|
+
const highlights = [];
|
|
75
|
+
const seenHighlights = /* @__PURE__ */ new Set();
|
|
76
|
+
const seenKeys = /* @__PURE__ */ new Set();
|
|
77
|
+
const translate = makeTranslate(translations, locale);
|
|
78
|
+
for (const key of highlightPrioritization) {
|
|
79
|
+
if (seenKeys.has(key)) continue;
|
|
80
|
+
seenKeys.add(key);
|
|
81
|
+
if (isFacilityAttributeKey(key)) {
|
|
82
|
+
const highlight = yield* renderVofficePropertyAttribute({
|
|
83
|
+
key,
|
|
84
|
+
metadata: VofficeUnitDataPropertyMetadata[key],
|
|
85
|
+
locale,
|
|
86
|
+
translate,
|
|
87
|
+
value: attributes.known[key]
|
|
88
|
+
});
|
|
89
|
+
if (highlight != null && !seenHighlights.has(highlight)) {
|
|
90
|
+
seenHighlights.add(highlight);
|
|
91
|
+
highlights.push(highlight);
|
|
92
|
+
}
|
|
93
|
+
continue;
|
|
94
|
+
}
|
|
95
|
+
const source = Object.hasOwn(highlightSources.byKey, key) ? highlightSources.byKey[key] : void 0;
|
|
96
|
+
if (source == null) continue;
|
|
97
|
+
for (const highlight of toLineList(attributes.unknown[source.v9], locale)) {
|
|
98
|
+
if (seenHighlights.has(highlight)) continue;
|
|
99
|
+
seenHighlights.add(highlight);
|
|
100
|
+
highlights.push(highlight);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
return highlights;
|
|
104
|
+
});
|
|
105
|
+
//#endregion
|
|
106
|
+
//#region src/legacy-v9/parser/rentals/to-property-type.ts
|
|
107
|
+
const propertyTypeByV9FacilityType = {
|
|
108
|
+
CAMPGROUND: "CAMPGROUND",
|
|
109
|
+
FARM: "FARM",
|
|
110
|
+
FLAT_FAC: "APARTMENT_COMPLEX",
|
|
111
|
+
HOSTEL: "HOSTEL",
|
|
112
|
+
HOTEL: "HOTEL",
|
|
113
|
+
HOUSE_FAC: "HOLIDAY_HOME_COMPLEX"
|
|
114
|
+
};
|
|
115
|
+
const isV9FacilityType = (value) => Object.hasOwn(propertyTypeByV9FacilityType, value);
|
|
116
|
+
const toPropertyType = ({ facilityType, locale, translations }) => Effect.gen(function* () {
|
|
117
|
+
if (facilityType == null || !isV9FacilityType(facilityType)) return void 0;
|
|
118
|
+
const propertyType = propertyTypeByV9FacilityType[facilityType];
|
|
119
|
+
return yield* makeTranslate(translations, locale)(`Property.propertyType.option.${propertyType}`, propertyType);
|
|
120
|
+
});
|
|
121
|
+
//#endregion
|
|
36
122
|
//#region src/legacy-v9/parser/rentals/to-property.ts
|
|
37
|
-
const toProperty = (facility, locale) => {
|
|
123
|
+
const toProperty = ({ facility, highlightPrioritization, highlightSources, locale, translations }) => Effect.gen(function* () {
|
|
38
124
|
const data = parseVofficeFacilityData(facility.data);
|
|
39
125
|
const name = toLocalizedString(data.known.name, locale);
|
|
40
|
-
const description =
|
|
126
|
+
const description = toDescription(data, locale);
|
|
41
127
|
const images = toFacilityImages(data.known.images ?? [], locale);
|
|
128
|
+
const propertyType = yield* toPropertyType({
|
|
129
|
+
facilityType: data.known.type,
|
|
130
|
+
locale,
|
|
131
|
+
translations
|
|
132
|
+
});
|
|
133
|
+
const location = toLocation(data.known.loc);
|
|
134
|
+
const address = toAddress(data, locale);
|
|
135
|
+
const attributes = yield* toPropertyAttributes({
|
|
136
|
+
attributes: data,
|
|
137
|
+
locale,
|
|
138
|
+
translations
|
|
139
|
+
});
|
|
140
|
+
const highlights = yield* toPropertyHighlights({
|
|
141
|
+
attributes: data,
|
|
142
|
+
highlightPrioritization,
|
|
143
|
+
highlightSources,
|
|
144
|
+
locale,
|
|
145
|
+
translations
|
|
146
|
+
});
|
|
42
147
|
const property = {
|
|
43
148
|
id: facility.id,
|
|
44
149
|
nameOrLabel: name ?? facility.name
|
|
45
150
|
};
|
|
46
|
-
if (
|
|
151
|
+
if (propertyType != null) property.propertyType = propertyType;
|
|
152
|
+
if (location != null) property.location = location;
|
|
153
|
+
if (Object.keys(address).length > 0) property.address = address;
|
|
154
|
+
if (Object.keys(description).length > 0) property.description = description;
|
|
47
155
|
if (images.length > 0) property.images = images;
|
|
156
|
+
if (attributes.length > 0) property.attributes = attributes;
|
|
157
|
+
if (highlights.length > 0) property.highlights = highlights;
|
|
48
158
|
return property;
|
|
49
|
-
};
|
|
159
|
+
});
|
|
50
160
|
//#endregion
|
|
51
161
|
//#region src/legacy-v9/parser/rentals/to-rental-attributes.ts
|
|
52
162
|
const GENERAL_CATEGORY$1 = {
|
|
@@ -243,21 +353,21 @@ const BED_ATTRIBUTE_LABEL_KEYS = {
|
|
|
243
353
|
openFootsection: "Bed.openFootsection.label",
|
|
244
354
|
raisedBeds: "Bed.raisedBeds.label"
|
|
245
355
|
};
|
|
246
|
-
const isRecord = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
356
|
+
const isRecord$1 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
247
357
|
const nonEmptyString = (value) => typeof value === "string" && value.length > 0 ? value : void 0;
|
|
248
358
|
const positiveInteger = (value) => typeof value === "number" && Number.isInteger(value) && value > 0 ? value : 0;
|
|
249
359
|
const toRooms = ({ locale, translations, roomDetails }) => Effect.gen(function* () {
|
|
250
360
|
const result = [];
|
|
251
361
|
const translate = makeTranslate(translations, locale);
|
|
252
362
|
for (const room of Array.isArray(roomDetails) ? roomDetails : []) {
|
|
253
|
-
if (!isRecord(room)) continue;
|
|
363
|
+
if (!isRecord$1(room)) continue;
|
|
254
364
|
const roomType = nonEmptyString(room.type);
|
|
255
365
|
if (roomType == null) continue;
|
|
256
366
|
const attributes = [];
|
|
257
367
|
for (const [key, labelKey] of Object.entries(ROOM_ATTRIBUTE_LABEL_KEYS)) if (room[key] === true) attributes.push(yield* translate(labelKey, key));
|
|
258
368
|
const beds = [];
|
|
259
369
|
for (const bed of Array.isArray(room.beds) ? room.beds : []) {
|
|
260
|
-
if (!isRecord(bed)) continue;
|
|
370
|
+
if (!isRecord$1(bed)) continue;
|
|
261
371
|
const bedType = nonEmptyString(bed.type);
|
|
262
372
|
if (bedType == null) continue;
|
|
263
373
|
const bedValue = { type: yield* translate(`${BED_TYPE_KEY_PREFIX}.${bedType}`, bedType) };
|
|
@@ -277,7 +387,7 @@ const toRooms = ({ locale, translations, roomDetails }) => Effect.gen(function*
|
|
|
277
387
|
});
|
|
278
388
|
//#endregion
|
|
279
389
|
//#region src/legacy-v9/parser/rentals/to-rental-list-item.ts
|
|
280
|
-
const toRentalRentalsOutput = ({ rental, locale, translations, imageProxyBaseUrl, rentalHighlightPrioritization, customAttributes }) => Effect.gen(function* () {
|
|
390
|
+
const toRentalRentalsOutput = ({ rental, locale, translations, imageProxyBaseUrl, rentalHighlightPrioritization, rentalPropertyHighlightPrioritization, customAttributes, v9PropertyHighlightSources }) => Effect.gen(function* () {
|
|
281
391
|
const data = parseVofficeUnitData(rental.data);
|
|
282
392
|
const rawRentalType = data.known.type?.trim();
|
|
283
393
|
const translatedRentalType = rawRentalType != null && rawRentalType.length > 0 ? yield* toRentalType({
|
|
@@ -331,12 +441,95 @@ const toRentalRentalsOutput = ({ rental, locale, translations, imageProxyBaseUrl
|
|
|
331
441
|
if (vicinity != null) item.vicinity = vicinity;
|
|
332
442
|
if (highlights != null) item.highlights = highlights;
|
|
333
443
|
if (rooms.length > 0) item.rooms = rooms;
|
|
334
|
-
if (rental.voffice_facility != null) item.property = toProperty(
|
|
444
|
+
if (rental.voffice_facility != null) item.property = yield* toProperty({
|
|
445
|
+
facility: rental.voffice_facility,
|
|
446
|
+
highlightPrioritization: rentalPropertyHighlightPrioritization,
|
|
447
|
+
highlightSources: v9PropertyHighlightSources,
|
|
448
|
+
locale,
|
|
449
|
+
translations
|
|
450
|
+
});
|
|
335
451
|
if (reviews != null) item.reviews = reviews;
|
|
336
452
|
return item;
|
|
337
453
|
});
|
|
338
454
|
//#endregion
|
|
455
|
+
//#region src/legacy-v9/static/associate-rentals-with-facilities-by-object-groups.ts
|
|
456
|
+
const operation = "v9.rentals.facility-object-group-relation";
|
|
457
|
+
const isRecord = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
458
|
+
const parseGroupIds = (value) => {
|
|
459
|
+
if (value == null) return [];
|
|
460
|
+
if (typeof value === "number") return Number.isSafeInteger(value) && value > 0 ? [value] : void 0;
|
|
461
|
+
if (typeof value === "string") {
|
|
462
|
+
const trimmed = value.trim();
|
|
463
|
+
if (trimmed.length === 0) return [];
|
|
464
|
+
if (!/^[\d\s,;]+$/.test(trimmed)) return void 0;
|
|
465
|
+
const groupIds = trimmed.split(/[\s,;]+/).filter((part) => part.length > 0).map(Number);
|
|
466
|
+
return groupIds.every((groupId) => Number.isSafeInteger(groupId) && groupId > 0) ? groupIds : void 0;
|
|
467
|
+
}
|
|
468
|
+
if (Array.isArray(value)) {
|
|
469
|
+
const groupIds = value.flatMap((part) => parseGroupIds(part) ?? [NaN]);
|
|
470
|
+
return groupIds.every((groupId) => Number.isSafeInteger(groupId) && groupId > 0) ? groupIds : void 0;
|
|
471
|
+
}
|
|
472
|
+
if (isRecord(value)) {
|
|
473
|
+
const groupIds = Object.values(value).flatMap((part) => parseGroupIds(part) ?? [NaN]);
|
|
474
|
+
return groupIds.every((groupId) => Number.isSafeInteger(groupId) && groupId > 0) ? groupIds : void 0;
|
|
475
|
+
}
|
|
476
|
+
};
|
|
477
|
+
const toFacilityId = (facility) => {
|
|
478
|
+
const facilityId = Number(facility.id);
|
|
479
|
+
if (Number.isSafeInteger(facilityId) && facilityId > 0) return facilityId;
|
|
480
|
+
throw new CoreSDKError({
|
|
481
|
+
source: "v9",
|
|
482
|
+
operation,
|
|
483
|
+
message: `Expected facility.id to be a positive integer, received "${facility.id}".`
|
|
484
|
+
});
|
|
485
|
+
};
|
|
486
|
+
const associateRentalsWithFacilitiesByObjectGroups = ({ attributeId, facilities, rentals }) => {
|
|
487
|
+
const attribute = `p_${attributeId}`;
|
|
488
|
+
const facilityByGroupId = /* @__PURE__ */ new Map();
|
|
489
|
+
for (const facility of facilities) {
|
|
490
|
+
const relation = parseVofficeFacilityData(facility.data).unknown[attribute];
|
|
491
|
+
const groupIds = parseGroupIds(relation);
|
|
492
|
+
if (groupIds === void 0) throw new CoreSDKError({
|
|
493
|
+
source: "v9",
|
|
494
|
+
operation,
|
|
495
|
+
message: `Facility "${facility.id}" has an invalid ${attribute} value.`
|
|
496
|
+
});
|
|
497
|
+
for (const groupId of new Set(groupIds)) {
|
|
498
|
+
const existingFacility = facilityByGroupId.get(groupId);
|
|
499
|
+
if (existingFacility != null && existingFacility.id !== facility.id) throw new CoreSDKError({
|
|
500
|
+
source: "v9",
|
|
501
|
+
operation,
|
|
502
|
+
message: `Object group "${groupId}" is assigned to facilities "${existingFacility.id}" and "${facility.id}".`
|
|
503
|
+
});
|
|
504
|
+
facilityByGroupId.set(groupId, facility);
|
|
505
|
+
}
|
|
506
|
+
}
|
|
507
|
+
if (facilityByGroupId.size === 0) throw new CoreSDKError({
|
|
508
|
+
source: "v9",
|
|
509
|
+
operation,
|
|
510
|
+
message: `No facility has a usable ${attribute} object-group relation.`
|
|
511
|
+
});
|
|
512
|
+
return rentals.map((rental) => {
|
|
513
|
+
const matchingFacilities = /* @__PURE__ */ new Map();
|
|
514
|
+
for (const group of rental.voffice_groups ?? []) {
|
|
515
|
+
const facility = facilityByGroupId.get(group.voffice_group_id);
|
|
516
|
+
if (facility != null) matchingFacilities.set(facility.id, facility);
|
|
517
|
+
}
|
|
518
|
+
if (matchingFacilities.size > 1) throw new CoreSDKError({
|
|
519
|
+
source: "v9",
|
|
520
|
+
operation,
|
|
521
|
+
message: `Rental "${rental.voffice_id}" matches several facilities through ${attribute}.`
|
|
522
|
+
});
|
|
523
|
+
const facility = matchingFacilities.values().next().value;
|
|
524
|
+
return {
|
|
525
|
+
...rental,
|
|
526
|
+
voffice_facility_id: facility == null ? null : toFacilityId(facility),
|
|
527
|
+
voffice_facility: facility ?? null
|
|
528
|
+
};
|
|
529
|
+
});
|
|
530
|
+
};
|
|
531
|
+
//#endregion
|
|
339
532
|
//#region src/legacy-v9/runtime/rentals.ts
|
|
340
533
|
const defaultRentalDataAttributes = Object.keys(VofficeUnitDataFieldSchemas);
|
|
341
534
|
//#endregion
|
|
342
|
-
export { defaultRentalDataAttributes, rentalsAllFeedbacksQuery, rentalsAllWithoutFeedbacksQuery, toRentalRentalsOutput };
|
|
535
|
+
export { associateRentalsWithFacilitiesByObjectGroups, defaultRentalDataAttributes, rentalFacilitiesForObjectGroupRelationQuery, rentalIdsQuery, rentalsAllByFacilityObjectGroupsWithoutFeedbacksQuery, rentalsAllFeedbacksQuery, rentalsAllWithoutFeedbacksQuery, toRentalRentalsOutput };
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import { a as parseQueryParameters, i as collectQueryParameters, n as makeV9CustomAttributeFilterCapabilities, o as toQueryString, r as toBasicQueryInputs, s as applyVofficeFilterDerivedBasicQueryInputs } from "./client-
|
|
2
|
-
import {
|
|
1
|
+
import { a as parseQueryParameters, i as collectQueryParameters, n as makeV9CustomAttributeFilterCapabilities, o as toQueryString, r as toBasicQueryInputs, s as applyVofficeFilterDerivedBasicQueryInputs } from "./client-BnA0oXd_.mjs";
|
|
2
|
+
import { c as parseVofficeUnitData, t as VofficeUnitDataFieldSchemas } from "./v9-data-BnYxa2Ek.mjs";
|
|
3
|
+
import { a as toAddress, i as toImages, s as searchQuery, t as toRentalHighlights } from "./to-rental-highlights-CJvDxSLw.mjs";
|
|
3
4
|
import { CoreSDKError, STABLE_SEARCH_INPUTS, daysBetweenLocalDates, expandCustomAttributeFilterCompositions, parseChildrenAges, parseOccupancyCount, resolveExpandedCompositions, toFormattedSearchPrice, toIsoDateFromPeriodQueryDate, toStableSearchInputBackendQueryKeys, toStableSearchInputParameterValues, toStableSearchInputQueryKeys, toUnusedFilterKeys } from "@v-office/sdk-core";
|
|
4
5
|
import { Effect } from "effect";
|
|
5
6
|
//#region src/legacy-v9/parser/search/input/search-input-error.ts
|