@lomray/microservice-payment-stripe
Version:
Stripe payment microservice based on NodeJS & inverted json.
151 lines (147 loc) • 7.22 kB
JavaScript
'use strict';
var tslib = require('tslib');
var microserviceNodejsLib = require('@lomray/microservice-nodejs-lib');
var Event = require('@lomray/microservices-client-api/constants/events/payment-stripe');
var _ = require('lodash');
var remote = require('../../config/remote.js');
var stripePaymentMethods = require('../../constants/stripe-payment-methods.js');
var customer = require('../../entities/customer.js');
var extractIdFromStripeInstance = require('../../helpers/extract-id-from-stripe-instance.js');
var fromExpirationDate = require('../../helpers/formatters/from-expiration-date.js');
var toExpirationDate = require('../../helpers/formatters/to-expiration-date.js');
var messages = require('../../helpers/validators/messages.js');
var card = require('../../repositories/card.js');
/**
* Setup intent Webhook Handler
*/
class SetupIntent {
/**
* @constructor
*/
constructor(manager) {
this.manager = manager;
this.cardRepository = manager.getCustomRepository(card);
this.customerRepository = manager.getRepository(customer);
}
/**
* Handles setup intent succeed
* @description Support cards. Should be called when webhook triggers
*/
handleSetupIntentSucceed(event, sdk) {
var _a, _b;
return tslib.__awaiter(this, void 0, void 0, function* () {
const { duplicatedCardsUsage } = yield remote();
/* eslint-disable camelcase */
const { id, payment_method } = event.data.object;
if (!payment_method) {
throw new microserviceNodejsLib.BaseException({
status: 500,
message: messages.getNotFoundMessage('The SetupIntent payment method'),
});
}
/**
* Get payment method data
*/
const paymentMethod = yield sdk.paymentMethods.retrieve(extractIdFromStripeInstance(payment_method), {
expand: [stripePaymentMethods.CARD],
});
if (!(paymentMethod === null || paymentMethod === void 0 ? void 0 : paymentMethod.card) || !(paymentMethod === null || paymentMethod === void 0 ? void 0 : paymentMethod.customer)) {
throw new microserviceNodejsLib.BaseException({
status: 500,
message: 'The payment method card or customer data is invalid.',
});
}
const customer = yield this.customerRepository.findOne({
customerId: extractIdFromStripeInstance(paymentMethod.customer),
});
if (!customer) {
throw new microserviceNodejsLib.BaseException({
status: 500,
message: messages.getNotFoundMessage('Customer'),
});
}
const { id: paymentMethodId, billing_details: billing, card: { brand, last4: lastDigits, exp_month: expMonth, exp_year: expYear, funding, country, issuer, fingerprint, }, } = paymentMethod;
const { userId } = customer;
const cardParams = Object.assign(Object.assign(Object.assign({ lastDigits,
brand,
userId,
funding,
fingerprint,
paymentMethodId, origin: country }, (((_a = billing.address) === null || _a === void 0 ? void 0 : _a.country) ? { country: billing.address.country } : {})), (((_b = billing.address) === null || _b === void 0 ? void 0 : _b.postal_code) ? { postalCode: billing.address.postal_code } : {})), { expired: toExpirationDate(expMonth, expYear) });
const cardEntity = this.cardRepository.create(Object.assign(Object.assign({}, cardParams), { params: {
isApproved: true,
setupIntentId: id,
issuer,
} }));
/**
* If we should reject duplicated cards - check
*/
if (duplicatedCardsUsage === 'reject') {
const cardData = yield card.getCardDataByFingerprint({
userId,
fingerprint,
shouldExpandCard: true,
});
/**
* Cancel set up card if this card already exist as the payment method
*/
if (cardData.isExist && cardData.type === 'paymentMethod') {
yield this.detachOrRenewWithDetachDuplicatedCard(paymentMethodId, cardEntity, cardData, sdk);
return;
}
}
const savedCard = yield this.cardRepository.save(cardEntity);
void microserviceNodejsLib.Microservice.eventPublish(Event.SetupIntentSucceeded, savedCard);
});
}
/**
* Detach duplicated card
* @description Will detach duplicated card from Stripe customer
*/
detachOrRenewWithDetachDuplicatedCard(paymentMethodId, cardEntity, { entity }, sdk) {
return tslib.__awaiter(this, void 0, void 0, function* () {
if (!entity) {
throw new microserviceNodejsLib.BaseException({
status: 500,
message: messages.getNotFoundMessage('Failed to validate duplicated card. Card'),
});
}
/**
* Card properties for renewal card that must be identical
*/
const cardProperties = ['lastDigits', 'brand', 'origin', 'fingerprint', 'funding', 'userId'];
const existingCardPaymentMethodId = card.extractPaymentMethodId(entity);
const { year: existingYear, month: existingMonth } = fromExpirationDate(entity.expired);
const { year: updatedYear, month: updatedMonth } = fromExpirationDate(cardEntity.expired);
/**
* Update renewal card details
* @description Stripe does not create new fingerprint if card was renewal with new expiration date
*/
if (entity.expired !== cardEntity.expired &&
// All other card details MUST be equal
_.isEqual(_.pick(entity, cardProperties), _.pick(cardEntity, cardProperties)) &&
// Check expiration dates
updatedYear >= existingYear &&
updatedMonth >= existingMonth) {
entity.expired = cardEntity.expired;
/**
* Update card details and next() detach new duplicated card
*/
yield sdk.paymentMethods.update(existingCardPaymentMethodId, {
card: {
exp_month: updatedMonth,
exp_year: updatedYear,
},
});
yield this.cardRepository.save(entity);
}
/**
* If customer trying to add identical, not renewal card
* @description Detach duplicated card from Stripe customer
*/
yield sdk.paymentMethods.detach(paymentMethodId);
yield microserviceNodejsLib.Microservice.eventPublish(Event.CardNotCreatedDuplicated, cardEntity);
});
}
}
module.exports = SetupIntent;