ti2-tourplan 1.0.28 → 1.0.30
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 +139 -70
- package/package.json +1 -1
- package/resolvers/product.js +35 -4
package/index.js
CHANGED
|
@@ -364,7 +364,14 @@ class Plugin {
|
|
|
364
364
|
xmlOptions: hostConnectXmlOptions,
|
|
365
365
|
};
|
|
366
366
|
// use cache if we are getting the full list
|
|
367
|
-
const replyObj =
|
|
367
|
+
const replyObj = optionId
|
|
368
|
+
? await this.callTourplan(payload)
|
|
369
|
+
: await this.cache.getOrExec({
|
|
370
|
+
fnParams: [model],
|
|
371
|
+
fn: () => this.callTourplan(payload),
|
|
372
|
+
ttl: 60 * 60 * 24, // 24 hours
|
|
373
|
+
forceRefresh: Boolean(forceRefresh),
|
|
374
|
+
});
|
|
368
375
|
let products = [];
|
|
369
376
|
if (replyObj === 'useFixture') {
|
|
370
377
|
products = require('./__fixtures__/fullacoptionlist.json');
|
|
@@ -396,74 +403,86 @@ class Plugin {
|
|
|
396
403
|
},
|
|
397
404
|
), replyObj);
|
|
398
405
|
}
|
|
399
|
-
const productFields = [{
|
|
400
|
-
id: 'productId',
|
|
401
|
-
title: 'Supplier',
|
|
402
|
-
type: 'extended-option',
|
|
403
|
-
requiredForAvailability: true,
|
|
404
|
-
requiredForBooking: true,
|
|
405
|
-
// options: products.map(p => ({
|
|
406
|
-
// value: p.productId,
|
|
407
|
-
// label: p.productName,
|
|
408
|
-
// })),
|
|
409
|
-
}, {
|
|
410
|
-
id: 'optionId',
|
|
411
|
-
title: 'Service',
|
|
412
|
-
type: 'extended-option',
|
|
413
|
-
requiredForAvailability: true,
|
|
414
|
-
requiredForBooking: true,
|
|
415
|
-
filterableBy: 'productId',
|
|
416
|
-
// options: R.chain(p => p.options.map(o => ({
|
|
417
|
-
// label: o.optionName,
|
|
418
|
-
// value: o.optionId,
|
|
419
|
-
// productId: p.productId,
|
|
420
|
-
// productName: p.productName,
|
|
421
|
-
// })), products),
|
|
422
|
-
}, {
|
|
423
|
-
id: 'startDate',
|
|
424
|
-
title: 'Date',
|
|
425
|
-
type: 'date',
|
|
426
|
-
requiredForAvailability: true,
|
|
427
|
-
requiredForBooking: true,
|
|
428
|
-
}, {
|
|
429
|
-
id: 'paxConfigs',
|
|
430
|
-
title: 'Pax',
|
|
431
|
-
type: 'list_of_fields',
|
|
432
|
-
requiredForAvailability: true,
|
|
433
|
-
requiredForBooking: true,
|
|
434
|
-
fields: [{
|
|
435
|
-
id: 'adults',
|
|
436
|
-
title: 'Adults',
|
|
437
|
-
type: 'count',
|
|
438
|
-
}, {
|
|
439
|
-
id: 'children',
|
|
440
|
-
title: 'Children',
|
|
441
|
-
type: 'count',
|
|
442
|
-
}, {
|
|
443
|
-
id: 'infants',
|
|
444
|
-
title: 'Infants',
|
|
445
|
-
type: 'count',
|
|
446
|
-
}, {
|
|
447
|
-
id: 'roomType',
|
|
448
|
-
title: 'Room Type',
|
|
449
|
-
type: 'extended-option',
|
|
450
|
-
options: [{ value: 'SG', label: 'Single' }, { value: 'DB', label: 'Double' }, { value: 'TW', label: 'Twin' }, { value: 'QD', label: 'Quad' }],
|
|
451
|
-
}],
|
|
452
|
-
requiredForCalendar: true,
|
|
453
|
-
}, {
|
|
454
|
-
id: 'chargeUnitQuanity', // secondary charge unit (SCU) quantity
|
|
455
|
-
description: 'number of nights or days or hours depending on charge unit',
|
|
456
|
-
title: 'Nights/Days',
|
|
457
|
-
type: 'count',
|
|
458
|
-
}];
|
|
459
406
|
return {
|
|
460
407
|
products,
|
|
461
|
-
productFields,
|
|
408
|
+
productFields: [],
|
|
462
409
|
...configuration,
|
|
463
410
|
};
|
|
464
411
|
}
|
|
465
412
|
|
|
466
413
|
|
|
414
|
+
async searchAvailability({
|
|
415
|
+
axios,
|
|
416
|
+
token: {
|
|
417
|
+
hostConnectEndpoint,
|
|
418
|
+
hostConnectAgentID,
|
|
419
|
+
hostConnectAgentPassword,
|
|
420
|
+
},
|
|
421
|
+
payload: {
|
|
422
|
+
optionId,
|
|
423
|
+
startDate,
|
|
424
|
+
reference,
|
|
425
|
+
/*
|
|
426
|
+
paxConfigs: [{ roomType: 'DB', adults: 2 }, { roomType: 'TW', children: 2 }]
|
|
427
|
+
*/
|
|
428
|
+
paxConfigs,
|
|
429
|
+
// passengers,
|
|
430
|
+
/*
|
|
431
|
+
The number of second charge units required (second charge units are discussed
|
|
432
|
+
in the OptionInfo section). Should only be specified for options that have SCUs.
|
|
433
|
+
Defaults to 1.
|
|
434
|
+
*/
|
|
435
|
+
chargeUnitQuanity,
|
|
436
|
+
},
|
|
437
|
+
}) {
|
|
438
|
+
const model = {
|
|
439
|
+
OptionInfoRequest: {
|
|
440
|
+
Opt: optionId,
|
|
441
|
+
Info: 'A',
|
|
442
|
+
DateFrom: startDate,
|
|
443
|
+
DateTo: startDate,
|
|
444
|
+
RoomConfigs: paxConfigs.map(obj => {
|
|
445
|
+
const RoomConfig = {
|
|
446
|
+
Adults: obj.adults || 0,
|
|
447
|
+
Children: obj.children || 0,
|
|
448
|
+
Infants: obj.infants || 0,
|
|
449
|
+
};
|
|
450
|
+
const RoomType = ({
|
|
451
|
+
Single: 'SG',
|
|
452
|
+
Double: 'DB',
|
|
453
|
+
Twin: 'TW',
|
|
454
|
+
Triple: 'TR',
|
|
455
|
+
Quad: 'QU',
|
|
456
|
+
})[obj.roomType];
|
|
457
|
+
if (RoomType) RoomConfig.RoomType = RoomType;
|
|
458
|
+
return { RoomConfig };
|
|
459
|
+
}),
|
|
460
|
+
AgentID: hostConnectAgentID,
|
|
461
|
+
Password: hostConnectAgentPassword,
|
|
462
|
+
},
|
|
463
|
+
};
|
|
464
|
+
const replyObj = await this.callTourplan({
|
|
465
|
+
model,
|
|
466
|
+
endpoint: hostConnectEndpoint,
|
|
467
|
+
axios,
|
|
468
|
+
xmlOptions: hostConnectXmlOptions,
|
|
469
|
+
});
|
|
470
|
+
const optAvail = R.path(['OptionInfoReply', 'Option', 'OptAvail'], replyObj);
|
|
471
|
+
/*
|
|
472
|
+
FROM TP DOCS:
|
|
473
|
+
Each integer in the list gives the availability for one of the days in the range requested,
|
|
474
|
+
from the start date through to the end date. The integer values are to be interpreted as
|
|
475
|
+
follows:
|
|
476
|
+
Greater than 0 means that inventory is available, with the integer specifying the
|
|
477
|
+
number of units available. For options with a service type of Y , the inventory is in
|
|
478
|
+
units of rooms. For other service types, the inventory is in units of pax.
|
|
479
|
+
-1 Not available.
|
|
480
|
+
-2 Available on free sell.
|
|
481
|
+
-3 Available on request.
|
|
482
|
+
Note: A return value of 0 or something less than -3 is impossible.
|
|
483
|
+
*/
|
|
484
|
+
}
|
|
485
|
+
|
|
467
486
|
async searchQuote({
|
|
468
487
|
axios,
|
|
469
488
|
token: {
|
|
@@ -473,6 +492,7 @@ class Plugin {
|
|
|
473
492
|
},
|
|
474
493
|
payload: {
|
|
475
494
|
quoteName,
|
|
495
|
+
rateId,
|
|
476
496
|
quoteId,
|
|
477
497
|
// existingQuoteId,
|
|
478
498
|
// existingLineId,
|
|
@@ -483,13 +503,15 @@ class Plugin {
|
|
|
483
503
|
paxConfigs: [{ roomType: 'DB', adults: 2 }, { roomType: 'TW', children: 2 }]
|
|
484
504
|
*/
|
|
485
505
|
paxConfigs,
|
|
486
|
-
// passengers,
|
|
487
506
|
/*
|
|
488
507
|
The number of second charge units required (second charge units are discussed
|
|
489
508
|
in the OptionInfo section). Should only be specified for options that have SCUs.
|
|
490
509
|
Defaults to 1.
|
|
491
510
|
*/
|
|
492
511
|
chargeUnitQuanity,
|
|
512
|
+
extras,
|
|
513
|
+
puInfo,
|
|
514
|
+
doInfo,
|
|
493
515
|
},
|
|
494
516
|
}) {
|
|
495
517
|
const model = {
|
|
@@ -501,25 +523,72 @@ class Plugin {
|
|
|
501
523
|
} : {
|
|
502
524
|
NewBookingInfo: { Name: quoteName, QB: 'Q' },
|
|
503
525
|
}),
|
|
526
|
+
...(rateId ? {
|
|
527
|
+
RateId: rateId,
|
|
528
|
+
} : {}),
|
|
529
|
+
...(puInfo ? {
|
|
530
|
+
puTime: puInfo.time,
|
|
531
|
+
puRemark: `Time: ${puInfo.time || 'NA'},
|
|
532
|
+
Location: ${puInfo.location || 'NA'},
|
|
533
|
+
Flight: ${puInfo.flightDetails || 'NA'},
|
|
534
|
+
`,
|
|
535
|
+
} : {}),
|
|
536
|
+
...(doInfo ? {
|
|
537
|
+
doTime: doInfo.time,
|
|
538
|
+
doRemark: `Time: ${doInfo.time || 'NA'},
|
|
539
|
+
Location: ${doInfo.location || 'NA'},
|
|
540
|
+
Flight: ${doInfo.flightDetails || 'NA'},
|
|
541
|
+
`,
|
|
542
|
+
} : {}),
|
|
543
|
+
...(extras && extras.length ? {
|
|
544
|
+
Remarks: extras.map((e, i) => `Extra ${i + 1}: ${e.name} x ${e.quantity}`).join(`\n`),
|
|
545
|
+
} : {}),
|
|
504
546
|
Opt: optionId,
|
|
505
547
|
DateFrom: startDate,
|
|
506
548
|
RateId: 'Default',
|
|
507
549
|
SCUqty: chargeUnitQuanity || 1,
|
|
508
550
|
AgentRef: reference,
|
|
509
|
-
RoomConfigs: paxConfigs.map(
|
|
510
|
-
const RoomConfig = {
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
551
|
+
RoomConfigs: paxConfigs.map(({ roomType, passengers }) => {
|
|
552
|
+
const RoomConfig = passengers.reduce((acc, p) => {
|
|
553
|
+
if (p.passengerType === 'Adult') {
|
|
554
|
+
acc.Adults += 1;
|
|
555
|
+
}
|
|
556
|
+
if (p.passengerType === 'Child') {
|
|
557
|
+
acc.Children += 1;
|
|
558
|
+
}
|
|
559
|
+
if (p.passengerType === 'Infant') {
|
|
560
|
+
acc.Infants += 1;
|
|
561
|
+
}
|
|
562
|
+
return acc;
|
|
563
|
+
}, {
|
|
564
|
+
Adults: 0,
|
|
565
|
+
Children: 0,
|
|
566
|
+
Infants: 0,
|
|
567
|
+
});
|
|
515
568
|
const RoomType = ({
|
|
516
569
|
Single: 'SG',
|
|
517
570
|
Double: 'DB',
|
|
518
571
|
Twin: 'TW',
|
|
519
572
|
Triple: 'TR',
|
|
520
573
|
Quad: 'QU',
|
|
521
|
-
})[
|
|
574
|
+
})[roomType];
|
|
522
575
|
if (RoomType) RoomConfig.RoomType = RoomType;
|
|
576
|
+
if (passengers && passengers.length) {
|
|
577
|
+
RoomConfig.PaxList = passengers.map(p => ({
|
|
578
|
+
PaxDetails: {
|
|
579
|
+
Forename: p.firstName,
|
|
580
|
+
Surname: p.lastName,
|
|
581
|
+
PaxType: {
|
|
582
|
+
Adult: 'A',
|
|
583
|
+
Child: 'C',
|
|
584
|
+
Infant: 'I',
|
|
585
|
+
}[p.passengerType],
|
|
586
|
+
Age: p.age,
|
|
587
|
+
DateOfBirth: p.dob,
|
|
588
|
+
Title: p.salutation,
|
|
589
|
+
},
|
|
590
|
+
}));
|
|
591
|
+
}
|
|
523
592
|
return { RoomConfig };
|
|
524
593
|
}),
|
|
525
594
|
},
|
package/package.json
CHANGED
package/resolvers/product.js
CHANGED
|
@@ -49,6 +49,38 @@ const translateTPOption = ({ optionsGroupedBySupplierId, supplierData }) => {
|
|
|
49
49
|
}`,
|
|
50
50
|
// Guides, Accommodation, Transfers, Entrance Fees, Meals, Other
|
|
51
51
|
serviceType: R.path(['OptGeneral', 'ButtonName'], option),
|
|
52
|
+
restrictions: {
|
|
53
|
+
MPFCU: R.path(['OptGeneral', 'MPFCU'], option),
|
|
54
|
+
roomTypeRequired: ['Y', 'P'].includes(R.path(['OptGeneral', 'SType'], option)),
|
|
55
|
+
Adult: {
|
|
56
|
+
allowed: R.path(['OptGeneral', 'AdultsAllowed'], option) === 'Y',
|
|
57
|
+
minAge: R.path(['OptGeneral', 'Adult_From'], option),
|
|
58
|
+
maxAge: R.path(['OptGeneral', 'Adult_To'], option),
|
|
59
|
+
},
|
|
60
|
+
Child: {
|
|
61
|
+
allowed: R.path(['OptGeneral', 'ChildrenAllowed'], option) === 'Y',
|
|
62
|
+
minAge: R.path(['OptGeneral', 'Child_From'], option),
|
|
63
|
+
maxAge: R.path(['OptGeneral', 'Child_To'], option),
|
|
64
|
+
},
|
|
65
|
+
Infant: {
|
|
66
|
+
allowed: R.path(['OptGeneral', 'InfantsAllowed'], option) === 'Y',
|
|
67
|
+
minAge: R.path(['OptGeneral', 'Infant_From'], option),
|
|
68
|
+
maxAge: R.path(['OptGeneral', 'Infant_To'], option),
|
|
69
|
+
},
|
|
70
|
+
...['Single', 'Twin', 'Double', 'Quad'].reduce((acc, roomType) => {
|
|
71
|
+
const unitAvail = R.path(['OptGeneral', `${roomType}_Avail`], option);
|
|
72
|
+
const unitMax = R.path(['OptGeneral', `${roomType}_Max`], option);
|
|
73
|
+
const unitAdMax = R.path(['OptGeneral', `${roomType}_Ad_Max`], option);
|
|
74
|
+
return {
|
|
75
|
+
...acc,
|
|
76
|
+
[roomType]: {
|
|
77
|
+
allowed: unitAvail === 'Y',
|
|
78
|
+
maxPax: unitMax,
|
|
79
|
+
maxAdults: unitAdMax,
|
|
80
|
+
},
|
|
81
|
+
};
|
|
82
|
+
}, {}),
|
|
83
|
+
},
|
|
52
84
|
};
|
|
53
85
|
/*
|
|
54
86
|
SType: One character that specifies the service type of the
|
|
@@ -68,7 +100,6 @@ const translateTPOption = ({ optionsGroupedBySupplierId, supplierData }) => {
|
|
|
68
100
|
unitName: 'Adults',
|
|
69
101
|
pricing: [],
|
|
70
102
|
restrictions: {
|
|
71
|
-
paxCount: R.path(['OptGeneral', 'MPFCU'], option),
|
|
72
103
|
minAge: R.path(['OptGeneral', 'Adult_From'], option),
|
|
73
104
|
maxAge: R.path(['OptGeneral', 'Adult_To'], option),
|
|
74
105
|
},
|
|
@@ -90,14 +121,14 @@ const translateTPOption = ({ optionsGroupedBySupplierId, supplierData }) => {
|
|
|
90
121
|
},
|
|
91
122
|
} : null].filter(Boolean);
|
|
92
123
|
}
|
|
93
|
-
if (R.path(['OptGeneral', 'SType'], option) === 'Y') {
|
|
94
|
-
return [
|
|
95
|
-
.filter(([_, unitName]) => R.path(['OptGeneral', `${unitName}_Avail`], option) === 'Y')
|
|
124
|
+
if (R.path(['OptGeneral', 'SType'], option) === 'Y' || R.path(['OptGeneral', 'SType'], option) === 'P') {
|
|
125
|
+
return ['Single', 'Twin', 'Double', 'Quad']
|
|
96
126
|
.map(([unitId, unitName]) => ({
|
|
97
127
|
unitId,
|
|
98
128
|
unitName,
|
|
99
129
|
pricing: [],
|
|
100
130
|
restrictions: {
|
|
131
|
+
allowed: R.path(['OptGeneral', `${unitName}_Avail`], option) === 'Y',
|
|
101
132
|
paxCount: R.path(['OptGeneral', `${unitName}_Max`], option)
|
|
102
133
|
|| R.path(['OptGeneral', `${unitName}_Ad_Max`], option),
|
|
103
134
|
},
|