UNPKG

braintree

Version:

A library for server-side integrating with Braintree.

297 lines (268 loc) 8.56 kB
"use strict"; const Gateway = require("./gateway").Gateway; const wrapPrototype = require("@braintree/wrap-promise").wrapPrototype; const exceptions = require("./exceptions"); const { GraphQLClient } = require("./graphql_client"); const { CreateCustomerSessionInput, CustomerRecommendations, CustomerRecommendationsInput, CustomerRecommendationsPayload, RecommendedPaymentOption, PaymentRecommendation, UpdateCustomerSessionInput, } = require("./graphql"); /** * Creates and manages PayPal customer sessions. This feature is available to authorized merchants. */ class CustomerSessionGateway extends Gateway { constructor(gateway) { super(); this._graphQLClient = gateway.graphQLClient; } /** * Creates a new customer session. * * Customer sessions can be created with or without a merchant-provided session * ID. If a session ID is not provided in the input, one will be generated by * the gateway. Attempt to create a duplicate session will result in an error. * Customer specific information such as email, phone number and device * information can be optionally included in the input object. * * Example: * * <pre> * <code> * var input = CreateCustomerSessionInput * .builder() * .sessionId(...) * .customer(...) * .build(); * * gateway.customerSession() * .createCustomerSession(input) * .then(function (result) { * if (result.success) { * console.log("session id",result.target); * } * }); * * </code> * </pre> * * @param {CreateCustomerSessionInput} input The input parameters for creating a customer session. * * @return {object} A result object containing the session ID if successful, or errors otherwise. * * @throws {InvalidKeysError} If invalid input object is provided. * @throws {ServerError} If an unexpected error occurs. */ createCustomerSession(input) { if (!(input instanceof CreateCustomerSessionInput)) { return Promise.reject( // eslint-disable-next-line new-cap exceptions.InvalidKeysError( "Invalid input type. Use CreateCustomerSessionInput to build the input object." ) ); } return this._executeMutation( `mutation CreateCustomerSession($input: CreateCustomerSessionInput!) { createCustomerSession(input: $input) { sessionId } }`, input, "createCustomerSession" ); } /** * Updates an existing customer session. * * Example: * * <pre> * <code> * var input = UpdateCustomerSessionInput * .builder(sessionId) * .customer(...) * .build(); * * gateway * .customerSession() * .updateCustomerSession(input) * .then((result) => { * if (result.success) { * console.log("session id", result.target); * } * }); * * </code> * </pre> * * @param {UpdateCustomerSessionInput} input The input parameters for updating a customer session. * * @return {object} A result object containing the session ID if successful, or errors otherwise. * * @throws {InvalidKeysError} If invalid input object is provided. * @throws {ServerError} If an unexpected error occurs. */ updateCustomerSession(input) { if (!(input instanceof UpdateCustomerSessionInput)) { return Promise.reject( // eslint-disable-next-line new-cap exceptions.InvalidKeysError( "Invalid input type. Use UpdateCustomerSessionInput to build the input object." ) ); } return this._executeMutation( `mutation UpdateCustomerSession($input: UpdateCustomerSessionInput!) { updateCustomerSession(input: $input) { sessionId } }`, input, "updateCustomerSession" ); } /** * Retrieves customer recommendations associated with a customer session. * * Example: * <pre> * <code> * * var input = CustomerRecommendationsInput * .builder() * .sessionId(sessionId) * .build(); * * gateway.customerSession().getCustomerRecommendations(input) * .then(function (result) { * if (result.success) { * var payload = result.target; * console.log("Payment recommendations", payload.recommendations.paymentRecommendations); * } * }); * * * </code> * </pre> * @param {CustomerRecommendationsInput} input The input parameters for retrieving customer recommendations. * * @return {object} A result object containing the customer recommendations if successful, or errors otherwise. * * @throws {InvalidKeysError} If invalid input object is provided. * @throws {ServerError} If an unexpected error occurs. */ getCustomerRecommendations(input) { if (!(input instanceof CustomerRecommendationsInput)) { return Promise.reject( // eslint-disable-next-line new-cap exceptions.InvalidKeysError( "Invalid input type. Use CustomerRecommendationsInput to build the input object." ) ); } const variables = { input: input.toGraphQLVariables() }; const query = `mutation GenerateCustomerRecommendations($input: GenerateCustomerRecommendationsInput!) { generateCustomerRecommendations(input: $input) { sessionId isInPayPalNetwork paymentRecommendations { paymentOption recommendedPriority } } }`; return this._graphQLClient.query(query, variables).then((response) => { const validationErrorCollection = GraphQLClient.getValidationErrors(response); if (validationErrorCollection) { return Promise.resolve({ success: false, errors: validationErrorCollection, }); } return Promise.resolve({ success: true, target: this._extractCustomerRecommendationsPayload(response), }); }); } _executeMutation(query, input, operationName) { const variables = { input: input.toGraphQLVariables() }; return this._graphQLClient.query(query, variables).then((response) => { const validationErrorCollection = GraphQLClient.getValidationErrors(response); if (validationErrorCollection) { return Promise.resolve({ success: false, errors: validationErrorCollection, }); } const sessionId = this._getValue( response, `data.${operationName}.sessionId` ); return Promise.resolve({ success: true, target: sessionId }); }); } _extractCustomerRecommendationsPayload(response) { const sessionId = this._getValue( response, "data.generateCustomerRecommendations.sessionId" ); const isInPayPalNetwork = this._getValue( response, "data.generateCustomerRecommendations.isInPayPalNetwork" ); const recommendationsMap = this._getValue( response, "data.generateCustomerRecommendations" ); const recommendations = new CustomerRecommendations( this._getPaymentRecommendations(recommendationsMap) ); return new CustomerRecommendationsPayload( sessionId, isInPayPalNetwork, recommendations ); } _getPaymentRecommendations(responseObj) { if (!responseObj) { return []; } const paymentRecommendationObjs = this._getValue( responseObj, "paymentRecommendations" ); return paymentRecommendationObjs.map((obj) => { const recommendedPriority = this._getValue(obj, "recommendedPriority"); const paymentOptionString = this._getValue(obj, "paymentOption"); const paymentOption = RecommendedPaymentOption[paymentOptionString]; return new PaymentRecommendation(paymentOption, recommendedPriority); }); } _getValue(nestedMap, path) { var map = nestedMap; const keys = path.split("."); for (const key of keys.slice(0, keys.length - 1)) { map = this._popValue(map, key); } const lastKey = keys[keys.length - 1]; return this._popValue(map, lastKey); } _popValue(map, key) { if (!(key in map)) { // eslint-disable-next-line new-cap throw exceptions.ServerError("Couldn't parse response"); } return map[key]; } } module.exports = { CustomerSessionGateway: wrapPrototype(CustomerSessionGateway), };