ti2-tourplan 1.0.35 → 1.0.37

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 CHANGED
@@ -229,6 +229,20 @@ 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, '&lt;')
242
+ .replace(/>/g, '&gt;')
243
+ .replace(/"/g, '&quot;')
244
+ .replace(/'/g, '&apos;')
245
+ }
232
246
  }
233
247
 
234
248
  async validateToken({
@@ -401,7 +415,7 @@ class Plugin {
401
415
  hostConnectAgentPassword,
402
416
  configuration,
403
417
  },
404
- payload: { optionId, forceRefresh },
418
+ payload: { optionId, forceRefresh, searchInput },
405
419
  }) {
406
420
  const model = {
407
421
  OptionInfoRequest: {
@@ -448,6 +462,19 @@ class Plugin {
448
462
  }),
449
463
  R.values,
450
464
  R.groupBy(R.path(['OptGeneral', 'SupplierId'])),
465
+ root => {
466
+ if (!searchInput) return root;
467
+ const getFullSearchStr = o => {
468
+ const fullPptionName = `${R.path(['OptGeneral', 'Description'], o) || ''}-${R.path(['OptGeneral', 'Comment'], o) || ''}`;
469
+ return `${R.path(['OptGeneral', 'SupplierName'], o) || ''} ${fullPptionName} ${R.path(['Opt'], o)} ${R.path(['OptGeneral', 'SupplierId'], o) || ''}`;
470
+ };
471
+ const inputValueLower = searchInput.trim().toLowerCase();
472
+ const parts = inputValueLower.split(' ').filter(Boolean); // Filter out any empty strings just in case
473
+ return root.filter(option => {
474
+ const fullSearchStr = getFullSearchStr(option).toLowerCase();
475
+ return parts.every(part => fullSearchStr.includes(part));
476
+ });
477
+ },
451
478
  root => {
452
479
  const options = R.pathOr([], ['OptionInfoReply', 'Option'], root);
453
480
  // due to the new parser, single option will be returned as an object
@@ -460,7 +487,7 @@ class Plugin {
460
487
  return {
461
488
  products,
462
489
  productFields: [],
463
- ...configuration,
490
+ ...(searchInput || optionId ? {} : configuration),
464
491
  };
465
492
  }
466
493
 
@@ -590,7 +617,10 @@ class Plugin {
590
617
  ...(quoteId ? {
591
618
  ExistingBookingInfo: { BookingId: quoteId },
592
619
  } : {
593
- NewBookingInfo: { Name: quoteName, QB: 'Q' },
620
+ NewBookingInfo: {
621
+ Name: this.escapeInvalidXmlChars(quoteName),
622
+ QB: 'Q',
623
+ },
594
624
  }),
595
625
  ...(rateId ? {
596
626
  RateId: rateId,
@@ -599,22 +629,22 @@ class Plugin {
599
629
  ...(puInfo.time && puInfo.time.replace(/\D/g, '') ? {
600
630
  puTime: puInfo.time.replace(/\D/g, ''),
601
631
  } : {}),
602
- puRemark: `Time: ${puInfo.time || 'NA'},
632
+ puRemark: this.escapeInvalidXmlChars(`Time: ${puInfo.time || 'NA'},
603
633
  Location: ${puInfo.location || 'NA'},
604
634
  Flight: ${puInfo.flightDetails || 'NA'},
605
- `,
635
+ `),
606
636
  } : {}),
607
637
  ...(doInfo ? {
608
638
  // only get numbers from doInfo.time
609
639
  ...(doInfo.time && doInfo.time.replace(/\D/g, '') ? {
610
640
  doTime: doInfo.time.replace(/\D/g, ''),
611
641
  } : {}),
612
- doRemark: `Time: ${doInfo.time || 'NA'},
642
+ doRemark: this.escapeInvalidXmlChars(`Time: ${doInfo.time || 'NA'},
613
643
  Location: ${doInfo.location || 'NA'},
614
644
  Flight: ${doInfo.flightDetails || 'NA'},
615
- `,
645
+ `),
616
646
  } : {}),
617
- Remarks: `${notes || ''} ${extraText ? `\nExtras: ${extraText}` : ''}`,
647
+ Remarks: this.escapeInvalidXmlChars(`${notes || ''} ${extraText ? `\nExtras: ${extraText}` : ''}`),
618
648
  Opt: optionId,
619
649
  DateFrom: startDate,
620
650
  RateId: 'Default',
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ti2-tourplan",
3
- "version": "1.0.35",
3
+ "version": "1.0.37",
4
4
  "description": "Tourplan's TI2 Plugin",
5
5
  "main": "index.js",
6
6
  "scripts": {
@@ -42,13 +42,14 @@ const translateTPOption = ({ optionsGroupedBySupplierId, supplierData }) => {
42
42
  serviceTypes: supplierData.serviceTypes,
43
43
  options: optionsGroupedBySupplierId.map(option => {
44
44
  const comment = R.path(['OptGeneral', 'Comment'], option);
45
+ const st = R.pathOr('', ['OptGeneral', 'ButtonName'], option);
45
46
  const keyData = {
46
47
  optionId: R.path(['Opt'], option),
47
48
  optionName: `${R.path(['OptGeneral', 'Description'], option)}${
48
49
  comment ? `-${comment}` : ''
49
50
  }`,
50
51
  // Guides, Accommodation, Transfers, Entrance Fees, Meals, Other
51
- serviceType: R.path(['OptGeneral', 'ButtonName'], option),
52
+ serviceType: typeof st === 'string' ? st : '',
52
53
  restrictions: {
53
54
  MPFCU: R.path(['OptGeneral', 'MPFCU'], option),
54
55
  roomTypeRequired: ['Y', 'P'].includes(R.path(['OptGeneral', 'SType'], option)),