UNPKG

braintree

Version:

A library for server-side integrating with Braintree.

317 lines (288 loc) 9 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, PaymentOptions, 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 {UnexpectedError} 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 {UnexpectedError} 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, * [Recommendations.PAYMENT_RECOMMENDATIONS] * ) * .build(); * * gateway.customerSession().getCustomerRecommendations(input) * .then(function (result) { * if (result.success) { * var payload = result.target; * console.log("Payment options", payload.recommendations.paymentOptions); * } * }); * * * </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 {UnexpectedError} 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() }; try { return this._graphQLClient .query( `query CustomerRecommendations($input: CustomerRecommendationsInput!) { customerRecommendations(input: $input) { isInPayPalNetwork recommendations { ... on PaymentRecommendations { paymentOptions { paymentOption recommendedPriority } } } } }`, 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), }); }); } catch (error) { // eslint-disable-next-line new-cap throw exceptions.UnexpectedError(error.message); } } _executeMutation(query, input, operationName) { const variables = { input: input.toGraphQLVariables() }; try { 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 }); }); } catch (error) { // eslint-disable-next-line new-cap throw exceptions.UnexpectedError(error.message); } } _extractCustomerRecommendationsPayload(response) { const isInPayPalNetwork = this._getValue( response, "data.customerRecommendations.isInPayPalNetwork" ); const recommendationsMap = this._getValue( response, "data.customerRecommendations.recommendations" ); const recommendations = new CustomerRecommendations( this._getPaymentOptions(recommendationsMap) ); return new CustomerRecommendationsPayload( isInPayPalNetwork, recommendations ); } _getPaymentOptions(recommendationObj) { if (!recommendationObj) { return []; } const paymentOptionObjs = this._getValue( recommendationObj, "paymentOptions" ); return paymentOptionObjs.map((paymentOptionObj) => { const recommendedPriority = this._getValue( paymentOptionObj, "recommendedPriority" ); const paymentOptionString = this._getValue( paymentOptionObj, "paymentOption" ); const paymentOption = RecommendedPaymentOption[paymentOptionString]; return new PaymentOptions(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.UnexpectedError("Couldn't parse response" + key); } return map[key]; } } module.exports = { CustomerSessionGateway: wrapPrototype(CustomerSessionGateway), };