tripstorekrabi-shared 1.25.0 → 1.25.2
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/booking.js +28 -14
- package/package.json +1 -1
- package/price.js +106 -73
package/booking.js
CHANGED
|
@@ -177,20 +177,34 @@ export function addBookingFromInvoice(
|
|
|
177
177
|
}
|
|
178
178
|
}
|
|
179
179
|
|
|
180
|
-
export function getOperatorSignature(
|
|
181
|
-
let signature =
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
180
|
+
export function getOperatorSignature(operatorName, contact) {
|
|
181
|
+
let signature = `<br><br>Warm regards,<br><br><strong>${operatorName}</strong><br>`;
|
|
182
|
+
|
|
183
|
+
if (contact && contact.phoneNumber) {
|
|
184
|
+
const cleanPhone = contact.phoneNumber.replace(/[^\d+]/g, '');
|
|
185
|
+
signature += `<br>📞 Phone: <a href="tel:${cleanPhone}">Call our office</a>`;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
if (contact && contact.email) {
|
|
189
|
+
signature += `<br>✉️ Email: <a href="mailto:${contact.email}">Send email</a>`;
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
if (contact && contact.respondNumber) {
|
|
193
|
+
const cleanRespond = contact.respondNumber.replace(/\D/g, '');
|
|
194
|
+
signature += `<br>💬 WhatsApp: <a href="https://wa.me/${cleanRespond}">Chat on WhatsApp</a>`;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
if (contact && contact.whatsappNumber) {
|
|
198
|
+
const cleanWhatsapp = contact.whatsappNumber.replace(/\D/g, '');
|
|
199
|
+
signature += `<br>💬 WhatsApp: <a href="https://wa.me/${cleanWhatsapp}">Call on WhatsApp</a>`;
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
signature += `<br>✈️ Telegram: <a href="https://t.me/tripstorekrabi_bot">Chat in Telegram</a>`;
|
|
203
|
+
|
|
204
|
+
signature += `<br>🟢 LINE: <a href="line://ti/p/@cjs7975w">Chat on LINE</a>`;
|
|
205
|
+
|
|
206
|
+
signature += `<br>📘 Facebook: <a href="https://m.me/tripstorekrabi">Message on Facebook</a>`;
|
|
207
|
+
|
|
194
208
|
return signature;
|
|
195
209
|
}
|
|
196
210
|
|
package/package.json
CHANGED
package/price.js
CHANGED
|
@@ -96,9 +96,9 @@ export function findVolume(people, context) {
|
|
|
96
96
|
|
|
97
97
|
if (!volumes || volumes.length === 0) return undefined;
|
|
98
98
|
|
|
99
|
-
const sortedVolumes = [...volumes].sort((v1, v2) => v1.max - v2.max);
|
|
99
|
+
const sortedVolumes = [...volumes].sort((v1, v2) => (v1.max ?? 0) - (v2.max ?? 0));
|
|
100
100
|
|
|
101
|
-
return sortedVolumes.find(v => total <= v.max) || sortedVolumes[sortedVolumes.length - 1];
|
|
101
|
+
return sortedVolumes.find(v => total <= (v.max ?? MAX_PAX)) || sortedVolumes[sortedVolumes.length - 1];
|
|
102
102
|
}
|
|
103
103
|
|
|
104
104
|
export function countMinPeople(pricing, bookingDate = dayjs(), departureDate = null) {
|
|
@@ -114,22 +114,27 @@ export function countMaxPeople(pricing, bookingDate = dayjs(), departureDate = n
|
|
|
114
114
|
}
|
|
115
115
|
|
|
116
116
|
export function calculateProductSellingPrice(booking, pricing) {
|
|
117
|
-
return booking
|
|
117
|
+
return booking?.customerPaymentStatus === "Refunded" ? 0 : calculateProductPrice(booking, pricing, { mode: SELLING_MODE });
|
|
118
118
|
}
|
|
119
119
|
|
|
120
120
|
export function calculateProductPartnerNetPrice(booking, pricing) {
|
|
121
|
-
return booking
|
|
121
|
+
return booking?.customerPaymentStatus === "Refunded" ? 0 : calculateProductPrice(booking, pricing, { mode: PARTNER_MODE });
|
|
122
122
|
}
|
|
123
123
|
|
|
124
124
|
export function calculateProductOperatorPrice(booking, pricing) {
|
|
125
|
-
return booking
|
|
125
|
+
return booking?.operatorPaymentStatus === "No Charge" ? 0 : calculateProductPrice(booking, pricing, { mode: OPERATOR_MODE });
|
|
126
126
|
}
|
|
127
127
|
|
|
128
128
|
function calculateSellingPrice(commissionRate = 0, price) {
|
|
129
|
-
|
|
129
|
+
if (price == null) return 0;
|
|
130
|
+
const comm = Number(commissionRate) || 0;
|
|
131
|
+
const factor = 100 - comm;
|
|
132
|
+
if (factor <= 0) return price;
|
|
133
|
+
return Math.floor((price * 100) / factor);
|
|
130
134
|
}
|
|
131
135
|
|
|
132
136
|
export function calculateInflatedSellingPrice(price, config, forceInflation = false) {
|
|
137
|
+
if (price == null) return 0;
|
|
133
138
|
if (!config || (!config.inflatedPrices && !forceInflation)) return price;
|
|
134
139
|
|
|
135
140
|
const discountRate = Number(config.discount) || 0;
|
|
@@ -146,6 +151,8 @@ export function calculateInflatedSellingPrice(price, config, forceInflation = fa
|
|
|
146
151
|
}
|
|
147
152
|
|
|
148
153
|
function calculateProductPrice(booking, pricing, options = { mode: SELLING_MODE }) {
|
|
154
|
+
if (!booking) return 0;
|
|
155
|
+
|
|
149
156
|
const context = resolvePricingContext(pricing, booking.date, booking.departureDate);
|
|
150
157
|
|
|
151
158
|
if (!context || !context.volumes || context.volumes.length === 0) {
|
|
@@ -155,12 +162,14 @@ function calculateProductPrice(booking, pricing, options = { mode: SELLING_MODE
|
|
|
155
162
|
|
|
156
163
|
const volume = findVolume(booking, context);
|
|
157
164
|
if (!volume) {
|
|
158
|
-
console.error(`No volume price found for ${booking.adults + booking.children} people`);
|
|
165
|
+
console.error(`No volume price found for ${(booking.adults ?? 0) + (booking.children ?? 0)} people`);
|
|
159
166
|
return 0;
|
|
160
167
|
}
|
|
161
168
|
|
|
162
169
|
let total = 0;
|
|
163
170
|
const bookingSourceKey = getBookingSourceKey(booking.otaPartnerRef);
|
|
171
|
+
const adults = booking.adults ?? 0;
|
|
172
|
+
const children = booking.children ?? 0;
|
|
164
173
|
|
|
165
174
|
if (context.type === "person") {
|
|
166
175
|
if (volume[bookingSourceKey]) {
|
|
@@ -168,23 +177,23 @@ function calculateProductPrice(booking, pricing, options = { mode: SELLING_MODE
|
|
|
168
177
|
|
|
169
178
|
if (options.mode === SELLING_MODE) {
|
|
170
179
|
const commRate = context.commissionRates?.[bookingSourceKey] || 0;
|
|
171
|
-
const finalPriceAdult = calculateInflatedSellingPrice(calculateSellingPrice(commRate, customPricing.adult
|
|
180
|
+
const finalPriceAdult = calculateInflatedSellingPrice(calculateSellingPrice(commRate, customPricing.adult?.partnerNetPrice ?? 0), customPricing);
|
|
172
181
|
|
|
173
182
|
let finalPriceChild = 0;
|
|
174
|
-
if (context.ageBands?.child?.active && volume.child &&
|
|
175
|
-
finalPriceChild = calculateInflatedSellingPrice(calculateSellingPrice(commRate, customPricing.child
|
|
183
|
+
if (context.ageBands?.child?.active && volume.child && children) {
|
|
184
|
+
finalPriceChild = calculateInflatedSellingPrice(calculateSellingPrice(commRate, customPricing.child?.partnerNetPrice ?? 0), customPricing);
|
|
176
185
|
}
|
|
177
|
-
total = (
|
|
186
|
+
total = (adults * finalPriceAdult) + (children ? children * finalPriceChild : 0);
|
|
178
187
|
} else if (options.mode === PARTNER_MODE) {
|
|
179
|
-
total = (
|
|
188
|
+
total = (adults * (customPricing.adult?.partnerNetPrice ?? 0)) + (context.ageBands?.child?.active && volume.child && children ? children * (customPricing.child?.partnerNetPrice ?? 0) : 0);
|
|
180
189
|
} else if (options.mode === OPERATOR_MODE) {
|
|
181
|
-
total = (
|
|
190
|
+
total = (adults * (customPricing.adult?.operatorNetPrice ?? volume.adult?.operatorNetPrice ?? 0)) + (context.ageBands?.child?.active && volume.child && children ? children * (customPricing.child?.operatorNetPrice ?? volume.child?.operatorNetPrice ?? 0) : 0);
|
|
182
191
|
}
|
|
183
192
|
} else {
|
|
184
193
|
if (options.mode === SELLING_MODE || options.mode === PARTNER_MODE) {
|
|
185
|
-
total = (
|
|
194
|
+
total = (adults * (volume.adult?.sellingPrice ?? 0)) + (context.ageBands?.child?.active && volume.child && children ? children * (volume.child?.sellingPrice ?? 0) : 0);
|
|
186
195
|
} else if (options.mode === OPERATOR_MODE) {
|
|
187
|
-
total = (
|
|
196
|
+
total = (adults * (volume.adult?.operatorNetPrice ?? 0)) + (context.ageBands?.child?.active && volume.child && children ? children * (volume.child?.operatorNetPrice ?? 0) : 0);
|
|
188
197
|
}
|
|
189
198
|
}
|
|
190
199
|
} else if (context.type === "group") {
|
|
@@ -193,17 +202,17 @@ function calculateProductPrice(booking, pricing, options = { mode: SELLING_MODE
|
|
|
193
202
|
|
|
194
203
|
if (options.mode === SELLING_MODE) {
|
|
195
204
|
const commRate = context.commissionRates?.[bookingSourceKey] || 0;
|
|
196
|
-
total = calculateInflatedSellingPrice(calculateSellingPrice(commRate, customPricing.partnerNetPrice), customPricing);
|
|
205
|
+
total = calculateInflatedSellingPrice(calculateSellingPrice(commRate, customPricing.partnerNetPrice ?? 0), customPricing);
|
|
197
206
|
} else if (options.mode === PARTNER_MODE) {
|
|
198
|
-
total = customPricing.partnerNetPrice;
|
|
207
|
+
total = customPricing.partnerNetPrice ?? 0;
|
|
199
208
|
} else if (options.mode === OPERATOR_MODE) {
|
|
200
|
-
total = customPricing.operatorNetPrice ?? volume.operatorNetPrice;
|
|
209
|
+
total = customPricing.operatorNetPrice ?? volume.operatorNetPrice ?? 0;
|
|
201
210
|
}
|
|
202
211
|
} else {
|
|
203
212
|
if (options.mode === SELLING_MODE || options.mode === PARTNER_MODE) {
|
|
204
|
-
total = volume.sellingPrice;
|
|
213
|
+
total = volume.sellingPrice ?? 0;
|
|
205
214
|
} else if (options.mode === OPERATOR_MODE) {
|
|
206
|
-
total = volume.operatorNetPrice;
|
|
215
|
+
total = volume.operatorNetPrice ?? 0;
|
|
207
216
|
}
|
|
208
217
|
}
|
|
209
218
|
} else {
|
|
@@ -214,43 +223,44 @@ function calculateProductPrice(booking, pricing, options = { mode: SELLING_MODE
|
|
|
214
223
|
}
|
|
215
224
|
|
|
216
225
|
export function getTotalAmountToBeReceived(booking, options = {}) {
|
|
217
|
-
let filter = (item) => (!options.filter || options.filter(item)) && !item
|
|
218
|
-
return booking
|
|
226
|
+
let filter = (item) => (!options.filter || options.filter(item)) && !item?.disabled && item?.paymentMethod !== PAY_ON_TOUR;
|
|
227
|
+
return booking?.customerPaymentStatus === "Refunded" ? 0 : (booking?.partnerNetPrice ?? 0) + calculateExtraPayments(booking, { ...options, mode: SELLING_MODE, filter });
|
|
219
228
|
}
|
|
220
229
|
|
|
221
230
|
export function calculatePartnerNetPrice(booking, product) {
|
|
222
231
|
return getExtraPaymentsPaidWithPartner(booking, product).reduce(
|
|
223
|
-
(prev, curr) => (prev ?? 0) + curr
|
|
224
|
-
calculateProductPartnerNetPrice(booking, product
|
|
232
|
+
(prev, curr) => (prev ?? 0) + (curr?.price ?? 0),
|
|
233
|
+
calculateProductPartnerNetPrice(booking, product?.pricing)
|
|
225
234
|
);
|
|
226
235
|
}
|
|
227
236
|
|
|
228
237
|
export function calculateTotalSellingPrice(booking, product) {
|
|
229
|
-
return booking
|
|
238
|
+
return booking?.customerPaymentStatus === "Refunded" ? 0 : calculateTotalPrice(booking, product, { mode: SELLING_MODE });
|
|
230
239
|
}
|
|
231
240
|
|
|
232
241
|
export function calculateTotalPartnerNetPrice(booking, product) {
|
|
233
|
-
return booking
|
|
242
|
+
return booking?.customerPaymentStatus === "Refunded" ? 0 : calculateTotalPrice(booking, product, { mode: PARTNER_MODE });
|
|
234
243
|
}
|
|
235
244
|
|
|
236
245
|
export function calculateTotalOperatorPrice(booking, product) {
|
|
237
|
-
return booking
|
|
246
|
+
return booking?.operatorPaymentStatus === "No Charge" ? 0 : calculateTotalPrice(booking, product, { mode: OPERATOR_MODE });
|
|
238
247
|
}
|
|
239
248
|
|
|
240
249
|
function calculateTotalPrice(booking, product, options = { mode: SELLING_MODE }) {
|
|
241
|
-
let total = calculateProductPrice(booking, product
|
|
242
|
-
total += calculateStartEndPointPrice(booking, findStartingPoint(product, booking
|
|
243
|
-
total += calculateStartEndPointPrice(booking, findEndPoint(product, booking
|
|
250
|
+
let total = calculateProductPrice(booking, product?.pricing, options) ?? 0;
|
|
251
|
+
total += calculateStartEndPointPrice(booking, findStartingPoint(product, booking?.startingPointId, false), options);
|
|
252
|
+
total += calculateStartEndPointPrice(booking, findEndPoint(product, booking?.endPointId, false), options);
|
|
244
253
|
total += calculateNationalParkFee(booking, product);
|
|
245
254
|
total += calculateExtraPayments(booking, {
|
|
246
255
|
...options,
|
|
247
256
|
filter: (item) => {
|
|
248
|
-
if (item
|
|
249
|
-
if (item
|
|
250
|
-
if (item
|
|
257
|
+
if (item?.disabled === true) return false;
|
|
258
|
+
if (item?.paymentMethod === PAY_ON_TOUR) return true;
|
|
259
|
+
if (item?.paymentMethod === PAY_BEFORE && item?.category === OTHER_EXTRA_PAYMENT) return true;
|
|
260
|
+
return false;
|
|
251
261
|
},
|
|
252
262
|
getPrice: (item, options) => {
|
|
253
|
-
if (item
|
|
263
|
+
if (item?.paymentMethod === PAY_ON_TOUR) {
|
|
254
264
|
return item.category !== OTHER_EXTRA_PAYMENT ? -getExtraPaymentPrice(item, options) : 0;
|
|
255
265
|
}
|
|
256
266
|
return getExtraPaymentPrice(item, options);
|
|
@@ -261,18 +271,21 @@ function calculateTotalPrice(booking, product, options = { mode: SELLING_MODE })
|
|
|
261
271
|
}
|
|
262
272
|
|
|
263
273
|
export function calculateNationalParkFee(booking, product) {
|
|
264
|
-
return booking
|
|
265
|
-
? (product.nationalPark.pricing.adult * booking
|
|
274
|
+
return booking?.nationalParkFee === ALREADY_PAID && product?.nationalPark?.pricing
|
|
275
|
+
? ((product.nationalPark.pricing.adult ?? 0) * (booking?.adults ?? 0)) + ((product.nationalPark.pricing.child ?? 0) * (booking?.children ?? 0))
|
|
266
276
|
: 0;
|
|
267
277
|
}
|
|
268
278
|
|
|
269
279
|
function getExtraPaymentPrice(item, options) {
|
|
280
|
+
if (!item) return 0;
|
|
270
281
|
switch (options.mode) {
|
|
271
282
|
case SELLING_MODE:
|
|
272
283
|
case PARTNER_MODE:
|
|
273
|
-
return item.receivedAmount ? item.receivedAmount : item.price;
|
|
284
|
+
return item.receivedAmount ? item.receivedAmount : (item.price ?? 0);
|
|
274
285
|
case OPERATOR_MODE:
|
|
275
|
-
return item.operatorPrice;
|
|
286
|
+
return item.operatorPrice ?? 0;
|
|
287
|
+
default:
|
|
288
|
+
return 0;
|
|
276
289
|
}
|
|
277
290
|
}
|
|
278
291
|
|
|
@@ -285,14 +298,14 @@ export function calculateTotalExtraPaymentsOperatorPrice(booking) {
|
|
|
285
298
|
}
|
|
286
299
|
|
|
287
300
|
function calculateExtraPayments(booking, options = { mode: SELLING_MODE }) {
|
|
288
|
-
let filter = options.filter ?? ((item) => !item
|
|
301
|
+
let filter = options.filter ?? ((item) => !item?.disabled);
|
|
289
302
|
let getPrice = options.getPrice ?? getExtraPaymentPrice;
|
|
290
303
|
let total = 0;
|
|
291
304
|
|
|
292
|
-
for (const item of Object.values(booking
|
|
305
|
+
for (const item of Object.values(booking?.extraPayments ?? {}).filter(filter)) {
|
|
293
306
|
total += getPrice(item, options);
|
|
294
307
|
if (item.paymentMethod === PAY_ON_TOUR && options.mode === OPERATOR_MODE) {
|
|
295
|
-
let ourCommission = item.price - item.operatorPrice;
|
|
308
|
+
let ourCommission = (item.price ?? 0) - (item.operatorPrice ?? 0);
|
|
296
309
|
if (ourCommission > 0) total -= ourCommission;
|
|
297
310
|
}
|
|
298
311
|
}
|
|
@@ -300,53 +313,57 @@ function calculateExtraPayments(booking, options = { mode: SELLING_MODE }) {
|
|
|
300
313
|
}
|
|
301
314
|
|
|
302
315
|
export function getExtraPaymentsPaidWithPartner(booking, product) {
|
|
303
|
-
let startingPoint = findStartingPoint(product, booking
|
|
304
|
-
let endPoint = findEndPoint(product, booking
|
|
316
|
+
let startingPoint = findStartingPoint(product, booking?.startingPointId);
|
|
317
|
+
let endPoint = findEndPoint(product, booking?.endPointId);
|
|
305
318
|
let addOnDefs = {};
|
|
306
319
|
|
|
307
|
-
(product
|
|
308
|
-
addOnDefs[addOn.id] = addOn;
|
|
320
|
+
(product?.addOns ?? []).forEach((addOn) => {
|
|
321
|
+
if (addOn?.id) addOnDefs[addOn.id] = addOn;
|
|
309
322
|
});
|
|
310
323
|
|
|
311
|
-
let addOns = Object.entries(booking
|
|
324
|
+
let addOns = Object.entries(booking?.addOns ?? {}).filter(([id]) => addOnDefs[id] != null).map(([id, addOn]) => {
|
|
312
325
|
let addOnDef = addOnDefs[id];
|
|
326
|
+
const adults = addOn?.adults ?? 0;
|
|
327
|
+
const children = addOn?.children ?? 0;
|
|
313
328
|
return {
|
|
314
329
|
category: ADD_ON_EXTRA_PAYMENT,
|
|
315
|
-
description: addOnDef
|
|
316
|
-
price: (
|
|
317
|
-
operatorPrice: (
|
|
318
|
-
}
|
|
330
|
+
description: addOnDef?.title ?? 'Add-on',
|
|
331
|
+
price: (adults * (addOnDef?.pricing?.adult?.sellingPrice ?? 0)) + (children * (addOnDef?.pricing?.child?.sellingPrice ?? 0)),
|
|
332
|
+
operatorPrice: (adults * (addOnDef?.pricing?.adult?.operatorNetPrice ?? 0)) + (children * (addOnDef?.pricing?.child?.operatorNetPrice ?? 0))
|
|
333
|
+
};
|
|
319
334
|
});
|
|
320
335
|
|
|
321
336
|
return [
|
|
322
|
-
{ category: STARTING_POINT_EXTRA_PAYMENT, description: startingPoint
|
|
323
|
-
{ category: END_POINT_EXTRA_PAYMENT, description: endPoint
|
|
324
|
-
{ category: NATIONAL_PARK_FEE_EXTRA_PAYMENT, description: `Entrance fee to ${product
|
|
337
|
+
{ category: STARTING_POINT_EXTRA_PAYMENT, description: startingPoint?.name ?? 'Starting Point', price: calculateStartEndPointSellingPrice(booking, startingPoint), operatorPrice: calculateStartEndPointOperatorPrice(booking, startingPoint) },
|
|
338
|
+
{ category: END_POINT_EXTRA_PAYMENT, description: endPoint?.name ?? 'End Point', price: calculateStartEndPointSellingPrice(booking, endPoint), operatorPrice: calculateStartEndPointOperatorPrice(booking, endPoint) },
|
|
339
|
+
{ category: NATIONAL_PARK_FEE_EXTRA_PAYMENT, description: `Entrance fee to ${product?.nationalPark?.title ?? 'National Park'}`, price: calculateNationalParkFee(booking, product), operatorPrice: calculateNationalParkFee(booking, product) },
|
|
325
340
|
...addOns
|
|
326
341
|
].filter(
|
|
327
342
|
(item) => (item.price > 0 || item.operatorPrice > 0) &&
|
|
328
|
-
!Object.values(booking
|
|
343
|
+
!Object.values(booking?.extraPayments ?? {}).find(ep => ep.category === item.category && !ep.disabled)
|
|
329
344
|
).map((item) => {
|
|
330
|
-
if (booking
|
|
331
|
-
if (booking
|
|
345
|
+
if (booking?.customerPaymentStatus === "Refunded") item.price = 0;
|
|
346
|
+
if (booking?.operatorPaymentStatus === "No Charge") item.operatorPrice = 0;
|
|
332
347
|
return item;
|
|
333
348
|
});
|
|
334
349
|
}
|
|
335
350
|
|
|
336
351
|
export function getActiveExtraPayments(extraPayments) {
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
.
|
|
352
|
+
// Respecting the rule: extraPayments passed from outside is always an array of entries
|
|
353
|
+
return [...(extraPayments ?? [])]
|
|
354
|
+
.filter(([id, item]) => !item?.disabled)
|
|
355
|
+
.sort(([id1, item1], [id2, item2]) => (item1?.description || '').localeCompare(item2?.description || ''));
|
|
340
356
|
}
|
|
341
357
|
|
|
342
358
|
export function getExtraPaymentsOperatorPrice(extraPayments) {
|
|
343
359
|
return getActiveExtraPayments(extraPayments).reduce((prev, curr) => {
|
|
344
360
|
let item = curr[1];
|
|
361
|
+
if (!item) return prev;
|
|
345
362
|
if (item.paymentMethod === PAY_ON_TOUR) {
|
|
346
|
-
let ourCommission = item.price - item.operatorPrice;
|
|
363
|
+
let ourCommission = (item.price ?? 0) - (item.operatorPrice ?? 0);
|
|
347
364
|
return prev + (ourCommission > 0 ? -ourCommission : 0);
|
|
348
365
|
}
|
|
349
|
-
return prev + item.operatorPrice;
|
|
366
|
+
return prev + (item.operatorPrice ?? 0);
|
|
350
367
|
}, 0);
|
|
351
368
|
}
|
|
352
369
|
|
|
@@ -354,11 +371,20 @@ export function calculateAddOnsPrice(booking, product, options = { mode: SELLING
|
|
|
354
371
|
let total = 0;
|
|
355
372
|
let isSelling = [SELLING_MODE, PARTNER_MODE].includes(options.mode);
|
|
356
373
|
|
|
357
|
-
for (const [id, addOn] of Object.entries(booking
|
|
358
|
-
let addOnDef = findAddOn(id, product
|
|
359
|
-
if (addOnDef) {
|
|
360
|
-
|
|
361
|
-
|
|
374
|
+
for (const [id, addOn] of Object.entries(booking?.addOns ?? {})) {
|
|
375
|
+
let addOnDef = findAddOn(id, product?.addOns ?? []);
|
|
376
|
+
if (addOnDef && addOnDef.pricing) {
|
|
377
|
+
const adultPrice = isSelling
|
|
378
|
+
? (addOnDef.pricing?.adult?.sellingPrice ?? 0)
|
|
379
|
+
: (addOnDef.pricing?.adult?.operatorNetPrice ?? 0);
|
|
380
|
+
const childPrice = isSelling
|
|
381
|
+
? (addOnDef.pricing?.child?.sellingPrice ?? 0)
|
|
382
|
+
: (addOnDef.pricing?.child?.operatorNetPrice ?? 0);
|
|
383
|
+
|
|
384
|
+
const adults = addOn?.adults ?? 0;
|
|
385
|
+
const children = addOn?.children ?? 0;
|
|
386
|
+
|
|
387
|
+
total += (adults * adultPrice) + (children * childPrice);
|
|
362
388
|
}
|
|
363
389
|
}
|
|
364
390
|
return total;
|
|
@@ -381,30 +407,37 @@ function calculateStartEndPointPrice(people, startEndPoint, options = { mode: SE
|
|
|
381
407
|
let isSelling = [SELLING_MODE, PARTNER_MODE].includes(options.mode);
|
|
382
408
|
|
|
383
409
|
if (pricing) {
|
|
384
|
-
const priceAmount = isSelling ? (pricing.sellingPrice ?? pricing.amount) : pricing.operatorNetPrice;
|
|
410
|
+
const priceAmount = isSelling ? (pricing.sellingPrice ?? pricing.amount ?? 0) : (pricing.operatorNetPrice ?? 0);
|
|
411
|
+
const adults = people?.adults ?? 0;
|
|
412
|
+
const children = people?.children ?? 0;
|
|
413
|
+
const pax = adults + children;
|
|
414
|
+
|
|
385
415
|
if (pricing.type === "group") {
|
|
386
|
-
|
|
416
|
+
const maxPax = pricing.max || 1;
|
|
417
|
+
return priceAmount * Math.ceil(pax / maxPax);
|
|
387
418
|
} else if (pricing.type === "person") {
|
|
388
|
-
return priceAmount *
|
|
419
|
+
return priceAmount * pax;
|
|
389
420
|
}
|
|
390
421
|
}
|
|
391
422
|
return 0;
|
|
392
423
|
}
|
|
393
424
|
|
|
394
425
|
export function findStartingPoint(product, startingPointId, useDefault = true) {
|
|
426
|
+
const startingPoints = product?.startingPoints ?? [];
|
|
395
427
|
return [
|
|
396
|
-
...
|
|
428
|
+
...startingPoints,
|
|
397
429
|
{ id: TELL_HOTEL_LATER_STARTING_POINT.id, name: TELL_HOTEL_LATER_STARTING_POINT.description, value: '' },
|
|
398
430
|
{ id: CUSTOM_MEETING_POINT.id, name: CUSTOM_MEETING_POINT.description, value: '' },
|
|
399
|
-
].find((item) => item
|
|
431
|
+
].find((item) => item?.id === startingPointId) ?? (useDefault ? startingPoints[0] : null);
|
|
400
432
|
}
|
|
401
433
|
|
|
402
434
|
export function findEndPoint(product, endPointId, useDefault = true) {
|
|
403
|
-
|
|
435
|
+
const endPoints = product?.endPoints ?? [];
|
|
436
|
+
return endPoints.find((item) => item?.id === endPointId) ?? (useDefault ? endPoints[0] ?? { name: "" } : null);
|
|
404
437
|
}
|
|
405
438
|
|
|
406
439
|
export function findAddOn(id, addOns) {
|
|
407
|
-
return addOns.find((item) => item
|
|
440
|
+
return (addOns ?? []).find((item) => item?.id === id);
|
|
408
441
|
}
|
|
409
442
|
|
|
410
443
|
export function inRange(expected, actual, boundary = 10) {
|