@ticketboothapp/booking 1.2.120 → 1.2.122
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/package.json +1 -1
- package/src/components/booking/AdminChangeBookingFlow.tsx +18 -0
- package/src/components/booking/PrivateShuttleBookingFlow.tsx +203 -20
- package/src/components/booking/provider-dashboard-change-booking.ts +11 -0
- package/src/lib/booking/pricing.ts +15 -4
- package/src/lib/booking-api.ts +2 -0
package/package.json
CHANGED
|
@@ -4230,6 +4230,22 @@ export function AdminChangeBookingFlow({
|
|
|
4230
4230
|
t,
|
|
4231
4231
|
]);
|
|
4232
4232
|
|
|
4233
|
+
const providerApplyAuthoritativeReceipt = useMemo(() => {
|
|
4234
|
+
if (!useAdminFeAuthoritativeQuote) return undefined;
|
|
4235
|
+
return {
|
|
4236
|
+
subtotalBeforeTax: adminFeAuthoritativeReceipt.subtotal,
|
|
4237
|
+
taxAmount: adminFeAuthoritativeReceipt.tax,
|
|
4238
|
+
totalAmount: adminFeAuthoritativeReceipt.total,
|
|
4239
|
+
currency: adminFeAuthoritativeReceipt.currency ?? currency,
|
|
4240
|
+
lineItems: adminFeAuthoritativeReceipt.lineItems.map((line) => ({
|
|
4241
|
+
type: String(line.type || 'FEE'),
|
|
4242
|
+
label: String(line.label || 'Adjustment'),
|
|
4243
|
+
amount: Number(line.amount) || 0,
|
|
4244
|
+
...(line.quantity != null ? { quantity: Number(line.quantity) || 0 } : {}),
|
|
4245
|
+
})),
|
|
4246
|
+
};
|
|
4247
|
+
}, [adminFeAuthoritativeReceipt, currency, useAdminFeAuthoritativeQuote]);
|
|
4248
|
+
|
|
4233
4249
|
const changeFlowClientEstimateDueBase = (() => {
|
|
4234
4250
|
if (!originalReceipt) return totalPrice;
|
|
4235
4251
|
if (unchangedReceiptAnchor) return 0;
|
|
@@ -5392,6 +5408,7 @@ export function AdminChangeBookingFlow({
|
|
|
5392
5408
|
: {}),
|
|
5393
5409
|
}
|
|
5394
5410
|
: undefined,
|
|
5411
|
+
authoritativeReceipt: providerApplyAuthoritativeReceipt,
|
|
5395
5412
|
capacitySeatCredit: {
|
|
5396
5413
|
enabled: true,
|
|
5397
5414
|
previousPassengerCount: changeFlowInitialTicketCount,
|
|
@@ -5787,6 +5804,7 @@ export function AdminChangeBookingFlow({
|
|
|
5787
5804
|
: {}),
|
|
5788
5805
|
}
|
|
5789
5806
|
: undefined,
|
|
5807
|
+
authoritativeReceipt: providerApplyAuthoritativeReceipt,
|
|
5790
5808
|
capacitySeatCredit: {
|
|
5791
5809
|
enabled: true,
|
|
5792
5810
|
previousPassengerCount: changeFlowInitialTicketCount,
|
|
@@ -119,6 +119,27 @@ interface PrivateShuttleBookingFlowProps {
|
|
|
119
119
|
const RESOURCE_CAPACITY = 13;
|
|
120
120
|
const ADDITIONAL_HOUR_PRICE = 170;
|
|
121
121
|
const DATE_ONLY_REGEX = /^\d{4}-\d{2}-\d{2}$/;
|
|
122
|
+
const MORAINE_LAKE_ROAD_ACCESS_FEE_TOOLTIP =
|
|
123
|
+
"Since 2025, Parks Canada charges a per-trip fee for License of Occupation at Moraine Lake. This fee contributes towards Parks Canada's Moraine Lake Road operations.";
|
|
124
|
+
|
|
125
|
+
function isMoraineLakeRoadAccessFeeName(name: string): boolean {
|
|
126
|
+
const normalized = name.toLowerCase();
|
|
127
|
+
return (
|
|
128
|
+
normalized.includes('moraine') &&
|
|
129
|
+
(normalized.includes('access') ||
|
|
130
|
+
normalized.includes('road') ||
|
|
131
|
+
normalized.includes('license'))
|
|
132
|
+
);
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
function isMoraineLakeLocationText(value: string): boolean {
|
|
136
|
+
const normalized = value.toLowerCase().replace(/[_-]+/g, ' ');
|
|
137
|
+
return normalized.includes('moraine') && normalized.includes('lake');
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
function roundMoney(amount: number): number {
|
|
141
|
+
return Math.round(amount * 100) / 100;
|
|
142
|
+
}
|
|
122
143
|
|
|
123
144
|
function parseAvailabilityDateTime(value: string): Date {
|
|
124
145
|
// If API omits timezone offset, treat it as UTC to prevent user-local day shifts.
|
|
@@ -352,7 +373,7 @@ export function PrivateShuttleBookingFlow({
|
|
|
352
373
|
itineraryDisplay?: ItineraryDisplayStep[] | null;
|
|
353
374
|
clientSecret: string;
|
|
354
375
|
ticketLinesForModal: CheckoutModalLineItem[];
|
|
355
|
-
feeLineItems: { name: string; totalAmount: number }[];
|
|
376
|
+
feeLineItems: { name: string; totalAmount: number; description?: string }[];
|
|
356
377
|
cancellationPolicyFee: number;
|
|
357
378
|
cancellationPolicyLabel?: string;
|
|
358
379
|
subtotal: number;
|
|
@@ -1095,6 +1116,38 @@ export function PrivateShuttleBookingFlow({
|
|
|
1095
1116
|
const cancellationPolicyFee = selectedCancellationPolicy
|
|
1096
1117
|
? (selectedCancellationPolicy.feeByCurrency[currency] ?? 0)
|
|
1097
1118
|
: 0;
|
|
1119
|
+
const draftItineraryIncludesMoraineLake = useMemo(() => {
|
|
1120
|
+
if (draftItineraryDestinations.length === 0) return false;
|
|
1121
|
+
const destinationLabelsById = new Map(
|
|
1122
|
+
(product.itineraryBuilder?.destinations ?? []).map((destination) => [
|
|
1123
|
+
destination.id,
|
|
1124
|
+
destination.label,
|
|
1125
|
+
])
|
|
1126
|
+
);
|
|
1127
|
+
return draftItineraryDestinations.some((destinationId) => {
|
|
1128
|
+
const label = destinationLabelsById.get(destinationId);
|
|
1129
|
+
return (
|
|
1130
|
+
isMoraineLakeLocationText(destinationId) ||
|
|
1131
|
+
(label ? isMoraineLakeLocationText(label) : false)
|
|
1132
|
+
);
|
|
1133
|
+
});
|
|
1134
|
+
}, [draftItineraryDestinations, product.itineraryBuilder?.destinations]);
|
|
1135
|
+
const perBookingFeeLineItems = useMemo(() => {
|
|
1136
|
+
if (isTaxIncludedInPrice) return [];
|
|
1137
|
+
const amountsByName = pricingConfig?.perBookingFeesByCurrency?.[currency];
|
|
1138
|
+
if (!amountsByName) return [];
|
|
1139
|
+
const feeMetadata = pricingConfig?.perBookingFees ?? {};
|
|
1140
|
+
return Object.entries(amountsByName)
|
|
1141
|
+
.filter(
|
|
1142
|
+
([name]) =>
|
|
1143
|
+
draftItineraryIncludesMoraineLake || !isMoraineLakeRoadAccessFeeName(name)
|
|
1144
|
+
)
|
|
1145
|
+
.map(([name, amount]) => ({
|
|
1146
|
+
name,
|
|
1147
|
+
totalAmount: amount,
|
|
1148
|
+
description: feeMetadata[name]?.description,
|
|
1149
|
+
}));
|
|
1150
|
+
}, [currency, draftItineraryIncludesMoraineLake, isTaxIncludedInPrice, pricingConfig]);
|
|
1098
1151
|
|
|
1099
1152
|
const addOnTotal = useMemo(() => {
|
|
1100
1153
|
let sum = 0;
|
|
@@ -1114,7 +1167,8 @@ export function PrivateShuttleBookingFlow({
|
|
|
1114
1167
|
}, [addOnSelections, addOns]);
|
|
1115
1168
|
|
|
1116
1169
|
const additionalHoursAmount = (isAdmin ? additionalHoursCount : 0) * ADDITIONAL_HOUR_PRICE;
|
|
1117
|
-
const
|
|
1170
|
+
const perBookingFeeTotal = perBookingFeeLineItems.reduce((sum, fee) => sum + fee.totalAmount, 0);
|
|
1171
|
+
const subtotal = basePrice + addOnTotal + additionalHoursAmount + perBookingFeeTotal;
|
|
1118
1172
|
const effectivePromoDiscountAmount = promoDiscountAmount > 0 ? promoDiscountAmount : 0;
|
|
1119
1173
|
const taxAmount = isTaxIncludedInPrice ? 0 : subtotal * taxRate;
|
|
1120
1174
|
const effectiveTaxAmount =
|
|
@@ -1122,6 +1176,116 @@ export function PrivateShuttleBookingFlow({
|
|
|
1122
1176
|
? (isTaxIncludedInPrice ? 0 : (subtotal - effectivePromoDiscountAmount) * taxRate)
|
|
1123
1177
|
: taxAmount;
|
|
1124
1178
|
const totalPrice = subtotal + effectiveTaxAmount - effectivePromoDiscountAmount;
|
|
1179
|
+
const providerChangeAuthoritativeReceipt = useMemo<
|
|
1180
|
+
ProviderDashboardChangeBookingPayload['authoritativeReceipt']
|
|
1181
|
+
>(() => {
|
|
1182
|
+
const lineItems: NonNullable<
|
|
1183
|
+
ProviderDashboardChangeBookingPayload['authoritativeReceipt']
|
|
1184
|
+
>['lineItems'] = [
|
|
1185
|
+
{
|
|
1186
|
+
type: 'TICKET',
|
|
1187
|
+
label: resourceCount > 1 ? 'Shuttles' : 'Shuttle',
|
|
1188
|
+
amount: roundMoney(basePrice),
|
|
1189
|
+
quantity: resourceCount,
|
|
1190
|
+
},
|
|
1191
|
+
];
|
|
1192
|
+
|
|
1193
|
+
for (const sel of addOnSelections) {
|
|
1194
|
+
const addOn = addOns.find((a) => a.addOnId === sel.addOnId);
|
|
1195
|
+
if (!addOn) continue;
|
|
1196
|
+
const hasVariant =
|
|
1197
|
+
(addOn.variantType === 'single_choice' || addOn.variantType === 'multi_quantity') &&
|
|
1198
|
+
sel.variantId;
|
|
1199
|
+
const variant = hasVariant
|
|
1200
|
+
? addOn.variants?.find((v) => v.id === sel.variantId)
|
|
1201
|
+
: null;
|
|
1202
|
+
const amount = ((addOn.price ?? 0) + (variant?.priceAdjustment ?? 0)) * (sel.quantity ?? 1);
|
|
1203
|
+
lineItems.push({
|
|
1204
|
+
type: 'FEE',
|
|
1205
|
+
label: variant?.label ? `${addOn.name} (${variant.label})` : addOn.name,
|
|
1206
|
+
amount: roundMoney(amount),
|
|
1207
|
+
});
|
|
1208
|
+
}
|
|
1209
|
+
|
|
1210
|
+
if (additionalHoursAmount > 0) {
|
|
1211
|
+
lineItems.push({
|
|
1212
|
+
type: 'FEE',
|
|
1213
|
+
label:
|
|
1214
|
+
additionalHoursCount === 1
|
|
1215
|
+
? 'Additional hour'
|
|
1216
|
+
: `Additional hours (${additionalHoursCount})`,
|
|
1217
|
+
amount: roundMoney(additionalHoursAmount),
|
|
1218
|
+
});
|
|
1219
|
+
}
|
|
1220
|
+
|
|
1221
|
+
for (const fee of perBookingFeeLineItems) {
|
|
1222
|
+
lineItems.push({
|
|
1223
|
+
type: 'FEE',
|
|
1224
|
+
label: fee.name,
|
|
1225
|
+
amount: roundMoney(fee.totalAmount),
|
|
1226
|
+
});
|
|
1227
|
+
}
|
|
1228
|
+
|
|
1229
|
+
if (cancellationPolicyFee > 0 && selectedCancellationPolicy) {
|
|
1230
|
+
lineItems.push({
|
|
1231
|
+
type: 'CANCELLATION_UPGRADE',
|
|
1232
|
+
label: selectedCancellationPolicy.label,
|
|
1233
|
+
amount: roundMoney(cancellationPolicyFee),
|
|
1234
|
+
});
|
|
1235
|
+
}
|
|
1236
|
+
|
|
1237
|
+
if (effectiveTaxAmount > 0) {
|
|
1238
|
+
lineItems.push({
|
|
1239
|
+
type: 'TAX',
|
|
1240
|
+
label: t('booking.tax') !== 'booking.tax' ? t('booking.tax') : 'Taxes and fees',
|
|
1241
|
+
amount: roundMoney(effectiveTaxAmount),
|
|
1242
|
+
});
|
|
1243
|
+
}
|
|
1244
|
+
|
|
1245
|
+
if (effectivePromoDiscountAmount > 0) {
|
|
1246
|
+
lineItems.push({
|
|
1247
|
+
type: isGiftCard ? 'GIFT_CARD' : 'PROMO_CODE',
|
|
1248
|
+
label: activePromoCode ? `Promo: ${activePromoCode}` : (t('booking.discount') || 'Discount'),
|
|
1249
|
+
amount: roundMoney(-effectivePromoDiscountAmount),
|
|
1250
|
+
});
|
|
1251
|
+
}
|
|
1252
|
+
|
|
1253
|
+
const expectedTotal = roundMoney(totalPrice);
|
|
1254
|
+
const lineTotal = roundMoney(lineItems.reduce((sum, line) => sum + line.amount, 0));
|
|
1255
|
+
const roundingDelta = roundMoney(expectedTotal - lineTotal);
|
|
1256
|
+
if (Math.abs(roundingDelta) >= 0.01) {
|
|
1257
|
+
lineItems.push({
|
|
1258
|
+
type: 'ROUNDING',
|
|
1259
|
+
label: t('booking.rounding') || 'Rounding',
|
|
1260
|
+
amount: roundingDelta,
|
|
1261
|
+
});
|
|
1262
|
+
}
|
|
1263
|
+
|
|
1264
|
+
return {
|
|
1265
|
+
currency,
|
|
1266
|
+
lineItems,
|
|
1267
|
+
subtotalBeforeTax: roundMoney(expectedTotal - roundMoney(effectiveTaxAmount)),
|
|
1268
|
+
taxAmount: roundMoney(effectiveTaxAmount),
|
|
1269
|
+
totalAmount: expectedTotal,
|
|
1270
|
+
};
|
|
1271
|
+
}, [
|
|
1272
|
+
activePromoCode,
|
|
1273
|
+
addOnSelections,
|
|
1274
|
+
addOns,
|
|
1275
|
+
additionalHoursAmount,
|
|
1276
|
+
additionalHoursCount,
|
|
1277
|
+
basePrice,
|
|
1278
|
+
cancellationPolicyFee,
|
|
1279
|
+
currency,
|
|
1280
|
+
effectivePromoDiscountAmount,
|
|
1281
|
+
effectiveTaxAmount,
|
|
1282
|
+
isGiftCard,
|
|
1283
|
+
perBookingFeeLineItems,
|
|
1284
|
+
resourceCount,
|
|
1285
|
+
selectedCancellationPolicy,
|
|
1286
|
+
t,
|
|
1287
|
+
totalPrice,
|
|
1288
|
+
]);
|
|
1125
1289
|
|
|
1126
1290
|
useEffect(() => {
|
|
1127
1291
|
if (!onPricePreviewChange) return;
|
|
@@ -1645,6 +1809,7 @@ export function PrivateShuttleBookingFlow({
|
|
|
1645
1809
|
promoCode: activePromoCode ?? null,
|
|
1646
1810
|
newTotalAmount: totalPrice,
|
|
1647
1811
|
additionalHoursCount: isAdmin ? additionalHoursCount : null,
|
|
1812
|
+
authoritativeReceipt: providerChangeAuthoritativeReceipt,
|
|
1648
1813
|
});
|
|
1649
1814
|
setLoading(false);
|
|
1650
1815
|
return;
|
|
@@ -1792,6 +1957,11 @@ export function PrivateShuttleBookingFlow({
|
|
|
1792
1957
|
},
|
|
1793
1958
|
]
|
|
1794
1959
|
: []),
|
|
1960
|
+
...perBookingFeeLineItems.map((fee) => ({
|
|
1961
|
+
label: fee.name,
|
|
1962
|
+
amount: fee.totalAmount,
|
|
1963
|
+
type: 'FEE' as const,
|
|
1964
|
+
})),
|
|
1795
1965
|
...(cancellationPolicyFee > 0 && selectedCancellationPolicy
|
|
1796
1966
|
? [
|
|
1797
1967
|
{
|
|
@@ -1929,23 +2099,26 @@ export function PrivateShuttleBookingFlow({
|
|
|
1929
2099
|
breakdown: null,
|
|
1930
2100
|
},
|
|
1931
2101
|
],
|
|
1932
|
-
feeLineItems:
|
|
1933
|
-
|
|
1934
|
-
|
|
1935
|
-
|
|
1936
|
-
|
|
1937
|
-
|
|
1938
|
-
|
|
1939
|
-
|
|
1940
|
-
|
|
1941
|
-
|
|
1942
|
-
|
|
1943
|
-
|
|
1944
|
-
|
|
1945
|
-
|
|
1946
|
-
|
|
1947
|
-
|
|
1948
|
-
|
|
2102
|
+
feeLineItems: [
|
|
2103
|
+
...addOnSelections
|
|
2104
|
+
.map((sel) => {
|
|
2105
|
+
const addOn = addOns.find((a) => a.addOnId === sel.addOnId);
|
|
2106
|
+
if (!addOn) return null;
|
|
2107
|
+
const base = addOn.price ?? 0;
|
|
2108
|
+
const hasVariant =
|
|
2109
|
+
(addOn.variantType === 'single_choice' || addOn.variantType === 'multi_quantity') &&
|
|
2110
|
+
sel.variantId;
|
|
2111
|
+
const adj = hasVariant
|
|
2112
|
+
? (addOn.variants?.find((v) => v.id === sel.variantId)?.priceAdjustment ?? 0)
|
|
2113
|
+
: 0;
|
|
2114
|
+
return {
|
|
2115
|
+
name: addOn.name,
|
|
2116
|
+
totalAmount: (base + adj) * (sel.quantity ?? 1),
|
|
2117
|
+
};
|
|
2118
|
+
})
|
|
2119
|
+
.filter(Boolean) as { name: string; totalAmount: number }[],
|
|
2120
|
+
...perBookingFeeLineItems,
|
|
2121
|
+
],
|
|
1949
2122
|
cancellationPolicyFee,
|
|
1950
2123
|
cancellationPolicyLabel: selectedCancellationPolicy?.label,
|
|
1951
2124
|
subtotal,
|
|
@@ -2036,7 +2209,7 @@ export function PrivateShuttleBookingFlow({
|
|
|
2036
2209
|
breakdown: null,
|
|
2037
2210
|
},
|
|
2038
2211
|
];
|
|
2039
|
-
const
|
|
2212
|
+
const addOnFeeLineItemsForModal = addOnSelections
|
|
2040
2213
|
.map((sel) => {
|
|
2041
2214
|
const addOn = addOns.find((a) => a.addOnId === sel.addOnId);
|
|
2042
2215
|
if (!addOn) return null;
|
|
@@ -2053,6 +2226,7 @@ export function PrivateShuttleBookingFlow({
|
|
|
2053
2226
|
};
|
|
2054
2227
|
})
|
|
2055
2228
|
.filter(Boolean) as { name: string; totalAmount: number }[];
|
|
2229
|
+
const feeLineItemsForModal = [...addOnFeeLineItemsForModal, ...perBookingFeeLineItems];
|
|
2056
2230
|
|
|
2057
2231
|
setCheckoutClientSecret(paymentIntent.clientSecret ?? '');
|
|
2058
2232
|
setCheckoutModalData({
|
|
@@ -2913,6 +3087,15 @@ export function PrivateShuttleBookingFlow({
|
|
|
2913
3087
|
},
|
|
2914
3088
|
]
|
|
2915
3089
|
: []),
|
|
3090
|
+
...perBookingFeeLineItems.map((fee) => ({
|
|
3091
|
+
kind: 'line' as const,
|
|
3092
|
+
label: fee.name,
|
|
3093
|
+
amount: fee.totalAmount,
|
|
3094
|
+
type: 'fee' as const,
|
|
3095
|
+
tooltip: isMoraineLakeRoadAccessFeeName(fee.name)
|
|
3096
|
+
? MORAINE_LAKE_ROAD_ACCESS_FEE_TOOLTIP
|
|
3097
|
+
: undefined,
|
|
3098
|
+
})),
|
|
2916
3099
|
...(cancellationPolicyFee > 0
|
|
2917
3100
|
? [
|
|
2918
3101
|
{
|
|
@@ -26,6 +26,17 @@ export type ProviderDashboardChangeBookingPayload = {
|
|
|
26
26
|
/** Signed major-unit rows; may include admin custom receipt lines merged with provider inline adjustments. */
|
|
27
27
|
additionalAdjustments?: Array<{ label: string; amount: number }>;
|
|
28
28
|
} | null;
|
|
29
|
+
/**
|
|
30
|
+
* Admin/provider change flow: when FE-authoritative quoting is used, apply must persist
|
|
31
|
+
* the exact receipt that was quoted instead of rebuilding from catalog pricing.
|
|
32
|
+
*/
|
|
33
|
+
authoritativeReceipt?: {
|
|
34
|
+
currency?: string | null;
|
|
35
|
+
lineItems: Array<{ type: string; label: string; amount: number; quantity?: number; reference?: string }>;
|
|
36
|
+
subtotalBeforeTax: number;
|
|
37
|
+
taxAmount: number;
|
|
38
|
+
totalAmount: number;
|
|
39
|
+
} | null;
|
|
29
40
|
capacitySeatCredit?: {
|
|
30
41
|
enabled: boolean;
|
|
31
42
|
previousPassengerCount?: number | null;
|
|
@@ -450,15 +450,26 @@ export function computeOrderSummary(
|
|
|
450
450
|
: 0;
|
|
451
451
|
|
|
452
452
|
const fees = pricingConfig.fees ?? {};
|
|
453
|
-
const
|
|
454
|
-
const
|
|
455
|
-
|
|
453
|
+
const perBookingFees = pricingConfig.perBookingFees ?? {};
|
|
454
|
+
const perPersonByCurrency = hasFees ? pricingConfig.feesByCurrency?.[currency] : undefined;
|
|
455
|
+
const perBookingByCurrency = pricingConfig.perBookingFeesByCurrency?.[currency];
|
|
456
|
+
const perPersonFeeLineItems: OrderSummaryFeeLine[] =
|
|
457
|
+
!hasFees || totalQuantity === 0 || isTaxIncludedInPrice || perPersonByCurrency == null
|
|
456
458
|
? []
|
|
457
|
-
: Object.entries(
|
|
459
|
+
: Object.entries(perPersonByCurrency).map(([name, amountPerPerson]) => ({
|
|
458
460
|
name,
|
|
459
461
|
totalAmount: round2(totalQuantity * amountPerPerson),
|
|
460
462
|
description: fees[name]?.description,
|
|
461
463
|
}));
|
|
464
|
+
const perBookingFeeLineItems: OrderSummaryFeeLine[] =
|
|
465
|
+
totalQuantity === 0 || isTaxIncludedInPrice || perBookingByCurrency == null
|
|
466
|
+
? []
|
|
467
|
+
: Object.entries(perBookingByCurrency).map(([name, amountPerBooking]) => ({
|
|
468
|
+
name,
|
|
469
|
+
totalAmount: round2(amountPerBooking),
|
|
470
|
+
description: perBookingFees[name]?.description,
|
|
471
|
+
}));
|
|
472
|
+
const feeLineItems = [...perPersonFeeLineItems, ...perBookingFeeLineItems];
|
|
462
473
|
|
|
463
474
|
const feesTotal = feeLineItems.reduce((s, f) => s + f.totalAmount, 0);
|
|
464
475
|
const subtotal = round2(basePrice + returnPriceAdjustment + cancellationPolicyFee + feesTotal);
|
package/src/lib/booking-api.ts
CHANGED
|
@@ -850,6 +850,8 @@ export interface PricingConfig {
|
|
|
850
850
|
currenciesWithTaxIncluded: string[];
|
|
851
851
|
fees?: Record<string, { feePerPerson: number; description?: string }>;
|
|
852
852
|
feesByCurrency?: Record<string, Record<string, number>>;
|
|
853
|
+
perBookingFees?: Record<string, { feePerBooking: number; description?: string }>;
|
|
854
|
+
perBookingFeesByCurrency?: Record<string, Record<string, number>>;
|
|
853
855
|
exchangeRates?: Record<string, number>;
|
|
854
856
|
cancellationPolicies?: CancellationPolicyOption[];
|
|
855
857
|
}
|