braintree
Version:
A library for server-side integrating with Braintree.
731 lines (672 loc) • 23.4 kB
JavaScript
"use strict";
/* eslint-disable no-console */
let AddressGateway = require("./address_gateway").AddressGateway;
let Gateway = require("./gateway").Gateway;
let Transaction = require("./transaction").Transaction;
let TransactionSearch = require("./transaction_search").TransactionSearch;
let Util = require("./util").Util;
let exceptions = require("./exceptions");
let wrapPrototype = require("@braintree/wrap-promise").wrapPrototype;
class TransactionGateway extends Gateway {
constructor(gateway) {
super();
this.gateway = gateway;
this.config = this.gateway.config;
}
adjustAuthorization(transactionId, amount) {
return this.gateway.http
.put(
`${this.config.baseMerchantPath()}/transactions/${transactionId}/adjust_authorization`,
{
transaction: { amount: amount },
}
)
.then(this.responseHandler());
}
cancelRelease(transactionId) {
let path = `${this.config.baseMerchantPath()}/transactions/${transactionId}/cancel_release`;
let body = {};
return this.gateway.http.put(path, body).then(this.responseHandler());
}
cloneTransaction(transactionId, attributes) {
return this.gateway.http
.post(
`${this.config.baseMerchantPath()}/transactions/${transactionId}/clone`,
{
transactionClone: attributes,
}
)
.then(this.responseHandler());
}
create(attributes) {
return this.gateway.http
.post(`${this.config.baseMerchantPath()}/transactions`, {
transaction: attributes,
})
.then(this.responseHandler());
}
credit(attributes) {
attributes.type = "credit";
return this.create(attributes);
}
find(transactionId) {
if (transactionId.trim() === "") {
return Promise.reject(exceptions.NotFoundError("Not Found"), null); // eslint-disable-line new-cap
}
return this.gateway.http
.get(`${this.config.baseMerchantPath()}/transactions/${transactionId}`)
.then((response) => {
return new Transaction(response.transaction, this.gateway);
});
}
refund(transactionId, options) {
if (typeof options === "function") {
options = {};
} else if (typeof options !== "object") {
options = { amount: options };
}
return this.gateway.http
.post(
`${this.config.baseMerchantPath()}/transactions/${transactionId}/refund`,
{ transaction: options }
)
.then(this.responseHandler());
}
responseHandler() {
return this.createResponseHandler("transaction", Transaction);
}
sale(attributes) {
let invalidKeysError;
this._checkForDeprecatedAttributes(attributes);
attributes.type = "sale";
invalidKeysError = Util.verifyKeys(this._createSignature(), attributes);
if (invalidKeysError) {
return Promise.reject(invalidKeysError, null);
}
return this.create(attributes);
}
search(fn, callback) {
let search = new TransactionSearch();
fn(search);
return this.createSearchResponse(
`${this.config.baseMerchantPath()}/transactions/advanced_search_ids`,
search,
this.pagingFunctionGenerator(search),
callback
);
}
submitForSettlement(transactionId, amount, options) {
let invalidKeysError;
options = options || {};
invalidKeysError = Util.verifyKeys(
this._submitForSettlementSignature(),
options
);
if (invalidKeysError) {
return Promise.reject(invalidKeysError, null);
}
return this.gateway.http
.put(
`${this.config.baseMerchantPath()}/transactions/${transactionId}/submit_for_settlement`,
{
transaction: Object.assign(
{
amount,
},
options
),
}
)
.then(this.responseHandler());
}
updateDetails(transactionId, options) {
let invalidKeysError = Util.verifyKeys(
this._updateDetailsSignature(),
options
);
if (invalidKeysError) {
return Promise.reject(invalidKeysError, null);
}
return this.gateway.http
.put(
`${this.config.baseMerchantPath()}/transactions/${transactionId}/update_details`,
{
transaction: options,
}
)
.then(this.responseHandler());
}
packageTracking(transactionId, attributes) {
let invalidKeysError = Util.verifyKeys(
this._packageTrackingSignature(),
attributes
);
if (invalidKeysError) {
return Promise.reject(invalidKeysError, null);
}
return this.gateway.http
.post(
`${this.config.baseMerchantPath()}/transactions/${transactionId}/shipments`,
{
shipment: attributes,
}
)
.then(this.responseHandler());
}
submitForPartialSettlement(transactionId, amount, options) {
let invalidKeysError;
options = options || {};
invalidKeysError = Util.verifyKeys(
this._submitForPartialSettlementSignature(),
options
);
if (invalidKeysError) {
return Promise.reject(invalidKeysError, null);
}
return this.gateway.http
.post(
`${this.config.baseMerchantPath()}/transactions/${transactionId}/submit_for_partial_settlement`,
{
transaction: Object.assign(
{
amount,
},
options
),
}
)
.then(this.responseHandler());
}
void(transactionId) {
return this.gateway.http
.put(
`${this.config.baseMerchantPath()}/transactions/${transactionId}/void`,
null
)
.then(this.responseHandler());
}
pagingFunctionGenerator(search) {
return super.pagingFunctionGenerator(
search,
"transactions/advanced_search",
Transaction,
"creditCardTransactions",
(response) => response.creditCardTransactions.transaction
);
}
_submitForSettlementSignature() {
return {
valid: [
"descriptor[name]",
"descriptor[phone]",
"descriptor[url]",
"discountAmount",
"industry",
"industry[data]",
"industry[data][additionalCharges][amount]",
"industry[data][additionalCharges][kind]",
"industry[data][advancedDeposit]",
"industry[data][arrivalDate]",
"industry[data][checkInDate]",
"industry[data][checkOutDate]",
"industry[data][countryCode]",
"industry[data][customerCode]",
"industry[data][dateOfBirth]",
"industry[data][departureDate]",
"industry[data][fareAmount]",
"industry[data][feeAmount]",
"industry[data][fireSafe]",
"industry[data][folioNumber]",
"industry[data][issuedDate]",
"industry[data][issuingCarrierCode]",
"industry[data][legs][arrivalAirportCode]",
"industry[data][legs][arrivalTime]",
"industry[data][legs][carrierCode]",
"industry[data][legs][conjunctionTicket]",
"industry[data][legs][couponNumber]",
"industry[data][legs][departureAirportCode]",
"industry[data][legs][departureDate]",
"industry[data][legs][departureTime]",
"industry[data][legs][endorsementOrRestrictions]",
"industry[data][legs][exchangeTicket]",
"industry[data][legs][fareAmount]",
"industry[data][legs][fareBasisCode]",
"industry[data][legs][feeAmount]",
"industry[data][legs][flightNumber]",
"industry[data][legs][serviceClass]",
"industry[data][legs][stopoverPermitted]",
"industry[data][legs][taxAmount]",
"industry[data][lodgingCheckInDate]",
"industry[data][lodgingCheckOutDate]",
"industry[data][lodgingName]",
"industry[data][noShow]",
"industry[data][passengerFirstName]",
"industry[data][passengerLastName]",
"industry[data][passengerMiddleInitial]",
"industry[data][passengerTitle]",
"industry[data][propertyPhone]",
"industry[data][restrictedTicket]",
"industry[data][roomRate]",
"industry[data][roomTax]",
"industry[data][taxAmount]",
"industry[data][ticketIssuerAddress]",
"industry[data][ticketNumber]",
"industry[data][travelAgencyName]",
"industry[data][travelAgencyCode]",
"industry[data][travelPackage]",
"industry[industryType]",
"lineItems[commodityCode]",
"lineItems[description]",
"lineItems[discountAmount]",
"lineItems[imageUrl]",
"lineItems[itemType]",
"lineItems[kind]",
"lineItems[name]",
"lineItems[productCode]",
"lineItems[quantity]",
"lineItems[taxAmount]",
"lineItems[totalAmount]",
"lineItems[unitAmount]",
"lineItems[unitOfMeasure]",
"lineItems[unitTaxAmount]",
"lineItems[upcCode]",
"lineItems[upcType]",
"lineItems[url]",
"orderId",
"purchaseOrderNumber",
"shipping[company]",
"shipping[countryCodeAlpha2]",
"shipping[countryCodeAlpha3]",
"shipping[countryCodeNumeric]",
"shipping[countryName]",
"shipping[extendedAddress]",
"shipping[firstName]",
"shipping[internationalPhone][countryCode]",
"shipping[internationalPhone][nationalNumber]",
"shipping[lastName]",
"shipping[locality]",
"shipping[phoneNumber]",
"shipping[postalCode]",
"shipping[region]",
"shipping[streetAddress]",
"shippingAddressId",
"shippingAmount",
"shippingTaxAmount",
"shipsFromPostalCode",
"taxAmount",
"taxExempt",
],
};
}
_submitForPartialSettlementSignature() {
let validKeys = this._submitForSettlementSignature();
validKeys.valid.push("finalCapture");
return validKeys;
}
_updateDetailsSignature() {
return {
valid: [
"amount",
"orderId",
"descriptor[name]",
"descriptor[phone]",
"descriptor[url]",
],
};
}
_packageTrackingSignature() {
return {
valid: [
"carrier",
"lineItems[commodityCode]",
"lineItems[description]",
"lineItems[discountAmount]",
"lineItems[imageUrl]",
"lineItems[kind]",
"lineItems[name]",
"lineItems[productCode]",
"lineItems[quantity]",
"lineItems[taxAmount]",
"lineItems[totalAmount]",
"lineItems[unitAmount]",
"lineItems[unitOfMeasure]",
"lineItems[unitTaxAmount]",
"lineItems[upcCode]",
"lineItems[upcType]",
"lineItems[url]",
"notifyPayer",
"trackingNumber",
],
};
}
_createSignature() {
let validKeys = [
"acceptPartialAuthorization",
"accountFundingTransaction",
"amount",
"customerId",
"exchangeRateQuoteId",
"merchantAccountId",
"orderId",
"channel",
"paymentMethodToken",
"purchaseOrderNumber",
"recurring",
"transactionSource",
"shippingAddressId",
"type",
"taxAmount",
"taxExempt",
// NEXT_MAJOR_VERSION remove "venmoSdkPaymentMethodCode"
"venmoSdkPaymentMethodCode",
// NEXT_MAJOR_VERSION remove deviceSessionId
"deviceSessionId",
"serviceFeeAmount",
"deviceData",
// NEXT_MAJOR_VERSION remove fraudMerchantId
"fraudMerchantId",
"billingAddressId",
"paymentMethodNonce",
"paymentMethodToken",
"acquirerReferenceNumber",
// NEXT_MAJOR_VERSION remove threeDSecureToken
"threeDSecureToken",
"threeDSecureAuthenticationId",
"sharedPaymentMethodToken",
"sharedPaymentMethodNonce",
"sharedBillingAddressId",
"sharedCustomerId",
"sharedShippingAddressId",
"riskData",
"riskData[customerBrowser]",
"riskData[customerDeviceId]",
"riskData[customerIp]",
"riskData[customerLocationZip]",
"riskData[customerTenure]",
"creditCard",
"creditCard[token]",
"creditCard[cardholderName]",
"creditCard[cvv]",
"creditCard[expirationDate]",
"creditCard[expirationMonth]",
"creditCard[expirationYear]",
"creditCard[networkTokenizationAttributes][cryptogram]",
"creditCard[networkTokenizationAttributes][ecommerceIndicator]",
"creditCard[networkTokenizationAttributes][tokenRequestorId]",
"creditCard[number]",
"creditCard[paymentReaderCardDetails][encryptedCardData]",
"creditCard[paymentReaderCardDetails][keySerialNumber]",
"customer",
"customer[id]",
"customer[company]",
"customer[email]",
"customer[fax]",
"customer[firstName]",
"customer[lastName]",
"customer[phone]",
"customer[website]",
"threeDSecurePassThru",
"threeDSecurePassThru[eciFlag]",
"threeDSecurePassThru[cavv]",
"threeDSecurePassThru[xid]",
"threeDSecurePassThru[threeDSecureVersion]",
"threeDSecurePassThru[authenticationResponse]",
"threeDSecurePassThru[directoryResponse]",
"threeDSecurePassThru[cavvAlgorithm]",
"threeDSecurePassThru[dsTransactionId]",
"options",
"options[addBillingAddressToPaymentMethod]",
"options[amexRewards]",
"options[amexRewards][currencyAmount]",
"options[amexRewards][currencyIsoCode]",
"options[amexRewards][requestId]",
"options[amexRewards][points]",
"options[credit_card][accountType]",
"options[credit_card][processDebitAsCredit]",
// NEXT_MAJOR_VERSION remove "options[venmoSdkSession]"
"options[payeeId]",
"options[payeeEmail]",
"options[paypal]",
"options[paypal][customField]",
"options[paypal][payeeId]",
"options[paypal][payeeEmail]",
"options[paypal][description]",
"options[paypal][recipientEmail]",
"options[paypal][recipientPhone][countryCode]",
"options[paypal][recipientPhone][nationalNumber]",
"options[processingOverrides]",
"options[processingOverrides][customerEmail]",
"options[processingOverrides][customerFirstName]",
"options[processingOverrides][customerLastName]",
"options[processingOverrides][customerTaxIdentifier]",
"options[skipAdvancedFraudChecking]",
"options[skipAvs]",
"options[skipCvv]",
"options[storeInVault]",
"options[storeInVaultOnSuccess]",
"options[storeShippingAddressInVault]",
"options[submitForSettlement]",
"options[threeDSecure]",
"options[threeDSecure][required]",
"options[venmo]",
"options[venmo][profileId]",
"options[venmoSdkSession]",
"options[us_bank_account]",
"options[us_bank_account][ach_type]",
"descriptor",
"descriptor[name]",
"descriptor[phone]",
"descriptor[url]",
"paypalAccount",
"paypalAccount[email]",
"paypalAccount[token]",
"paypalAccount[paypalData]",
"paypalAccount[payeeId]",
"paypalAccount[payeeEmail]",
"paypalAccount[payerId]",
"paypalAccount[paymentId]",
"processingMerchantCategoryCode",
"productSku",
"industry",
"industry[data]",
"industry[data][additionalCharges][kind]",
"industry[data][additionalCharges][amount]",
"industry[data][advancedDeposit]",
"industry[data][arrivalDate]",
"industry[data][checkInDate]",
"industry[data][checkOutDate]",
"industry[data][countryCode]",
"industry[data][customerCode]",
"industry[data][dateOfBirth]",
"industry[data][departureDate]",
"industry[data][fareAmount]",
"industry[data][feeAmount]",
"industry[data][fireSafe]",
"industry[data][folioNumber]",
"industry[data][issuedDate]",
"industry[data][issuingCarrierCode]",
"industry[data][legs][arrivalAirportCode]",
"industry[data][legs][arrivalTime]",
"industry[data][legs][carrierCode]",
"industry[data][legs][conjunctionTicket]",
"industry[data][legs][couponNumber]",
"industry[data][legs][departureAirportCode]",
"industry[data][legs][departureDate]",
"industry[data][legs][departureTime]",
"industry[data][legs][endorsementOrRestrictions]",
"industry[data][legs][exchangeTicket]",
"industry[data][legs][fareAmount]",
"industry[data][legs][fareBasisCode]",
"industry[data][legs][feeAmount]",
"industry[data][legs][flightNumber]",
"industry[data][legs][serviceClass]",
"industry[data][legs][stopoverPermitted]",
"industry[data][legs][taxAmount]",
"industry[data][lodgingCheckInDate]",
"industry[data][lodgingCheckOutDate]",
"industry[data][lodgingName]",
"industry[data][noShow]",
"industry[data][passengerFirstName]",
"industry[data][passengerLastName]",
"industry[data][passengerMiddleInitial]",
"industry[data][passengerTitle]",
"industry[data][propertyPhone]",
"industry[data][restrictedTicket]",
"industry[data][roomRate]",
"industry[data][roomTax]",
"industry[data][taxAmount]",
"industry[data][ticketIssuerAddress]",
"industry[data][ticketNumber]",
"industry[data][travelAgencyCode]",
"industry[data][travelAgencyName]",
"industry[data][travelPackage]",
"industry[industryType]",
"installments[count]",
"discountAmount",
"shippingAmount",
"shippingTaxAmount",
"shipsFromPostalCode",
"lineItems[commodityCode]",
"lineItems[description]",
"lineItems[discountAmount]",
"lineItems[imageUrl]",
"lineItems[kind]",
"lineItems[name]",
"lineItems[productCode]",
"lineItems[quantity]",
"lineItems[taxAmount]",
"lineItems[totalAmount]",
"lineItems[unitAmount]",
"lineItems[unitOfMeasure]",
"lineItems[unitTaxAmount]",
"lineItems[upcCode]",
"lineItems[upcType]",
"lineItems[url]",
"applePayCard",
"applePayCard[number]",
"applePayCard[cardholderName]",
"applePayCard[cryptogram]",
"applePayCard[expirationMonth]",
"applePayCard[expirationYear]",
"applePayCard[eciIndicator]",
// NEXT_MAJOR_VERSION rename Android Pay to Google Pay
"androidPayCard",
"androidPayCard[number]",
"androidPayCard[cryptogram]",
"androidPayCard[googleTransactionId]",
"androidPayCard[expirationMonth]",
"androidPayCard[expirationYear]",
"androidPayCard[sourceCardType]",
"androidPayCard[sourceCardLastFour]",
"androidPayCard[eciIndicator]",
"subscriptionId",
"externalVault",
"externalVault[status]",
"externalVault[previousNetworkTransactionId]",
"scaExemption",
"foreignRetailer",
"paymentFacilitator",
"paymentFacilitator[paymentFacilitatorId]",
"paymentFacilitator[subMerchant]",
"paymentFacilitator[subMerchant][referenceNumber]",
"paymentFacilitator[subMerchant][taxId]",
"paymentFacilitator[subMerchant][legalName]",
"paymentFacilitator[subMerchant][address]",
"paymentFacilitator[subMerchant][address][streetAddress]",
"paymentFacilitator[subMerchant][address][locality]",
"paymentFacilitator[subMerchant][address][region]",
"paymentFacilitator[subMerchant][address][countryCodeAlpha2]",
"paymentFacilitator[subMerchant][address][postalCode]",
"paymentFacilitator[subMerchant][address][internationalPhone]",
"paymentFacilitator[subMerchant][address][internationalPhone][countryCode]",
"paymentFacilitator[subMerchant][address][internationalPhone][nationalNumber]",
"transfer",
"transfer[type]",
"usBankAccount",
"usBankAccount[achMandateText]",
"usBankAccount[achMandateAcceptedAt]",
"transfer[sender]",
"transfer[sender][accountReferenceNumber]",
"transfer[sender][dateOfBirth]",
"transfer[sender][firstName]",
"transfer[sender][lastName]",
"transfer[sender][middleName]",
"transfer[sender][taxId]",
"transfer[sender][address]",
"transfer[sender][address][streetAddress]",
"transfer[sender][address][extendedAddress]",
"transfer[sender][address][locality]",
"transfer[sender][address][region]",
"transfer[sender][address][countryCodeAlpha2]",
"transfer[sender][address][postalCode]",
"transfer[sender][address][internationalPhone]",
"transfer[sender][address][internationalPhone][countryCode]",
"transfer[sender][address][internationalPhone][nationalNumber]",
"transfer[receiver]",
"transfer[receiver][accountReferenceNumber]",
"transfer[receiver][firstName]",
"transfer[receiver][lastName]",
"transfer[receiver][middleName]",
"transfer[receiver][taxId]",
"transfer[receiver][address]",
"transfer[receiver][address][streetAddress]",
"transfer[receiver][address][extendedAddress]",
"transfer[receiver][address][locality]",
"transfer[receiver][address][region]",
"transfer[receiver][address][countryCodeAlpha2]",
"transfer[receiver][address][postalCode]",
"transfer[receiver][address][internationalPhone]",
"transfer[receiver][address][internationalPhone][countryCode]",
"transfer[receiver][address][internationalPhone][nationalNumber]",
];
let validShippingKeys = new AddressGateway(this)
.sharedSignature("shipping")
.concat("shipping[shippingMethod]");
let validBillingKeys = new AddressGateway(this).sharedSignature("billing");
validKeys = validKeys.concat(validShippingKeys, validBillingKeys);
return {
valid: validKeys,
ignore: ["customFields", "options[paypal][supplementaryData]"],
};
}
_checkForDeprecatedAttributes(attributes) {
if (attributes.recurring != null) {
console.warn(
"[DEPRECATED] `recurring` is a deprecated param for transaction.sale calls. Use `transactionSource` instead"
);
}
if (attributes.deviceSessionId != null) {
console.warn(
"[DEPRECATED] `deviceSessionId` is a deprecated param for transaction.sale calls. Use `deviceData` instead"
);
}
if (attributes.fraudMerchantId != null) {
console.warn(
"[DEPRECATED] `fraudMerchantId` is a deprecated param for transaction.sale calls. Use `deviceData` instead"
);
}
if (attributes.threeDSecureToken != null) {
console.warn(
"[DEPRECATED] `threeDSecureToken` is a deprecated param for transaction.sale calls. Use `threeDSecureAuthenticationId` instead"
);
}
if (attributes.venmoSdkPaymentMethodCode != null) {
console.warn(
"The Venmo SDK integration is Unsupported. Please update your integration to use Pay with Venmo instead (https://developer.paypal.com/braintree/docs/guides/venmo/overview)"
);
}
if (
attributes.options != null &&
attributes.options.venmoSdkSession != null
) {
console.warn(
"The Venmo SDK integration is Unsupported. Please update your integration to use Pay with Venmo instead (https://developer.paypal.com/braintree/docs/guides/venmo/overview)"
);
}
}
}
module.exports = {
TransactionGateway: wrapPrototype(TransactionGateway, {
ignoreMethods: ["search"],
}),
};