ti2-tourplan 1.0.59 → 1.0.61
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/__fixtures__/1f31a4c2a86da422468b2d63e91aee5af5f474a4.txt +1 -0
- package/__fixtures__/2dddcacad6843b2e1925595ba5a83729f73d9255.txt +1 -0
- package/__fixtures__/53bbb66ab400767d8acbf07cbbf0a209425dbe5a.txt +1 -0
- package/__fixtures__/5dc8cf72c01e5936707bca9dc93886b052876710.txt +1 -0
- package/__fixtures__/7ff49d0caa3c1349cf6d55d3b7497179bbf5472d.txt +54 -0
- package/__snapshots__/index.test.js.snap +10 -79
- package/index.js +81 -210
- package/index.test.js +24 -7
- package/package.json +1 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<?xml version="1.0" encoding="utf-8"?><!DOCTYPE Reply SYSTEM "hostConnect_5_05_000.dtd"><Reply><OptionInfoReply><Option><Opt>AKLACAKLSOFDYNAMC</Opt><OptionNumber>46052</OptionNumber><OptAvail>3</OptAvail></Option></OptionInfoReply></Reply>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<?xml version="1.0" encoding="utf-8"?><!DOCTYPE Reply SYSTEM "hostConnect_5_05_000.dtd"><Reply><OptionInfoReply /></Reply>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<?xml version="1.0" encoding="utf-8"?><!DOCTYPE Reply SYSTEM "hostConnect_5_05_000.dtd"><Reply><OptionInfoReply><Option><Opt>LONTRDAVIDSHDWBVC</Opt><OptionNumber>46051</OptionNumber><OptAvail>-1</OptAvail></Option></OptionInfoReply></Reply>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<?xml version="1.0" encoding="utf-8"?><!DOCTYPE Reply SYSTEM "hostConnect_5_05_000.dtd"><Reply><OptionInfoReply><Option><Opt>FWMACINVCASFBSB</Opt><OptionNumber>4138</OptionNumber><OptAvail>-3 </OptAvail></Option></OptionInfoReply></Reply>
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
|
2
|
+
<!DOCTYPE Reply SYSTEM "http://localhost:8080/iCom/hostConnect_4_06_009.dtd">
|
|
3
|
+
<Reply>
|
|
4
|
+
<AgentInfoReply>
|
|
5
|
+
<Currency>GBP</Currency>
|
|
6
|
+
<Email></Email>
|
|
7
|
+
<Name>Audley Travel</Name>
|
|
8
|
+
<PriceCodes>2AU2152GS2CO</PriceCodes>
|
|
9
|
+
<IsSubLogin>N</IsSubLogin>
|
|
10
|
+
<HasBookingRights>N</HasBookingRights>
|
|
11
|
+
<AgentCurrencies>
|
|
12
|
+
<AgentCurrencyInfo>
|
|
13
|
+
<Currency>EUR</Currency>
|
|
14
|
+
<CreditLimit>0</CreditLimit>
|
|
15
|
+
</AgentCurrencyInfo>
|
|
16
|
+
<AgentCurrencyInfo>
|
|
17
|
+
<Currency>GBP</Currency>
|
|
18
|
+
<CreditLimit>0</CreditLimit>
|
|
19
|
+
</AgentCurrencyInfo>
|
|
20
|
+
<AgentCurrencyInfo>
|
|
21
|
+
<Currency>USD</Currency>
|
|
22
|
+
<CreditLimit>0</CreditLimit>
|
|
23
|
+
</AgentCurrencyInfo>
|
|
24
|
+
</AgentCurrencies>
|
|
25
|
+
<Balances>
|
|
26
|
+
<Balance>
|
|
27
|
+
<Currency>GBP</Currency>
|
|
28
|
+
<CurrentBalance>449392</CurrentBalance>
|
|
29
|
+
<Overdue1>0</Overdue1>
|
|
30
|
+
<Overdue2>0</Overdue2>
|
|
31
|
+
<Overdue3>0</Overdue3>
|
|
32
|
+
<Overdue4>14557</Overdue4>
|
|
33
|
+
<FutureEntered>169171190</FutureEntered>
|
|
34
|
+
<Future1>0</Future1>
|
|
35
|
+
<Future2>0</Future2>
|
|
36
|
+
<Future3>0</Future3>
|
|
37
|
+
<Future4>0</Future4>
|
|
38
|
+
</Balance>
|
|
39
|
+
<Balance>
|
|
40
|
+
<Currency>BC</Currency>
|
|
41
|
+
<CurrentBalance>0</CurrentBalance>
|
|
42
|
+
<Overdue1>0</Overdue1>
|
|
43
|
+
<Overdue2>0</Overdue2>
|
|
44
|
+
<Overdue3>0</Overdue3>
|
|
45
|
+
<Overdue4>0</Overdue4>
|
|
46
|
+
<FutureEntered>0</FutureEntered>
|
|
47
|
+
<Future1>0</Future1>
|
|
48
|
+
<Future2>0</Future2>
|
|
49
|
+
<Future3>0</Future3>
|
|
50
|
+
<Future4>0</Future4>
|
|
51
|
+
</Balance>
|
|
52
|
+
</Balances>
|
|
53
|
+
</AgentInfoReply>
|
|
54
|
+
</Reply>
|
|
@@ -3240,7 +3240,15 @@ Object {
|
|
|
3240
3240
|
}
|
|
3241
3241
|
`;
|
|
3242
3242
|
|
|
3243
|
-
exports[`search tests searchAvailabilityForItinerary - bookable 1`] = `
|
|
3243
|
+
exports[`search tests searchAvailabilityForItinerary - bookable - on request 1`] = `
|
|
3244
|
+
Object {
|
|
3245
|
+
"bookable": true,
|
|
3246
|
+
"rates": Array [],
|
|
3247
|
+
"type": "on request",
|
|
3248
|
+
}
|
|
3249
|
+
`;
|
|
3250
|
+
|
|
3251
|
+
exports[`search tests searchAvailabilityForItinerary - bookable - static with inventory 1`] = `
|
|
3244
3252
|
Object {
|
|
3245
3253
|
"bookable": true,
|
|
3246
3254
|
"rates": Array [
|
|
@@ -3289,6 +3297,7 @@ Object {
|
|
|
3289
3297
|
"rateId": "$NZD48493f27a57b8c65,4,DOUB,C5 B1INF SKB DOUB BRKF",
|
|
3290
3298
|
},
|
|
3291
3299
|
],
|
|
3300
|
+
"type": "inventory",
|
|
3292
3301
|
}
|
|
3293
3302
|
`;
|
|
3294
3303
|
|
|
@@ -3296,84 +3305,6 @@ exports[`search tests searchItineraries 1`] = `
|
|
|
3296
3305
|
Object {
|
|
3297
3306
|
"bookings": Array [
|
|
3298
3307
|
Object {
|
|
3299
|
-
"AccountingDetails": Object {
|
|
3300
|
-
"AmountDue": 0,
|
|
3301
|
-
"CreditsTotal": 0,
|
|
3302
|
-
"FutureBilling": 187795,
|
|
3303
|
-
"InvoicedTotal": 0,
|
|
3304
|
-
"ReceivedTotal": 0,
|
|
3305
|
-
},
|
|
3306
|
-
"AgentRef": "2356674/1",
|
|
3307
|
-
"BookingId": 316559,
|
|
3308
|
-
"BookingStatus": "Quotation",
|
|
3309
|
-
"BookingType": "F",
|
|
3310
|
-
"BookingUpdateCount": 2,
|
|
3311
|
-
"CanAddServices": "Y",
|
|
3312
|
-
"CanCancel": "Y",
|
|
3313
|
-
"Consult": "",
|
|
3314
|
-
"Currency": "GBP",
|
|
3315
|
-
"Dialogue": "",
|
|
3316
|
-
"Email": "",
|
|
3317
|
-
"EnteredDate": "2024-09-12",
|
|
3318
|
-
"IsInternetBooking": "Y",
|
|
3319
|
-
"Name": "2356674/1 Sean Conta",
|
|
3320
|
-
"QB": "Q",
|
|
3321
|
-
"ReadOnly": "N",
|
|
3322
|
-
"Ref": "ALFI393706",
|
|
3323
|
-
"Remarks": "",
|
|
3324
|
-
"Services": Array [
|
|
3325
|
-
Object {
|
|
3326
|
-
"CanAccept": "N",
|
|
3327
|
-
"CanUpdate": "N",
|
|
3328
|
-
"CancelDeleteStatus": "D",
|
|
3329
|
-
"Comment": "Deluxe King Room",
|
|
3330
|
-
"CostedInBooking": "Y",
|
|
3331
|
-
"Date": "2025-08-13",
|
|
3332
|
-
"Description": "Bed and Full Buffet Breakfast",
|
|
3333
|
-
"LinePrice": 187795,
|
|
3334
|
-
"LocationCode": "LON",
|
|
3335
|
-
"Opt": "LONHOSANLONBFBDLX",
|
|
3336
|
-
"OptionNumber": 77490,
|
|
3337
|
-
"Remarks": "Passenger Notes: NA.
|
|
3338
|
-
Service Notes: NA.",
|
|
3339
|
-
"RoomConfigs": Object {
|
|
3340
|
-
"RoomConfig": Object {
|
|
3341
|
-
"Adults": 1,
|
|
3342
|
-
"Children": 0,
|
|
3343
|
-
"Infants": 0,
|
|
3344
|
-
"PaxList": Object {
|
|
3345
|
-
"PaxDetails": Object {
|
|
3346
|
-
"Forename": "Sean",
|
|
3347
|
-
"PaxType": "A",
|
|
3348
|
-
"PersonId": 628199,
|
|
3349
|
-
"Surname": "Conta",
|
|
3350
|
-
"Title": "Mr",
|
|
3351
|
-
},
|
|
3352
|
-
},
|
|
3353
|
-
"RoomType": "DB",
|
|
3354
|
-
},
|
|
3355
|
-
},
|
|
3356
|
-
"SCU": "night",
|
|
3357
|
-
"SCUqty": 4,
|
|
3358
|
-
"SequenceNumber": 10,
|
|
3359
|
-
"ServiceExtras": Object {
|
|
3360
|
-
"ServiceExtra": Object {
|
|
3361
|
-
"ChargeBasis": "Room",
|
|
3362
|
-
"Description": "Extra Bed",
|
|
3363
|
-
"IsCompulsory": "N",
|
|
3364
|
-
"IsPricePerPerson": "N",
|
|
3365
|
-
"Quantity": 1,
|
|
3366
|
-
"SequenceNumber": 1,
|
|
3367
|
-
},
|
|
3368
|
-
},
|
|
3369
|
-
"ServiceLineId": 745684,
|
|
3370
|
-
"ServiceLineUpdateCount": 1,
|
|
3371
|
-
"SupplierName": "Sanderson",
|
|
3372
|
-
"paxList": Array [],
|
|
3373
|
-
},
|
|
3374
|
-
],
|
|
3375
|
-
"TotalPrice": 187795,
|
|
3376
|
-
"TravelDate": "2025-08-13",
|
|
3377
3308
|
"agentRef": "2356674/1",
|
|
3378
3309
|
"bookingId": "316559",
|
|
3379
3310
|
"bookingStatus": "Quotation",
|
package/index.js
CHANGED
|
@@ -525,10 +525,14 @@ class BuyerPlugin {
|
|
|
525
525
|
chargeUnitQuantity,
|
|
526
526
|
},
|
|
527
527
|
}) {
|
|
528
|
-
|
|
528
|
+
/*
|
|
529
|
+
Need to S check and A check separately
|
|
530
|
+
because if A check is onRuest, AS will still result in empty response
|
|
531
|
+
*/
|
|
532
|
+
const getModel = checkType => ({
|
|
529
533
|
OptionInfoRequest: {
|
|
530
534
|
Opt: optionId,
|
|
531
|
-
Info:
|
|
535
|
+
Info: checkType,
|
|
532
536
|
DateFrom: startDate,
|
|
533
537
|
SCUqty: (() => {
|
|
534
538
|
const num = parseInt(chargeUnitQuantity, 10);
|
|
@@ -539,12 +543,15 @@ class BuyerPlugin {
|
|
|
539
543
|
AgentID: hostConnectAgentID,
|
|
540
544
|
Password: hostConnectAgentPassword,
|
|
541
545
|
},
|
|
542
|
-
};
|
|
543
|
-
const
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
546
|
+
});
|
|
547
|
+
const [SCheck, ACheck] = await Promise.map(['S', 'A'], async checkType => {
|
|
548
|
+
const replyObj = await this.callTourplan({
|
|
549
|
+
model: getModel(checkType),
|
|
550
|
+
endpoint: hostConnectEndpoint,
|
|
551
|
+
axios,
|
|
552
|
+
xmlOptions: hostConnectXmlOptions,
|
|
553
|
+
});
|
|
554
|
+
return R.path(['OptionInfoReply', 'Option'], replyObj);
|
|
548
555
|
});
|
|
549
556
|
/*
|
|
550
557
|
If not rates, optionInfoReply is null, meaning it's not bookable
|
|
@@ -589,11 +596,55 @@ class BuyerPlugin {
|
|
|
589
596
|
}
|
|
590
597
|
}
|
|
591
598
|
*/
|
|
592
|
-
const
|
|
593
|
-
|
|
599
|
+
const SCheckPass = Boolean(SCheck);
|
|
600
|
+
const ACheckPass = (() => {
|
|
601
|
+
/*
|
|
602
|
+
FROM TP DOCS:
|
|
603
|
+
Each integer in the list gives the availability for one of the days in the range requested,
|
|
604
|
+
from the start date through to the end date. The integer values are to be interpreted as
|
|
605
|
+
follows:
|
|
606
|
+
Greater than 0 means that inventory is available, with the integer specifying the
|
|
607
|
+
number of units available. For options with a service type of Y , the inventory is in
|
|
608
|
+
units of rooms. For other service types, the inventory is in units of pax.
|
|
609
|
+
-1 Not available.
|
|
610
|
+
-2 Available on free sell.
|
|
611
|
+
-3 Available on request.
|
|
612
|
+
Note: A return value of 0 or something less than -3 is impossible.
|
|
613
|
+
*/
|
|
614
|
+
const optAvail = parseInt(R.pathOr('-4', ['OptAvail'], ACheck), 10);
|
|
615
|
+
if (optAvail === -1) {
|
|
616
|
+
return {
|
|
617
|
+
available: false,
|
|
618
|
+
};
|
|
619
|
+
}
|
|
620
|
+
if (optAvail === -2) {
|
|
621
|
+
return {
|
|
622
|
+
available: true,
|
|
623
|
+
type: 'free sell',
|
|
624
|
+
};
|
|
625
|
+
}
|
|
626
|
+
if (optAvail === -3) {
|
|
627
|
+
return {
|
|
628
|
+
available: true,
|
|
629
|
+
type: 'on request',
|
|
630
|
+
};
|
|
631
|
+
}
|
|
632
|
+
if (optAvail > 0) {
|
|
633
|
+
return {
|
|
634
|
+
available: true,
|
|
635
|
+
type: 'inventory',
|
|
636
|
+
quantity: optAvail,
|
|
637
|
+
};
|
|
638
|
+
}
|
|
639
|
+
return {
|
|
640
|
+
available: false,
|
|
641
|
+
};
|
|
642
|
+
})();
|
|
643
|
+
let OptStayResults = R.pathOr([], ['OptStayResults'], SCheck);
|
|
594
644
|
if (!Array.isArray(OptStayResults)) OptStayResults = [OptStayResults];
|
|
595
645
|
return {
|
|
596
|
-
bookable: Boolean(
|
|
646
|
+
bookable: Boolean(SCheckPass || ACheckPass.available),
|
|
647
|
+
type: ACheckPass.type,
|
|
597
648
|
rates: OptStayResults.map(rate => {
|
|
598
649
|
let externalRateText = R.pathOr('', ['ExternalRateDetails', 'ExtOptionDescr'], rate);
|
|
599
650
|
const extRatePlanDescr = R.pathOr('', ['ExternalRateDetails', 'ExtRatePlanDescr'], rate);
|
|
@@ -606,166 +657,6 @@ class BuyerPlugin {
|
|
|
606
657
|
};
|
|
607
658
|
}),
|
|
608
659
|
};
|
|
609
|
-
// THE BELOW CODE is for A check, might still need it on user's future request
|
|
610
|
-
// const optAvail = parseInt(R.pathOr('-4', ['OptionInfoReply', 'Option', 'OptAvail'], replyObj), 10);
|
|
611
|
-
// /*
|
|
612
|
-
// FROM TP DOCS:
|
|
613
|
-
// Each integer in the list gives the availability for one of the days in the range requested,
|
|
614
|
-
// from the start date through to the end date. The integer values are to be interpreted as
|
|
615
|
-
// follows:
|
|
616
|
-
// Greater than 0 means that inventory is available, with the integer specifying the
|
|
617
|
-
// number of units available. For options with a service type of Y , the inventory is in
|
|
618
|
-
// units of rooms. For other service types, the inventory is in units of pax.
|
|
619
|
-
// -1 Not available.
|
|
620
|
-
// -2 Available on free sell.
|
|
621
|
-
// -3 Available on request.
|
|
622
|
-
// Note: A return value of 0 or something less than -3 is impossible.
|
|
623
|
-
// */
|
|
624
|
-
// if (optAvail === -1) {
|
|
625
|
-
// return {
|
|
626
|
-
// available: false,
|
|
627
|
-
// };
|
|
628
|
-
// }
|
|
629
|
-
// if (optAvail === -2) {
|
|
630
|
-
// return {
|
|
631
|
-
// available: true,
|
|
632
|
-
// type: 'free sell',
|
|
633
|
-
// };
|
|
634
|
-
// }
|
|
635
|
-
// if (optAvail === -3) {
|
|
636
|
-
// return {
|
|
637
|
-
// available: true,
|
|
638
|
-
// type: 'on request',
|
|
639
|
-
// };
|
|
640
|
-
// }
|
|
641
|
-
// if (optAvail > 0) {
|
|
642
|
-
// return {
|
|
643
|
-
// available: true,
|
|
644
|
-
// type: 'inventory',
|
|
645
|
-
// quantity: optAvail,
|
|
646
|
-
// };
|
|
647
|
-
// }
|
|
648
|
-
// return {
|
|
649
|
-
// available: false,
|
|
650
|
-
// };
|
|
651
|
-
}
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
// TODO: safe to deprecate 7-14 days after release date
|
|
655
|
-
async searchQuote({
|
|
656
|
-
axios,
|
|
657
|
-
token: {
|
|
658
|
-
hostConnectEndpoint,
|
|
659
|
-
hostConnectAgentID,
|
|
660
|
-
hostConnectAgentPassword,
|
|
661
|
-
},
|
|
662
|
-
payload: {
|
|
663
|
-
quoteName,
|
|
664
|
-
rateId,
|
|
665
|
-
quoteId,
|
|
666
|
-
// existingQuoteId,
|
|
667
|
-
// existingLineId,
|
|
668
|
-
optionId,
|
|
669
|
-
startDate,
|
|
670
|
-
reference,
|
|
671
|
-
/*
|
|
672
|
-
paxConfigs: [{ roomType: 'DB', adults: 2 }, { roomType: 'TW', children: 2 }]
|
|
673
|
-
*/
|
|
674
|
-
paxConfigs,
|
|
675
|
-
/*
|
|
676
|
-
The number of second charge units required (second charge units are discussed
|
|
677
|
-
in the OptionInfo section). Should only be specified for options that have SCUs.
|
|
678
|
-
Defaults to 1.
|
|
679
|
-
*/
|
|
680
|
-
chargeUnitQuanity,
|
|
681
|
-
extras,
|
|
682
|
-
puInfo,
|
|
683
|
-
doInfo,
|
|
684
|
-
notes,
|
|
685
|
-
QB,
|
|
686
|
-
directHeaderPayload,
|
|
687
|
-
directLinePayload,
|
|
688
|
-
customFieldValues = [],
|
|
689
|
-
},
|
|
690
|
-
}) {
|
|
691
|
-
const cfvPerService = customFieldValues.filter(f => f.isPerService && f.value)
|
|
692
|
-
.reduce((acc, f) => {
|
|
693
|
-
if (f.type === 'extended-option') {
|
|
694
|
-
acc[f.id] = f.value.value || f.value;
|
|
695
|
-
} else {
|
|
696
|
-
acc[f.id] = f.value;
|
|
697
|
-
}
|
|
698
|
-
return acc;
|
|
699
|
-
}, {});
|
|
700
|
-
const model = {
|
|
701
|
-
AddServiceRequest: {
|
|
702
|
-
AgentID: hostConnectAgentID,
|
|
703
|
-
Password: hostConnectAgentPassword,
|
|
704
|
-
...(quoteId ? {
|
|
705
|
-
ExistingBookingInfo: { BookingId: quoteId },
|
|
706
|
-
} : {
|
|
707
|
-
NewBookingInfo: {
|
|
708
|
-
Name: this.escapeInvalidXmlChars(quoteName),
|
|
709
|
-
QB: QB || 'Q',
|
|
710
|
-
...(directHeaderPayload || {}),
|
|
711
|
-
},
|
|
712
|
-
}),
|
|
713
|
-
...(puInfo && (puInfo.time || puInfo.location || puInfo.flightDetails) ? {
|
|
714
|
-
...(puInfo.time && puInfo.time.replace(/\D/g, '') ? {
|
|
715
|
-
puTime: puInfo.time.replace(/\D/g, ''),
|
|
716
|
-
} : {}),
|
|
717
|
-
puRemark: this.escapeInvalidXmlChars(`${puInfo.location ? `Location: ${puInfo.location || 'NA'},` : ''}
|
|
718
|
-
${puInfo.flightDetails ? `Flight: ${puInfo.flightDetails || 'NA'},` : ''}
|
|
719
|
-
`),
|
|
720
|
-
} : {}),
|
|
721
|
-
...(doInfo && (doInfo.time || doInfo.location || doInfo.flightDetails) ? {
|
|
722
|
-
// only get numbers from doInfo.time
|
|
723
|
-
...(doInfo.time && doInfo.time.replace(/\D/g, '') ? {
|
|
724
|
-
doTime: doInfo.time.replace(/\D/g, ''),
|
|
725
|
-
} : {}),
|
|
726
|
-
doRemark: this.escapeInvalidXmlChars(`${doInfo.location ? `Location: ${doInfo.location || 'NA'},` : ''}
|
|
727
|
-
${doInfo.flightDetails ? `Flight: ${doInfo.flightDetails || 'NA'},` : ''}
|
|
728
|
-
`),
|
|
729
|
-
} : {}),
|
|
730
|
-
...(extras && extras.filter(e => e.selectedExtra && e.selectedExtra.id).length ? {
|
|
731
|
-
ExtraQuantities: {
|
|
732
|
-
ExtraQuantityItem: extras.filter(e => e.selectedExtra && e.selectedExtra.id).map(e => ({
|
|
733
|
-
SequenceNumber: e.selectedExtra.id,
|
|
734
|
-
ExtraQuantity: e.quantity,
|
|
735
|
-
})),
|
|
736
|
-
},
|
|
737
|
-
} : {}),
|
|
738
|
-
Remarks: this.escapeInvalidXmlChars(notes).slice(0, 220),
|
|
739
|
-
Opt: optionId,
|
|
740
|
-
DateFrom: startDate,
|
|
741
|
-
RateId: rateId || 'Default',
|
|
742
|
-
SCUqty: (() => {
|
|
743
|
-
const num = parseInt(chargeUnitQuanity, 10);
|
|
744
|
-
if (isNaN(num) || num < 1) return 1;
|
|
745
|
-
return num;
|
|
746
|
-
})(),
|
|
747
|
-
AgentRef: reference,
|
|
748
|
-
RoomConfigs: this.getRoomConfigs(paxConfigs),
|
|
749
|
-
...(directLinePayload || {}),
|
|
750
|
-
...(cfvPerService || {}),
|
|
751
|
-
},
|
|
752
|
-
};
|
|
753
|
-
const replyObj = await this.callTourplan({
|
|
754
|
-
model,
|
|
755
|
-
endpoint: hostConnectEndpoint,
|
|
756
|
-
axios,
|
|
757
|
-
xmlOptions: hostConnectXmlOptions,
|
|
758
|
-
});
|
|
759
|
-
return {
|
|
760
|
-
message: R.path(['AddServiceReply', 'Status'], replyObj)
|
|
761
|
-
=== 'NO' ? 'Service cannot be added to quote for the requested date/stay. (e.g. no rates, block out period, on request, minimum stay etc.)' : '',
|
|
762
|
-
quote: {
|
|
763
|
-
id: R.path(['AddServiceReply', 'BookingId'], replyObj) || quoteId,
|
|
764
|
-
reference: R.path(['AddServiceReply', 'Ref'], replyObj),
|
|
765
|
-
linePrice: R.path(['AddServiceReply', 'Services', 'Service', 'LinePrice'], replyObj),
|
|
766
|
-
lineId: R.path(['AddServiceReply', 'ServiceLineId'], replyObj),
|
|
767
|
-
},
|
|
768
|
-
};
|
|
769
660
|
}
|
|
770
661
|
|
|
771
662
|
async addServiceToItinerary({
|
|
@@ -999,47 +890,27 @@ class BuyerPlugin {
|
|
|
999
890
|
const replyObjs = await Promise.all(allSearches);
|
|
1000
891
|
const bookingHeaders = R.flatten(replyObjs.map(o => R.pathOr([], ['ListBookingsReply', 'BookingHeaders', 'BookingHeader'], o)));
|
|
1001
892
|
const bookings = await Promise.map(bookingHeaders, async bookingHeader => {
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
const paxList = actualRoomConfigs.reduce((acc, roomConfig) => {
|
|
1021
|
-
const paxDetails = R.pathOr([], ['PaxList', 'PaxDetails'], roomConfig);
|
|
1022
|
-
if (!Array.isArray(paxDetails)) return acc;
|
|
1023
|
-
return [...acc, ...paxDetails];
|
|
1024
|
-
}, [])
|
|
1025
|
-
.map(p => ({
|
|
1026
|
-
personId: R.path(['PersonId'], p),
|
|
1027
|
-
firstName: R.path(['Forename'], p),
|
|
1028
|
-
lastName: R.path(['Surname'], p),
|
|
1029
|
-
}));
|
|
1030
|
-
return {
|
|
1031
|
-
...s,
|
|
1032
|
-
paxList,
|
|
1033
|
-
};
|
|
1034
|
-
});
|
|
1035
|
-
return {
|
|
1036
|
-
...newBooking,
|
|
1037
|
-
...booking,
|
|
1038
|
-
Services,
|
|
1039
|
-
};
|
|
893
|
+
try {
|
|
894
|
+
const getBookingPayload = getPayload('GetBookingRequest', {
|
|
895
|
+
BookingId: R.prop('BookingId', bookingHeader),
|
|
896
|
+
ReturnAccountInfo: 'Y',
|
|
897
|
+
ReturnRoomConfigs: 'Y',
|
|
898
|
+
});
|
|
899
|
+
const bookingReply = await this.callTourplan(getBookingPayload);
|
|
900
|
+
const booking = R.path(['GetBookingReply'], bookingReply);
|
|
901
|
+
const newBooking = await translateItineraryBooking({
|
|
902
|
+
rootValue: booking,
|
|
903
|
+
typeDefs: itineraryBookingTypeDefs,
|
|
904
|
+
query: itineraryBookingQuery,
|
|
905
|
+
});
|
|
906
|
+
return newBooking;
|
|
907
|
+
} catch (err) {
|
|
908
|
+
console.log('error in searchBooking', err);
|
|
909
|
+
return null;
|
|
910
|
+
}
|
|
1040
911
|
}, { concurrency: 10 });
|
|
1041
912
|
return {
|
|
1042
|
-
bookings,
|
|
913
|
+
bookings: bookings.filter(b => b),
|
|
1043
914
|
};
|
|
1044
915
|
}
|
|
1045
916
|
}
|
package/index.test.js
CHANGED
|
@@ -52,7 +52,7 @@ describe('search tests', () => {
|
|
|
52
52
|
};
|
|
53
53
|
const dateFormat = 'DD/MM/YYYY';
|
|
54
54
|
describe('tooling', () => {
|
|
55
|
-
describe
|
|
55
|
+
describe('validateToken', () => {
|
|
56
56
|
it('valid token', async () => {
|
|
57
57
|
axios.mockImplementation(getFixture);
|
|
58
58
|
const retVal = await app.validateToken({
|
|
@@ -65,12 +65,12 @@ describe('search tests', () => {
|
|
|
65
65
|
axios.mockImplementation(getFixture);
|
|
66
66
|
const retVal = await app.validateToken({
|
|
67
67
|
axios,
|
|
68
|
-
token: { ...token, username: 'somerandom' },
|
|
68
|
+
token: { ...token, username: 'somerandom', hostConnectAgentPassword: 'somerandom' },
|
|
69
69
|
});
|
|
70
70
|
expect(retVal).toBeFalsy();
|
|
71
71
|
});
|
|
72
72
|
});
|
|
73
|
-
describe
|
|
73
|
+
describe('template tests', () => {
|
|
74
74
|
let template;
|
|
75
75
|
it('get the template', async () => {
|
|
76
76
|
template = await app.tokenTemplate();
|
|
@@ -96,7 +96,7 @@ describe('search tests', () => {
|
|
|
96
96
|
});
|
|
97
97
|
});
|
|
98
98
|
});
|
|
99
|
-
it
|
|
99
|
+
it('read allotment empty', async () => {
|
|
100
100
|
const request = axios.mockImplementation(getFixture);
|
|
101
101
|
const retVal = await app.queryAllotment({
|
|
102
102
|
axios,
|
|
@@ -119,7 +119,7 @@ describe('search tests', () => {
|
|
|
119
119
|
expect(sentPayload.Date_From[0]).toBe('2022-08-01');
|
|
120
120
|
expect(sentPayload.Date_To[0]).toBe('2022-08-15');
|
|
121
121
|
});
|
|
122
|
-
it
|
|
122
|
+
it('read allotment not empty', async () => {
|
|
123
123
|
const request = axios.mockImplementation(getFixture);
|
|
124
124
|
const retVal = await app.queryAllotment({
|
|
125
125
|
axios,
|
|
@@ -155,7 +155,7 @@ describe('search tests', () => {
|
|
|
155
155
|
expect(sentPayload.Date_From[0]).toBe('2021-09-02');
|
|
156
156
|
expect(sentPayload.Date_To[0]).toBe('2021-10-02');
|
|
157
157
|
});
|
|
158
|
-
it
|
|
158
|
+
it('read allotment that applies to more products', async () => {
|
|
159
159
|
const request = axios.mockImplementation(getFixture);
|
|
160
160
|
const retVal = await app.queryAllotment({
|
|
161
161
|
axios,
|
|
@@ -218,7 +218,7 @@ describe('search tests', () => {
|
|
|
218
218
|
expect(retVal.bookable).toBeFalsy();
|
|
219
219
|
expect(retVal.rates.length).toBe(0);
|
|
220
220
|
});
|
|
221
|
-
it('searchAvailabilityForItinerary - bookable', async () => {
|
|
221
|
+
it('searchAvailabilityForItinerary - bookable - static with inventory', async () => {
|
|
222
222
|
axios.mockImplementation(getFixture);
|
|
223
223
|
const retVal = await app.searchAvailabilityForItinerary({
|
|
224
224
|
axios,
|
|
@@ -233,6 +233,23 @@ describe('search tests', () => {
|
|
|
233
233
|
expect(retVal).toMatchSnapshot();
|
|
234
234
|
expect(retVal.bookable).toBeTruthy();
|
|
235
235
|
expect(retVal.rates.length).toBeGreaterThan(0);
|
|
236
|
+
expect(retVal.type).toBe('inventory');
|
|
237
|
+
});
|
|
238
|
+
it('searchAvailabilityForItinerary - bookable - on request', async () => {
|
|
239
|
+
axios.mockImplementation(getFixture);
|
|
240
|
+
const retVal = await app.searchAvailabilityForItinerary({
|
|
241
|
+
axios,
|
|
242
|
+
token,
|
|
243
|
+
payload: {
|
|
244
|
+
optionId: 'FWMACINVCASFBSB',
|
|
245
|
+
startDate: '2025-04-01',
|
|
246
|
+
chargeUnitQuantity: 1,
|
|
247
|
+
paxConfigs: [{ roomType: 'DB', adults: 1 }],
|
|
248
|
+
},
|
|
249
|
+
});
|
|
250
|
+
expect(retVal).toMatchSnapshot();
|
|
251
|
+
expect(retVal.bookable).toBeTruthy();
|
|
252
|
+
expect(retVal.type).toBe('on request');
|
|
236
253
|
});
|
|
237
254
|
it('searchItineraries', async () => {
|
|
238
255
|
axios.mockImplementation(getFixture);
|