tripstorekrabi-shared 1.13.67 → 1.13.69
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 +169 -132
- package/package.json +2 -2
- package/utils.js +280 -156
package/booking.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import dayjs from
|
|
1
|
+
import dayjs from 'dayjs';
|
|
2
2
|
import advancedFormat from 'dayjs/plugin/advancedFormat.js';
|
|
3
|
-
import utc from
|
|
4
|
-
import timezone from
|
|
3
|
+
import utc from 'dayjs/plugin/utc.js';
|
|
4
|
+
import timezone from 'dayjs/plugin/timezone.js';
|
|
5
5
|
import { PAY_ON_TOUR, calculateTotalOperatorPrice } from './price.js';
|
|
6
6
|
|
|
7
7
|
dayjs.extend(advancedFormat);
|
|
@@ -10,131 +10,155 @@ dayjs.extend(timezone);
|
|
|
10
10
|
|
|
11
11
|
const PHONE_REGEXP = /[^\d+]/g;
|
|
12
12
|
|
|
13
|
-
export function addBookingFromInvoice(
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
13
|
+
export function addBookingFromInvoice(
|
|
14
|
+
firestore,
|
|
15
|
+
admin,
|
|
16
|
+
invoice,
|
|
17
|
+
paymentData,
|
|
18
|
+
comment = ''
|
|
19
|
+
) {
|
|
20
|
+
let bookingNumberDoc = firestore.collection('meta').doc('BOOKING_NUMBER');
|
|
21
|
+
|
|
22
|
+
return firestore.runTransaction((transaction) => {
|
|
23
|
+
return bookingNumberDoc.get().then(async (snapshot) => {
|
|
24
|
+
let nextBookingNumber = (snapshot.get('last') ?? 0) + 1;
|
|
25
|
+
let processed = 0;
|
|
26
|
+
comment =
|
|
27
|
+
[comment, invoice.comment].filter((item) => item).join(', ') ?? '';
|
|
28
|
+
|
|
29
|
+
for (let i = 0; i < invoice.items.length; i++) {
|
|
30
|
+
let item = invoice.items[i];
|
|
31
|
+
|
|
32
|
+
// process only product items
|
|
33
|
+
let hasProduct = item.productId?.length > 0;
|
|
34
|
+
let productSnapshot = null;
|
|
35
|
+
let productDescription;
|
|
36
|
+
if (hasProduct) {
|
|
37
|
+
productSnapshot = await firestore
|
|
38
|
+
.collection('products')
|
|
39
|
+
.doc(item.productId)
|
|
40
|
+
.get();
|
|
41
|
+
productDescription = productSnapshot.get('shortName');
|
|
42
|
+
} else {
|
|
43
|
+
productDescription = item.description;
|
|
44
|
+
}
|
|
36
45
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
46
|
+
let data = {
|
|
47
|
+
referenceNumber: 'TSK' + (nextBookingNumber + processed),
|
|
48
|
+
hint: '',
|
|
49
|
+
specialRequirements: item.dietary?.toUpperCase() ?? '',
|
|
50
|
+
productDescription,
|
|
51
|
+
productRef: hasProduct
|
|
52
|
+
? firestore.collection('products').doc(item.productId)
|
|
53
|
+
: null,
|
|
54
|
+
operator: productSnapshot?.get('operator.default.name') ?? '',
|
|
55
|
+
departureDate: admin.firestore.Timestamp.fromDate(
|
|
56
|
+
dayjs(item.departureDate).toDate()
|
|
57
|
+
),
|
|
58
|
+
schedule: item.schedule ?? '',
|
|
59
|
+
pickupTime: '?',
|
|
60
|
+
adults: item.adults ?? 0,
|
|
61
|
+
children: item.children ?? 0,
|
|
62
|
+
infants: item.infants ?? 0,
|
|
63
|
+
leadTraveller: invoice.name,
|
|
64
|
+
email: invoice.email ?? '',
|
|
65
|
+
phoneNumber: invoice.phoneNumber ?? '',
|
|
66
|
+
cc: '',
|
|
67
|
+
customerBookingStatus: 'Pending',
|
|
68
|
+
operatorBookingStatus: 'Pending',
|
|
69
|
+
sentToOperator: false,
|
|
70
|
+
startingPointDescription: '',
|
|
71
|
+
pickupHotel: item.pickupHotel ?? null,
|
|
72
|
+
roomNumber: item.roomNumber ?? '',
|
|
73
|
+
flight: item.flight ?? null,
|
|
74
|
+
train: item.train ?? null,
|
|
75
|
+
comment,
|
|
76
|
+
customerPaymentStatus: 'Paid',
|
|
77
|
+
operatorPaymentStatus: 'Pending',
|
|
78
|
+
extraPayments: {},
|
|
79
|
+
addOns: item.addOns ?? null,
|
|
80
|
+
labels: ['NEW'],
|
|
81
|
+
paypalInvoiceId: '',
|
|
82
|
+
paypalTransactionId: '',
|
|
83
|
+
omiseChargeId: '',
|
|
84
|
+
invoiceNumber: '',
|
|
85
|
+
date: admin.firestore.FieldValue.serverTimestamp(),
|
|
86
|
+
createdBy: 'Trip Store Krabi Next',
|
|
87
|
+
lastModified: dayjs().toDate(),
|
|
88
|
+
lastModifiedBy: 'Trip Store Krabi Next',
|
|
89
|
+
};
|
|
90
|
+
|
|
91
|
+
if (item.startingPointId) {
|
|
92
|
+
data.startingPointId = item.startingPointId;
|
|
93
|
+
}
|
|
80
94
|
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
95
|
+
if (item.dropoffHotel && item.dropoffHotel.length > 0) {
|
|
96
|
+
data.dropoffHotel = item.dropoffHotel;
|
|
97
|
+
}
|
|
84
98
|
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
99
|
+
if (i > 0) {
|
|
100
|
+
data.partnerNetPrice = 0;
|
|
101
|
+
}
|
|
88
102
|
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
103
|
+
if (item.nationalParkFee) {
|
|
104
|
+
data.nationalParkFee = item.nationalParkFee;
|
|
105
|
+
}
|
|
92
106
|
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
107
|
+
if (item.tourGuideLanguage) {
|
|
108
|
+
data.tourGuideLanguage = item.tourGuideLanguage;
|
|
109
|
+
}
|
|
96
110
|
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
}
|
|
103
|
-
}
|
|
104
|
-
if (endPointId) {
|
|
105
|
-
data.endPointId = endPointId;
|
|
111
|
+
let endPointId = item.endPointId;
|
|
112
|
+
if (!endPointId) {
|
|
113
|
+
let endPoints = productSnapshot?.get('endPoints');
|
|
114
|
+
if (endPoints && endPoints.length === 1) {
|
|
115
|
+
endPointId = endPoints[0].id;
|
|
106
116
|
}
|
|
117
|
+
}
|
|
118
|
+
if (endPointId) {
|
|
119
|
+
data.endPointId = endPointId;
|
|
120
|
+
}
|
|
107
121
|
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
data
|
|
112
|
-
|
|
122
|
+
if (productSnapshot) {
|
|
123
|
+
data.operatorNetPrice = calculateTotalOperatorPrice(
|
|
124
|
+
data,
|
|
125
|
+
productSnapshot.data()
|
|
126
|
+
);
|
|
127
|
+
} else {
|
|
128
|
+
data.operatorNetPrice = 0;
|
|
129
|
+
}
|
|
113
130
|
|
|
114
|
-
|
|
131
|
+
data = { ...data, ...paymentData };
|
|
115
132
|
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
133
|
+
let doc = firestore.collection('bookings').doc();
|
|
134
|
+
transaction.set(doc, data);
|
|
135
|
+
processed++;
|
|
136
|
+
}
|
|
120
137
|
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
138
|
+
transaction.set(
|
|
139
|
+
bookingNumberDoc,
|
|
140
|
+
{
|
|
141
|
+
last: admin.firestore.FieldValue.increment(processed),
|
|
142
|
+
},
|
|
143
|
+
{ merge: true }
|
|
144
|
+
);
|
|
128
145
|
});
|
|
146
|
+
});
|
|
129
147
|
}
|
|
130
148
|
|
|
131
149
|
export function getOperatorSignature(agent, operatorName, contact) {
|
|
132
150
|
let signature =
|
|
133
|
-
'<br><br>Warm regards,<br><br>' +
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
signature +=
|
|
137
|
-
|
|
151
|
+
'<br><br>Warm regards,<br><br>' +
|
|
152
|
+
(agent ? agent + ' - ' : '') +
|
|
153
|
+
operatorName;
|
|
154
|
+
signature += `<br>WhatsApp chat: <a href='https://wa.me/${contact.respondNumber.replace(
|
|
155
|
+
/\D/g,
|
|
156
|
+
''
|
|
157
|
+
)}'>${contact.respondNumber}</a>`;
|
|
158
|
+
signature += `<br>WhatsApp call: <a href='https://wa.me/${contact.whatsappNumber.replace(
|
|
159
|
+
/\D/g,
|
|
160
|
+
''
|
|
161
|
+
)}'>${contact.whatsappNumber}</a>`;
|
|
138
162
|
signature +=
|
|
139
163
|
"<br>Telegram chat: <a href='https://t.me/tripstorekrabi_bot'>@tripstorekrabi_bot</a>";
|
|
140
164
|
return signature;
|
|
@@ -144,7 +168,7 @@ export function buildIndex(id, booking) {
|
|
|
144
168
|
let referenceNumbers = [booking.referenceNumber];
|
|
145
169
|
if (booking.expediaVoucherNumbers) {
|
|
146
170
|
booking.expediaVoucherNumbers.forEach((voucherNumber) => {
|
|
147
|
-
referenceNumbers.push(voucherNumber +
|
|
171
|
+
referenceNumbers.push(voucherNumber + '');
|
|
148
172
|
});
|
|
149
173
|
}
|
|
150
174
|
|
|
@@ -157,7 +181,7 @@ export function buildIndex(id, booking) {
|
|
|
157
181
|
|
|
158
182
|
let emails = [];
|
|
159
183
|
let email = booking.email;
|
|
160
|
-
if (email && email !==
|
|
184
|
+
if (email && email !== 'info@tripstorekrabi.com') {
|
|
161
185
|
emails.push(email);
|
|
162
186
|
}
|
|
163
187
|
|
|
@@ -165,7 +189,7 @@ export function buildIndex(id, booking) {
|
|
|
165
189
|
emails.push(booking.cc);
|
|
166
190
|
}
|
|
167
191
|
|
|
168
|
-
let pickupHotel = booking.pickupHotel ??
|
|
192
|
+
let pickupHotel = booking.pickupHotel ?? '';
|
|
169
193
|
|
|
170
194
|
let phoneNumbers = [];
|
|
171
195
|
let phoneNumber = booking.phoneNumber;
|
|
@@ -178,18 +202,25 @@ export function buildIndex(id, booking) {
|
|
|
178
202
|
}
|
|
179
203
|
phoneNumbers = [...new Set(phoneNumbers)];
|
|
180
204
|
|
|
181
|
-
return {
|
|
205
|
+
return {
|
|
206
|
+
id,
|
|
207
|
+
referenceNumbers,
|
|
208
|
+
travellers,
|
|
209
|
+
emails,
|
|
210
|
+
pickupHotel,
|
|
211
|
+
phoneNumbers,
|
|
212
|
+
};
|
|
182
213
|
}
|
|
183
214
|
|
|
184
215
|
function addPhoneNumbers(phoneNumbers, phoneNumber) {
|
|
185
|
-
phoneNumber = (phoneNumber +
|
|
186
|
-
phoneNumber = phoneNumber.replace(PHONE_REGEXP,
|
|
187
|
-
if (phoneNumber.startsWith(
|
|
216
|
+
phoneNumber = (phoneNumber + '').trim();
|
|
217
|
+
phoneNumber = phoneNumber.replace(PHONE_REGEXP, '');
|
|
218
|
+
if (phoneNumber.startsWith('+')) {
|
|
188
219
|
phoneNumbers.push(phoneNumber);
|
|
189
220
|
phoneNumbers.push(phoneNumber.substring(1));
|
|
190
221
|
} else {
|
|
191
222
|
phoneNumbers.push(phoneNumber);
|
|
192
|
-
phoneNumbers.push(
|
|
223
|
+
phoneNumbers.push('+' + phoneNumber);
|
|
193
224
|
}
|
|
194
225
|
}
|
|
195
226
|
|
|
@@ -203,13 +234,11 @@ export function getStartingPointMessage(booking, product) {
|
|
|
203
234
|
text += ' at ' + booking.pickupTime;
|
|
204
235
|
}
|
|
205
236
|
|
|
206
|
-
let now = dayjs().tz(
|
|
207
|
-
let dayjsDate = dayjs.tz(booking.departureDate.toDate(),
|
|
237
|
+
let now = dayjs().tz('Asia/Bangkok');
|
|
238
|
+
let dayjsDate = dayjs.tz(booking.departureDate.toDate(), 'Asia/Bangkok');
|
|
208
239
|
let date = dayjsDate.format('Do MMM');
|
|
209
240
|
|
|
210
|
-
if (
|
|
211
|
-
now.add(1, 'day').isSame(dayjsDate, 'day')
|
|
212
|
-
) {
|
|
241
|
+
if (now.add(1, 'day').isSame(dayjsDate, 'day')) {
|
|
213
242
|
text += ' tomorrow the ' + date;
|
|
214
243
|
} else if (now.isSame(dayjsDate, 'day')) {
|
|
215
244
|
text += ' today the ' + date;
|
|
@@ -219,10 +248,17 @@ export function getStartingPointMessage(booking, product) {
|
|
|
219
248
|
|
|
220
249
|
text += '. Please watch out for the staff of ' + booking.operator + '.';
|
|
221
250
|
|
|
251
|
+
if (product?.whatToBring?.length > 0) {
|
|
252
|
+
text += '\n\nWHAT TO BRING: ' + product.whatToBring;
|
|
253
|
+
}
|
|
254
|
+
|
|
222
255
|
if (booking.specialRequirements) {
|
|
223
256
|
text +=
|
|
224
|
-
'\n\nSPECIAL REQUIREMENTS: ' +
|
|
225
|
-
|
|
257
|
+
'\n\nSPECIAL REQUIREMENTS: ' + booking.specialRequirements.toUpperCase();
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
if (product?.customerInformation?.length > 0) {
|
|
261
|
+
text += '\n\nIMPORTANT INFORMATION: ' + product.customerInformation;
|
|
226
262
|
}
|
|
227
263
|
|
|
228
264
|
let payOnTour = [];
|
|
@@ -233,8 +269,7 @@ export function getStartingPointMessage(booking, product) {
|
|
|
233
269
|
item += ' to ' + product?.nationalPark.title;
|
|
234
270
|
}
|
|
235
271
|
|
|
236
|
-
if (product?.nationalPark?.pricing
|
|
237
|
-
) {
|
|
272
|
+
if (product?.nationalPark?.pricing) {
|
|
238
273
|
item +=
|
|
239
274
|
' of ' +
|
|
240
275
|
product.nationalPark.pricing.adult +
|
|
@@ -247,12 +282,14 @@ export function getStartingPointMessage(booking, product) {
|
|
|
247
282
|
payOnTour.push(` • ${item}`);
|
|
248
283
|
}
|
|
249
284
|
|
|
250
|
-
let extraPayments = Object.values(booking.extraPayments)
|
|
285
|
+
let extraPayments = Object.values(booking.extraPayments)
|
|
286
|
+
.filter((item) => !item.disabled && item.paymentMethod === PAY_ON_TOUR)
|
|
287
|
+
.map((item) => ` • ${item.description}: ${item.price} THB`);
|
|
251
288
|
payOnTour = [...payOnTour, ...extraPayments];
|
|
252
289
|
if (payOnTour.length > 0) {
|
|
253
|
-
text += '\n\nTO BE PAID ON TOUR:\n' + payOnTour.join(
|
|
290
|
+
text += '\n\nTO BE PAID ON TOUR:\n' + payOnTour.join('\n');
|
|
254
291
|
text += '\n\nPlease bring the total amount in cash to the trip.';
|
|
255
292
|
}
|
|
256
293
|
|
|
257
294
|
return text;
|
|
258
|
-
}
|
|
295
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "tripstorekrabi-shared",
|
|
3
|
-
"version": "1.13.
|
|
3
|
+
"version": "1.13.69",
|
|
4
4
|
"description": "Shared library for Trip Store Krabi",
|
|
5
5
|
"author": "Stefan Sommer <tonprince@gmail.com>",
|
|
6
6
|
"repository": {
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
"./product": "./product.js"
|
|
16
16
|
},
|
|
17
17
|
"dependencies": {
|
|
18
|
-
"dayjs": "^1.11.
|
|
18
|
+
"dayjs": "^1.11.10"
|
|
19
19
|
},
|
|
20
20
|
"scripts": {
|
|
21
21
|
"deploy": "npm publish"
|
package/utils.js
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import dayjs from
|
|
2
|
-
import customParseFormat from
|
|
1
|
+
import dayjs from 'dayjs';
|
|
2
|
+
import customParseFormat from 'dayjs/plugin/customParseFormat.js';
|
|
3
3
|
import advancedFormat from 'dayjs/plugin/advancedFormat.js';
|
|
4
|
-
import isSameOrBefore from
|
|
4
|
+
import isSameOrBefore from 'dayjs/plugin/isSameOrBefore.js';
|
|
5
5
|
import utc from 'dayjs/plugin/utc.js';
|
|
6
6
|
import timezone from 'dayjs/plugin/timezone.js';
|
|
7
|
-
import { findEndPoint, findStartingPoint } from
|
|
7
|
+
import { findEndPoint, findStartingPoint } from './price.js';
|
|
8
8
|
|
|
9
9
|
dayjs.extend(customParseFormat);
|
|
10
10
|
dayjs.extend(advancedFormat);
|
|
@@ -12,15 +12,22 @@ dayjs.extend(isSameOrBefore);
|
|
|
12
12
|
dayjs.extend(utc);
|
|
13
13
|
dayjs.extend(timezone);
|
|
14
14
|
|
|
15
|
-
export const PROD_URL =
|
|
15
|
+
export const PROD_URL = 'https://www.tripstorekrabi.com';
|
|
16
16
|
export const MAX_AGE_SEC = 60 * 60 * 24;
|
|
17
17
|
export const NO_ROOM = 'NO ROOM';
|
|
18
18
|
export const IN_HOUSE = 'IN HOUSE';
|
|
19
19
|
export const CHECK_IN_LATE = 'CHECK-IN LATE';
|
|
20
20
|
export const ROOM_NUMBER_LIST = [NO_ROOM, IN_HOUSE, CHECK_IN_LATE];
|
|
21
21
|
|
|
22
|
-
const
|
|
23
|
-
const
|
|
22
|
+
export const TRIPSTORE_AGENCYID_IN_PHAYUN = '2Z5NPZTmd62tm22q0RNB';
|
|
23
|
+
export const GYG_AGENCYID_IN_PHAYUN = 'lPZIMbXgzaFwA366uzia';
|
|
24
|
+
export const KLK_AGENCYID_IN_PHAYUN = 'JSYggp9yw8RBdIkhuPvo';
|
|
25
|
+
export const TIQ_AGENCYID_IN_PHAYUN = 'HPiO2Z6OdD8A3O5Zbi96';
|
|
26
|
+
|
|
27
|
+
const EMAIL_PATTERN = new RegExp(
|
|
28
|
+
/^[a-zA-Z0-9.!#$%&' * +/=?^_`{|}~-]+@[a-zA-Z0-9-]+(?:\.[a-zA-Z0-9-]+)*$/
|
|
29
|
+
);
|
|
30
|
+
const MEALS = ['lunch', 'meal', 'breakfast', 'dinner'];
|
|
24
31
|
const SCHEDULE_PATTERN = new RegExp('^(0[0-9]|1[0-9]|2[0-3]):[0-5][0-9]$');
|
|
25
32
|
|
|
26
33
|
export function validateEmail(email) {
|
|
@@ -28,13 +35,18 @@ export function validateEmail(email) {
|
|
|
28
35
|
}
|
|
29
36
|
|
|
30
37
|
export function resizeGoogleImage(image, size) {
|
|
31
|
-
return image
|
|
32
|
-
/\/w.\d+-.\d+-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
.replace(
|
|
36
|
-
|
|
37
|
-
|
|
38
|
+
return image
|
|
39
|
+
.replace(/\/w.\d+-.\d+-p\//, '/' + size + '/')
|
|
40
|
+
.replace(/\/w.\d+-.\d+-c\//, '/' + size + '/')
|
|
41
|
+
.replace(/\/w.\d+-.\d+-no\//, '/' + size + '/')
|
|
42
|
+
.replace(/\/w.\d+-.\d+\//, '/' + size + '/')
|
|
43
|
+
.replace(/\/s.\d+\//, '/' + size + '/')
|
|
44
|
+
.replace(/\=w.\d+-.\d+-p/, '=' + size)
|
|
45
|
+
.replace(/\=w.\d+-.\d+-c/, '=' + size)
|
|
46
|
+
.replace(/\=w.\d+-.\d+-no/, '=' + size)
|
|
47
|
+
.replace(/\=w.\d+-.\d+/, '=' + size)
|
|
48
|
+
.replace(/\=s.\d+/, '=' + size)
|
|
49
|
+
.replace(/\=s.\d+/, '=' + size);
|
|
38
50
|
}
|
|
39
51
|
|
|
40
52
|
export function resizeStorageImage(path, size) {
|
|
@@ -46,9 +58,9 @@ export function createPdfPreview(path, size) {
|
|
|
46
58
|
}
|
|
47
59
|
|
|
48
60
|
export function formatNumber(number, fraction = 2) {
|
|
49
|
-
return number.toLocaleString(
|
|
61
|
+
return number.toLocaleString('th-TH', {
|
|
50
62
|
minimumFractionDigits: fraction,
|
|
51
|
-
maximumFractionDigits: fraction
|
|
63
|
+
maximumFractionDigits: fraction,
|
|
52
64
|
});
|
|
53
65
|
}
|
|
54
66
|
|
|
@@ -69,30 +81,34 @@ export function getDurationSummary(schedules) {
|
|
|
69
81
|
}
|
|
70
82
|
});
|
|
71
83
|
|
|
72
|
-
return minDuration == maxDuration
|
|
84
|
+
return minDuration == maxDuration
|
|
85
|
+
? formatDuration(minDuration)
|
|
86
|
+
: `${formatDuration(minDuration)} - ${formatDuration(maxDuration)}`;
|
|
73
87
|
}
|
|
74
88
|
|
|
75
89
|
export function getDuration(schedule) {
|
|
76
90
|
if (schedule) {
|
|
77
|
-
let schedules = schedule.split(
|
|
78
|
-
let minutes = dayjs(schedules[1].trim(),
|
|
91
|
+
let schedules = schedule.split('-');
|
|
92
|
+
let minutes = dayjs(schedules[1].trim(), 'HH:mm').diff(
|
|
93
|
+
dayjs(schedules[0].trim(), 'HH:mm'),
|
|
94
|
+
'minute'
|
|
95
|
+
);
|
|
79
96
|
if (minutes < 0) {
|
|
80
97
|
minutes = 24 * 60 + minutes;
|
|
81
98
|
}
|
|
82
99
|
return minutes;
|
|
83
|
-
}
|
|
84
|
-
else {
|
|
100
|
+
} else {
|
|
85
101
|
return 0;
|
|
86
102
|
}
|
|
87
103
|
}
|
|
88
104
|
|
|
89
105
|
export function formatDuration(minutes) {
|
|
90
106
|
if (minutes === 0) {
|
|
91
|
-
return
|
|
107
|
+
return '-';
|
|
92
108
|
} else if (minutes > 60) {
|
|
93
|
-
return (minutes / 60).toFixed(1) +
|
|
109
|
+
return (minutes / 60).toFixed(1) + ' hours';
|
|
94
110
|
} else {
|
|
95
|
-
return minutes +
|
|
111
|
+
return minutes + ' minutes';
|
|
96
112
|
}
|
|
97
113
|
}
|
|
98
114
|
|
|
@@ -100,25 +116,30 @@ export function getPickuptimeSummary(pickupZones) {
|
|
|
100
116
|
if (pickupZones && pickupZones.length > 0) {
|
|
101
117
|
let pickupTimesArray = [];
|
|
102
118
|
pickupZones.forEach((pickupZone) => {
|
|
103
|
-
let pickupLength = pickupZone.indexOf(
|
|
119
|
+
let pickupLength = pickupZone.indexOf(': ');
|
|
104
120
|
let pickupTimes = pickupZone.substring(pickupLength + 1).trim();
|
|
105
|
-
if (pickupZone.indexOf(
|
|
106
|
-
pickupTimesArray.push(pickupTimes.split(
|
|
121
|
+
if (pickupZone.indexOf(' / ') != -1) {
|
|
122
|
+
pickupTimesArray.push(pickupTimes.split(' / '));
|
|
107
123
|
} else {
|
|
108
124
|
pickupTimesArray.push([pickupTimes]);
|
|
109
125
|
}
|
|
110
126
|
});
|
|
111
127
|
|
|
112
|
-
|
|
113
|
-
|
|
128
|
+
pickupTimesArray = pickupTimesArray[0].map((_, colIndex) =>
|
|
129
|
+
pickupTimesArray.map((row) => row[colIndex])
|
|
130
|
+
);
|
|
114
131
|
|
|
115
132
|
return pickupTimesArray.map((items) => {
|
|
116
|
-
let pickupTimes = [
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
133
|
+
let pickupTimes = [
|
|
134
|
+
...new Set(
|
|
135
|
+
items.reduce((r, e) => {
|
|
136
|
+
e.split(' - ').forEach((item) => {
|
|
137
|
+
r.push(item);
|
|
138
|
+
});
|
|
139
|
+
return r;
|
|
140
|
+
}, [])
|
|
141
|
+
),
|
|
142
|
+
].sort();
|
|
122
143
|
|
|
123
144
|
if (pickupTimes.length == 1) {
|
|
124
145
|
return pickupTimes[0];
|
|
@@ -132,62 +153,88 @@ export function getPickuptimeSummary(pickupZones) {
|
|
|
132
153
|
}
|
|
133
154
|
|
|
134
155
|
export function getDeparture(schedule) {
|
|
135
|
-
return schedule.split(
|
|
156
|
+
return schedule.split('-')[0].trim();
|
|
136
157
|
}
|
|
137
158
|
|
|
138
159
|
export function getPickupTime(schedule, offset = 30) {
|
|
139
|
-
if (schedule.indexOf(
|
|
140
|
-
return dayjs(schedule.split(
|
|
160
|
+
if (schedule.indexOf('-') != -1) {
|
|
161
|
+
return dayjs(schedule.split('-')[0].trim(), 'HH:mm')
|
|
162
|
+
.subtract(offset, 'minute')
|
|
163
|
+
.format('HH:mm');
|
|
141
164
|
} else {
|
|
142
|
-
return dayjs(schedule,
|
|
165
|
+
return dayjs(schedule, 'HH:mm').subtract(offset, 'minute').format('HH:mm');
|
|
143
166
|
}
|
|
144
167
|
}
|
|
145
168
|
|
|
146
169
|
export function getArrival(schedule) {
|
|
147
|
-
return schedule.split(
|
|
170
|
+
return schedule.split('-')[1].trim();
|
|
148
171
|
}
|
|
149
172
|
|
|
150
173
|
export function isHotelPickup(value) {
|
|
151
174
|
value = value.toLowerCase();
|
|
152
|
-
return (
|
|
175
|
+
return (
|
|
176
|
+
(value.includes('picked up') ||
|
|
177
|
+
value.includes('pickup') ||
|
|
178
|
+
value.includes('round-trip')) &&
|
|
179
|
+
value.includes('hotel')
|
|
180
|
+
);
|
|
153
181
|
}
|
|
154
182
|
|
|
155
183
|
export function isHotelDropOff(value) {
|
|
156
184
|
value = value.toLowerCase();
|
|
157
|
-
return (
|
|
185
|
+
return (
|
|
186
|
+
(value.includes('dropped off') ||
|
|
187
|
+
value.includes('drop-off') ||
|
|
188
|
+
value.includes('transfer')) &&
|
|
189
|
+
value.includes('hotel')
|
|
190
|
+
);
|
|
158
191
|
}
|
|
159
192
|
|
|
160
193
|
export function isAirportPickup(value) {
|
|
161
194
|
value = value.toLowerCase();
|
|
162
|
-
value = value
|
|
163
|
-
|
|
195
|
+
value = value
|
|
196
|
+
.replace('pick up', 'pickup')
|
|
197
|
+
.replace('picked up', 'pickup')
|
|
198
|
+
.replace('pick-up', 'pickup');
|
|
199
|
+
return (
|
|
200
|
+
(value.includes('pickup') || value.includes('meet')) &&
|
|
201
|
+
value.includes('airport')
|
|
202
|
+
);
|
|
164
203
|
}
|
|
165
204
|
|
|
166
205
|
export function isAirportDropOff(value) {
|
|
167
206
|
value = value.toLowerCase();
|
|
168
207
|
|
|
169
|
-
let result =
|
|
208
|
+
let result =
|
|
209
|
+
(value.includes('drop-off') || value.includes('transfer')) &&
|
|
210
|
+
value.includes('airport');
|
|
170
211
|
|
|
171
|
-
if (!result && value.includes(
|
|
172
|
-
result = value.substring(value.indexOf(
|
|
212
|
+
if (!result && value.includes(' to ')) {
|
|
213
|
+
result = value.substring(value.indexOf(' to ')).includes(' airport');
|
|
173
214
|
}
|
|
174
215
|
return result;
|
|
175
216
|
}
|
|
176
217
|
|
|
177
218
|
export function isMeetingPoint(value) {
|
|
178
219
|
value = value.toLowerCase();
|
|
179
|
-
value = value
|
|
180
|
-
|
|
220
|
+
value = value
|
|
221
|
+
.replace('pick up', 'pickup')
|
|
222
|
+
.replace('picked up', 'pickup')
|
|
223
|
+
.replace('pick-up', 'pickup');
|
|
224
|
+
return (
|
|
225
|
+
value.indexOf('meet ') != -1 ||
|
|
226
|
+
(value.indexOf('pickup') != -1 && value.indexOf('hotel') == -1)
|
|
227
|
+
);
|
|
181
228
|
}
|
|
182
229
|
|
|
183
230
|
export function isTrainStation(value) {
|
|
184
231
|
value = value.toLowerCase();
|
|
185
|
-
return value.includes(
|
|
232
|
+
return value.includes('train') && value.includes('station');
|
|
186
233
|
}
|
|
187
234
|
|
|
188
235
|
export function isMealIncluded(includes) {
|
|
189
236
|
if (includes) {
|
|
190
|
-
let includesString = includes.join(
|
|
237
|
+
let includesString = includes.join(' ').toLowerCase();
|
|
191
238
|
return MEALS.some((item) => includesString.includes(item));
|
|
192
239
|
} else {
|
|
193
240
|
return false;
|
|
@@ -197,7 +244,7 @@ export function isMealIncluded(includes) {
|
|
|
197
244
|
export function validateName(name) {
|
|
198
245
|
name = name.trim();
|
|
199
246
|
if (name) {
|
|
200
|
-
return name.indexOf(
|
|
247
|
+
return name.indexOf(' ') != -1;
|
|
201
248
|
} else {
|
|
202
249
|
return false;
|
|
203
250
|
}
|
|
@@ -208,7 +255,7 @@ export function scrollContainer() {
|
|
|
208
255
|
}
|
|
209
256
|
|
|
210
257
|
export function toTitleCase(str) {
|
|
211
|
-
return str.replace(/\b\S/g, t => t.toUpperCase());
|
|
258
|
+
return str.replace(/\b\S/g, (t) => t.toUpperCase());
|
|
212
259
|
}
|
|
213
260
|
|
|
214
261
|
export function capitalize(string) {
|
|
@@ -253,23 +300,25 @@ function chunkArray(array, chunk_size) {
|
|
|
253
300
|
}
|
|
254
301
|
|
|
255
302
|
export function encodeURL(url) {
|
|
256
|
-
return toTitleCase(url).replace(/ /g,
|
|
303
|
+
return toTitleCase(url).replace(/ /g, '-');
|
|
257
304
|
}
|
|
258
305
|
|
|
259
306
|
export function formatPeople(people) {
|
|
260
307
|
let result = [];
|
|
261
308
|
if (people.adults > 0) {
|
|
262
|
-
result.push(`${people.adults} ${people.adults > 1 ?
|
|
309
|
+
result.push(`${people.adults} ${people.adults > 1 ? 'adults' : 'adult'}`);
|
|
263
310
|
}
|
|
264
311
|
if (people.children > 0) {
|
|
265
|
-
result.push(
|
|
266
|
-
}`
|
|
312
|
+
result.push(
|
|
313
|
+
`${people.children} ${people.children > 1 ? 'children' : 'child'}`
|
|
314
|
+
);
|
|
267
315
|
}
|
|
268
316
|
if (people.infants > 0) {
|
|
269
|
-
result.push(
|
|
270
|
-
}`
|
|
317
|
+
result.push(
|
|
318
|
+
`${people.infants} ${people.infants > 1 ? 'infants' : 'infant'}`
|
|
319
|
+
);
|
|
271
320
|
}
|
|
272
|
-
return result.join(
|
|
321
|
+
return result.join(', ');
|
|
273
322
|
}
|
|
274
323
|
|
|
275
324
|
export function countPeople(people) {
|
|
@@ -281,34 +330,53 @@ export function isNumeric(n) {
|
|
|
281
330
|
}
|
|
282
331
|
|
|
283
332
|
export function getBookingSummary(booking, options = {}) {
|
|
284
|
-
let summary =
|
|
333
|
+
let summary = '';
|
|
285
334
|
if (!options.excludeReferenceNumber) {
|
|
286
335
|
summary += booking.referenceNumber;
|
|
287
336
|
if (booking.code) {
|
|
288
|
-
summary +=
|
|
337
|
+
summary += ', Code: ' + booking.code;
|
|
289
338
|
}
|
|
290
339
|
|
|
291
340
|
if (options.includeVersion && booking.version) {
|
|
292
|
-
summary +=
|
|
341
|
+
summary += ', Version: ' + booking.version;
|
|
293
342
|
}
|
|
294
|
-
summary +=
|
|
343
|
+
summary += ': ';
|
|
295
344
|
}
|
|
296
345
|
|
|
297
|
-
if (
|
|
298
|
-
|
|
299
|
-
|
|
346
|
+
if (
|
|
347
|
+
booking.productDescription &&
|
|
348
|
+
booking.operator &&
|
|
349
|
+
booking.departureDate &&
|
|
350
|
+
booking.schedule &&
|
|
351
|
+
booking.leadTraveller
|
|
352
|
+
) {
|
|
353
|
+
let departureDate = dayjs(booking.departureDate.toDate())
|
|
354
|
+
.tz('Asia/Bangkok')
|
|
355
|
+
.format('DD.MM.YYYY');
|
|
356
|
+
summary += booking.productDescription + ', ' + departureDate;
|
|
300
357
|
|
|
301
358
|
if (!options.hideOperator) {
|
|
302
|
-
summary +=
|
|
359
|
+
summary += ', ' + booking.operator;
|
|
303
360
|
}
|
|
304
361
|
|
|
305
|
-
summary +=
|
|
306
|
-
|
|
362
|
+
summary +=
|
|
363
|
+
', ' +
|
|
364
|
+
booking.adults +
|
|
365
|
+
', ' +
|
|
366
|
+
booking.children +
|
|
367
|
+
', ' +
|
|
368
|
+
booking.infants +
|
|
369
|
+
', ' +
|
|
370
|
+
booking.leadTraveller;
|
|
307
371
|
|
|
308
372
|
if (booking.startingPointDescription) {
|
|
309
|
-
summary +=
|
|
373
|
+
summary +=
|
|
374
|
+
', ' +
|
|
375
|
+
(isHotelPickup(booking.startingPointDescription) && booking.noHotelYet
|
|
376
|
+
? 'NO HOTEL YET'
|
|
377
|
+
: booking.startingPointDescription);
|
|
310
378
|
} else if (booking.noHotelYet) {
|
|
311
|
-
summary +=
|
|
379
|
+
summary += ', NO HOTEL YET';
|
|
312
380
|
}
|
|
313
381
|
|
|
314
382
|
let hasHotelPickup = isHotelPickup(booking.startingPointDescription);
|
|
@@ -320,31 +388,33 @@ export function getBookingSummary(booking, options = {}) {
|
|
|
320
388
|
}
|
|
321
389
|
}
|
|
322
390
|
|
|
323
|
-
summary +=
|
|
391
|
+
summary += ', ' + booking.schedule;
|
|
324
392
|
|
|
325
|
-
if (booking.pickupTime && booking.pickupTime !=
|
|
393
|
+
if (booking.pickupTime && booking.pickupTime != '?') {
|
|
326
394
|
if (hasHotelPickup) {
|
|
327
|
-
summary +=
|
|
395
|
+
summary += ' (Pickup';
|
|
328
396
|
|
|
329
|
-
if (booking.pickupTime.indexOf(
|
|
330
|
-
summary +=
|
|
397
|
+
if (booking.pickupTime.indexOf('-') != -1) {
|
|
398
|
+
summary +=
|
|
399
|
+
' between ' +
|
|
400
|
+
booking.pickupTime.replace(' - ', ' and ').replace('-', ' and ');
|
|
331
401
|
} else {
|
|
332
|
-
summary +=
|
|
402
|
+
summary += ' at ' + booking.pickupTime;
|
|
333
403
|
}
|
|
334
|
-
summary +=
|
|
404
|
+
summary += ')';
|
|
335
405
|
} else if (isMeetingPoint(booking.startingPointDescription)) {
|
|
336
|
-
summary +=
|
|
406
|
+
summary += ' (Meet';
|
|
337
407
|
|
|
338
|
-
if (booking.pickupTime.indexOf(
|
|
339
|
-
summary +=
|
|
408
|
+
if (booking.pickupTime.indexOf('-') != -1) {
|
|
409
|
+
summary += ' at ' + booking.pickupTime.split('-')[0].trim();
|
|
340
410
|
} else {
|
|
341
|
-
summary +=
|
|
411
|
+
summary += ' at ' + booking.pickupTime;
|
|
342
412
|
}
|
|
343
|
-
summary +=
|
|
413
|
+
summary += ')';
|
|
344
414
|
}
|
|
345
415
|
}
|
|
346
416
|
} else {
|
|
347
|
-
summary +=
|
|
417
|
+
summary += '«THE BOOKING IS INCOMPLETE»';
|
|
348
418
|
}
|
|
349
419
|
|
|
350
420
|
return summary;
|
|
@@ -354,24 +424,28 @@ export function getItemSummary(item, product) {
|
|
|
354
424
|
let summary = item.description;
|
|
355
425
|
|
|
356
426
|
if (item.departureDate) {
|
|
357
|
-
summary +=
|
|
427
|
+
summary +=
|
|
428
|
+
', ' + dayjs(item.departureDate).tz('Asia/Bangkok').format('DD.MM.YYYY');
|
|
358
429
|
}
|
|
359
430
|
|
|
360
431
|
if (item.schedule) {
|
|
361
|
-
summary +=
|
|
432
|
+
summary += ', ' + item.schedule;
|
|
362
433
|
}
|
|
363
434
|
|
|
364
435
|
if (item.adults || item.children || item.infants) {
|
|
365
|
-
summary +=
|
|
436
|
+
summary += ', ' + formatPeople(item) + ', ';
|
|
366
437
|
}
|
|
367
438
|
|
|
368
439
|
if (item.startingPointId) {
|
|
369
|
-
let startingPointDescription = findStartingPoint(
|
|
440
|
+
let startingPointDescription = findStartingPoint(
|
|
441
|
+
product,
|
|
442
|
+
item.startingPointId
|
|
443
|
+
).value;
|
|
370
444
|
if (isHotelPickup(startingPointDescription)) {
|
|
371
445
|
if (item.noHotelYet === true) {
|
|
372
|
-
summary +=
|
|
446
|
+
summary += 'Hotel pickup (hotel not known yet)';
|
|
373
447
|
} else {
|
|
374
|
-
summary +=
|
|
448
|
+
summary += 'Hotel pickup from ' + item.pickupHotel;
|
|
375
449
|
|
|
376
450
|
if (item.roomNumber) {
|
|
377
451
|
summary += ` (${item.roomNumber})`;
|
|
@@ -385,7 +459,7 @@ export function getItemSummary(item, product) {
|
|
|
385
459
|
if (item.endPointId) {
|
|
386
460
|
let endPointDescription = findEndPoint(product, item.endPointId).value;
|
|
387
461
|
if (isHotelDropOff(endPointDescription) && item.dropoffHotel) {
|
|
388
|
-
summary +=
|
|
462
|
+
summary += ', Hotel drop-off at ' + item.dropoffHotel;
|
|
389
463
|
}
|
|
390
464
|
}
|
|
391
465
|
|
|
@@ -393,26 +467,36 @@ export function getItemSummary(item, product) {
|
|
|
393
467
|
}
|
|
394
468
|
|
|
395
469
|
export function validateSchedule(schedule, schedules = [], context) {
|
|
396
|
-
if (schedule ===
|
|
470
|
+
if (schedule === '?') {
|
|
397
471
|
return true;
|
|
398
|
-
} else if (schedule.indexOf(
|
|
399
|
-
let times = schedule.split(
|
|
472
|
+
} else if (schedule.indexOf(' - ') != -1) {
|
|
473
|
+
let times = schedule.split(' - ');
|
|
400
474
|
let from = times[0];
|
|
401
475
|
let to = times[1];
|
|
402
476
|
|
|
403
|
-
if (
|
|
404
|
-
|
|
477
|
+
if (
|
|
478
|
+
!SCHEDULE_PATTERN.test(from) ||
|
|
479
|
+
!SCHEDULE_PATTERN.test(to) ||
|
|
480
|
+
from === to
|
|
481
|
+
) {
|
|
482
|
+
return context.createError({
|
|
483
|
+
message: "Invalid schedule format: for example use '09:00 - 15:30'",
|
|
484
|
+
path: context.path,
|
|
485
|
+
});
|
|
405
486
|
}
|
|
406
487
|
} else {
|
|
407
|
-
return context.createError({
|
|
488
|
+
return context.createError({
|
|
489
|
+
message: "Invalid schedule format: for example use '09:00 - 15:30'",
|
|
490
|
+
path: context.path,
|
|
491
|
+
});
|
|
408
492
|
}
|
|
409
493
|
|
|
410
|
-
if (schedule !=
|
|
494
|
+
if (schedule != '') {
|
|
411
495
|
if (schedules.length > 0 && schedules.indexOf(schedule) == -1) {
|
|
412
496
|
return context.createError({
|
|
413
|
-
message:
|
|
497
|
+
message: 'The value does not match the product schedules',
|
|
414
498
|
path: context.path,
|
|
415
|
-
params: { status:
|
|
499
|
+
params: { status: 'warning' },
|
|
416
500
|
});
|
|
417
501
|
}
|
|
418
502
|
}
|
|
@@ -420,26 +504,42 @@ export function validateSchedule(schedule, schedules = [], context) {
|
|
|
420
504
|
return true;
|
|
421
505
|
}
|
|
422
506
|
|
|
423
|
-
export function validatePickupTime(pickupTime, schedule =
|
|
424
|
-
let departureTime = schedule.split(
|
|
507
|
+
export function validatePickupTime(pickupTime, schedule = '', context) {
|
|
508
|
+
let departureTime = schedule.split(' - ')[0];
|
|
425
509
|
|
|
426
|
-
if (pickupTime ===
|
|
510
|
+
if (pickupTime === '?' || schedule === '?') {
|
|
427
511
|
return true;
|
|
428
|
-
} else if (pickupTime.indexOf(
|
|
429
|
-
let times = pickupTime.split(
|
|
512
|
+
} else if (pickupTime.indexOf(' - ') != -1) {
|
|
513
|
+
let times = pickupTime.split(' - ');
|
|
430
514
|
let from = times[0];
|
|
431
515
|
let to = times[1];
|
|
432
516
|
|
|
433
|
-
if (
|
|
434
|
-
|
|
517
|
+
if (
|
|
518
|
+
!SCHEDULE_PATTERN.test(from) ||
|
|
519
|
+
!SCHEDULE_PATTERN.test(to) ||
|
|
520
|
+
from === to
|
|
521
|
+
) {
|
|
522
|
+
return context.createError({
|
|
523
|
+
message:
|
|
524
|
+
"Invalid pickup time format: for example use '09:00' or '08:45 - 09:00'",
|
|
525
|
+
});
|
|
435
526
|
} else {
|
|
436
527
|
return checkTime(from, departureTime, context);
|
|
437
528
|
}
|
|
438
|
-
} else if (pickupTime.indexOf(
|
|
439
|
-
return context.createError({
|
|
529
|
+
} else if (pickupTime.indexOf('-') != -1) {
|
|
530
|
+
return context.createError({
|
|
531
|
+
message: `Invalid pickup time format, use spaces around the dash: ${pickupTime
|
|
532
|
+
.replace(/ /g, '')
|
|
533
|
+
.replace('-', ' - ')}`,
|
|
534
|
+
path: context.path,
|
|
535
|
+
});
|
|
440
536
|
} else {
|
|
441
537
|
if (!SCHEDULE_PATTERN.test(pickupTime)) {
|
|
442
|
-
return context.createError({
|
|
538
|
+
return context.createError({
|
|
539
|
+
message:
|
|
540
|
+
"Invalid pickup time format: for example use '09:00' or '08:45 - 09:00'",
|
|
541
|
+
path: context.path,
|
|
542
|
+
});
|
|
443
543
|
} else {
|
|
444
544
|
return checkTime(pickupTime, departureTime, context);
|
|
445
545
|
}
|
|
@@ -447,11 +547,11 @@ export function validatePickupTime(pickupTime, schedule = "", context) {
|
|
|
447
547
|
}
|
|
448
548
|
|
|
449
549
|
export function isPickupTimeBeforeDepartureTime(schedule, pickupTime) {
|
|
450
|
-
let departureTime = schedule.split(
|
|
451
|
-
if (pickupTime ===
|
|
550
|
+
let departureTime = schedule.split(' - ')[0];
|
|
551
|
+
if (pickupTime === '?' || schedule === '?') {
|
|
452
552
|
return true;
|
|
453
|
-
} else if (pickupTime.indexOf(
|
|
454
|
-
let times = pickupTime.split(
|
|
553
|
+
} else if (pickupTime.indexOf(' - ') != -1) {
|
|
554
|
+
let times = pickupTime.split(' - ');
|
|
455
555
|
pickupTime = times[0];
|
|
456
556
|
}
|
|
457
557
|
|
|
@@ -459,25 +559,39 @@ export function isPickupTimeBeforeDepartureTime(schedule, pickupTime) {
|
|
|
459
559
|
}
|
|
460
560
|
|
|
461
561
|
function checkTime(pickupTimeValue, departureTimeValue, context) {
|
|
462
|
-
if (pickupTimeValue ===
|
|
562
|
+
if (pickupTimeValue === '' || departureTimeValue === '') {
|
|
463
563
|
return false;
|
|
464
564
|
}
|
|
465
565
|
|
|
466
566
|
try {
|
|
467
|
-
let pickupTimeValues = pickupTimeValue.split(
|
|
468
|
-
let pickupTime = dayjs()
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
567
|
+
let pickupTimeValues = pickupTimeValue.split(':');
|
|
568
|
+
let pickupTime = dayjs()
|
|
569
|
+
.hour(pickupTimeValues[0])
|
|
570
|
+
.minute(pickupTimeValues[1])
|
|
571
|
+
.second(0);
|
|
572
|
+
|
|
573
|
+
let departureTimeValues = departureTimeValue.split(':');
|
|
574
|
+
let departureTime = dayjs()
|
|
575
|
+
.hour(departureTimeValues[0])
|
|
576
|
+
.minute(departureTimeValues[1])
|
|
577
|
+
.second(0);
|
|
578
|
+
|
|
579
|
+
return pickupTime.isSameOrBefore(departureTime)
|
|
580
|
+
? true
|
|
581
|
+
: context
|
|
582
|
+
? context.createError({
|
|
583
|
+
message: 'Pickup time should be before or equals departure time',
|
|
584
|
+
path: context.path,
|
|
585
|
+
params: { status: 'warning' },
|
|
586
|
+
})
|
|
587
|
+
: false;
|
|
474
588
|
} catch (e) {
|
|
475
589
|
return false;
|
|
476
590
|
}
|
|
477
591
|
}
|
|
478
592
|
|
|
479
593
|
export function isActivity(url) {
|
|
480
|
-
return url.includes(
|
|
594
|
+
return url.includes('/Activities/');
|
|
481
595
|
}
|
|
482
596
|
|
|
483
597
|
export function getGoogleDocId(url) {
|
|
@@ -488,18 +602,22 @@ export function createVoucherRequest(booking, product) {
|
|
|
488
602
|
let request = {
|
|
489
603
|
booking: {
|
|
490
604
|
referenceNumber: booking.referenceNumber,
|
|
491
|
-
specialRequirements: booking.specialRequirements
|
|
605
|
+
specialRequirements: booking.specialRequirements
|
|
606
|
+
? booking.specialRequirements.toUpperCase()
|
|
607
|
+
: '',
|
|
492
608
|
nationalParkFee:
|
|
493
609
|
product && product.nationalPark
|
|
494
|
-
?
|
|
495
|
-
|
|
496
|
-
:
|
|
610
|
+
? 'NATIONAL PARK ENTRANCE FEE: ' +
|
|
611
|
+
booking.nationalParkFee.toUpperCase()
|
|
612
|
+
: '',
|
|
497
613
|
productDescription: booking.productDescription,
|
|
498
614
|
leadTraveller: booking.leadTraveller,
|
|
499
615
|
adults: booking.adults,
|
|
500
616
|
children: booking.children,
|
|
501
617
|
infants: booking.infants,
|
|
502
|
-
departureDate: dayjs(booking.departureDate.toDate())
|
|
618
|
+
departureDate: dayjs(booking.departureDate.toDate())
|
|
619
|
+
.tz('Asia/Bangkok')
|
|
620
|
+
.format('Do MMM YYYY'),
|
|
503
621
|
operator: booking.operator,
|
|
504
622
|
startingPointDescription: booking.startingPointDescription,
|
|
505
623
|
roomNumber: booking.roomNumber,
|
|
@@ -507,84 +625,84 @@ export function createVoucherRequest(booking, product) {
|
|
|
507
625
|
pickupTime: booking.pickupTime,
|
|
508
626
|
mobileVoucher: product
|
|
509
627
|
? product.operator.mobileVoucher ??
|
|
510
|
-
|
|
628
|
+
product.operator.default.mobileVoucher
|
|
511
629
|
: true,
|
|
512
630
|
},
|
|
513
631
|
};
|
|
514
632
|
if (booking.voucherUrl) {
|
|
515
|
-
request[
|
|
633
|
+
request['id'] = getGoogleDocId(booking.voucherUrl);
|
|
516
634
|
}
|
|
517
635
|
|
|
518
636
|
return request;
|
|
519
637
|
}
|
|
520
638
|
|
|
521
639
|
export function isGYGBooking(referenceNumber) {
|
|
522
|
-
return referenceNumber.startsWith(
|
|
640
|
+
return referenceNumber.startsWith('GYG');
|
|
523
641
|
}
|
|
524
642
|
|
|
525
643
|
export function isViatorBooking(referenceNumber) {
|
|
526
|
-
return referenceNumber.startsWith(
|
|
644
|
+
return referenceNumber.startsWith('BR-');
|
|
527
645
|
}
|
|
528
646
|
|
|
529
647
|
export function isExpediaBooking(referenceNumber) {
|
|
530
|
-
return referenceNumber.startsWith(
|
|
648
|
+
return referenceNumber.startsWith('EXP-');
|
|
531
649
|
}
|
|
532
650
|
|
|
533
651
|
export function isKlookBooking(referenceNumber) {
|
|
534
|
-
return referenceNumber.startsWith(
|
|
652
|
+
return referenceNumber.startsWith('KLK-');
|
|
535
653
|
}
|
|
536
654
|
|
|
537
655
|
export function isMusementBooking(referenceNumber) {
|
|
538
|
-
return referenceNumber.startsWith(
|
|
656
|
+
return referenceNumber.startsWith('MUS');
|
|
539
657
|
}
|
|
540
658
|
|
|
541
659
|
export function isAirbnbBooking(referenceNumber) {
|
|
542
|
-
return referenceNumber.startsWith(
|
|
660
|
+
return referenceNumber.startsWith('Airbnb-');
|
|
543
661
|
}
|
|
544
662
|
|
|
545
663
|
export function isKKdayBooking(referenceNumber) {
|
|
546
|
-
return referenceNumber.startsWith(
|
|
664
|
+
return referenceNumber.startsWith('KKday-');
|
|
547
665
|
}
|
|
548
666
|
|
|
549
667
|
export function isTiqetsBooking(referenceNumber) {
|
|
550
|
-
return referenceNumber.startsWith(
|
|
668
|
+
return referenceNumber.startsWith('TIQ-');
|
|
551
669
|
}
|
|
552
670
|
|
|
553
671
|
export function isCivitatisBooking(referenceNumber) {
|
|
554
|
-
return referenceNumber.startsWith(
|
|
672
|
+
return referenceNumber.startsWith('CIV-');
|
|
555
673
|
}
|
|
556
674
|
|
|
557
675
|
export function isTSKBooking(referenceNumber) {
|
|
558
|
-
return referenceNumber.startsWith(
|
|
676
|
+
return referenceNumber.startsWith('TSK');
|
|
559
677
|
}
|
|
560
678
|
|
|
561
679
|
export function getBookingType(referenceNumber) {
|
|
562
680
|
if (!referenceNumber) {
|
|
563
|
-
return
|
|
681
|
+
return '';
|
|
564
682
|
}
|
|
565
683
|
if (isGYGBooking(referenceNumber)) {
|
|
566
|
-
return
|
|
684
|
+
return 'gyg';
|
|
567
685
|
} else if (isViatorBooking(referenceNumber)) {
|
|
568
|
-
return
|
|
686
|
+
return 'br';
|
|
569
687
|
} else if (isExpediaBooking(referenceNumber)) {
|
|
570
|
-
return
|
|
688
|
+
return 'exp';
|
|
571
689
|
} else if (isKlookBooking(referenceNumber)) {
|
|
572
|
-
return
|
|
690
|
+
return 'klk';
|
|
573
691
|
} else if (isMusementBooking(referenceNumber)) {
|
|
574
|
-
return
|
|
692
|
+
return 'mus';
|
|
575
693
|
} else if (isAirbnbBooking(referenceNumber)) {
|
|
576
|
-
return
|
|
694
|
+
return 'air';
|
|
577
695
|
} else if (isKKdayBooking(referenceNumber)) {
|
|
578
|
-
return
|
|
696
|
+
return 'kkday';
|
|
579
697
|
} else if (isTiqetsBooking(referenceNumber)) {
|
|
580
|
-
return
|
|
698
|
+
return 'tiq';
|
|
581
699
|
} else if (isTSKBooking(referenceNumber)) {
|
|
582
|
-
return
|
|
700
|
+
return 'tsk';
|
|
583
701
|
}
|
|
584
702
|
}
|
|
585
703
|
|
|
586
704
|
export function hasCustomPricing(pricing, bookingType) {
|
|
587
|
-
return pricing[bookingType] || bookingType ===
|
|
705
|
+
return pricing[bookingType] || bookingType === 'tsk';
|
|
588
706
|
}
|
|
589
707
|
|
|
590
708
|
export function truncate(str, num) {
|
|
@@ -592,7 +710,13 @@ export function truncate(str, num) {
|
|
|
592
710
|
}
|
|
593
711
|
|
|
594
712
|
export function isJSON(text) {
|
|
595
|
-
return /^[\],:{}\s]*$/.test(
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
713
|
+
return /^[\],:{}\s]*$/.test(
|
|
714
|
+
text
|
|
715
|
+
.replace(/\\["\\\/bfnrtu]/g, '@')
|
|
716
|
+
.replace(
|
|
717
|
+
/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,
|
|
718
|
+
']'
|
|
719
|
+
)
|
|
720
|
+
.replace(/(?:^|:|,)(?:\s*\[)+/g, '')
|
|
721
|
+
);
|
|
722
|
+
}
|