ti2-tourplan 1.0.40 → 1.0.42

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.
Files changed (2) hide show
  1. package/index.js +58 -54
  2. package/package.json +1 -1
package/index.js CHANGED
@@ -104,6 +104,11 @@ class Plugin {
104
104
  regExp: /.+/,
105
105
  },
106
106
  });
107
+ this.cacheSettings = {
108
+ bookingsProductSearch: {
109
+ skipTTL: true,
110
+ },
111
+ };
107
112
  this.callTourplan = async ({
108
113
  model,
109
114
  endpoint,
@@ -165,13 +170,14 @@ class Plugin {
165
170
  }
166
171
  const requestType = R.keys(model)[0];
167
172
  if (!replyObj) throw new Error(`${requestType} failed: ${errorStr || 'no reply object'}`);
168
- const error = replyObj.error || R.path(['Reply', 'ErrorReply', 'Error'], replyObj);
173
+ let error = replyObj.error || R.path(['Reply', 'ErrorReply', 'Error'], replyObj);
169
174
  if (error) {
170
- if (error.indexOf('2050 SCN Request denied for TEST connecting from') > -1
171
- && requestType === 'OptionInfoRequest'
172
- && endpoint.indexOf('actour') > -1
173
- ) {
174
- return 'useFixture';
175
+ if (error.includes('DateFrom in the past')) {
176
+ error = '1002 - Date is in the past';
177
+ } else if (error.includes('1052 SCN')) {
178
+ error = '1052 - OptionId not found(Check if it is Internet Enabled)';
179
+ } else if (error.includes('SCN Server overloaded')) {
180
+ error = "2051 - The Tourplan server is unavailable. Please wait a minute and try again. If you keep getting this error, please contact your team's Tourplan administrator or Tourplan support."
175
181
  }
176
182
  throw new Error(`${requestType} failed: ${error}`);
177
183
  }
@@ -437,57 +443,57 @@ class Plugin {
437
443
  xmlOptions: hostConnectXmlOptions,
438
444
  };
439
445
  // use cache if we are getting the full list
446
+ // for example: for searchInput (backend search), we shouldn't get the full list from
447
+ // tourplan each time user search
440
448
  const replyObj = optionId
441
449
  ? await this.callTourplan(payload)
442
450
  : await this.cache.getOrExec({
443
451
  fnParams: [model],
444
452
  fn: () => this.callTourplan(payload),
445
- ttl: 60 * 60 * 24, // 24 hours
453
+ ttl: 60 * 60 * 2, // 2 hours
446
454
  forceRefresh: Boolean(forceRefresh),
447
455
  });
448
- let products = [];
449
- if (replyObj === 'useFixture') {
450
- products = require('./__fixtures__/fullacoptionlist.json');
451
- } else {
452
- products = R.call(R.compose(
453
- R.map(optionsGroupedBySupplierId => {
454
- const OptGeneral = R.pathOr({}, [0, 'OptGeneral'], optionsGroupedBySupplierId);
455
- const supplierData = {
456
- supplierId: R.path(['SupplierId'], OptGeneral),
457
- supplierName: R.path(['SupplierName'], OptGeneral),
458
- supplierAddress: `${R.pathOr('', ['Address1'], OptGeneral)}, ${R.pathOr('', ['Address2'], OptGeneral)}, ${R.pathOr('', ['Address3'], OptGeneral)}, ${R.pathOr('', ['Address4'], OptGeneral)}, ${R.pathOr('', ['Address5'], OptGeneral)}`,
459
- serviceTypes: R.uniq(optionsGroupedBySupplierId.map(R.path(['OptGeneral', 'ButtonName']))),
460
- };
461
- return translateTPOption({
462
- supplierData,
463
- optionsGroupedBySupplierId,
464
- typeDefs: productTypeDefs,
465
- query: productQuery,
466
- });
467
- }),
468
- R.values,
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
- },
483
- root => {
484
- const options = R.pathOr([], ['OptionInfoReply', 'Option'], root);
485
- // due to the new parser, single option will be returned as an object
486
- // instead of an array
487
- if (Array.isArray(options)) return options;
488
- return [options];
489
- },
490
- ), replyObj);
456
+ const products = R.call(R.compose(
457
+ R.map(optionsGroupedBySupplierId => {
458
+ const OptGeneral = R.pathOr({}, [0, 'OptGeneral'], optionsGroupedBySupplierId);
459
+ const supplierData = {
460
+ supplierId: R.path(['SupplierId'], OptGeneral),
461
+ supplierName: R.path(['SupplierName'], OptGeneral),
462
+ supplierAddress: `${R.pathOr('', ['Address1'], OptGeneral)}, ${R.pathOr('', ['Address2'], OptGeneral)}, ${R.pathOr('', ['Address3'], OptGeneral)}, ${R.pathOr('', ['Address4'], OptGeneral)}, ${R.pathOr('', ['Address5'], OptGeneral)}`,
463
+ serviceTypes: R.uniq(optionsGroupedBySupplierId.map(R.path(['OptGeneral', 'ButtonName']))),
464
+ };
465
+ return translateTPOption({
466
+ supplierData,
467
+ optionsGroupedBySupplierId,
468
+ typeDefs: productTypeDefs,
469
+ query: productQuery,
470
+ });
471
+ }),
472
+ R.values,
473
+ R.groupBy(R.path(['OptGeneral', 'SupplierId'])),
474
+ root => {
475
+ if (!searchInput) return root;
476
+ const getFullSearchStr = o => {
477
+ const fullPptionName = `${R.path(['OptGeneral', 'Description'], o) || ''}-${R.path(['OptGeneral', 'Comment'], o) || ''}`;
478
+ return `${R.path(['OptGeneral', 'SupplierName'], o) || ''} ${fullPptionName} ${R.path(['Opt'], o)} ${R.path(['OptGeneral', 'SupplierId'], o) || ''}`;
479
+ };
480
+ const inputValueLower = searchInput.trim().toLowerCase();
481
+ const parts = inputValueLower.split(' ').filter(Boolean); // Filter out any empty strings just in case
482
+ return root.filter(option => {
483
+ const fullSearchStr = getFullSearchStr(option).toLowerCase();
484
+ return parts.every(part => fullSearchStr.includes(part));
485
+ });
486
+ },
487
+ root => {
488
+ const options = R.pathOr([], ['OptionInfoReply', 'Option'], root);
489
+ // due to the new parser, single option will be returned as an object
490
+ // instead of an array
491
+ if (Array.isArray(options)) return options;
492
+ return [options];
493
+ },
494
+ ), replyObj);
495
+ if (!(products && products.length)) {
496
+ throw new Error('No products found');
491
497
  }
492
498
  return {
493
499
  products,
@@ -675,8 +681,7 @@ class Plugin {
675
681
  ...(puInfo.time && puInfo.time.replace(/\D/g, '') ? {
676
682
  puTime: puInfo.time.replace(/\D/g, ''),
677
683
  } : {}),
678
- puRemark: this.escapeInvalidXmlChars(`${puInfo.time ? `Time: ${puInfo.time || 'NA'},` : ''}
679
- ${puInfo.location ? `Location: ${puInfo.location || 'NA'},` : ''}
684
+ puRemark: this.escapeInvalidXmlChars(`${puInfo.location ? `Location: ${puInfo.location || 'NA'},` : ''}
680
685
  ${puInfo.flightDetails ? `Flight: ${puInfo.flightDetails || 'NA'},` : ''}
681
686
  `),
682
687
  } : {}),
@@ -685,8 +690,7 @@ class Plugin {
685
690
  ...(doInfo.time && doInfo.time.replace(/\D/g, '') ? {
686
691
  doTime: doInfo.time.replace(/\D/g, ''),
687
692
  } : {}),
688
- doRemark: this.escapeInvalidXmlChars(`${doInfo.time ? `Time: ${doInfo.time || 'NA'},` : ''}
689
- ${doInfo.location ? `Location: ${doInfo.location || 'NA'},` : ''}
693
+ doRemark: this.escapeInvalidXmlChars(`${doInfo.location ? `Location: ${doInfo.location || 'NA'},` : ''}
690
694
  ${doInfo.flightDetails ? `Flight: ${doInfo.flightDetails || 'NA'},` : ''}
691
695
  `),
692
696
  } : {}),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ti2-tourplan",
3
- "version": "1.0.40",
3
+ "version": "1.0.42",
4
4
  "description": "Tourplan's TI2 Plugin",
5
5
  "main": "index.js",
6
6
  "scripts": {