ti2-tourplan 1.0.28 → 1.0.29
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 +114 -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: {
|
|
@@ -483,7 +502,6 @@ class Plugin {
|
|
|
483
502
|
paxConfigs: [{ roomType: 'DB', adults: 2 }, { roomType: 'TW', children: 2 }]
|
|
484
503
|
*/
|
|
485
504
|
paxConfigs,
|
|
486
|
-
// passengers,
|
|
487
505
|
/*
|
|
488
506
|
The number of second charge units required (second charge units are discussed
|
|
489
507
|
in the OptionInfo section). Should only be specified for options that have SCUs.
|
|
@@ -506,20 +524,46 @@ class Plugin {
|
|
|
506
524
|
RateId: 'Default',
|
|
507
525
|
SCUqty: chargeUnitQuanity || 1,
|
|
508
526
|
AgentRef: reference,
|
|
509
|
-
RoomConfigs: paxConfigs.map(
|
|
510
|
-
const RoomConfig = {
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
527
|
+
RoomConfigs: paxConfigs.map(({ roomType, passengers }) => {
|
|
528
|
+
const RoomConfig = passengers.reduce((acc, p) => {
|
|
529
|
+
if (p.passengerType === 'Adult') {
|
|
530
|
+
acc.Adults += 1;
|
|
531
|
+
}
|
|
532
|
+
if (p.passengerType === 'Child') {
|
|
533
|
+
acc.Children += 1;
|
|
534
|
+
}
|
|
535
|
+
if (p.passengerType === 'Infant') {
|
|
536
|
+
acc.Infants += 1;
|
|
537
|
+
}
|
|
538
|
+
return acc;
|
|
539
|
+
}, {
|
|
540
|
+
Adults: 0,
|
|
541
|
+
Children: 0,
|
|
542
|
+
Infants: 0,
|
|
543
|
+
});
|
|
515
544
|
const RoomType = ({
|
|
516
545
|
Single: 'SG',
|
|
517
546
|
Double: 'DB',
|
|
518
547
|
Twin: 'TW',
|
|
519
548
|
Triple: 'TR',
|
|
520
549
|
Quad: 'QU',
|
|
521
|
-
})[
|
|
550
|
+
})[roomType];
|
|
522
551
|
if (RoomType) RoomConfig.RoomType = RoomType;
|
|
552
|
+
if (passengers && passengers.length) {
|
|
553
|
+
RoomConfig.PaxList = passengers.map(p => ({
|
|
554
|
+
PaxDetails: {
|
|
555
|
+
Forename: p.firstName,
|
|
556
|
+
Surname: p.lastName,
|
|
557
|
+
PaxType: {
|
|
558
|
+
Adult: 'A',
|
|
559
|
+
Child: 'C',
|
|
560
|
+
Infant: 'I',
|
|
561
|
+
}[p.passengerType],
|
|
562
|
+
Age: p.age,
|
|
563
|
+
Title: p.salutation,
|
|
564
|
+
},
|
|
565
|
+
}));
|
|
566
|
+
}
|
|
523
567
|
return { RoomConfig };
|
|
524
568
|
}),
|
|
525
569
|
},
|
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
|
},
|