Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat/amad integration #75

Merged
merged 41 commits into from
Sep 21, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
41 commits
Select commit Hold shift + click to select a range
a11f830
fixed old tests
kostysh Jul 16, 2020
d239719
add tests
kostysh Jul 17, 2020
14d0911
fixed wrong GLIDER_ORGID env
kostysh Jul 19, 2020
e2e811a
added tests for parsers (used in hotels search)
kostysh Jul 19, 2020
111bdf3
added code coverage tool and configuration
kostysh Jul 20, 2020
4d1da92
added test for GliderError class
kostysh Jul 20, 2020
ba9dc90
added "code" case for the test for GliderError class
kostysh Jul 20, 2020
c49eb43
updated tests runner configuration
kostysh Jul 20, 2020
5269492
added test for searchHorel resolver
kostysh Jul 20, 2020
f8bad8f
added test for orderCreateWithOffer hotel order resolver
kostysh Jul 20, 2020
b2180f1
added test for mapFromOffer
kostysh Jul 20, 2020
eb21f7a
disabled mongo calls in testing mode
kostysh Jul 20, 2020
8e7ddca
fix lintig errors
kostysh Jul 20, 2020
edea38c
Linting enabled in CI configuration
kostysh Jul 20, 2020
cb0a918
added test for reduceContactInformation
kostysh Jul 22, 2020
647ec80
added tests for parsers: useDictionary, mergeHourAndDate
kostysh Jul 23, 2020
c303ca4
added test for parser: convertDateToAirportTime
kostysh Jul 23, 2020
4a325d4
added test for parser: reduceToProperty
kostysh Jul 23, 2020
2d003f0
added tests for parsers: roundCommissionDecimals & deepMerge
kostysh Jul 23, 2020
3ed02d9
fixed type in config; minor update for tests
kostysh Jul 23, 2020
467d9bc
added tests for utils: uniqueObjectsList & flatOneDepth
kostysh Jul 24, 2020
c5cb04d
tests structure changed
kostysh Jul 24, 2020
0929e89
tests structure update and new tests
kostysh Jul 24, 2020
5ce8f41
more tests for transformInputData
kostysh Aug 3, 2020
85f9faf
tests for transforInputData utils and soapTemplates
kostysh Aug 4, 2020
fc791bc
Amadeus GDS - offer price
tomashq Aug 16, 2020
6d65573
Amadeus GDS - entire flow
tomashq Aug 26, 2020
3f14330
squashed last pushes
tomashq Sep 18, 2020
e5df6b9
Merge remote-tracking branch 'origin_tk/feat/amadeus_integration' int…
tomashq Sep 18, 2020
10159d3
seatmap requests decoupled
tomashq Sep 19, 2020
5871546
fulfillment requests decoupled
tomashq Sep 20, 2020
eae6f88
ndcclient externalized
tomashq Sep 20, 2020
622905a
simplified response from flight providers
tomashq Sep 20, 2020
ce1a65a
Amadeus provider refactored
tomashq Sep 20, 2020
02a035b
Hotels templates decoupled
tomashq Sep 20, 2020
02ccd8e
Hotels templates decoupled
tomashq Sep 20, 2020
47b0fb9
Fixed hotel search results processing
tomashq Sep 20, 2020
ec06089
Fixed hotel search results processing
tomashq Sep 20, 2020
c1d646b
Fixed hotel search results processing
tomashq Sep 20, 2020
1537e2c
added 'amadeus staging configuration' to vercel
tomashq Sep 20, 2020
0dc919e
added 'amadeus staging configuration' to vercel
tomashq Sep 20, 2020
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions .github/workflows/unit.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@ jobs:
- name: Install Dependencies
run: npm ci

# - name: Code Linting
# run: npm run lint
- name: Code Linting
run: npm run lint

