ti2-tourplan 1.0.36 → 1.0.38
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/index.js +129 -53
- package/package.json +1 -1
package/index.js
CHANGED
|
@@ -201,7 +201,7 @@ class Plugin {
|
|
|
201
201
|
Double: 'DB',
|
|
202
202
|
Twin: 'TW',
|
|
203
203
|
Triple: 'TR',
|
|
204
|
-
Quad: '
|
|
204
|
+
Quad: 'QD',
|
|
205
205
|
})[roomType];
|
|
206
206
|
if (RoomType) RoomConfig.RoomType = RoomType;
|
|
207
207
|
if (passengers && passengers.length && !noPaxList) {
|
|
@@ -229,6 +229,25 @@ class Plugin {
|
|
|
229
229
|
}
|
|
230
230
|
return { RoomConfig };
|
|
231
231
|
});
|
|
232
|
+
this.escapeInvalidXmlChars = str => {
|
|
233
|
+
if (!str) return '';
|
|
234
|
+
return str.replace(/[^\x00-\x7F]+/g, '')
|
|
235
|
+
.replace(/’/g, "'")
|
|
236
|
+
.replace(/‘/g, "'")
|
|
237
|
+
.replace(/“/g, '"')
|
|
238
|
+
.replace(/”/g, '"')
|
|
239
|
+
.replace(/–/g, '-')
|
|
240
|
+
.replace(/&/g, '&')
|
|
241
|
+
.replace(/</g, '<')
|
|
242
|
+
.replace(/>/g, '>')
|
|
243
|
+
.replace(/"/g, '"')
|
|
244
|
+
.replace(/'/g, ''')
|
|
245
|
+
};
|
|
246
|
+
|
|
247
|
+
// this.errorPathsAxiosErrors = () => ([ // axios triggered errors
|
|
248
|
+
// ['response', 'data', 'error'],
|
|
249
|
+
// ]);
|
|
250
|
+
// this.errorPathsAxiosAny = () => ([]); // 200's that should be errors
|
|
232
251
|
}
|
|
233
252
|
|
|
234
253
|
async validateToken({
|
|
@@ -401,7 +420,7 @@ class Plugin {
|
|
|
401
420
|
hostConnectAgentPassword,
|
|
402
421
|
configuration,
|
|
403
422
|
},
|
|
404
|
-
payload: { optionId, forceRefresh },
|
|
423
|
+
payload: { optionId, forceRefresh, searchInput },
|
|
405
424
|
}) {
|
|
406
425
|
const model = {
|
|
407
426
|
OptionInfoRequest: {
|
|
@@ -448,6 +467,19 @@ class Plugin {
|
|
|
448
467
|
}),
|
|
449
468
|
R.values,
|
|
450
469
|
R.groupBy(R.path(['OptGeneral', 'SupplierId'])),
|
|
470
|
+
root => {
|
|
471
|
+
if (!searchInput) return root;
|
|
472
|
+
const getFullSearchStr = o => {
|
|
473
|
+
const fullPptionName = `${R.path(['OptGeneral', 'Description'], o) || ''}-${R.path(['OptGeneral', 'Comment'], o) || ''}`;
|
|
474
|
+
return `${R.path(['OptGeneral', 'SupplierName'], o) || ''} ${fullPptionName} ${R.path(['Opt'], o)} ${R.path(['OptGeneral', 'SupplierId'], o) || ''}`;
|
|
475
|
+
};
|
|
476
|
+
const inputValueLower = searchInput.trim().toLowerCase();
|
|
477
|
+
const parts = inputValueLower.split(' ').filter(Boolean); // Filter out any empty strings just in case
|
|
478
|
+
return root.filter(option => {
|
|
479
|
+
const fullSearchStr = getFullSearchStr(option).toLowerCase();
|
|
480
|
+
return parts.every(part => fullSearchStr.includes(part));
|
|
481
|
+
});
|
|
482
|
+
},
|
|
451
483
|
root => {
|
|
452
484
|
const options = R.pathOr([], ['OptionInfoReply', 'Option'], root);
|
|
453
485
|
// due to the new parser, single option will be returned as an object
|
|
@@ -460,7 +492,7 @@ class Plugin {
|
|
|
460
492
|
return {
|
|
461
493
|
products,
|
|
462
494
|
productFields: [],
|
|
463
|
-
...configuration,
|
|
495
|
+
...(searchInput || optionId ? {} : configuration),
|
|
464
496
|
};
|
|
465
497
|
}
|
|
466
498
|
|
|
@@ -491,7 +523,7 @@ class Plugin {
|
|
|
491
523
|
const model = {
|
|
492
524
|
OptionInfoRequest: {
|
|
493
525
|
Opt: optionId,
|
|
494
|
-
Info: '
|
|
526
|
+
Info: 'S',
|
|
495
527
|
DateFrom: startDate,
|
|
496
528
|
DateTo: startDate,
|
|
497
529
|
RoomConfigs: this.getPaxConfigs(paxConfigs, true),
|
|
@@ -505,47 +537,84 @@ class Plugin {
|
|
|
505
537
|
axios,
|
|
506
538
|
xmlOptions: hostConnectXmlOptions,
|
|
507
539
|
});
|
|
508
|
-
const optAvail = R.path(['OptionInfoReply', 'Option', 'OptAvail'], replyObj);
|
|
509
540
|
/*
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
541
|
+
If not rates, optionInfoReply is null, meaning it's not bookable
|
|
542
|
+
otherwise, example data:
|
|
543
|
+
{
|
|
544
|
+
optionInfoReply: {
|
|
545
|
+
Option: {
|
|
546
|
+
Opt: 'LHRTRDAVIDSHABTVC',
|
|
547
|
+
OptStayResults: {
|
|
548
|
+
AgentPrice: '51175',
|
|
549
|
+
Availability: 'RQ',
|
|
550
|
+
CancelHours: '96',
|
|
551
|
+
CommissionPercent: '0.00',
|
|
552
|
+
Currency: 'GBP',
|
|
553
|
+
PeriodValueAdds: {
|
|
554
|
+
PeriodValueAdd: {
|
|
555
|
+
DateFrom: '2024-08-10',
|
|
556
|
+
DateTo: '2024-08-10',
|
|
557
|
+
RateName: 'Std-Mon Sun',
|
|
558
|
+
RateText: 'Std'
|
|
559
|
+
}
|
|
560
|
+
},
|
|
561
|
+
RateId: 'Default',
|
|
562
|
+
RateName: 'Std-Mon Sun',
|
|
563
|
+
RateText: 'Std',
|
|
564
|
+
SaleFrom: '2023-12-20',
|
|
565
|
+
TotalPrice: '51175'
|
|
566
|
+
},
|
|
567
|
+
OptionNumber: '70461'
|
|
568
|
+
}
|
|
569
|
+
}
|
|
570
|
+
}
|
|
521
571
|
*/
|
|
522
|
-
|
|
523
|
-
return {
|
|
524
|
-
available: false,
|
|
525
|
-
};
|
|
526
|
-
}
|
|
527
|
-
if (optAvail === -2) {
|
|
528
|
-
return {
|
|
529
|
-
available: true,
|
|
530
|
-
type: 'free sell',
|
|
531
|
-
};
|
|
532
|
-
}
|
|
533
|
-
if (optAvail === -3) {
|
|
534
|
-
return {
|
|
535
|
-
available: true,
|
|
536
|
-
type: 'on request',
|
|
537
|
-
};
|
|
538
|
-
}
|
|
539
|
-
if (optAvail > 0) {
|
|
540
|
-
return {
|
|
541
|
-
available: true,
|
|
542
|
-
type: 'inventory',
|
|
543
|
-
quantity: optAvail,
|
|
544
|
-
};
|
|
545
|
-
}
|
|
572
|
+
const optionInfoReply = R.path(['OptionInfoReply'], replyObj);
|
|
546
573
|
return {
|
|
547
|
-
|
|
574
|
+
bookable: Boolean(optionInfoReply),
|
|
548
575
|
};
|
|
576
|
+
// THE BELOW CODE is for A check, might still need it on user's future request
|
|
577
|
+
// const optAvail = parseInt(R.pathOr('-4', ['OptionInfoReply', 'Option', 'OptAvail'], replyObj), 10);
|
|
578
|
+
// /*
|
|
579
|
+
// FROM TP DOCS:
|
|
580
|
+
// Each integer in the list gives the availability for one of the days in the range requested,
|
|
581
|
+
// from the start date through to the end date. The integer values are to be interpreted as
|
|
582
|
+
// follows:
|
|
583
|
+
// Greater than 0 means that inventory is available, with the integer specifying the
|
|
584
|
+
// number of units available. For options with a service type of Y , the inventory is in
|
|
585
|
+
// units of rooms. For other service types, the inventory is in units of pax.
|
|
586
|
+
// -1 Not available.
|
|
587
|
+
// -2 Available on free sell.
|
|
588
|
+
// -3 Available on request.
|
|
589
|
+
// Note: A return value of 0 or something less than -3 is impossible.
|
|
590
|
+
// */
|
|
591
|
+
// if (optAvail === -1) {
|
|
592
|
+
// return {
|
|
593
|
+
// available: false,
|
|
594
|
+
// };
|
|
595
|
+
// }
|
|
596
|
+
// if (optAvail === -2) {
|
|
597
|
+
// return {
|
|
598
|
+
// available: true,
|
|
599
|
+
// type: 'free sell',
|
|
600
|
+
// };
|
|
601
|
+
// }
|
|
602
|
+
// if (optAvail === -3) {
|
|
603
|
+
// return {
|
|
604
|
+
// available: true,
|
|
605
|
+
// type: 'on request',
|
|
606
|
+
// };
|
|
607
|
+
// }
|
|
608
|
+
// if (optAvail > 0) {
|
|
609
|
+
// return {
|
|
610
|
+
// available: true,
|
|
611
|
+
// type: 'inventory',
|
|
612
|
+
// quantity: optAvail,
|
|
613
|
+
// };
|
|
614
|
+
// }
|
|
615
|
+
// return {
|
|
616
|
+
// available: false,
|
|
617
|
+
// };
|
|
549
618
|
}
|
|
550
619
|
|
|
551
620
|
async searchQuote({
|
|
@@ -590,31 +659,34 @@ class Plugin {
|
|
|
590
659
|
...(quoteId ? {
|
|
591
660
|
ExistingBookingInfo: { BookingId: quoteId },
|
|
592
661
|
} : {
|
|
593
|
-
NewBookingInfo: {
|
|
662
|
+
NewBookingInfo: {
|
|
663
|
+
Name: this.escapeInvalidXmlChars(quoteName),
|
|
664
|
+
QB: 'Q',
|
|
665
|
+
},
|
|
594
666
|
}),
|
|
595
667
|
...(rateId ? {
|
|
596
668
|
RateId: rateId,
|
|
597
669
|
} : {}),
|
|
598
|
-
...(puInfo ? {
|
|
670
|
+
...(puInfo && (puInfo.time || puInfo.location || puInfo.flightDetails) ? {
|
|
599
671
|
...(puInfo.time && puInfo.time.replace(/\D/g, '') ? {
|
|
600
672
|
puTime: puInfo.time.replace(/\D/g, ''),
|
|
601
673
|
} : {}),
|
|
602
|
-
puRemark: `Time: ${puInfo.time || 'NA'}
|
|
603
|
-
Location: ${puInfo.location || 'NA'}
|
|
604
|
-
Flight: ${puInfo.flightDetails || 'NA'}
|
|
605
|
-
|
|
674
|
+
puRemark: this.escapeInvalidXmlChars(`${puInfo.time ? `Time: ${puInfo.time || 'NA'},` : ''}
|
|
675
|
+
${puInfo.location ? `Location: ${puInfo.location || 'NA'},` : ''}
|
|
676
|
+
${puInfo.flightDetails ? `Flight: ${puInfo.flightDetails || 'NA'},` : ''}
|
|
677
|
+
`),
|
|
606
678
|
} : {}),
|
|
607
|
-
...(doInfo ? {
|
|
679
|
+
...(doInfo && (doInfo.time || doInfo.location || doInfo.flightDetails) ? {
|
|
608
680
|
// only get numbers from doInfo.time
|
|
609
681
|
...(doInfo.time && doInfo.time.replace(/\D/g, '') ? {
|
|
610
682
|
doTime: doInfo.time.replace(/\D/g, ''),
|
|
611
683
|
} : {}),
|
|
612
|
-
doRemark: `Time: ${doInfo.time || 'NA'}
|
|
613
|
-
Location: ${doInfo.location || 'NA'}
|
|
614
|
-
Flight: ${doInfo.flightDetails || 'NA'}
|
|
615
|
-
|
|
684
|
+
doRemark: this.escapeInvalidXmlChars(`${doInfo.time ? `Time: ${doInfo.time || 'NA'},` : ''}
|
|
685
|
+
${doInfo.location ? `Location: ${doInfo.location || 'NA'},` : ''}
|
|
686
|
+
${doInfo.flightDetails ? `Flight: ${doInfo.flightDetails || 'NA'},` : ''}
|
|
687
|
+
`),
|
|
616
688
|
} : {}),
|
|
617
|
-
Remarks: `${notes || ''} ${extraText ? `\nExtras: ${extraText}` : ''}
|
|
689
|
+
Remarks: this.escapeInvalidXmlChars(`${notes || ''} ${extraText ? `\nExtras: ${extraText}` : ''}`).slice(0, 240),
|
|
618
690
|
Opt: optionId,
|
|
619
691
|
DateFrom: startDate,
|
|
620
692
|
RateId: 'Default',
|
|
@@ -692,6 +764,10 @@ class Plugin {
|
|
|
692
764
|
try {
|
|
693
765
|
reply = await this.callTourplan(getPayload('ListBookingsRequest', { [key]: bookingId }));
|
|
694
766
|
} catch (err) {
|
|
767
|
+
if (err.includes && err.includes('Request failed with status code')) {
|
|
768
|
+
throw Error(err);
|
|
769
|
+
}
|
|
770
|
+
// if it's not server error, we just considered as no booking is found
|
|
695
771
|
console.log('error in searchBooking', err);
|
|
696
772
|
reply = { ListBookingsReply: { BookingHeaders: { BookingHeader: [] } } };
|
|
697
773
|
}
|