Skip to content

Commit 8a503d0

Browse files
authored
E-Revmax Certification (#14)
* Small fixes during certification erevmax * Fixes after the live tests with erevmax * Parsing proper response from server during reservation * library cleanup * Implemented simulator for erevmax availability
1 parent e8078c6 commit 8a503d0

File tree

10 files changed

+76
-35
lines changed

10 files changed

+76
-35
lines changed

api/v1/orders/createWithOffer.js

+1
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ function returnCleanError(err, res) {
2424

2525
// Default Error
2626
else {
27+
console.log(err);
2728
res.status(500).json({message: 'A server error occured ', details: err});
2829
}
2930
}

config.js

+1
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ const JWT = process.env.JWT;
3737
const redisUrl = process.env.REDIS_URL;
3838

3939
const erevmax = {
40+
availabilityUrl: process.env.EREVMAX_AVAILABILITY_URL,
4041
reservationUrl: process.env.EREVMAX_RESERVATION_URL,
4142
};
4243

helpers/camaroTemplates/hotelAvail.js

+2-2
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ const hotelAvailTransformTemplate = {
2929
type: '#photo',
3030
width: '@width',
3131
height: '@height',
32-
url: '@url',
32+
url: '@url',
3333
}],
3434
}],
3535
_roomStays_: ['/soap:Envelope/soap:Body/OTA_HotelAvailRS/RoomStays/RoomStay', {
@@ -72,7 +72,7 @@ const hotelAvailTransformTemplate = {
7272
type: '#photo',
7373
width: '@width',
7474
height: '@height',
75-
url: '@url',
75+
url: '@url',
7676
}],
7777
policies: ['TPA_Extensions/RoomPolicy/policy', {
7878
_id_: '@Policy_Type',

helpers/camaroTemplates/hotelResNotifRS.js

+2-2
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@ const template = {
44
reservationNumber: '/SOAP-ENV:Envelope/SOAP-ENV:Body/OTA_HotelResNotifRS/HotelReservations/HotelReservation/ResGlobalInfo/HotelReservationIDs/HotelReservationID/@ResID_Value',
55
success: '/SOAP-ENV:Envelope/SOAP-ENV:Body/OTA_HotelResNotifRS/Success',
66
errors: ['/SOAP-ENV:Envelope/SOAP-ENV:Body/OTA_HotelResNotifRS/Errors/Error', {
7-
message: '@ShortText',
8-
code: '@Code',
7+
message: '.',
8+
type: '@Type',
99
}],
1010
};
1111

helpers/resolvers/hotel/orderCreateWithOffer.js

+18-12
Original file line numberDiff line numberDiff line change
@@ -16,28 +16,33 @@ module.exports = async (offer, passengers) => {
1616
const otaHotelResNotifRQData = hotelResNotif.mapFromOffer(offer, passengers);
1717
const otaRequestBody = mapOTAHotelResNotifSoap(otaHotelResNotifRQData);
1818

19-
// Send the request
20-
axios.post(
21-
config.erevmax.reservationUrl,
22-
otaRequestBody,
23-
{
24-
headers: {
25-
'Content-Type': 'application/xml',
26-
SOAPAction: 'http://www.opentravel.org/OTA/2003/05/getOTAHotelAvailability',
27-
},
28-
}
29-
)
19+
//console.log(otaRequestBody);
20+
axios({
21+
method: 'post',
22+
url: config.erevmax.reservationUrl,
23+
headers: {
24+
'Content-Type': 'text/xml;charset=UTF-8',
25+
'Accept': '*/*',
26+
'Accept-Encoding': 'gzip, deflate, br',
27+
'SOAPAction': 'http://www.opentravel.org/OTA/2003/05/getOTAHotelAvailability',
28+
},
29+
data: otaRequestBody,
30+
//responseType: 'stream'
31+
})
3032

3133
// Handle the response
3234
.then(response => {
35+
3336
// Transform the XML answer
3437
transform(response.data, responseTemplate)
3538

3639
// Build the answer according to API doc
3740
.then(responseData => {
41+
console.log(responseData);
3842
// If any error, send it
3943
if(responseData.errors.length >0 ) {
40-
reject({code:502, message: responseData.errors.join(', ')});
44+
const errors = responseData.errors.map(({type, message}) => `[${type}] ${message}`);
45+
reject({code:502, message: errors.join(' ,')});
4146
}
4247

4348
// if no error
@@ -52,6 +57,7 @@ module.exports = async (offer, passengers) => {
5257
console.log(err);
5358
reject({code:502, message: 'Error parsing answer from reservation partner'});
5459
});
60+
5561
})
5662

5763
// Handle an error

helpers/resolvers/searchHotel.js

+4-2
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ const {
1212
} = require('../parsers');
1313

1414
const offer = require('../models/offer');
15+
const config = require('../../config');
1516

1617
const searchHotel = async (body) => {
1718
// Select the Hotels matching the rectangle
@@ -49,8 +50,9 @@ const searchHotel = async (body) => {
4950
const requestBody = hotelAvailRequestTemplate(requestData);
5051

5152
// Fire the request
52-
const response = await axios.post('https://searchnbook.ratetiger.com/ARIShopService-WS/services/ARIShopService',
53-
requestBody,
53+
const response = await axios.post(
54+
config.erevmax.availabilityUrl,
55+
requestBody,
5456
{
5557
headers: {
5658
'Content-Type': 'application/xml',

helpers/soapTemplates/ota/otaHotelResNotifRQ.js

+33-10
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,10 @@ const { v4: uuidv4 } = require('uuid');
33

44
/* Mapping for Guest Counts */
55
const mapGuestCount = OTA_GuestCount => {
6-
if(OTA_GuestCount.Count = 0) return '';
6+
if(OTA_GuestCount.Count == 0) return '';
77
let guestCount = '';
8-
guestCount += ` AgeQualifyingCode="${OTA_GuestCount.AgeQualifyingCode}`;
9-
guestCount += ` Count="${OTA_GuestCount.Count}`;
8+
guestCount += ` AgeQualifyingCode="${OTA_GuestCount.AgeQualifyingCode}"`;
9+
guestCount += ` Count="${OTA_GuestCount.Count}"`;
1010
return `<GuestCount${guestCount}/>`;
1111
}
1212

@@ -49,7 +49,9 @@ const mapRoomRate = OTA_RoomRate => `
4949

5050
/* Mapping for Guarantee */
5151
const mapPaymentCard = OTA_PaymentCard => {
52-
let paymentCard = '';
52+
let paymentCard = '<PaymentCard';
53+
54+
// Add Payment Card attributes
5355
paymentCard += ` CardCode="${OTA_PaymentCard.CardCode}"`;
5456
paymentCard += ` CardNumber="${OTA_PaymentCard.CardNumber}"`;
5557
paymentCard += ` CardType="${OTA_PaymentCard.CardType}"`;
@@ -58,8 +60,19 @@ const mapPaymentCard = OTA_PaymentCard => {
5860
if(OTA_PaymentCard.SeriesCode !== undefined) {
5961
paymentCard += ` SeriesCode="${OTA_PaymentCard.SeriesCode}"`;
6062
}
63+
paymentCard += '>'
64+
65+
// Cardholder name is mandatory
66+
if(OTA_PaymentCard.CardHolderName !== undefined) {
67+
paymentCard += `<CardHolderName>${OTA_PaymentCard.CardHolderName}</CardHolderName>`;
68+
} else {
69+
paymentCard += '<CardHolderName/>';
70+
}
71+
72+
// Finish the object
73+
paymentCard += '</PaymentCard>'
6174

62-
return `<PaymentCard${paymentCard}/>`;
75+
return paymentCard;
6376
}
6477

6578
const mapGuarantee = OTA_Guarantee => `
@@ -97,13 +110,24 @@ const mapRoomStay = OTA_RoomStay => `
97110
<Total
98111
AmountAfterTax="${OTA_RoomStay.Total.AmountAfterTax}"
99112
CurrencyCode="${OTA_RoomStay.Total.CurrencyCode}">
113+
<Taxes Amount="00.00" CurrencyCode="EUR">
114+
<Tax Type="Exclusive" Amount="00.00" CurrencyCode="EUR"/>
115+
</Taxes>
100116
</Total>
101117
<BasicPropertyInfo
102118
HotelCode="${OTA_RoomStay.BasicPropertyInfo.HotelCode}"/>
103119
<ResGuestRPHs>
104120
<ResGuestRPH
105121
RPH="${OTA_RoomStay.ResGuestRPHs.ResGuestRPH.RPH}"/>
106122
</ResGuestRPHs>
123+
<Comments>
124+
<Comment GuestViewable="0">
125+
<Text>Booked via Winding Tree</Text>
126+
</Comment>
127+
</Comments>
128+
<SpecialRequests>
129+
<SpecialRequest RequestCode="" CodeContext=""/>
130+
</SpecialRequests>
107131
</RoomStay>
108132
`.trim();
109133

@@ -125,7 +149,7 @@ const mapPOS = OTA_POS => `
125149
`.trim();
126150

127151
const mapAddress = OTA_Address => {
128-
if(OTA_Address == undefined) return '';
152+
if(OTA_Address == undefined) return '<Address Type="1"><AddressLine/><CityName/><PostalCode/><StateProv StateCode=""/><CountryName Code=""/></Address>';
129153
return `
130154
<Address Type="${OTA_Address.Type}">
131155
<AddressLine>${OTA_Address.AddressLines[0]}</AddressLine>
@@ -251,15 +275,14 @@ const mapSoapHeader = uuid => `
251275
</soap:Header>
252276
`.trim();
253277

254-
const mapHotelResNotifSoap = ({OTA_HotelResNotifRQ}) => `
255-
<?xml version="1.0" ?>
278+
const mapHotelResNotifSoap = ({OTA_HotelResNotifRQ}) =>
279+
`<?xml version="1.0" ?>
256280
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
257281
${mapSoapHeader(uuidv4())}
258282
<soap:Body>
259283
${mapHotelResNotif(OTA_HotelResNotifRQ)}
260284
</soap:Body>
261-
</soap:Envelope>
262-
`
285+
</soap:Envelope>`
263286
.replace(/>\n/g,'>')
264287
.replace(/\n/g,' ')
265288
.replace(/(\s{4})/g,'')

helpers/transformInputData/hotelResNotif.js

+11-4
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,9 @@ var emailValidator = require("email-validator");
77
Maps an offer and passengers to an OTA HotelResNotifRQ structure
88
*/
99
function mapFromOffer(offer, passengers ) {
10+
11+
const orderId = uuidv4();
12+
const resId = orderId.substr(24);
1013

1114
// Build the POS
1215
const pos = {
@@ -33,7 +36,7 @@ function mapFromOffer(offer, passengers ) {
3336
PaymentCard: {
3437
CardType: '1', // 1-Credit as per erevmax doc,
3538
CardCode: 'VI',
36-
CardNumber: '123456789',
39+
CardNumber: '4444333322221111',
3740
ExpireDate: '0420', // MMYY format,
3841
//CardHolderName: OPTIONAL
3942
},
@@ -55,7 +58,7 @@ function mapFromOffer(offer, passengers ) {
5558
));
5659

5760
// Build the Guest counts
58-
const guestCounts = Object.values(offer.guestCounts).map(({type, count}) => ({
61+
const guestCounts = offer.guestCounts.map(({type, count}) => ({
5962
AgeQualifyingCode: type === 'ADT' ? 10 : 8,
6063
Count: count === undefined ? 1 : count,
6164
}));
@@ -73,6 +76,10 @@ function mapFromOffer(offer, passengers ) {
7376
NumberOfUnits: '1',
7477
RatePlanCode: offer.rateCode,
7578
Rates: rates,
79+
Total: {
80+
CurrencyCode: offer.currency,
81+
AmountAfterTax: offer.amountAfterTax,
82+
},
7683
},
7784
},
7885
GuestCounts: guestCounts,
@@ -147,7 +154,7 @@ function mapFromOffer(offer, passengers ) {
147154
CreatorID: 'WindingTree',
148155
ResStatus: 'Commit',
149156
UniqueID: {
150-
ID: 'WTTest123',
157+
ID: resId,
151158
Type: '14',
152159
},
153160
RoomStays: {
@@ -175,7 +182,7 @@ function mapFromOffer(offer, passengers ) {
175182
HotelReservationID: {
176183
ResID_Source: 'Windingtree',
177184
ResID_Type: '22',
178-
ResID_Value: 'WTTest123'
185+
ResID_Value: resId
179186
},
180187
},
181188
},

now.json

+2-1
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@
6060
"AF_PARTICIPANT_RECIPENT_NAME": "@af_participant_recipent_name",
6161
"JWT": "@staging.wt-aggregator.jwt",
6262
"REDIS_URL": "@staging.wt-aggregator.redis_url",
63-
"EREVMAX_RESERVATION_URL": "@staging.wt-aggregator.erevmax_reservation_url"
63+
"EREVMAX_RESERVATION_URL": "@staging.wt-aggregator.erevmax_reservation_url",
64+
"EREVMAX_AVAILABILITY_URL": "@staging.wt-aggregator.erevmax_availability_url"
6465
}
6566
}

public/wt-aggregator.yaml

+2-2
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ paths:
5454
},
5555
"passengers": [
5656
{"type": "ADT", "count": 2},
57-
{"type": "CHD"},
57+
{"type": "CHD"}
5858
]
5959
}
6060
hotelSearch:
@@ -75,7 +75,7 @@ paths:
7575
},
7676
"passengers": [
7777
{"type": "ADT", "count": 2},
78-
{"type": "CHD", "count": 1},
78+
{"type": "CHD", "count": 1}
7979
]
8080
}
8181
required: true

0 commit comments

Comments
 (0)