@lomray/microservice-payment-stripe
Version:
Stripe payment microservice based on NodeJS & inverted json.
147 lines (143 loc) • 9.02 kB
JavaScript
;
var tslib = require('tslib');
var microserviceHelpers = require('@lomray/microservice-helpers');
var microserviceNodejsLib = require('@lomray/microservice-nodejs-lib');
var toSmallestUnit = require('@lomray/microservices-client-api/helpers/parsers/to-smallest-unit');
var stripeTransactionStatus = require('../../constants/stripe-transaction-status.js');
var transactionType = require('../../constants/transaction-type.js');
var card = require('../../entities/card.js');
var transaction = require('../../entities/transaction.js');
var extractIdFromStripeInstance = require('../../helpers/extract-id-from-stripe-instance.js');
var messages = require('../../helpers/validators/messages.js');
var card$1 = require('../../repositories/card.js');
var parser = require('../parser.js');
/**
* Payment intent webhook handlers
*/
class PaymentIntent {
/**
* @constructor
*/
constructor(manager) {
this.manager = manager;
this.transactionRepository = manager.getRepository(transaction);
}
/**
* Handles payment intent statuses
*/
handlePaymentIntent(event, sdk) {
return tslib.__awaiter(this, void 0, void 0, function* () {
const { id, status, latest_charge: latestCharge, last_payment_error: lastPaymentError, transfer_data: transferData, } = event.data.object;
yield this.manager.transaction((entityManager) => tslib.__awaiter(this, void 0, void 0, function* () {
const transactionRepository = entityManager.getRepository(transaction);
const transactions = yield transactionRepository.find({ transactionId: id });
if (!transactions.length) {
const errorMessage = messages.getNotFoundMessage(`Failed to handle payment intent "${event.type}". Debit or credit transaction`);
microserviceHelpers.Log.error(errorMessage);
throw new microserviceNodejsLib.BaseException({
status: 500,
message: errorMessage,
payload: { eventName: event.type },
});
}
// Sonar warning
const { transactionId, taxCalculationId } = (transactions === null || transactions === void 0 ? void 0 : transactions[0]) || {};
let stripeTaxTransaction = null;
/**
* If tax collecting and payment intent succeeded - create tax transaction
* @description Create tax transaction cost is $0.5. Create only if payment intent succeeded
*/
if (taxCalculationId && status === stripeTransactionStatus.SUCCEEDED) {
// Create tax transaction (for Stripe Tax reports)
stripeTaxTransaction = yield sdk.tax.transactions.createFromCalculation({
calculation: taxCalculationId,
// Stripe payment intent id
reference: transactionId,
});
}
transactions.forEach((transaction) => {
transaction.status = parser.parseStripeTransactionStatus(status);
// Attach related charge
if (!transaction.chargeId && latestCharge) {
transaction.chargeId = extractIdFromStripeInstance(latestCharge);
}
// Attach destination funds transfer connect account
if (!transaction.params.transferDestinationConnectAccountId && (transferData === null || transferData === void 0 ? void 0 : transferData.destination)) {
transaction.params.transferDestinationConnectAccountId = extractIdFromStripeInstance(transferData.destination);
}
// Attach tax transaction if reference
if (stripeTaxTransaction) {
transaction.taxTransactionId = stripeTaxTransaction.id;
}
if (!lastPaymentError) {
return;
}
// Attach error data if it occurs
transaction.params.errorMessage = lastPaymentError.message;
transaction.params.errorCode = lastPaymentError.code;
transaction.params.declineCode = lastPaymentError.decline_code;
});
if (stripeTaxTransaction) {
// Sync payment intent with the microservice transactions
yield sdk.paymentIntents.update(transactionId, {
metadata: {
taxTransactionId: stripeTaxTransaction === null || stripeTaxTransaction === void 0 ? void 0 : stripeTaxTransaction.id,
},
});
}
yield transactionRepository.save(transactions);
}));
});
}
/**
* Handles payment intent failure creation
* @description Payment intent will be created with the failed status: card was declined -
* high fraud risk but stripe will throw error on creation and send webhook event with the creation
*/
handlePaymentIntentPaymentFailed(event, sdk) {
return tslib.__awaiter(this, void 0, void 0, function* () {
const { id, status, metadata, amount, latest_charge: latestCharge, last_payment_error: lastPaymentError, } = event.data.object;
yield this.manager.transaction((entityManager) => tslib.__awaiter(this, void 0, void 0, function* () {
const transactionRepository = entityManager.getRepository(transaction);
const transactions = yield transactionRepository.find({ transactionId: id });
/**
* If transactions weren't created cause payment intent failed on create
*/
if (transactions.length) {
return;
}
const { entityId, title, feesPayer, cardId, entityCost, senderId, receiverId, taxExpiresAt, taxCreatedAt, taxBehaviour, receiverRevenue, taxAutoCalculateFee, taxFee, taxTransactionId, taxCalculationId, } = metadata;
const card$2 = yield entityManager
.getRepository(card)
.createQueryBuilder('card')
.where('card.userId = :userId AND card.id = :cardId', { userId: senderId, cardId })
.getOne();
if (!card$2) {
throw new microserviceNodejsLib.BaseException({
status: 500,
message: messages.getNotFoundMessage('Failed to create transaction. Card'),
});
}
/* eslint-enable camelcase */
const transactionData = Object.assign(Object.assign(Object.assign(Object.assign({ entityId,
title, paymentMethodId: card$1.extractPaymentMethodId(card$2), cardId, transactionId: id, status: parser.parseStripeTransactionStatus(status) }, (latestCharge ? { chargeId: extractIdFromStripeInstance(latestCharge) } : {})), (taxTransactionId ? { taxTransactionId } : {})), (taxCalculationId ? { taxCalculationId } : {})), {
// eslint-disable-next-line camelcase
params: Object.assign(Object.assign({ feesPayer, entityCost: toSmallestUnit(entityCost), errorCode: lastPaymentError === null || lastPaymentError === void 0 ? void 0 : lastPaymentError.code, errorMessage: lastPaymentError === null || lastPaymentError === void 0 ? void 0 : lastPaymentError.message, declineCode: lastPaymentError === null || lastPaymentError === void 0 ? void 0 : lastPaymentError.decline_code, taxExpiresAt,
taxCreatedAt,
taxBehaviour }, (taxCalculationId && taxAutoCalculateFee
? { taxAutoCalculateFee: toSmallestUnit(taxAutoCalculateFee) }
: {})), (taxTransactionId && taxFee ? { taxFee: toSmallestUnit(taxFee) } : {})) });
yield Promise.all([
transactionRepository.save(transactionRepository.create(Object.assign(Object.assign({}, transactionData), { userId: senderId, type: transactionType.CREDIT, amount, params: transactionData.params }))),
transactionRepository.save(transactionRepository.create(Object.assign(Object.assign({}, transactionData), { userId: receiverId, type: transactionType.DEBIT, amount: toSmallestUnit(receiverRevenue), params: transactionData.params }))),
]);
// Do not support update payment intent, only recharge via creating new payment
if (status !== stripeTransactionStatus.REQUIRES_PAYMENT_METHOD) {
return;
}
yield sdk.paymentIntents.cancel(id);
}));
});
}
}
module.exports = PaymentIntent;