UNPKG

@lomray/microservice-payment-stripe

Version:

Stripe payment microservice based on NodeJS & inverted json.

147 lines (143 loc) 9.02 kB
'use strict'; 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;