braintree
Version:
A library for server-side integrating with Braintree.
297 lines (268 loc) • 8.56 kB
JavaScript
;
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),
};