From 2e0ff84fb6dfbf66905779bc55ecace73ce268ae Mon Sep 17 00:00:00 2001 From: Oleg Drozdovich Date: Mon, 19 Feb 2024 02:28:17 +0100 Subject: [PATCH 1/4] docs(payment-stripe): move out calculation to common --- .../payment-stripe/__tests__/services/calculation-test.ts | 4 ++-- .../payment-stripe/src/methods/stripe/payment-intent-fees.ts | 2 +- .../payment-stripe/src/services/{ => common}/calculation.ts | 0 .../payment-stripe/src/services/payment-gateway/stripe.ts | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) rename microservices/payment-stripe/src/services/{ => common}/calculation.ts (100%) diff --git a/microservices/payment-stripe/__tests__/services/calculation-test.ts b/microservices/payment-stripe/__tests__/services/calculation-test.ts index 98e003a0..120ed3e0 100644 --- a/microservices/payment-stripe/__tests__/services/calculation-test.ts +++ b/microservices/payment-stripe/__tests__/services/calculation-test.ts @@ -7,9 +7,9 @@ import { configMock } from '@__mocks__/config'; import * as remoteConfig from '@config/remote'; import TaxBehaviour from '@constants/tax-behaviour'; import TransactionRole from '@constants/transaction-role'; -import Calculation from '@services/calculation'; +import Calculation from '@services/common/calculation'; -describe('services/calculation', () => { +describe('services/common/calculation', () => { const sandbox = sinon.createSandbox(); const mathRoundSpy = sinon.spy(Math, 'round'); const remoteConfigStub = sinon.stub().resolves(configMock); diff --git a/microservices/payment-stripe/src/methods/stripe/payment-intent-fees.ts b/microservices/payment-stripe/src/methods/stripe/payment-intent-fees.ts index d0e594f6..8760f38d 100644 --- a/microservices/payment-stripe/src/methods/stripe/payment-intent-fees.ts +++ b/microservices/payment-stripe/src/methods/stripe/payment-intent-fees.ts @@ -2,7 +2,7 @@ import { Endpoint, IsUndefinable } from '@lomray/microservice-helpers'; import { IsBoolean, IsEnum, IsNumber } from 'class-validator'; import { JSONSchema } from 'class-validator-jsonschema'; import TransactionRole from '@constants/transaction-role'; -import Calculation from '@services/calculation'; +import Calculation from '@services/common/calculation'; import Stripe from '@services/payment-gateway/stripe'; class PaymentIntentFeesInput { diff --git a/microservices/payment-stripe/src/services/calculation.ts b/microservices/payment-stripe/src/services/common/calculation.ts similarity index 100% rename from microservices/payment-stripe/src/services/calculation.ts rename to microservices/payment-stripe/src/services/common/calculation.ts diff --git a/microservices/payment-stripe/src/services/payment-gateway/stripe.ts b/microservices/payment-stripe/src/services/payment-gateway/stripe.ts index 8bb408bb..763cd615 100644 --- a/microservices/payment-stripe/src/services/payment-gateway/stripe.ts +++ b/microservices/payment-stripe/src/services/payment-gateway/stripe.ts @@ -38,7 +38,7 @@ import TCurrency from '@interfaces/currency'; import IFees from '@interfaces/fees'; import type ITax from '@interfaces/tax'; import CardRepository from '@repositories/card'; -import Calculation from '@services/calculation'; +import Calculation from '@services/common/calculation'; import Parser from '@services/parser'; import WebhookHandlers from '@services/webhook-handlers'; import type { From 6673c18dee0993b0471af33eb245701b7a5c2907 Mon Sep 17 00:00:00 2001 From: Oleg Drozdovich Date: Mon, 19 Feb 2024 02:30:36 +0100 Subject: [PATCH 2/4] docs(payment-stripe): update jsdocs --- microservices/payment-stripe/src/entities/transaction.ts | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/microservices/payment-stripe/src/entities/transaction.ts b/microservices/payment-stripe/src/entities/transaction.ts index d6332a10..84a99b73 100644 --- a/microservices/payment-stripe/src/entities/transaction.ts +++ b/microservices/payment-stripe/src/entities/transaction.ts @@ -187,12 +187,9 @@ class Transaction { @IsNullable() cardId: string | null; - /** - * Setup intent don't have card or bank account id - */ @JSONSchema({ description: `Payment method that was used to charge, for instance: card, bank account, etc.. Payment method is - stripe entity that attached to customer`, + stripe entity that attached to customer. Setup intent don't have card or bank account id`, example: 'pm_1N0vl32eZvKYlo2CiORpHAvo', }) @Column({ type: 'varchar', length: 27, default: null }) From b696f75c15eeba6cfe1f150366d6c5bc8a5a75cb Mon Sep 17 00:00:00 2001 From: Oleg Drozdovich Date: Mon, 19 Feb 2024 02:39:06 +0100 Subject: [PATCH 3/4] docs(payment-stripe): update methods accessors --- .../src/services/payment-gateway/stripe.ts | 176 +++++++++--------- .../src/services/webhook-handlers/index.ts | 3 +- 2 files changed, 89 insertions(+), 90 deletions(-) diff --git a/microservices/payment-stripe/src/services/payment-gateway/stripe.ts b/microservices/payment-stripe/src/services/payment-gateway/stripe.ts index 763cd615..7746ad77 100644 --- a/microservices/payment-stripe/src/services/payment-gateway/stripe.ts +++ b/microservices/payment-stripe/src/services/payment-gateway/stripe.ts @@ -1490,6 +1490,93 @@ class Stripe extends Abstract { }; } + /** + * Returns payout method data + */ + protected async getPayoutMethodAllowances( + userId: string, + payoutMethod?: IPayoutMethod, + ): Promise<{ externalAccountId: string; isInstantPayoutAllowed: boolean } | undefined> { + const externalAccountNotFoundError = messages.getNotFoundMessage( + 'External account for instant payout', + ); + + if (!payoutMethod) { + const queries = [ + this.bankAccountRepository.createQueryBuilder('pm'), + this.cardRepository.createQueryBuilder('pm'), + ]; + + const selectQueries = queries.map((query) => + query + .where('pm.userId = :userId AND pm."isInstantPayoutAllowed" = true', { userId }) + .getOne(), + ); + + const results = await Promise.all(selectQueries); + + if (!results.length) { + throw new BaseException({ + status: 500, + message: 'User does not have any available instant payout method.', + }); + } + + const [bankAccount, card] = results as [BankAccount | undefined, Card | undefined]; + + const externalAccountId = bankAccount?.params?.bankAccountId || card?.params?.cardId; + + if (!externalAccountId) { + throw new BaseException({ + status: 500, + message: externalAccountNotFoundError, + }); + } + + return { + externalAccountId, + isInstantPayoutAllowed: + Boolean(bankAccount?.isInstantPayoutAllowed) || Boolean(card?.isInstantPayoutAllowed), + }; + } + + const { method, id } = payoutMethod; + + if (method === PayoutMethodType.CARD) { + const card = await this.cardRepository.findOne(id, { + select: ['id', 'params'], + }); + + if (!card?.params?.cardId) { + throw new BaseException({ + status: 500, + message: externalAccountNotFoundError, + }); + } + + return { + externalAccountId: card.params.cardId, + isInstantPayoutAllowed: Boolean(card?.isInstantPayoutAllowed), + }; + } + + const bankAccount = await this.bankAccountRepository.findOne(id, { + select: ['id', 'params'], + }); + + if (!bankAccount?.params?.bankAccountId) { + throw new BaseException({ + status: 500, + message: externalAccountNotFoundError, + }); + } + + return { + externalAccountId: bankAccount?.params?.bankAccountId, + isInstantPayoutAllowed: Boolean(bankAccount?.isInstantPayoutAllowed), + }; + } + /** * Returns card for charging payment */ @@ -1636,7 +1723,7 @@ class Stripe extends Abstract { /** * Process webhook event */ - private async processWebhookEvent(event: StripeSdk.Event, webhookType: string): Promise { + protected async processWebhookEvent(event: StripeSdk.Event, webhookType: string): Promise { const webhookHandlers = WebhookHandlers.init(this.manager); switch (event.type) { @@ -1908,93 +1995,6 @@ class Stripe extends Abstract { percent_off: percentOff, }; } - - /** - * Returns payout method data - */ - private async getPayoutMethodAllowances( - userId: string, - payoutMethod?: IPayoutMethod, - ): Promise<{ externalAccountId: string; isInstantPayoutAllowed: boolean } | undefined> { - const externalAccountNotFoundError = messages.getNotFoundMessage( - 'External account for instant payout', - ); - - if (!payoutMethod) { - const queries = [ - this.bankAccountRepository.createQueryBuilder('pm'), - this.cardRepository.createQueryBuilder('pm'), - ]; - - const selectQueries = queries.map((query) => - query - .where('pm.userId = :userId AND pm."isInstantPayoutAllowed" = true', { userId }) - .getOne(), - ); - - const results = await Promise.all(selectQueries); - - if (!results.length) { - throw new BaseException({ - status: 500, - message: 'User does not have any available instant payout method.', - }); - } - - const [bankAccount, card] = results as [BankAccount | undefined, Card | undefined]; - - const externalAccountId = bankAccount?.params?.bankAccountId || card?.params?.cardId; - - if (!externalAccountId) { - throw new BaseException({ - status: 500, - message: externalAccountNotFoundError, - }); - } - - return { - externalAccountId, - isInstantPayoutAllowed: - Boolean(bankAccount?.isInstantPayoutAllowed) || Boolean(card?.isInstantPayoutAllowed), - }; - } - - const { method, id } = payoutMethod; - - if (method === PayoutMethodType.CARD) { - const card = await this.cardRepository.findOne(id, { - select: ['id', 'params'], - }); - - if (!card?.params?.cardId) { - throw new BaseException({ - status: 500, - message: externalAccountNotFoundError, - }); - } - - return { - externalAccountId: card.params.cardId, - isInstantPayoutAllowed: Boolean(card?.isInstantPayoutAllowed), - }; - } - - const bankAccount = await this.bankAccountRepository.findOne(id, { - select: ['id', 'params'], - }); - - if (!bankAccount?.params?.bankAccountId) { - throw new BaseException({ - status: 500, - message: externalAccountNotFoundError, - }); - } - - return { - externalAccountId: bankAccount?.params?.bankAccountId, - isInstantPayoutAllowed: Boolean(bankAccount?.isInstantPayoutAllowed), - }; - } } export default Stripe; diff --git a/microservices/payment-stripe/src/services/webhook-handlers/index.ts b/microservices/payment-stripe/src/services/webhook-handlers/index.ts index 036789e3..329e0ecb 100644 --- a/microservices/payment-stripe/src/services/webhook-handlers/index.ts +++ b/microservices/payment-stripe/src/services/webhook-handlers/index.ts @@ -68,7 +68,6 @@ class WebhookHandlers { /** * @constructor - * @private */ private constructor(manager: EntityManager) { this.customer = new Customer(manager); @@ -87,7 +86,7 @@ class WebhookHandlers { * Init service */ public static init(manager: EntityManager): WebhookHandlers { - return new WebhookHandlers(manager); + return new this(manager); } } From dc9fa09db25247d8e5d1ea92283c24789354d6ce Mon Sep 17 00:00:00 2001 From: Oleg Drozdovich Date: Mon, 19 Feb 2024 03:45:40 +0100 Subject: [PATCH 4/4] docs(payment-stripe): update jsdocs --- .../src/services/payment-gateway/stripe.ts | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/microservices/payment-stripe/src/services/payment-gateway/stripe.ts b/microservices/payment-stripe/src/services/payment-gateway/stripe.ts index 7746ad77..3a05bf9b 100644 --- a/microservices/payment-stripe/src/services/payment-gateway/stripe.ts +++ b/microservices/payment-stripe/src/services/payment-gateway/stripe.ts @@ -1323,18 +1323,16 @@ class Stripe extends Abstract { * Returns positive int amount * @description Should return the positive integer representing how much * to charge in the smallest currency unit + * @TODO: remove. use client api parser */ public toSmallestCurrencyUnit(amount: number | string): number { - /** - * Convert the amount to a number if it's a string - */ - const parsedAmount = typeof amount === 'string' ? Number(amount) : amount; - - return parsedAmount * 100; + // Convert the amount to a number if it's a string + return Number(amount) * 100; } /** * Returns float value from unit + * @TODO: remove. use client api parser */ public fromSmallestCurrencyUnit(amount: number): number { return amount / 100; @@ -1722,6 +1720,7 @@ class Stripe extends Abstract { /** * Process webhook event + * @TODO: make this extendable */ protected async processWebhookEvent(event: StripeSdk.Event, webhookType: string): Promise { const webhookHandlers = WebhookHandlers.init(this.manager); @@ -1943,7 +1942,7 @@ class Stripe extends Abstract { /** * Validate and transform coupon duration input */ - private static validateAndTransformCouponDurationInput({ + protected static validateAndTransformCouponDurationInput({ duration, durationInMonths, }: Pick): Pick< @@ -1967,7 +1966,7 @@ class Stripe extends Abstract { /** * Validate and transform coupon discount input */ - private static validateAndTransformCouponDiscountInput({ + protected static validateAndTransformCouponDiscountInput({ percentOff, amountOff, }: Pick): Pick<