UNPKG

proxy-generics-stripe

Version:
688 lines (645 loc) 24.1 kB
/* eslint no-console: [0] */ 'use strict' module.exports = class ProxyGenericsStripe { constructor(options) { this.options = options } /** * Create Stripe Instance * @returns {*} Stripe Instance */ stripe() { return require('stripe')( this.options.secret ) } /** * resolves error code to proxy-cart error_code * @param {Object} err * @returns {String} */ resolveStripeCardError(err) { let errorCode switch (err.code) { case 'card_declined': errorCode = 'card_declined' break case 'incorrect_cvc': errorCode = 'incorrect_cvc' break case 'expired_card': errorCode = 'expired_card' break case 'processing_error': errorCode = 'processing_error' break case 'incorrect_number': errorCode = 'incorrect_number' break case 'invalid_expiry_month': errorCode = 'invalid_expiry_date' break case 'invalid_expiry_year': errorCode = 'invalid_expiry_date' break case 'invalid_cvc': errorCode = 'invalid_cvc' break default: errorCode = 'processing_error' } return errorCode } /** * * @param stripeCard * @returns {{type: string, gateway: string, avs_result_code: string, credit_card_iin: string, credit_card_company: *, credit_card_number: string, credit_card_last4: *, credit_card_exp_month: (number|*), credit_card_exp_year: (string|number|*), cvv_result_code: string, gateway_token: (string|*)}} */ resolveToPaymentDetails(stripeCard) { const paymentDetails = { // The type of Source: credit_card, debit_card, prepaid_card, apple_pay, bitcoin type: `${stripeCard.funding }_card`, // the Gateway used gateway: 'stripe', // The Response code from AVS the address verification system. The code is a single letter; see this chart for the codes and their definitions. avs_result_code: 'Y', // The issuer identification number (IIN), formerly known as bank identification number (BIN) ] of the customer's credit card. This is made up of the first few digits of the credit card number. credit_card_iin: '', // The Cardholder name. credit_card_name: stripeCard.name, // The name of the company who issued the customer's credit card. credit_card_company: stripeCard.brand, // The customer's credit card number, with most of the leading digits redacted with Xs. credit_card_number: `**** **** **** ${ stripeCard.last4 }`, // the last 4 of the customer's credit card number credit_card_last4: stripeCard.last4, // the 2 digit month credit_card_exp_month: stripeCard.exp_month, // the 2-4 digit year credit_card_exp_year: stripeCard.exp_year, // The address credit_card_address_city: stripeCard.address_city, credit_card_address_country: stripeCard.address_country, credit_card_address_line1: stripeCard.address_line1, credit_card_address_line1_check: stripeCard.address_line1_check, credit_card_address_line2: stripeCard.address_line2, credit_card_address_state: stripeCard.address_state, credit_card_address_zip: stripeCard.address_zip, credit_card_address_zip_check: stripeCard.address_zip_check, // The Response code from the credit card company indicating whether the customer entered the card security code, a.k.a. card verification value, correctly. The code is a single letter or empty string; see this chart http://www.emsecommerce.net/avs_cvv2_response_codes.htm for the codes and their definitions. cvv_result_code: 'S', // The card token from the Gateway gateway_token: stripeCard.id } return paymentDetails } /** * * @param transaction * @returns {Promise} */ authorize(transaction) { // Set the kind immediately transaction.kind = 'authorize' if (!transaction.payment_details) { transaction.payment_details = { gateway: 'stripe' } } const sale = { amount: transaction.amount, currency: transaction.currency || 'usd', source: transaction.payment_details.gateway_token, description: transaction.description || 'Transaction Authorize', capture: false } if (transaction.payment_details.source) { sale.customer = transaction.payment_details.source.account_foreign_id sale.source = transaction.payment_details.source.foreign_id } else { sale.source = transaction.payment_details.gateway_token } // Stripe Doesn't Allow payments less than 50 cents if (transaction.amount <= 50) { transaction.authorization = transaction.payment_details.source ? transaction.payment_details.source.foreign_id : transaction.payment_details.gateway_token transaction.authorization_exp = new Date(new Date().getTime() + 7 * 24 * 60 * 60 * 1000) transaction.status = 'success' // Load blank payment details transaction.payment_details.type = 'no_card' transaction.payment_details.avs_result_code = 'U' transaction.payment_details.credit_card_iin = null transaction.payment_details.credit_card_company = null transaction.payment_details.credit_card_number = null transaction.payment_details.credit_card_exp_month = null transaction.payment_details.credit_card_exp_year = null transaction.payment_details.cvv_result_code = null transaction.payment_details.credit_card_address_city = null transaction.payment_details.credit_card_address_country = null transaction.payment_details.credit_card_address_line1 = null transaction.payment_details.credit_card_address_line1_check = null transaction.payment_details.credit_card_address_line2 = null transaction.payment_details.credit_card_address_state = null transaction.payment_details.credit_card_address_zip = null transaction.payment_details.credit_card_address_zip_check = null return Promise.resolve(transaction) } return new Promise((resolve, reject) => { this.stripe().charges.create(sale, (err, charge) => { if (err) { transaction.error_code = this.resolveStripeCardError(err) transaction.status = 'failure' return resolve(transaction) } transaction.amount = charge.amount transaction.status = 'success' transaction.receipt = charge transaction.authorization = charge.id transaction.authorization_exp = new Date(new Date().getTime() + 7 * 24 * 60 * 60 * 1000) transaction.payment_details.type = `${charge.source.funding}_${charge.source.object}` if (charge.source.object === 'card') { transaction.payment_details.avs_result_code = 'Y' transaction.payment_details.credit_card_iin = null transaction.payment_details.credit_card_name = charge.source.name transaction.payment_details.credit_card_company = charge.source.brand transaction.payment_details.credit_card_number = `**** **** **** ${charge.source.last4}` transaction.payment_details.credit_card_exp_month = charge.source.exp_month transaction.payment_details.credit_card_exp_year = charge.source.exp_year transaction.payment_details.cvv_result_code = charge.source.cvc_check transaction.payment_details.credit_card_address_city = charge.source.address_city transaction.payment_details.credit_card_address_country = charge.source.address_country transaction.payment_details.credit_card_address_line1 = charge.source.address_line1 transaction.payment_details.credit_card_address_line1_check = charge.source.address_line1_check transaction.payment_details.credit_card_address_line2 = charge.source.address_line2 transaction.payment_details.credit_card_address_state = charge.source.address_state transaction.payment_details.credit_card_address_zip = charge.source.address_zip transaction.payment_details.credit_card_address_zip_check = charge.source.address_zip_check } return resolve(transaction) }) }) } /** * * @param transaction * @returns {Promise} */ capture(transaction) { transaction.kind = 'capture' if (!transaction.payment_details) { transaction.payment_details = { gateway: 'stripe' } } // Stripe Doesn't Allow payments less than 50 cents if (transaction.amount <= 50) { transaction.status = 'success' return Promise.resolve(transaction) } return new Promise((resolve, reject) => { this.stripe().charges.capture( transaction.authorization , (err, charge) => { if (err) { transaction.error_code = this.resolveStripeCardError(err) transaction.status = 'failure' return resolve(transaction) } transaction.amount = charge.amount transaction.status = 'success' transaction.receipt = charge transaction.authorization = charge.id transaction.payment_details.type = `${charge.source.funding}_${charge.source.object}` if (charge.source.object === 'card') { transaction.payment_details.avs_result_code = 'Y' transaction.payment_details.credit_card_iin = null transaction.payment_details.credit_card_name = charge.source.name transaction.payment_details.credit_card_company = charge.source.brand transaction.payment_details.credit_card_number = `**** **** **** ${charge.source.last4}` transaction.payment_details.credit_card_exp_month = charge.source.exp_month transaction.payment_details.credit_card_exp_year = charge.source.exp_year transaction.payment_details.cvv_result_code = charge.source.cvc_check transaction.payment_details.credit_card_address_city = charge.source.address_city transaction.payment_details.credit_card_address_country = charge.source.address_country transaction.payment_details.credit_card_address_line1 = charge.source.address_line1 transaction.payment_details.credit_card_address_line1_check = charge.source.address_line1_check transaction.payment_details.credit_card_address_line2 = charge.source.address_line2 transaction.payment_details.credit_card_address_state = charge.source.address_state transaction.payment_details.credit_card_address_zip = charge.source.address_zip transaction.payment_details.credit_card_address_zip_check = charge.source.address_zip_check } return resolve(transaction) }) }) } /** * * @param transaction * @returns {Promise} */ sale(transaction) { // Set the kind immediately transaction.kind = 'sale' if (!transaction.payment_details) { transaction.payment_details = { gateway: 'stripe' } } const sale = { amount: transaction.amount, currency: transaction.currency || 'usd', description: transaction.description || 'Transaction Sale', capture: true } if (transaction.payment_details.source) { sale.customer = transaction.payment_details.source.account_foreign_id sale.source = transaction.payment_details.source.foreign_id } else { sale.source = transaction.payment_details.gateway_token } // Stripe Doesn't Allow payments less than 50 cents if (transaction.amount <= 50) { transaction.authorization = transaction.payment_details.source ? transaction.payment_details.source.foreign_id : transaction.payment_details.gateway_token transaction.authorization_exp = new Date(new Date().getTime() + 7 * 24 * 60 * 60 * 1000) transaction.status = 'success' // Load blank payment details transaction.payment_details.type = 'no_card' transaction.payment_details.avs_result_code = 'U' transaction.payment_details.credit_card_iin = null transaction.payment_details.credit_card_company = null transaction.payment_details.credit_card_number = null transaction.payment_details.credit_card_exp_month = null transaction.payment_details.credit_card_exp_year = null transaction.payment_details.cvv_result_code = null transaction.payment_details.credit_card_address_city = null transaction.payment_details.credit_card_address_country = null transaction.payment_details.credit_card_address_line1 = null transaction.payment_details.credit_card_address_line1_check = null transaction.payment_details.credit_card_address_line2 = null transaction.payment_details.credit_card_address_state = null transaction.payment_details.credit_card_address_zip = null transaction.payment_details.credit_card_address_zip_check = null return Promise.resolve(transaction) } return new Promise((resolve, reject) => { this.stripe().charges.create(sale, (err, charge) => { if (err) { transaction.error_code = this.resolveStripeCardError(err) transaction.status = 'failure' return resolve(transaction) } transaction.amount = charge.amount transaction.status = 'success' transaction.receipt = charge transaction.authorization = charge.id transaction.payment_details.type = `${charge.source.funding}_${charge.source.object}` if (charge.source.object === 'card') { transaction.payment_details.avs_result_code = 'Y' transaction.payment_details.credit_card_iin = null transaction.payment_details.credit_card_name = charge.source.name transaction.payment_details.credit_card_company = charge.source.brand transaction.payment_details.credit_card_number = `**** **** **** ${charge.source.last4}` transaction.payment_details.credit_card_exp_month = charge.source.exp_month transaction.payment_details.credit_card_exp_year = charge.source.exp_year transaction.payment_details.cvv_result_code = charge.source.cvc_check transaction.payment_details.credit_card_address_city = charge.source.address_city transaction.payment_details.credit_card_address_country = charge.source.address_country transaction.payment_details.credit_card_address_line1 = charge.source.address_line1 transaction.payment_details.credit_card_address_line1_check = charge.source.address_line1_check transaction.payment_details.credit_card_address_line2 = charge.source.address_line2 transaction.payment_details.credit_card_address_state = charge.source.address_state transaction.payment_details.credit_card_address_zip = charge.source.address_zip transaction.payment_details.credit_card_address_zip_check = charge.source.address_zip_check } return resolve(transaction) }) }) } /** * * @param transaction * @returns {Promise} */ void(transaction) { transaction.kind = 'void' if (!transaction.payment_details) { transaction.payment_details = { gateway: 'stripe' } } const refund = { charge: transaction.authorization } if (transaction.amount) { refund.amount = transaction.amount } return new Promise((resolve, reject) => { this.stripe().refunds.create(refund, (err, refund) => { if (err) { transaction.error_code = this.resolveStripeCardError(err) transaction.status = 'failure' return resolve(transaction) } transaction.amount = refund.amount transaction.status = 'success' transaction.receipt = refund return resolve(transaction) }) }) } /** * * @param transaction * @returns {Promise} */ refund(transaction) { transaction.kind = 'refund' if (!transaction.payment_details) { transaction.payment_details = { gateway: 'stripe' } } const refund = { charge: transaction.authorization } if (transaction.amount) { refund.amount = transaction.amount } return new Promise((resolve, reject) => { this.stripe().refunds.create(refund, (err, refund) => { if (err) { transaction.error_code = this.resolveStripeCardError(err) transaction.status = 'failure' return resolve(transaction) } transaction.amount = refund.amount transaction.status = 'success' transaction.receipt = refund return resolve(transaction) }) }) } /** * * @param customer * @returns {Promise.<T>} */ createCustomer(customer) { return new Promise((resolve, reject) => { const create = { email: customer.email, description: customer.description || 'Customer Account' } if (customer.payment_token) { create.source = customer.payment_token } this.stripe().customers.create(create, function(err, stripeCustomer) { if (err) { return reject(err) } const ret = { gateway: 'stripe', foreign_key: stripeCustomer.object, foreign_id: stripeCustomer.id, data: stripeCustomer } return resolve(ret) }) }) } /** * * @param source * @returns {Promise.<T>} */ createCustomerSource(source) { return new Promise((resolve, reject) => { const create = {} if (source.gateway_token) { create.source = source.gateway_token } // TODO If normal Credit Card Conventions are followed. // if (source.name){ // create.name = source.name // } // if (source.address_city){ // create.address_city = source.address_city // } // if (source.address_country){ // create.address_country = source.address_country // } // if (source.address_line1){ // create.address_line1 = source.address_line1 // } // if (source.address_line2){ // create.address_line2 = source.address_line2 // } // if (source.address_state){ // create.address_state = source.address_state // } // if (source.address_zip){ // create.address_zip = source.address_zip // } // if (source.exp_month){ // create.exp_month = source.exp_month // } // if (source.exp_year){ // create.exp_year = source.exp_year // } // if (source.metadata){ // create.metadata = source.metadata // } this.stripe().customers.createSource(source.account_foreign_id, create, (err, stripeCard) => { if (err) { return reject(err) } const paymentDetails = this.resolveToPaymentDetails(stripeCard) const ret = { gateway: 'stripe', account_foreign_key: 'customer', account_foreign_id: stripeCard.customer, foreign_key: stripeCard.object, foreign_id: stripeCard.id, payment_details: paymentDetails } return resolve(ret) }) }) } /** * * @param customer * @returns {Promise.<T>} */ findCustomer(customer) { return new Promise((resolve, reject) => { this.stripe().customers.retrieve(customer.foreign_id, function(err, stripeCustomer) { if (err) { return reject(err) } const ret = { gateway: 'stripe', foreign_key: stripeCustomer.object, foreign_id: stripeCustomer.id, data: stripeCustomer } return resolve(ret) }) }) } /** * * @param customer * @returns {Promise.<T>} */ findCustomerSource(source) { return new Promise((resolve, reject) => { this.stripe().customers.retrieveCard(source.account_foreign_id, source.foreign_id, (err, stripeCard) => { if (err) { return reject(err) } const paymentDetails = this.resolveToPaymentDetails(stripeCard) const ret = { gateway: 'stripe', account_foreign_key: 'customer', account_foreign_id: stripeCard.customer, foreign_key: stripeCard.object, foreign_id: stripeCard.id, payment_details: paymentDetails } return resolve(ret) }) }) } getCustomerSources(customer) { return new Promise((resolve, reject) => { this.stripe().customers.listCards(customer.foreign_id, (err, stripeCards) => { if (err) { return reject(err) } const sources = stripeCards.data.map(stripeCard => { const paymentDetails = this.resolveToPaymentDetails(stripeCard) return { gateway: 'stripe', account_foreign_key: 'customer', account_foreign_id: stripeCard.customer, foreign_key: stripeCard.object, foreign_id: stripeCard.id, payment_details: paymentDetails } }) const ret = { gateway: 'stripe', foreign_key: customer.foreign_key, foreign_id: customer.foreign_id, data: customer.data, sources: sources } return resolve(ret) }) }) } /** * * @param customer * @returns {Promise.<T>} */ updateCustomer(customer) { return new Promise((resolve, reject) => { const update = {} if (customer.source) { update.source = customer.source } if (customer.email) { update.email = customer.email } if (customer.description) { update.description = customer.description } this.stripe().customers.update(customer.foreign_id, update, function(err, stripeCustomer) { if (err) { return reject(err) } const ret = { gateway: 'stripe', foreign_key: stripeCustomer.object, foreign_id: stripeCustomer.id, data: stripeCustomer } return resolve(ret) }) }) } /** * * @param source * @returns {Promise.<T>} */ updateCustomerSource(source) { return new Promise((resolve, reject) => { const update = {} if (source.name){ update.name = source.name } if (source.address_city){ update.address_city = source.address_city } if (source.address_country){ update.address_country = source.address_country } if (source.address_line1){ update.address_line1 = source.address_line1 } if (source.address_line2){ update.address_line2 = source.address_line2 } if (source.address_state){ update.address_state = source.address_state } if (source.address_zip){ update.address_zip = source.address_zip } if (source.exp_month){ update.exp_month = source.exp_month } if (source.exp_year){ update.exp_year = source.exp_year } if (source.metadata){ update.metadata = source.metadata } this.stripe().customers.updateCard(source.account_foreign_id, source.foreign_id, update, (err, stripeCard) => { if (err) { return reject(err) } const paymentDetails = this.resolveToPaymentDetails(stripeCard) const ret = { gateway: 'stripe', account_foreign_key: 'customer', account_foreign_id: stripeCard.customer, foreign_key: stripeCard.object, foreign_id: stripeCard.id, payment_details: paymentDetails } return resolve(ret) }) }) } /** * * @param source * @returns {Promise.<T>} */ removeCustomerSource(source) { return new Promise((resolve, reject) => { this.stripe().customers.deleteCard(source.account_foreign_id, source.foreign_id, (err, stripeCard) => { if (err) { return reject(err) } source.gateway = 'stripe' return resolve(source) }) }) } }