- name: Start Redis
uses: superchargejs/redis-github-action@master
Expand All @@ -22,7 +22,7 @@ jobs:
- name: Unit testing
run: npm test
env:
GLIDER_ORGID: '0x71cd1781a3082f33d2521ac8290c9d4b3b3b116e4e8548a4914b71a1f7201da0'
GLIDER_ORGID: '0x94bf5a57b850a35b4d1d7b59f663ce3a8a76fd9928ef2067cc772fc97fb0ad75'
INFURA_ENDPOINT: wss://ropsten.infura.io/ws/v3
INFURA_PROJECT_ID: ${{ secrets.INFURA_PROJECT_ID }}
REDIS_URL: redis://localhost:6379
10 changes: 10 additions & 0 deletions .nycrc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"all": true,
"extension": [
".js"
],
"include": [
"api/**",
"helpers/**"
]
}
1 change: 1 addition & 0 deletions api/v1/index.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
/* istanbul ignore file */
const { name, description, version } = require('../package.json');

module.exports = async (req, res) => {
Expand Down
10 changes: 4 additions & 6 deletions api/v1/offers.js
Original file line number Diff line number Diff line change
@@ -1,16 +1,14 @@
/* istanbul ignore file */
const GliderError = require('../../helpers/error');
const { basicDecorator } = require('../../decorators/basic');
const { offerPriceRQ } = require('../../helpers/resolvers/flight/offerPrice');
const { validateOptionSelection } = require('../../payload/validators');

module.exports = basicDecorator(async (req, res) => {
const { method, query, body } = req;

if (method !== 'POST') {
throw new GliderError(
'Method not allowed',
405,
);
throw new GliderError('Method not allowed', 405);
}
validateOptionSelection(body);

const offerResult = await offerPriceRQ(query.offerIds, body);

Expand Down
152 changes: 19 additions & 133 deletions api/v1/orders/[orderId]/fulfill.js
Original file line number Diff line number Diff line change
@@ -1,161 +1,47 @@
const { ready, transform } = require('camaro');
const { basicDecorator } = require('../../../../decorators/basic');
const GliderError = require('../../../../helpers/error');
const {
airFranceConfig,
airCanadaConfig
} = require('../../../../config');
const { createFlightProvider } = require('../../../../helpers/providers/providerFactory');
const { ordersManager } = require('../../../..//helpers/models/order');
const {
mapNdcRequestData_AF,
mapNdcRequestHeaderData_AC,
mapNdcRequestData_AC
} = require('../../../../helpers/transformInputData/fulfillOrder');
const {
fulfillOrderTemplate_AF,
fulfillOrderTemplate_AC
} = require('../../../../helpers/soapTemplates/fulfillOrder');
const {
ErrorsTransformTemplate_AF,
ErrorsTransformTemplate_AC,
FaultsTransformTemplate_AC,
fulfillOrderTransformTemplate_AF,
fulfillOrderTransformTemplate_AC
} = require('../../../../helpers/camaroTemplates/fulfillOrder');
const {
reduceToObjectByKey,
reduceToProperty
} = require('../../../../helpers/parsers');
const {
getGuarantee,
claimGuarantee,
claimGuaranteeWithCard
} = require('../../../../helpers/guarantee');
const {
callProvider
} = require('../../../../helpers/resolvers/utils/flightUtils');

const { reduceToObjectByKey, reduceToProperty } = require('../../../../helpers/parsers');
const { getGuarantee, claimGuarantee, claimGuaranteeWithCard } = require('../../../../helpers/guarantee');


module.exports = basicDecorator(async (req, res) => {
const { body, query } = req;
let guaranteeClaim;
const { orderId } = query;

// Get the order
const order = await ordersManager.getOrder(query.orderId);


if (order.offer && order.offer.extraData && order.offer.extraData.mappedPassengers) {
body.passengerReferences = body.passengerReferences
.map(p => order.offer.extraData.mappedPassengers[p]);
} else {
throw new GliderError(
'Mapped passengers Ids not found in the offer',
500
500,
);
}

// Get the guarantee and verify
const guarantee = await getGuarantee(body.guaranteeId, {
currency: order.order.order.price.currency,
amountAfterTax: order.order.order.price.public
amountAfterTax: order.order.order.price.public,
});
//claim
let guaranteeClaim = await claimGuaranteeWithCard(body.guaranteeId);

let ndcRequestHeaderData;
let ndcRequestData;
let providerUrl;
let apiKey;
let SOAPAction;
let ndcBody;
let responseTransformTemplate;
let errorsTransformTemplate;
let faultsTransformTemplate;

switch (order.provider) {
case 'AF':
ndcRequestData = mapNdcRequestData_AF(airFranceConfig, body, query);
providerUrl = 'https://ndc-rct.airfranceklm.com/passenger/distribmgmt/001489v01/EXT';
apiKey = airFranceConfig.apiKey;
SOAPAction = '"http://www.af-klm.com/services/passenger/AirDocIssue/airDocIssue"';
ndcBody = fulfillOrderTemplate_AF(ndcRequestData);
responseTransformTemplate = fulfillOrderTransformTemplate_AF;
errorsTransformTemplate = ErrorsTransformTemplate_AF;
faultsTransformTemplate = null;
break;
case 'AC':
guaranteeClaim = await claimGuaranteeWithCard(body.guaranteeId);
ndcRequestHeaderData = mapNdcRequestHeaderData_AC(guaranteeClaim);
ndcRequestData = mapNdcRequestData_AC(airCanadaConfig, order, body, guaranteeClaim);
providerUrl = `${airCanadaConfig.baseUrlPci}/OrderCreate`;
apiKey = airCanadaConfig.apiKey;
ndcBody = fulfillOrderTemplate_AC(ndcRequestHeaderData, ndcRequestData);
// console.log('@@@', ndcBody);
responseTransformTemplate = fulfillOrderTransformTemplate_AC;
errorsTransformTemplate = ErrorsTransformTemplate_AC;
faultsTransformTemplate = FaultsTransformTemplate_AC;
break;
default:
return Promise.reject('Unsupported flight operator');
}

const { response, error } = await callProvider(
order.provider,
providerUrl,
apiKey,
ndcBody,
SOAPAction
);

if (error && !error.isAxiosError) {

throw new GliderError(
response.error.message,
502
);
}

let faultsResult;

if (faultsTransformTemplate) {
await ready();
faultsResult = await transform(response.data, faultsTransformTemplate);
}

// Attempt to parse as a an error
await ready();
const errorsResult = await transform(response.data, errorsTransformTemplate);

// Because of two types of errors can be returned: NDCMSG_Fault and Errors
const combinedErrors = [
...(faultsResult ? faultsResult.errors : []),
...errorsResult.errors
];
let provider = order.provider;
let providerImpl = createFlightProvider(provider);
let fulfillResults = await providerImpl.orderFulfill(orderId, order, body, guaranteeClaim);

// If an error is found, stop here
if (combinedErrors.length) {
throw new GliderError(
combinedErrors.map(e => e.message).join('; '),
502
);
} else if (error) {
throw new GliderError(
error.message,
502
);
}

await ready();
const fulfillResults = await transform(
response.data,
responseTransformTemplate
);

fulfillResults.travelDocuments.etickets = reduceToObjectByKey(
fulfillResults.travelDocuments.etickets
);

fulfillResults.travelDocuments.etickets = reduceToProperty(
fulfillResults.travelDocuments.etickets,
'_passenger_'
);
fulfillResults.travelDocuments.etickets = reduceToObjectByKey(fulfillResults.travelDocuments.etickets);
fulfillResults.travelDocuments.etickets = reduceToProperty(fulfillResults.travelDocuments.etickets, '_passenger_');

//FIXME - do we need to claim after or before fulfill call?
if (!guaranteeClaim) {
guaranteeClaim = await claimGuarantee(body.guaranteeId);
}
Expand All @@ -167,8 +53,8 @@ module.exports = basicDecorator(async (req, res) => {
guarantee: guarantee,
guaranteeClaim: guaranteeClaim,
order: fulfillResults,
offer: order.offer
}
offer: order.offer,
},
);

res.status(200).json(fulfillResults);
Expand Down
27 changes: 16 additions & 11 deletions api/v1/orders/createWithOffer.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@ const {
} = require('../../../helpers/guarantee');
const hotelResolver = require('../../../helpers/resolvers/hotel/orderCreateWithOffer');
const flightResolver = require('../../../helpers/resolvers/flight/orderCreateWithOffer');
const { setOrderStatus, assertOrgerStatus } = require('../../../helpers/resolvers/utils/offers');
const { validateCreateOfferPayload } = require('../../../payload/validators');
const { setOrderStatus, assertOrderStatus } = require('../../../helpers/resolvers/utils/offers');

module.exports = basicDecorator(async (req, res) => {
const requestBody = req.body;

Expand All @@ -23,26 +23,31 @@ module.exports = basicDecorator(async (req, res) => {
400
);
}
validateCreateOfferPayload(requestBody);

// Retrieve the offer
const storedOffer = await offerManager.getOffer(requestBody.offerId);

let originOffers = [];

if (storedOffer instanceof FlightOffer) {

// in case of not priced offer
// there possible situation when storedOffer.extraData.originOffers is undefined
if (storedOffer instanceof FlightOffer &&
storedOffer.extraData &&
storedOffer.extraData.originOffers) {

originOffers = await Promise.all(
storedOffer.extraData.originOffers.map(
offerId => offerManager.getOffer(offerId)
)
);
}

const allOffers = [
storedOffer,
...originOffers
];

assertOrgerStatus(allOffers);
assertOrderStatus(allOffers);

try {
await setOrderStatus(allOffers, 'CREATING');
Expand All @@ -54,12 +59,12 @@ module.exports = basicDecorator(async (req, res) => {
if (requestBody.guaranteeId) {
// Get the guarantee
guarantee = await getGuarantee(requestBody.guaranteeId, storedOffer);

// Claim the guarantee
guaranteeClaim = await claimGuaranteeWithCard(requestBody.guaranteeId);
}

// Handle an Accomodation offer
// Handle an Accommodation offer
if (storedOffer instanceof AccommodationOffer) {

if (!guaranteeClaim) {
Expand Down Expand Up @@ -125,7 +130,7 @@ module.exports = basicDecorator(async (req, res) => {
}
);
orderCreationResults.order.passengers = changedPassengers.passengers;

// Change passengers Ids in travelDocuments to internal values
if (orderCreationResults.travelDocuments) {
orderCreationResults.travelDocuments.etickets =
Expand Down Expand Up @@ -163,7 +168,7 @@ module.exports = basicDecorator(async (req, res) => {
{}
);
}

await ordersManager.saveOrder(
orderCreationResults.orderId,
{
Expand Down
45 changes: 13 additions & 32 deletions api/v1/searchOffers.js
Original file line number Diff line number Diff line change
@@ -1,40 +1,21 @@
/* istanbul ignore file */
const { basicDecorator } = require('../../decorators/basic');
const GliderError = require('../../helpers/error');
const { searchHotel } = require('../../helpers/resolvers/searchHotel');
const { searchFlight } = require('../../helpers/resolvers/searchFlight');
const { checkCallsTrustRequirements } = require('../../helpers/requirements/apiCallsLimits');
const { validateSearchCriteria } = require('../../payload/validators');
const {
checkCallsTrustRequirements
} = require('../../helpers/requirements/apiCallsLimits');

module.exports = basicDecorator(async (req, res) => {
const { body } = req;
validateSearchCriteria(body);
await checkCallsTrustRequirements(
'/api/v1/searchOffers',
req.verificationResult.didResult.id,
req.verificationResult.didResult.lifDeposit.deposit
);

let resolver = () => {
throw new GliderError(
'accommodation or itinerary missing in body',
400
);
};

if (body.accommodation) {
resolver = searchHotel;
} else if (body.itinerary) {
resolver = searchFlight;
} else {
throw new GliderError(
'Invalid search criteria: missing itinerary or accommodation objects',
400
);
let { body } = req;
body = validateSearchCriteria(body);
await checkCallsTrustRequirements('/api/v1/searchOffers', req.verificationResult.didResult.id, req.verificationResult.didResult.lifDeposit.deposit);
// const controller = new OfferController();
let result;
const { itinerary, accommodation/*, passengers */ } = body;
if (accommodation) {
result = await searchHotel(body);
} else if (itinerary) {
// result = await controller.flightsSearch(itinerary,passengers);
result = await searchFlight(body);
}

const result = await resolver(body);

res.status(200).json(result);
});
2 changes: 1 addition & 1 deletion api/v1/seatmap.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
/* istanbul ignore file */
const GliderError = require('../../helpers/error');
const { basicDecorator } = require('../../decorators/basic');
const { seatMapRQ } = require('../../helpers/resolvers/flight/seatAvailability');
Expand All @@ -13,6 +14,5 @@ module.exports = basicDecorator(async (req, res) => {
}

const seatResult = await seatMapRQ(query.offerIds);

res.status(200).json(seatResult);
});
Loading