@v-office/website-sdk 1.0.1 → 1.2.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.
@@ -0,0 +1,609 @@
1
+ import { Data, DateTime, Duration, Effect, Option, Schema } from "effect";
2
+ //#region src/domain/quote/error.ts
3
+ var InvalidAdditionalServiceQuantity = class extends Data.TaggedError("InvalidAdditionalServiceQuantity") {};
4
+ var UnknownAdditionalService = class extends Data.TaggedError("UnknownAdditionalService") {};
5
+ var AdditionalServiceLimitExceeded = class extends Data.TaggedError("AdditionalServiceLimitExceeded") {};
6
+ var UnknownCancellationPolicy = class extends Data.TaggedError("UnknownCancellationPolicy") {};
7
+ var UnavailableCancellationPolicyQuote = class extends Data.TaggedError("UnavailableCancellationPolicyQuote") {};
8
+ var UnresolvableMultiRate = class extends Data.TaggedError("UnresolvableMultiRate") {};
9
+ var AmbiguousMultiRate = class extends Data.TaggedError("AmbiguousMultiRate") {};
10
+ //#endregion
11
+ //#region src/adapters/shared/parser/local-date.ts
12
+ const ISO_LOCAL_DATE_PATTERN = /^\d{4}-\d{2}-\d{2}$/;
13
+ const isLocalDateString = (value) => {
14
+ if (!ISO_LOCAL_DATE_PATTERN.test(value)) return false;
15
+ const date = DateTime.make(value);
16
+ return Option.isSome(date) && DateTime.formatIsoDateUtc(date.value) === value;
17
+ };
18
+ const daysBetweenLocalDates = ({ start, end }) => {
19
+ const startDate = DateTime.removeTime(DateTime.makeUnsafe(start));
20
+ const endDate = DateTime.removeTime(DateTime.makeUnsafe(end));
21
+ const duration = DateTime.toEpochMillis(endDate) - DateTime.toEpochMillis(startDate);
22
+ return Math.trunc(Duration.toDays(Duration.millis(duration)));
23
+ };
24
+ //#endregion
25
+ //#region src/adapters/shared/parser/period-query-date.ts
26
+ const PREFERRED_QUERY_DATE_PATTERN = /^(\d{2})-(\d{2})-(\d{4})$/;
27
+ const ISO_QUERY_DATE_PATTERN = /^\d{4}-\d{2}-\d{2}$/;
28
+ const QUERY_MONTH_PATTERN = /^(\d{2})-(\d{4})$/;
29
+ const toIsoDateFromPeriodQueryDate = (value) => {
30
+ const preferredMatch = PREFERRED_QUERY_DATE_PATTERN.exec(value);
31
+ const isoDate = preferredMatch == null ? ISO_QUERY_DATE_PATTERN.test(value) ? value : void 0 : `${preferredMatch[3]}-${preferredMatch[2]}-${preferredMatch[1]}`;
32
+ if (isoDate === void 0) return;
33
+ return isLocalDateString(isoDate) ? isoDate : void 0;
34
+ };
35
+ const toYearMonthFromPeriodQueryMonth = (value) => {
36
+ const match = QUERY_MONTH_PATTERN.exec(value);
37
+ if (!match) return;
38
+ const [, month, year] = match;
39
+ const monthNumber = Number.parseInt(month, 10);
40
+ return monthNumber >= 1 && monthNumber <= 12 ? {
41
+ year: Number.parseInt(year, 10),
42
+ month: monthNumber
43
+ } : void 0;
44
+ };
45
+ //#endregion
46
+ //#region src/adapters/shared/parser/locale.ts
47
+ const localeToLanguage = (locale) => locale.split("-")[0] ?? locale;
48
+ //#endregion
49
+ //#region src/adapters/shared/parser/translation.ts
50
+ const makeTranslate = (translations, locale) => (key, fallback) => translations.translate(locale, key, fallback);
51
+ //#endregion
52
+ //#region src/adapters/shared/parser/to-country.ts
53
+ const toCountry = (country, locale) => {
54
+ const normalizedCountryCode = country.trim().toUpperCase();
55
+ if (!/^[A-Z]{2}$/.test(normalizedCountryCode)) return country;
56
+ return new Intl.DisplayNames([locale], { type: "region" }).of(normalizedCountryCode) ?? country;
57
+ };
58
+ //#endregion
59
+ //#region src/adapters/shared/parser/to-formatted-search-price.ts
60
+ const toFormattedSearchPrice = ({ amount, currency, locale }) => formatCurrency(amount, locale, currency);
61
+ //#endregion
62
+ //#region src/adapters/shared/parser/to-night-count.ts
63
+ const toNightCount = (input) => {
64
+ const nights = daysBetweenLocalDates({
65
+ start: input.period.start,
66
+ end: input.period.end
67
+ });
68
+ return Math.max(1, nights);
69
+ };
70
+ //#endregion
71
+ //#region src/adapters/shared/parser/unknown.ts
72
+ const asRecord = (value) => typeof value === "object" && value !== null ? value : {};
73
+ const asArray = (value) => Array.isArray(value) ? value : value === void 0 || value === null ? [] : [value];
74
+ const firstString = (...values) => values.find((value) => typeof value === "string" && value.length > 0);
75
+ const firstNumber = (...values) => values.find((value) => typeof value === "number" && Number.isFinite(value));
76
+ //#endregion
77
+ //#region src/domain/insurance/index.ts
78
+ const InsuranceOptionKindNone = Schema.Literal("none");
79
+ const InsuranceOptionKindInsurance = Schema.Literal("insurance");
80
+ const InsurancePaymentOptionSEPA = Schema.Literal("sepa_debit");
81
+ const InsurancePaymentOptionExternalURL = Schema.Literal("external_url");
82
+ const NoInsuranceOptionOutputSchema = Schema.Struct({
83
+ kind: InsuranceOptionKindNone,
84
+ label: Schema.String,
85
+ description: Schema.optionalKey(Schema.String)
86
+ });
87
+ const InsuranceRequiredInformationNone = Schema.Literal("none");
88
+ const InsuranceRequiredInformationTravelers = Schema.Literal("travelers");
89
+ const InsuranceRequiredInformationSchema = Schema.Union([Schema.Struct({ kind: InsuranceRequiredInformationNone }), Schema.Struct({ kind: InsuranceRequiredInformationTravelers })]);
90
+ const InsuranceResourceSchema = Schema.Struct({
91
+ label: Schema.String,
92
+ url: Schema.String
93
+ });
94
+ const InsuranceOptionOutputSchema = Schema.Struct({
95
+ kind: InsuranceOptionKindInsurance,
96
+ id: Schema.String,
97
+ formattedPrice: Schema.String,
98
+ label: Schema.String,
99
+ requiredInformation: InsuranceRequiredInformationSchema,
100
+ description: Schema.optionalKey(Schema.String),
101
+ logoUrl: Schema.optionalKey(Schema.String),
102
+ features: Schema.optionalKey(Schema.Array(Schema.String)),
103
+ resources: Schema.optionalKey(Schema.Array(InsuranceResourceSchema))
104
+ });
105
+ const SelectableInsuranceOptionOutputSchema = Schema.Union([NoInsuranceOptionOutputSchema, InsuranceOptionOutputSchema]);
106
+ const InsuranceTravelerSchema = Schema.Struct({
107
+ salutation: Schema.String,
108
+ forename: Schema.String,
109
+ surname: Schema.String,
110
+ title: Schema.optionalKey(Schema.String),
111
+ birthday: Schema.optionalKey(Schema.String)
112
+ });
113
+ const SelectedInsuranceInformationInputSchema = Schema.Union([Schema.Struct({ kind: InsuranceOptionKindNone }), Schema.Struct({
114
+ kind: InsuranceOptionKindInsurance,
115
+ id: Schema.String,
116
+ travelers: Schema.optionalKey(Schema.Array(InsuranceTravelerSchema))
117
+ })]);
118
+ const InsuranceCustomerInformationInputSchema = Schema.Struct({
119
+ destinationCountryCode: Schema.String,
120
+ address: Schema.Struct({
121
+ street: Schema.String,
122
+ housenumber: Schema.optionalKey(Schema.String),
123
+ postalcode: Schema.String,
124
+ city: Schema.String,
125
+ countryCode: Schema.String
126
+ }),
127
+ email: Schema.String,
128
+ mobile: Schema.String
129
+ });
130
+ const InsuranceDocumentSchema = Schema.Struct({
131
+ label: Schema.String,
132
+ url: Schema.String
133
+ });
134
+ const InsurancePreContractOutputSchema = Schema.Union([
135
+ Schema.Struct({ kind: Schema.Literal("none_selected") }),
136
+ Schema.Struct({ kind: Schema.Literal("not_required") }),
137
+ Schema.Struct({
138
+ kind: Schema.Literal("created"),
139
+ id: Schema.String,
140
+ documents: Schema.optionalKey(Schema.Array(InsuranceDocumentSchema))
141
+ })
142
+ ]);
143
+ const InsurancePaymentOptionOutputSchema = Schema.Union([Schema.Struct({
144
+ kind: InsurancePaymentOptionSEPA,
145
+ label: Schema.String,
146
+ description: Schema.optionalKey(Schema.String)
147
+ }), Schema.Struct({
148
+ kind: InsurancePaymentOptionExternalURL,
149
+ label: Schema.String,
150
+ url: Schema.String,
151
+ description: Schema.optionalKey(Schema.String)
152
+ })]);
153
+ const InsurancePaymentInformationInputSchema = Schema.Union([Schema.Struct({
154
+ kind: InsurancePaymentOptionSEPA,
155
+ iban: Schema.String,
156
+ bic: Schema.optionalKey(Schema.String)
157
+ }), Schema.Struct({ kind: InsurancePaymentOptionExternalURL })]);
158
+ const GuestQuoteInsuranceSchema = Schema.Struct({
159
+ options: Schema.Array(SelectableInsuranceOptionOutputSchema),
160
+ selected: SelectedInsuranceInformationInputSchema,
161
+ preContract: InsurancePreContractOutputSchema,
162
+ paymentOptions: Schema.Array(InsurancePaymentOptionOutputSchema),
163
+ destinationCountryCode: Schema.optionalKey(Schema.String),
164
+ customerInformation: Schema.optionalKey(InsuranceCustomerInformationInputSchema),
165
+ paymentInformation: Schema.optionalKey(InsurancePaymentInformationInputSchema)
166
+ });
167
+ Schema.Union([
168
+ Schema.Struct({ kind: Schema.Literal("none_selected") }),
169
+ Schema.Struct({ kind: Schema.Literal("not_required") }),
170
+ Schema.Struct({
171
+ kind: Schema.Literal("booked"),
172
+ policyNumber: Schema.String,
173
+ documents: Schema.optionalKey(Schema.Array(InsuranceDocumentSchema))
174
+ })
175
+ ]);
176
+ //#endregion
177
+ //#region src/domain/quote/amount.ts
178
+ const NonNegativeAmountSchema = Schema.Number.check(Schema.isGreaterThanOrEqualTo(0));
179
+ const PositiveQuantitySchema = Schema.Int.check(Schema.isGreaterThanOrEqualTo(1));
180
+ Schema.Union([
181
+ Schema.Literal("FLAT"),
182
+ Schema.Literal("PER_NIGHT"),
183
+ Schema.Literal("PER_DAY"),
184
+ Schema.Literal("PER_USAGE")
185
+ ]);
186
+ const AdditionalServiceSchema = Schema.Struct({
187
+ id: Schema.String,
188
+ label: Schema.String,
189
+ charge: Schema.String,
190
+ preSelectedQuantity: Schema.optionalKey(PositiveQuantitySchema),
191
+ maxPerBooking: Schema.optionalKey(PositiveQuantitySchema),
192
+ description: Schema.optionalKey(Schema.String),
193
+ images: Schema.optionalKey(Schema.Array(Schema.Struct({
194
+ src: Schema.String,
195
+ alt: Schema.String
196
+ })))
197
+ });
198
+ const toPublicAdditionalService = ({ chargeAmount: _chargeAmount, calculation: _calculation, leadTimeDays: _leadTimeDays, ...service }) => service;
199
+ //#endregion
200
+ //#region src/domain/quote/backend-context.ts
201
+ const withQuoteBackendContextSelections = (context, updateContext, selections) => {
202
+ if (context === void 0 || updateContext === void 0) return context;
203
+ return updateContext(context, selections);
204
+ };
205
+ //#endregion
206
+ //#region src/domain/quote/format-currency.ts
207
+ const formatCurrency = (amount, locale, currency) => new Intl.NumberFormat(locale, {
208
+ style: "currency",
209
+ currency
210
+ }).format(amount / 100);
211
+ //#endregion
212
+ //#region src/domain/quote/booking-card.ts
213
+ const GuestQuoteBookingCardModifierSchema = Schema.Struct({
214
+ label: Schema.String,
215
+ amount: Schema.String
216
+ });
217
+ const GuestQuoteBookingCardItemSchema = Schema.Struct({
218
+ position: Schema.String,
219
+ appliedCharge: Schema.String,
220
+ modifiers: Schema.optionalKey(Schema.Array(GuestQuoteBookingCardModifierSchema)),
221
+ totalBeforeModifiers: Schema.optionalKey(Schema.String)
222
+ });
223
+ const GuestQuoteBookingCardLineSchema = Schema.Struct({
224
+ item: GuestQuoteBookingCardItemSchema,
225
+ subItems: Schema.optionalKey(Schema.Array(GuestQuoteBookingCardItemSchema))
226
+ });
227
+ const GuestQuoteBookingCardSectionSchema = Schema.Struct({ lines: Schema.Array(GuestQuoteBookingCardLineSchema) });
228
+ const GuestQuoteBookingCardSchema = Schema.Struct({
229
+ sections: Schema.Array(GuestQuoteBookingCardSectionSchema),
230
+ total: Schema.String,
231
+ totalBeforeModifiers: Schema.optionalKey(Schema.String)
232
+ });
233
+ const InternalGuestQuoteBookingCardModifierSchema = Schema.Struct({
234
+ label: Schema.String,
235
+ amount: Schema.Number
236
+ });
237
+ const InternalGuestQuoteBookingCardItemSchema = Schema.Struct({
238
+ position: Schema.String,
239
+ appliedCharge: Schema.Union([Schema.Number, Schema.String]),
240
+ modifiers: Schema.optionalKey(Schema.Array(InternalGuestQuoteBookingCardModifierSchema)),
241
+ totalBeforeModifiers: Schema.optionalKey(Schema.Number)
242
+ });
243
+ const InternalGuestQuoteBookingCardLineSchema = Schema.Struct({
244
+ item: InternalGuestQuoteBookingCardItemSchema,
245
+ subItems: Schema.optionalKey(Schema.Array(InternalGuestQuoteBookingCardItemSchema))
246
+ });
247
+ const InternalGuestQuoteBookingCardSectionSchema = Schema.Struct({ lines: Schema.Array(InternalGuestQuoteBookingCardLineSchema) });
248
+ const InternalGuestQuoteBookingCardSchema = Schema.Struct({
249
+ sections: Schema.Array(InternalGuestQuoteBookingCardSectionSchema),
250
+ total: NonNegativeAmountSchema,
251
+ totalBeforeModifiers: Schema.optionalKey(NonNegativeAmountSchema)
252
+ });
253
+ const toModifierDifference = (modifiers) => (modifiers ?? []).reduce((total, modifier) => total - modifier.amount, 0);
254
+ const toDerivedItemTotalBeforeModifiers = (item) => {
255
+ if (typeof item.appliedCharge === "string") return void 0;
256
+ const modifierDifference = toModifierDifference(item.modifiers);
257
+ if (modifierDifference === 0) return void 0;
258
+ return item.appliedCharge + modifierDifference;
259
+ };
260
+ const toDerivedTotalBeforeModifiers = (bookingCardInformation) => {
261
+ const modifierDifference = bookingCardInformation.sections.reduce((sectionTotal, section) => sectionTotal + section.lines.reduce((lineTotal, line) => lineTotal + toModifierDifference(line.item.modifiers) + (line.subItems ?? []).reduce((subItemTotal, item) => subItemTotal + toModifierDifference(item.modifiers), 0), 0), 0);
262
+ if (modifierDifference === 0) return void 0;
263
+ return bookingCardInformation.total + modifierDifference;
264
+ };
265
+ const toPublicModifiers = (modifiers, locale, currency) => {
266
+ if (modifiers === void 0) return void 0;
267
+ const modifiersByLabel = /* @__PURE__ */ new Map();
268
+ for (const modifier of modifiers) modifiersByLabel.set(modifier.label, (modifiersByLabel.get(modifier.label) ?? 0) + modifier.amount);
269
+ return Array.from(modifiersByLabel, ([label, amount]) => ({
270
+ label,
271
+ amount: formatCurrency(amount, locale, currency)
272
+ }));
273
+ };
274
+ const toPublicBookingCardItem = (item, locale, currency) => {
275
+ const totalBeforeModifiers = item.totalBeforeModifiers ?? toDerivedItemTotalBeforeModifiers(item);
276
+ const modifiers = toPublicModifiers(item.modifiers, locale, currency);
277
+ if (typeof item.appliedCharge === "string") return {
278
+ position: item.position,
279
+ appliedCharge: item.appliedCharge,
280
+ ...modifiers === void 0 ? {} : { modifiers },
281
+ ...totalBeforeModifiers === void 0 ? {} : { totalBeforeModifiers: formatCurrency(totalBeforeModifiers, locale, currency) }
282
+ };
283
+ return {
284
+ position: item.position,
285
+ appliedCharge: formatCurrency(item.appliedCharge, locale, currency),
286
+ ...modifiers === void 0 ? {} : { modifiers },
287
+ ...totalBeforeModifiers === void 0 ? {} : { totalBeforeModifiers: formatCurrency(totalBeforeModifiers, locale, currency) }
288
+ };
289
+ };
290
+ const toPublicBookingCardInformation = (bookingCardInformation, locale, currency) => {
291
+ const totalBeforeModifiers = bookingCardInformation.totalBeforeModifiers ?? toDerivedTotalBeforeModifiers(bookingCardInformation);
292
+ return {
293
+ sections: bookingCardInformation.sections.map((section) => ({ lines: section.lines.map((line) => ({
294
+ item: toPublicBookingCardItem(line.item, locale, currency),
295
+ ...line.subItems === void 0 ? {} : { subItems: line.subItems.map((item) => toPublicBookingCardItem(item, locale, currency)) }
296
+ })) })),
297
+ total: formatCurrency(bookingCardInformation.total, locale, currency),
298
+ ...totalBeforeModifiers === void 0 ? {} : { totalBeforeModifiers: formatCurrency(totalBeforeModifiers, locale, currency) }
299
+ };
300
+ };
301
+ //#endregion
302
+ //#region src/domain/quote/format-percentage.ts
303
+ const formatPercentage = (value, locale) => `${new Intl.NumberFormat(locale, { maximumFractionDigits: 2 }).format(value / 100)}%`;
304
+ //#endregion
305
+ //#region src/domain/quote/cancellation-policy.ts
306
+ Schema.Literals(["default", "alternative"]);
307
+ const CancellationRuleSchema = Schema.Struct({
308
+ daysBeforeArrival: Schema.Number,
309
+ refundPercentage: Schema.String
310
+ });
311
+ const CancellationPolicyOptionSchema = Schema.Struct({
312
+ id: Schema.String,
313
+ label: Schema.String,
314
+ description: Schema.optionalKey(Schema.String),
315
+ selected: Schema.Boolean,
316
+ rules: Schema.optionalKey(Schema.Array(CancellationRuleSchema)),
317
+ markUpPercentage: Schema.optionalKey(Schema.String),
318
+ processingFee: Schema.optionalKey(Schema.String)
319
+ });
320
+ const toPublicCancellationPolicyOption = ({ option, selection, locale, currency }) => ({
321
+ id: option.id,
322
+ label: option.label,
323
+ ...option.description === void 0 ? {} : { description: option.description },
324
+ selected: selection?.policyId === option.id,
325
+ ...option.rules === void 0 ? {} : { rules: option.rules.map((rule) => ({
326
+ daysBeforeArrival: rule.daysBeforeArrival,
327
+ refundPercentage: formatPercentage(rule.valuePercentage, locale)
328
+ })) },
329
+ ...option.markUpPercentage === void 0 ? {} : { markUpPercentage: formatPercentage(option.markUpPercentage, locale) },
330
+ ...option.processingFee === void 0 ? {} : { processingFee: formatCurrency(option.processingFee, locale, currency) }
331
+ });
332
+ //#endregion
333
+ //#region src/domain/quote/internal-state.ts
334
+ const GuestQuoteInternalState = Symbol("@v-office/cms-sdk/GuestQuoteInternalState");
335
+ const getGuestQuoteBackendContext = (quote) => quote[GuestQuoteInternalState].backendContext;
336
+ const getGuestQuoteInput = (quote) => quote[GuestQuoteInternalState].input;
337
+ const getGuestQuoteCancellationPolicySelection = (quote) => quote[GuestQuoteInternalState].cancellationPolicySelection;
338
+ const getGuestQuoteMultiRateContext = (quote) => quote[GuestQuoteInternalState].multiRateContext;
339
+ //#endregion
340
+ //#region src/domain/quote/selection.ts
341
+ const QuoteSelectionSchema = Schema.Struct({
342
+ id: Schema.String,
343
+ quantity: PositiveQuantitySchema
344
+ });
345
+ const parsePositiveQuantity = (quantity) => Schema.decodeUnknownEffect(PositiveQuantitySchema)(quantity).pipe(Effect.mapError((cause) => new InvalidAdditionalServiceQuantity({
346
+ quantity,
347
+ cause
348
+ })));
349
+ //#endregion
350
+ //#region src/domain/quote/guest-quote.ts
351
+ const GuestQuoteSelectionMutations = Symbol("@v-office/cms-sdk/GuestQuoteSelectionMutations");
352
+ const runGuestQuoteSelection = (effect) => Effect.runSync(effect.pipe(Effect.match({
353
+ onFailure: (error) => ({
354
+ ok: false,
355
+ error
356
+ }),
357
+ onSuccess: (quote) => ({
358
+ ok: true,
359
+ quote
360
+ })
361
+ })));
362
+ const addGuestQuoteAdditionalServiceSelection = ({ quote, id }) => quote[GuestQuoteSelectionMutations].addAdditionalService({ id });
363
+ const removeGuestQuoteAdditionalServiceSelection = ({ quote, id }) => quote[GuestQuoteSelectionMutations].removeAdditionalService({ id });
364
+ const clearGuestQuoteAdditionalServiceSelections = ({ quote }) => quote[GuestQuoteSelectionMutations].clearAdditionalServices();
365
+ const selectGuestQuoteCancellationPolicySelection = ({ quote, id }) => quote[GuestQuoteSelectionMutations].selectCancellationPolicy({ id });
366
+ const withGuestQuoteInsurance = ({ quote, insurance }) => quote[GuestQuoteSelectionMutations].withInsurance(insurance);
367
+ const toSelectedAdditionalServiceTotal = ({ input, selection, service }) => {
368
+ const chargeAmount = service.chargeAmount * selection.quantity;
369
+ switch (service.calculation) {
370
+ case "FLAT": return chargeAmount;
371
+ case "PER_USAGE": return chargeAmount;
372
+ case "PER_NIGHT": return chargeAmount * toNightCount(input);
373
+ case "PER_DAY": return chargeAmount * toNightCount(input);
374
+ }
375
+ };
376
+ const toAdditionalServicesTotal = (input, selections, additionalServices) => {
377
+ let total = 0;
378
+ for (const selection of selections) {
379
+ const service = additionalServices.find((additionalService) => additionalService.id === selection.id);
380
+ if (service !== void 0) total += toSelectedAdditionalServiceTotal({
381
+ input,
382
+ selection,
383
+ service
384
+ });
385
+ }
386
+ return total;
387
+ };
388
+ const toBookingCardInformation = ({ additionalServices, bookingCardInformation, additionalServicesTotal, input, selections, total }) => {
389
+ const lines = selections.flatMap((selection) => {
390
+ const service = additionalServices.find((additionalService) => additionalService.id === selection.id);
391
+ if (service === void 0) return [];
392
+ return [{ item: {
393
+ position: service.label,
394
+ appliedCharge: toSelectedAdditionalServiceTotal({
395
+ input,
396
+ selection,
397
+ service
398
+ })
399
+ } }];
400
+ });
401
+ return {
402
+ sections: lines.length === 0 ? bookingCardInformation.sections : [...bookingCardInformation.sections, { lines }],
403
+ total,
404
+ ...bookingCardInformation.totalBeforeModifiers === void 0 ? {} : { totalBeforeModifiers: bookingCardInformation.totalBeforeModifiers + additionalServicesTotal }
405
+ };
406
+ };
407
+ var GuestQuote = class GuestQuote extends Schema.Class("@v-office/cms-sdk/GuestQuote")({
408
+ bookingCardInformation: GuestQuoteBookingCardSchema,
409
+ additionalServices: Schema.Array(AdditionalServiceSchema),
410
+ cancellationPolicies: Schema.optionalKey(Schema.Array(CancellationPolicyOptionSchema)),
411
+ insurance: Schema.optionalKey(GuestQuoteInsuranceSchema)
412
+ }) {
413
+ #input;
414
+ #currency;
415
+ #baseTotal;
416
+ #bookingCardInformation;
417
+ #additionalServices;
418
+ #selections;
419
+ #cancellationPolicies;
420
+ #cancellationPolicySelection;
421
+ #cancellationPolicyQuoteVariants;
422
+ #multiRateContext;
423
+ constructor(props) {
424
+ const baseTotal = Schema.decodeUnknownSync(NonNegativeAmountSchema)(props.baseTotal);
425
+ const bookingCardInformation = Schema.decodeUnknownSync(InternalGuestQuoteBookingCardSchema)(props.bookingCardInformation);
426
+ const additionalServices = props.additionalServices.map((service) => ({
427
+ ...service,
428
+ chargeAmount: Schema.decodeUnknownSync(NonNegativeAmountSchema)(service.chargeAmount)
429
+ }));
430
+ const decodeSelection = Schema.decodeUnknownSync(QuoteSelectionSchema);
431
+ const selections = (props.selections ?? []).map((selection) => decodeSelection(selection));
432
+ const cancellationPolicies = props.cancellationPolicies ?? [];
433
+ const cancellationPolicySelection = props.cancellationPolicySelection ?? (cancellationPolicies[0] === void 0 ? void 0 : {
434
+ policyId: cancellationPolicies[0].id,
435
+ kind: cancellationPolicies[0].kind,
436
+ withAlternativeCancellationPolicy: cancellationPolicies[0].withAlternativeCancellationPolicy
437
+ });
438
+ const additionalServicesTotal = toAdditionalServicesTotal(props.input, selections, additionalServices);
439
+ const total = Schema.decodeUnknownSync(NonNegativeAmountSchema)(baseTotal + additionalServicesTotal);
440
+ const publicBookingCardInformation = toPublicBookingCardInformation(toBookingCardInformation({
441
+ additionalServices,
442
+ bookingCardInformation,
443
+ additionalServicesTotal,
444
+ input: props.input,
445
+ selections,
446
+ total
447
+ }), props.input.locale, props.currency);
448
+ super({
449
+ bookingCardInformation: publicBookingCardInformation,
450
+ additionalServices: additionalServices.map(toPublicAdditionalService),
451
+ ...cancellationPolicies.length === 0 ? {} : { cancellationPolicies: cancellationPolicies.map((option) => toPublicCancellationPolicyOption({
452
+ option,
453
+ locale: props.input.locale,
454
+ currency: props.currency,
455
+ ...cancellationPolicySelection === void 0 ? {} : { selection: cancellationPolicySelection }
456
+ })) },
457
+ ...props.insurance === void 0 ? {} : { insurance: props.insurance }
458
+ });
459
+ this.#input = props.input;
460
+ this.#currency = props.currency;
461
+ this.#baseTotal = baseTotal;
462
+ this.#bookingCardInformation = bookingCardInformation;
463
+ this.#additionalServices = additionalServices;
464
+ this.#selections = selections;
465
+ this.#cancellationPolicies = cancellationPolicies;
466
+ this.#cancellationPolicySelection = cancellationPolicySelection;
467
+ this.#cancellationPolicyQuoteVariants = props.cancellationPolicyQuoteVariants ?? [];
468
+ this.#multiRateContext = props.multiRateContext;
469
+ Object.defineProperty(this, GuestQuoteInternalState, { value: {
470
+ input: props.input,
471
+ ...props.backendContext === void 0 ? {} : { backendContext: props.backendContext },
472
+ ...props.updateBackendContext === void 0 ? {} : { updateBackendContext: props.updateBackendContext },
473
+ selections,
474
+ ...cancellationPolicySelection === void 0 ? {} : { cancellationPolicySelection },
475
+ ...props.multiRateContext === void 0 ? {} : { multiRateContext: props.multiRateContext }
476
+ } });
477
+ Object.defineProperty(this, GuestQuoteSelectionMutations, { value: {
478
+ addAdditionalService: (input) => runGuestQuoteSelection(this.addAdditionalServiceEffect(input.id, 1)),
479
+ removeAdditionalService: (input) => runGuestQuoteSelection(this.removeAdditionalServiceEffect(input.id, 1)),
480
+ clearAdditionalServices: () => this.clearAdditionalServicesSelection(),
481
+ selectCancellationPolicy: (input) => runGuestQuoteSelection(this.selectCancellationPolicyEffect(input.id)),
482
+ withInsurance: (insurance) => this.rebuild({ insurance })
483
+ } });
484
+ }
485
+ rebuild(props = {}) {
486
+ const backendContext = props.backendContext ?? this[GuestQuoteInternalState].backendContext;
487
+ const updateBackendContext = props.updateBackendContext ?? this[GuestQuoteInternalState].updateBackendContext;
488
+ const cancellationPolicySelection = props.cancellationPolicySelection ?? this.#cancellationPolicySelection;
489
+ const multiRateContext = props.multiRateContext ?? this.#multiRateContext;
490
+ return new GuestQuote({
491
+ input: props.input ?? this.#input,
492
+ bookingCardInformation: props.bookingCardInformation ?? this.#bookingCardInformation,
493
+ baseTotal: props.baseTotal ?? this.#baseTotal,
494
+ currency: props.currency ?? this.#currency,
495
+ additionalServices: props.additionalServices ?? this.#additionalServices,
496
+ selections: props.selections ?? this.#selections,
497
+ cancellationPolicies: props.cancellationPolicies ?? this.#cancellationPolicies,
498
+ cancellationPolicyQuoteVariants: props.cancellationPolicyQuoteVariants ?? this.#cancellationPolicyQuoteVariants,
499
+ ...backendContext === void 0 ? {} : { backendContext },
500
+ ...updateBackendContext === void 0 ? {} : { updateBackendContext },
501
+ ...cancellationPolicySelection === void 0 ? {} : { cancellationPolicySelection },
502
+ ...multiRateContext === void 0 ? {} : { multiRateContext },
503
+ ...props.insurance === void 0 ? this.insurance === void 0 ? {} : { insurance: this.insurance } : { insurance: props.insurance }
504
+ });
505
+ }
506
+ addAdditionalServiceEffect(id, quantity = 1) {
507
+ const selections = this.#selections;
508
+ const additionalServices = () => this.#additionalServices;
509
+ const withAdditionalServiceSelections = (nextSelections) => this.withAdditionalServiceSelections(nextSelections);
510
+ return Effect.gen(function* () {
511
+ const additionalQuantity = yield* parsePositiveQuantity(quantity);
512
+ const service = additionalServices().find((additionalService) => additionalService.id === id);
513
+ if (service === void 0) return yield* Effect.fail(new UnknownAdditionalService({ id }));
514
+ const nextQuantity = (selections.find((selection) => selection.id === id)?.quantity ?? 0) + additionalQuantity;
515
+ if (service.maxPerBooking !== void 0 && nextQuantity > service.maxPerBooking) return yield* Effect.fail(new AdditionalServiceLimitExceeded({
516
+ id,
517
+ label: service.label,
518
+ maxPerBooking: service.maxPerBooking,
519
+ requestedQuantity: nextQuantity
520
+ }));
521
+ return yield* withAdditionalServiceSelections([...selections.filter((selection) => selection.id !== id), {
522
+ id,
523
+ quantity: nextQuantity
524
+ }]);
525
+ });
526
+ }
527
+ removeAdditionalServiceEffect(id, quantity = 1) {
528
+ const selections = this.#selections;
529
+ const currentQuote = () => this;
530
+ const withAdditionalServiceSelections = (nextSelections) => this.withAdditionalServiceSelections(nextSelections);
531
+ return Effect.gen(function* () {
532
+ const quantityToRemove = yield* parsePositiveQuantity(quantity);
533
+ const existingSelection = selections.find((selection) => selection.id === id);
534
+ if (existingSelection === void 0) return currentQuote();
535
+ const nextQuantity = existingSelection.quantity - quantityToRemove;
536
+ const remainingSelections = selections.filter((selection) => selection.id !== id);
537
+ return yield* withAdditionalServiceSelections(nextQuantity <= 0 ? remainingSelections : [...remainingSelections, {
538
+ ...existingSelection,
539
+ quantity: nextQuantity
540
+ }]);
541
+ });
542
+ }
543
+ clearAdditionalServicesSelection() {
544
+ if (this.#selections.length === 0) return {
545
+ ok: true,
546
+ quote: this
547
+ };
548
+ const backendContext = withQuoteBackendContextSelections(this[GuestQuoteInternalState].backendContext, this[GuestQuoteInternalState].updateBackendContext, []);
549
+ return {
550
+ ok: true,
551
+ quote: this.rebuild({
552
+ selections: [],
553
+ ...backendContext === void 0 ? {} : { backendContext }
554
+ })
555
+ };
556
+ }
557
+ selectCancellationPolicyEffect(id) {
558
+ const option = this.#cancellationPolicies.find((policy) => policy.id === id);
559
+ if (option === void 0) return Effect.fail(new UnknownCancellationPolicy({ id }));
560
+ if (this.#cancellationPolicySelection?.policyId === id) return Effect.succeed(this);
561
+ const variant = this.#cancellationPolicyQuoteVariants.find((quoteVariant) => quoteVariant.policyId === id);
562
+ if (variant === void 0) return Effect.fail(new UnavailableCancellationPolicyQuote({ id }));
563
+ const selection = {
564
+ policyId: option.id,
565
+ kind: option.kind,
566
+ withAlternativeCancellationPolicy: option.withAlternativeCancellationPolicy
567
+ };
568
+ const backendContext = withQuoteBackendContextSelections(variant.backendContext, this[GuestQuoteInternalState].updateBackendContext, this.#selections);
569
+ return this.validateAdditionalServiceSelections({
570
+ additionalServices: variant.additionalServices,
571
+ selections: this.#selections
572
+ }).pipe(Effect.as(this.rebuild({
573
+ bookingCardInformation: variant.bookingCardInformation,
574
+ baseTotal: variant.baseTotal,
575
+ currency: variant.currency,
576
+ additionalServices: variant.additionalServices,
577
+ cancellationPolicySelection: selection,
578
+ ...backendContext === void 0 ? {} : { backendContext }
579
+ })));
580
+ }
581
+ withAdditionalServiceSelections(selections) {
582
+ return this.validateAdditionalServiceSelections({
583
+ additionalServices: this.#additionalServices,
584
+ selections
585
+ }).pipe(Effect.flatMap(() => this.withValidatedAdditionalServiceSelections(selections)));
586
+ }
587
+ validateAdditionalServiceSelections({ additionalServices, selections }) {
588
+ for (const selection of selections) {
589
+ const service = additionalServices.find((additionalService) => additionalService.id === selection.id);
590
+ if (service === void 0) return Effect.fail(new UnknownAdditionalService({ id: selection.id }));
591
+ if (service.maxPerBooking !== void 0 && selection.quantity > service.maxPerBooking) return Effect.fail(new AdditionalServiceLimitExceeded({
592
+ id: selection.id,
593
+ label: service.label,
594
+ maxPerBooking: service.maxPerBooking,
595
+ requestedQuantity: selection.quantity
596
+ }));
597
+ }
598
+ return Effect.void;
599
+ }
600
+ withValidatedAdditionalServiceSelections(selections) {
601
+ const backendContext = withQuoteBackendContextSelections(this[GuestQuoteInternalState].backendContext, this[GuestQuoteInternalState].updateBackendContext, selections);
602
+ return Effect.succeed(this.rebuild({
603
+ selections: [...selections],
604
+ ...backendContext === void 0 ? {} : { backendContext }
605
+ }));
606
+ }
607
+ };
608
+ //#endregion
609
+ export { daysBetweenLocalDates as C, UnknownAdditionalService as D, InvalidAdditionalServiceQuantity as E, UnresolvableMultiRate as O, toYearMonthFromPeriodQueryMonth as S, AmbiguousMultiRate as T, toFormattedSearchPrice as _, selectGuestQuoteCancellationPolicySelection as a, localeToLanguage as b, getGuestQuoteCancellationPolicySelection as c, formatCurrency as d, asArray as f, toNightCount as g, firstString as h, removeGuestQuoteAdditionalServiceSelection as i, getGuestQuoteInput as l, firstNumber as m, addGuestQuoteAdditionalServiceSelection as n, withGuestQuoteInsurance as o, asRecord as p, clearGuestQuoteAdditionalServiceSelections as r, getGuestQuoteBackendContext as s, GuestQuote as t, getGuestQuoteMultiRateContext as u, toCountry as v, AdditionalServiceLimitExceeded as w, toIsoDateFromPeriodQueryDate as x, makeTranslate as y };
@@ -1,8 +1,8 @@
1
- import { F as parseVofficeFacilityData, I as parseVofficeFeedbackData, L as parseVofficeUnitData, M as VofficeUnitDataPropertyCategoryLabelKeys, N as VofficeUnitDataPropertyCategoryValues, P as VofficeUnitDataPropertyMetadata } from "./client-BFtPZZZh.mjs";
1
+ import { F as parseVofficeFacilityData, I as parseVofficeFeedbackData, L as parseVofficeUnitData, M as VofficeUnitDataPropertyCategoryLabelKeys, N as VofficeUnitDataPropertyCategoryValues, P as VofficeUnitDataPropertyMetadata } from "./client-DYP0Y59i.mjs";
2
2
  import "./errors-2cuUGSvi.mjs";
3
- import { c as localeToLanguage, s as makeTranslate } from "./parser-D6UAf8Ld.mjs";
4
- import { i as renderLabeledAttributeValue, t as renderCustomAttributeHighlight } from "./custom-attribute-ChCbJKf_.mjs";
5
- import { n as toAddress, r as toLocalizedString, t as toRentalHighlights } from "./to-rental-highlights-CkHgZINu.mjs";
3
+ import { b as localeToLanguage, y as makeTranslate } from "./quote-CRjV_lf-.mjs";
4
+ import { i as renderLabeledAttributeValue, t as renderCustomAttributeHighlight } from "./custom-attribute-D5Kb1YHA.mjs";
5
+ import { n as toAddress, r as toLocalizedString, t as toRentalHighlights } from "./to-rental-highlights-BShYK50C.mjs";
6
6
  import { Effect } from "effect";
7
7
  //#region src/adapters/v9/parser/rentals/to-description.ts
8
8
  const toDescription = (data, locale) => {
@@ -1,7 +1,7 @@
1
- import { S as toAddress, _ as GENERATED_RENTAL_METADATA_CATALOG, b as toLocation, g as toRentalHighlights, h as toRentalType, m as toScope, v as toProperty, x as toImages, y as toDescription } from "./client-BFtPZZZh.mjs";
1
+ import { S as toAddress, _ as GENERATED_RENTAL_METADATA_CATALOG, b as toLocation, g as toRentalHighlights, h as toRentalType, m as toScope, v as toProperty, x as toImages, y as toDescription } from "./client-DYP0Y59i.mjs";
2
2
  import "./errors-2cuUGSvi.mjs";
3
- import { c as localeToLanguage, s as makeTranslate } from "./parser-D6UAf8Ld.mjs";
4
- import { t as renderCustomAttributeHighlight } from "./custom-attribute-ChCbJKf_.mjs";
3
+ import { b as localeToLanguage, y as makeTranslate } from "./quote-CRjV_lf-.mjs";
4
+ import { t as renderCustomAttributeHighlight } from "./custom-attribute-D5Kb1YHA.mjs";
5
5
  import { Effect } from "effect";
6
6
  //#region src/adapters/v10/parser/rentals/to-rental-attributes.ts
7
7
  const RENTAL_ATTRIBUTE_DEFINITIONS = GENERATED_RENTAL_METADATA_CATALOG.attributes;