From 606e75dc67c2395c6418d85db364105e031996f9 Mon Sep 17 00:00:00 2001 From: Nghia Tran Date: Sat, 10 Aug 2024 22:39:40 +0700 Subject: [PATCH 1/2] PICT-235: Configure due date period for bank transfer payments --- connect.yaml | 3 + processor/.env.jest | 1 + processor/src/types/index.types.ts | 1 + processor/src/utils/config.utils.ts | 1 + processor/src/utils/constant.utils.ts | 4 + processor/src/utils/map.utils.ts | 6 +- processor/src/utils/mollie.utils.ts | 27 +++ processor/src/validators/env.validators.ts | 10 +- .../src/validators/helpers.validators.ts | 26 ++- .../src/validators/payment.validators.ts | 20 ++ processor/tests/utils/config.utils.spec.ts | 11 +- processor/tests/utils/constant.utils.spec.ts | 11 + processor/tests/utils/map.utils.spec.ts | 25 ++- processor/tests/utils/mollie.utils.spec.ts | 30 ++- .../validators/helpers.validators.spec.ts | 130 ++++++++++- .../validators/payment.validators.spec.ts | 201 ++++++++++++++++++ 16 files changed, 492 insertions(+), 15 deletions(-) diff --git a/connect.yaml b/connect.yaml index 42bed82..3e275aa 100644 --- a/connect.yaml +++ b/connect.yaml @@ -23,6 +23,9 @@ deployAs: description: Debug mode (0 or 1) required: false default: "0" + - key: MOLLIE_BANK_TRANSFER_DUE_DATE + description: Payment method Bank Transfer due date (1d -> 100d) + default: "14d" securedConfiguration: - key: MOLLIE_API_TEST_KEY description: Mollie PSP test API key diff --git a/processor/.env.jest b/processor/.env.jest index 610d232..e4013e3 100644 --- a/processor/.env.jest +++ b/processor/.env.jest @@ -12,5 +12,6 @@ MOLLIE_CARD_COMPONENT=0 CONNECTOR_MODE=test ## Either test or live MOLLIE_API_TEST_KEY=test_12345 MOLLIE_API_LIVE_KEY=live_12345 +MOLLIE_BANK_TRANSFER_DUE_DATE= CONNECT_SERVICE_URL=http://localhost:3000/processor diff --git a/processor/src/types/index.types.ts b/processor/src/types/index.types.ts index 0ef36da..49c0ce2 100644 --- a/processor/src/types/index.types.ts +++ b/processor/src/types/index.types.ts @@ -29,5 +29,6 @@ export type ConnectorEnvVars = { profileId: string; debug: string; cardComponent: string; + bankTransferDueDate: string; }; }; diff --git a/processor/src/utils/config.utils.ts b/processor/src/utils/config.utils.ts index 871029e..828230e 100644 --- a/processor/src/utils/config.utils.ts +++ b/processor/src/utils/config.utils.ts @@ -24,6 +24,7 @@ export const readConfiguration = () => { debug: process.env.DEBUG as string, profileId: process.env.MOLLIE_PROFILE_ID as string, cardComponent: process.env.MOLLIE_CARD_COMPONENT as string, + bankTransferDueDate: process.env.MOLLIE_BANK_TRANSFER_DUE_DATE as string, }, }; diff --git a/processor/src/utils/constant.utils.ts b/processor/src/utils/constant.utils.ts index f74dcae..82cfab4 100644 --- a/processor/src/utils/constant.utils.ts +++ b/processor/src/utils/constant.utils.ts @@ -44,3 +44,7 @@ export const ErrorMessages = { export const PAY_LATER_ENUMS = [PaymentMethod.klarnapaylater, PaymentMethod.klarnasliceit]; export const CancelStatusText = 'Cancelled from shop side'; + +export const DUE_DATE_PATTERN = /^(\d+)d$/; + +export const DEFAULT_DUE_DATE = 14; diff --git a/processor/src/utils/map.utils.ts b/processor/src/utils/map.utils.ts index 17e2bc9..705968a 100644 --- a/processor/src/utils/map.utils.ts +++ b/processor/src/utils/map.utils.ts @@ -1,11 +1,12 @@ import { CustomFields } from './constant.utils'; import { logger } from './logger.utils'; -import { makeMollieAmount } from './mollie.utils'; +import { calculateDueDate, makeMollieAmount } from './mollie.utils'; import { CustomPaymentMethod, ParsedMethodsRequestType } from '../types/mollie.types'; import { Payment } from '@commercetools/platform-sdk'; import CustomError from '../errors/custom.error'; import { MethodsListParams, PaymentCreateParams, PaymentMethod } from '@mollie/api-client'; import { parseStringToJsonObject, removeEmptyProperties } from './app.utils'; +import { readConfiguration } from './config.utils'; const extractMethodsRequest = (ctPayment: Payment): ParsedMethodsRequestType | undefined => { return ctPayment?.custom?.fields?.[CustomFields.payment.request]; @@ -71,8 +72,7 @@ const getSpecificPaymentParams = (method: PaymentMethod | CustomPaymentMethod, p return { applePayPaymentToken: paymentRequest.applePayPaymentToken ?? '' }; case PaymentMethod.banktransfer: return { - dueDate: paymentRequest.dueDate ?? '', - billingEmail: paymentRequest.billingEmail ?? '', + dueDate: calculateDueDate(readConfiguration().mollie.bankTransferDueDate), }; case PaymentMethod.przelewy24: return { billingEmail: paymentRequest.billingEmail ?? '' }; diff --git a/processor/src/utils/mollie.utils.ts b/processor/src/utils/mollie.utils.ts index 4d15849..0fc1e4f 100644 --- a/processor/src/utils/mollie.utils.ts +++ b/processor/src/utils/mollie.utils.ts @@ -2,6 +2,9 @@ import { CentPrecisionMoney } from '@commercetools/platform-sdk'; import { Amount } from '@mollie/api-client/dist/types/src/data/global'; import { CTMoney, CTTransactionState } from '../types/commercetools.types'; import { PaymentStatus, RefundStatus } from '@mollie/api-client'; +import { DEFAULT_DUE_DATE, DUE_DATE_PATTERN } from './constant.utils'; +import { logger } from './logger.utils'; +import CustomError from '../errors/custom.error'; const convertCTToMollieAmountValue = (ctValue: number, fractionDigits = 2): string => { const divider = Math.pow(10, fractionDigits); @@ -94,3 +97,27 @@ export const shouldRefundStatusUpdate = ( } return shouldUpdate; }; + +export const calculateDueDate = (input?: string): string => { + if (!input) { + input = DEFAULT_DUE_DATE + 'd'; + } + + const match = input.match(DUE_DATE_PATTERN); + + if (match) { + const days = parseInt(match[1]); + if (!isNaN(days)) { + const today = new Date(); + const futureDate = new Date(today.getTime() + days * 24 * 60 * 60 * 1000); + + return futureDate.toISOString().split('T')[0] as string; + } + } + + const errorMessage = `SCTM - calculateDueDate - Failed to calculate the due date, input: ${input}`; + + logger.error(errorMessage); + + throw new CustomError(400, errorMessage); +} diff --git a/processor/src/validators/env.validators.ts b/processor/src/validators/env.validators.ts index 09967ae..95d5ef5 100644 --- a/processor/src/validators/env.validators.ts +++ b/processor/src/validators/env.validators.ts @@ -1,4 +1,4 @@ -import { optional, standardKey, standardString, region } from './helpers.validators'; +import { optional, standardKey, standardString, region, standardDueDate } from './helpers.validators'; /** * Create here your own validators @@ -102,6 +102,14 @@ const envValidators = [ max: 4, }, ), + standardDueDate( + ['mollie', 'bankTransferDueDate'], + { + code: 'InvalidBankTransferDueDate', + message: 'Bank transfer due date must be from 1d to 100d, the number must be an integer. If it was not set, the default will be 14d', + referencedBy: 'environmentVariables', + }, + ), ]; export default envValidators; diff --git a/processor/src/validators/helpers.validators.ts b/processor/src/validators/helpers.validators.ts index 528f2c0..4fe74c9 100644 --- a/processor/src/validators/helpers.validators.ts +++ b/processor/src/validators/helpers.validators.ts @@ -1,8 +1,9 @@ // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-nocheck -import validator from 'validator'; +import validator, { isInt } from 'validator'; import { ValidatorCreator, Wrapper } from '../types/index.types'; +import { DUE_DATE_PATTERN } from '../utils/constant.utils'; /** * File used to create helpers to validate the fields @@ -20,6 +21,29 @@ export const standardString: ValidatorCreator = (path, message, overrideConfig = export const standardEmail: ValidatorCreator = (path, message) => [path, [[required(validator.isEmail), message]]]; +export const standardDueDate = (path, message) => [ + path, + [ + [ + required((value) => { + if (!value) { + return true; + } + + const match = value.match(DUE_DATE_PATTERN); + + if (match) { + const days = parseInt(match[1]); + + return days >= 1 && days <= 100; + } + + return false; + }), message + ] + ] +] + export const standardNaturalNumber = (path, message) => [ path, [[required((value) => validator.isNumeric(String(value), { no_symbols: true })), message]], diff --git a/processor/src/validators/payment.validators.ts b/processor/src/validators/payment.validators.ts index 0ace696..b63d151 100644 --- a/processor/src/validators/payment.validators.ts +++ b/processor/src/validators/payment.validators.ts @@ -264,6 +264,26 @@ export const checkPaymentMethodSpecificParameters = (ctPayment: CTPayment, metho break; } + case MolliePaymentMethods.banktransfer: { + if (!paymentCustomFields?.billingAddress || !paymentCustomFields?.billingAddress?.email) { + logger.error(`SCTM - PAYMENT PROCESSING - email is required for payment method banktransfer. Please make sure you have sent it in billingAddress.email of the custom field`, { + commerceToolsPayment: ctPayment, + }); + + throw new CustomError(400, 'SCTM - PAYMENT PROCESSING - email is required for payment method banktransfer. Please make sure you have sent it in billingAddress.email of the custom field'); + } + + if (!validateEmail(paymentCustomFields.billingAddress.email)) { + logger.error(`SCTM - PAYMENT PROCESSING - email must be a valid email address`, { + commerceToolsPayment: ctPayment, + }); + + throw new CustomError(400, 'SCTM - PAYMENT PROCESSING - email must be a valid email address'); + } + + break; + } + case CustomPaymentMethod.blik: if (ctPayment.amountPlanned.currencyCode.toLowerCase() !== 'pln') { logger.error(`SCTM - PAYMENT PROCESSING - Currency Code must be PLN for payment method BLIK`, { diff --git a/processor/tests/utils/config.utils.spec.ts b/processor/tests/utils/config.utils.spec.ts index 9a71f63..3aee51e 100644 --- a/processor/tests/utils/config.utils.spec.ts +++ b/processor/tests/utils/config.utils.spec.ts @@ -1,6 +1,9 @@ import { readConfiguration } from '../../src/utils/config.utils'; import CustomError from '../../src/errors/custom.error'; -import { describe, expect, test } from '@jest/globals'; +import { describe, expect, test, beforeEach } from '@jest/globals'; +import * as dotenv from 'dotenv'; + +const env = process.env; describe('Test src/utils/config.utils.ts', () => { test('should return the correct configuration when all env vars are valid', () => { @@ -20,6 +23,7 @@ describe('Test src/utils/config.utils.ts', () => { debug: process.env.DEBUG, profileId: process.env.MOLLIE_PROFILE_ID, cardComponent: process.env.MOLLIE_CARD_COMPONENT, + bankTransferDueDate: process.env.MOLLIE_BANK_TRANSFER_DUE_DATE, }, }); }); @@ -73,4 +77,9 @@ describe('Test src/utils/config.utils.ts', () => { delete process.env.CONNECTOR_MODE; expect(() => readConfiguration()).toThrow(CustomError); }); + + test('should throw an error when MOLLIE_BANK_TRANSFER_DUE_DATE is invalid', () => { + process.env.MOLLIE_BANK_TRANSFER_DUE_DATE = 'dummy'; + expect(() => readConfiguration()).toThrow(CustomError); + }) }); diff --git a/processor/tests/utils/constant.utils.spec.ts b/processor/tests/utils/constant.utils.spec.ts index 77654d0..e5bfac0 100644 --- a/processor/tests/utils/constant.utils.spec.ts +++ b/processor/tests/utils/constant.utils.spec.ts @@ -7,6 +7,8 @@ import { LIBRARY_NAME, LIBRARY_VERSION, PAY_LATER_ENUMS, + DUE_DATE_PATTERN, + DEFAULT_DUE_DATE, } from '../../src/utils/constant.utils'; import { version } from '../../package.json'; @@ -67,4 +69,13 @@ describe('Test constant.utils.ts', () => { expect(PAY_LATER_ENUMS).toContain('klarnapaylater'); expect(PAY_LATER_ENUMS).toContain('klarnasliceit'); }); + + test('should return correct {DUE_DATE_PATTERN} pattern', () => { + expect(DUE_DATE_PATTERN).toBeDefined(); + }); + + test('should return correct {DEFAULT_DUE_DATE} pattern', () => { + expect(DEFAULT_DUE_DATE).toBeDefined(); + expect(DEFAULT_DUE_DATE).toBe(14); + }); }); diff --git a/processor/tests/utils/map.utils.spec.ts b/processor/tests/utils/map.utils.spec.ts index e8d1ed1..87cf5e2 100644 --- a/processor/tests/utils/map.utils.spec.ts +++ b/processor/tests/utils/map.utils.spec.ts @@ -1,13 +1,21 @@ -import { describe, test, expect, it } from '@jest/globals'; +import { describe, test, expect, it, jest } from '@jest/globals'; import { createMollieCreatePaymentParams, mapCommercetoolsPaymentCustomFieldsToMollieListParams, } from '../../src/utils/map.utils'; import { Payment } from '@commercetools/platform-sdk'; import { MethodsListParams, PaymentCreateParams, PaymentMethod } from '@mollie/api-client'; -import { makeMollieAmount } from '../../src/utils/mollie.utils'; +import { calculateDueDate, makeMollieAmount } from '../../src/utils/mollie.utils'; import { CustomPaymentMethod } from '../../src/types/mollie.types'; +jest.mock('../../src/utils/mollie.utils.ts', () => ({ + // @ts-expect-error ignore type error + ...jest.requireActual('../../src/utils/mollie.utils.ts'), + // __esModule: true, + calculateDueDate: jest.fn() + +})); + describe('Test map.utils.ts', () => { let mockCtPayment: Payment; let mockMolObject: MethodsListParams; @@ -267,8 +275,9 @@ describe('createMollieCreatePaymentParams', () => { locale: 'en_GB', redirectUrl: 'https://example.com/success', webhookUrl: 'https://example.com/webhook', - dueDate: '2024-01-01', - billingEmail: 'test@mollie.com', + billingAddress: { + email: 'test@mollie.com' + }, }; const CTPayment: Payment = { @@ -300,7 +309,11 @@ describe('createMollieCreatePaymentParams', () => { }; const extensionUrl = 'https://example.com/webhook'; + const dueDate = '2024-01-01'; + (calculateDueDate as jest.Mock).mockReturnValueOnce(dueDate); + const mollieCreatePaymentParams: PaymentCreateParams = createMollieCreatePaymentParams(CTPayment, extensionUrl); + expect(mollieCreatePaymentParams).toEqual({ method: PaymentMethod.banktransfer, amount: { @@ -311,8 +324,8 @@ describe('createMollieCreatePaymentParams', () => { redirectUrl: customFieldObject.redirectUrl, webhookUrl: extensionUrl, description: customFieldObject.description, - dueDate: customFieldObject.dueDate, - billingEmail: customFieldObject.billingEmail, + billingAddress: customFieldObject.billingAddress, + dueDate }); }); diff --git a/processor/tests/utils/mollie.utils.spec.ts b/processor/tests/utils/mollie.utils.spec.ts index f53791d..bca4c80 100644 --- a/processor/tests/utils/mollie.utils.spec.ts +++ b/processor/tests/utils/mollie.utils.spec.ts @@ -7,9 +7,12 @@ import { isPayment, shouldPaymentStatusUpdate, shouldRefundStatusUpdate, + calculateDueDate, } from '../../src/utils/mollie.utils'; import { Amount } from '@mollie/api-client/dist/types/src/data/global'; -import { expect, describe, it } from '@jest/globals'; +import { expect, describe, it, test, jest } from '@jest/globals'; +import { logger } from '../../src/utils/logger.utils'; +import CustomError from '../../src/errors/custom.error'; describe('Test mollie.utils.ts', () => { describe('convertCTToMollieAmountValue', () => { @@ -179,4 +182,29 @@ describe('Test mollie.utils.ts', () => { expect(shouldRefundStatusUpdate('unknown' as RefundStatus, CTTransactionState.Pending)).toBe(false); }); }); + + describe('Test calculateDueDate', () => { + test('return the date which is 14 days later in format YYYY-MM-DD when the input is not defined', () => { + jest.useFakeTimers().setSystemTime(new Date('2024-01-01')); + + expect(calculateDueDate()).toEqual('2024-01-15'); + }); + + test('return the date which is to day + input day in format YYYY-MM-DD when the input is defined', () => { + jest.useFakeTimers().setSystemTime(new Date('2024-01-01')); + + expect(calculateDueDate('5d')).toEqual('2024-01-06'); + }); + + test('should throw error if no matches', () => { + try { + calculateDueDate('5') + } catch (error: unknown) { + expect(logger.error).toBeCalledTimes(1); + expect(logger.error).toBeCalledWith('SCTM - calculateDueDate - Failed to calculate the due date, input: 5'); + + expect(error).toBeInstanceOf(CustomError); + } + }) + }) }); diff --git a/processor/tests/validators/helpers.validators.spec.ts b/processor/tests/validators/helpers.validators.spec.ts index aa624c2..eaf3a18 100644 --- a/processor/tests/validators/helpers.validators.spec.ts +++ b/processor/tests/validators/helpers.validators.spec.ts @@ -1,4 +1,5 @@ -import { describe, test, expect, jest } from '@jest/globals'; +import { standardDueDate } from './../../src/validators/helpers.validators'; +import { describe, test, expect, jest, it } from '@jest/globals'; import { array, standardEmail, @@ -10,7 +11,7 @@ import { optional, region, } from '../../src/validators/helpers.validators'; -import { Message } from '../../src/types/index.types'; +import { ConnectorEnvVars, Message } from '../../src/types/index.types'; import envValidators from '../../src/validators/env.validators'; const mockObject = { @@ -67,6 +68,14 @@ const mockObject = { referencedBy: 'environmentVariables', } as Message, }, + standardDueDate: { + path: ['./demo/path/dueDate'] as string[], + message: { + code: 'InvalidBankTransferDueDate', + message: 'Bank transfer due date must be from 1d to 100d, the number must be an integer. If it was not set, the default will be 14d', + referencedBy: 'environmentVariables', + } as Message, + } }; const mockResponse = { @@ -98,6 +107,19 @@ const mockResponse = { ], ], ], + standardDueDate: [ + ['./demo/path/dueDate'], + [ + [ + [jest.fn()], + { + code: 'InvalidBankTransferDueDate', + message: 'Bank transfer due date must be from 1d to 100d, the number must be an integer. If it was not set, the default will be 14d', + referencedBy: 'environmentVariables', + }, + ], + ], + ], standardNaturalNumber: [ ['./demo/path/naturalNumber'], [ @@ -239,6 +261,7 @@ describe('Test helpers.validators.ts', () => { debug: (process.env.DEBUG ?? '0') as string, profileId: process.env.MOLLIE_PROFILE_ID as string, cardComponent: (process.env.MOLLIE_CARD_COMPONENT ?? '0') as string, + bankTransferDueDate: process.env.MOLLIE_BANK_TRANSFER_DUE_DATE }, }; const error = getValidateMessages(envValidators, vars); @@ -262,6 +285,7 @@ describe('Test helpers.validators.ts', () => { debug: (process.env.DEBUG ?? '0') as string, profileId: process.env.MOLLIE_PROFILE_ID as string, cardComponent: (process.env.MOLLIE_CARD_COMPONENT ?? '0') as string, + bankTransferDueDate: process.env.MOLLIE_BANK_TRANSFER_DUE_DATE }, }; const error = getValidateMessages(envValidators, vars); @@ -299,4 +323,106 @@ describe('Test helpers.validators.ts', () => { expect(response[0]).toStrictEqual(mockResponse.region[0]); expect(response[1][0][1]).toStrictEqual(mockResponse.region[1][0][1]); }); + + test('call standardDuedate', async () => { + const response = standardDueDate(mockObject.standardDueDate.path, mockObject.standardDueDate.message); + expect(response).toBeDefined(); + expect(response[0]).toStrictEqual(mockResponse.standardDueDate[0]); + expect(response[1][0][1]).toStrictEqual(mockResponse.standardDueDate[1][0][1]); + }); }); + +describe('test getValidateMessages', () => { + it('should able to return suitable error message when MOLLIE_BANK_TRANSFER_DUE_DATE is invalid', () => { + const envVars: ConnectorEnvVars = { + commerceTools: { + clientId: process.env.CTP_CLIENT_ID as string, + clientSecret: process.env.CTP_CLIENT_SECRET as string, + projectKey: process.env.CTP_PROJECT_KEY as string, + scope: process.env.CTP_SCOPE as string, + region: process.env.CTP_REGION as string, + }, + mollie: { + testApiKey: process.env.MOLLIE_API_TEST_KEY as string, + liveApiKey: process.env.MOLLIE_API_LIVE_KEY as string, + mode: process.env.CONNECTOR_MODE as string, + debug: process.env.DEBUG as string, + profileId: process.env.MOLLIE_PROFILE_ID as string, + cardComponent: process.env.MOLLIE_CARD_COMPONENT as string, + bankTransferDueDate: 'dummy', + }, + }; + + const result = getValidateMessages(envValidators, envVars); + + expect(result).toEqual([ + { + code: 'InvalidBankTransferDueDate', + message: 'Bank transfer due date must be from 1d to 100d, the number must be an integer. If it was not set, the default will be 14d', + referencedBy: 'environmentVariables' + } + ]) + }) + + it('should able to return suitable error message when MOLLIE_BANK_TRANSFER_DUE_DATE is invalid', () => { + const envVars: ConnectorEnvVars = { + commerceTools: { + clientId: process.env.CTP_CLIENT_ID as string, + clientSecret: process.env.CTP_CLIENT_SECRET as string, + projectKey: process.env.CTP_PROJECT_KEY as string, + scope: process.env.CTP_SCOPE as string, + region: process.env.CTP_REGION as string, + }, + mollie: { + testApiKey: process.env.MOLLIE_API_TEST_KEY as string, + liveApiKey: process.env.MOLLIE_API_LIVE_KEY as string, + mode: process.env.CONNECTOR_MODE as string, + debug: process.env.DEBUG as string, + profileId: process.env.MOLLIE_PROFILE_ID as string, + cardComponent: process.env.MOLLIE_CARD_COMPONENT as string, + bankTransferDueDate: 'dummy', + }, + }; + + const result = getValidateMessages(envValidators, envVars); + + expect(result).toEqual([ + { + code: 'InvalidBankTransferDueDate', + message: 'Bank transfer due date must be from 1d to 100d, the number must be an integer. If it was not set, the default will be 14d', + referencedBy: 'environmentVariables' + } + ]) + }) + + it('should able to return suitable error message when MOLLIE_BANK_TRANSFER_DUE_DATE is more than 100 days', () => { + const envVars: ConnectorEnvVars = { + commerceTools: { + clientId: process.env.CTP_CLIENT_ID as string, + clientSecret: process.env.CTP_CLIENT_SECRET as string, + projectKey: process.env.CTP_PROJECT_KEY as string, + scope: process.env.CTP_SCOPE as string, + region: process.env.CTP_REGION as string, + }, + mollie: { + testApiKey: process.env.MOLLIE_API_TEST_KEY as string, + liveApiKey: process.env.MOLLIE_API_LIVE_KEY as string, + mode: process.env.CONNECTOR_MODE as string, + debug: process.env.DEBUG as string, + profileId: process.env.MOLLIE_PROFILE_ID as string, + cardComponent: process.env.MOLLIE_CARD_COMPONENT as string, + bankTransferDueDate: '101d', + }, + }; + + const result = getValidateMessages(envValidators, envVars); + + expect(result).toEqual([ + { + code: 'InvalidBankTransferDueDate', + message: 'Bank transfer due date must be from 1d to 100d, the number must be an integer. If it was not set, the default will be 14d', + referencedBy: 'environmentVariables' + } + ]) + }) +}) diff --git a/processor/tests/validators/payment.validators.spec.ts b/processor/tests/validators/payment.validators.spec.ts index 7f72c62..4167482 100644 --- a/processor/tests/validators/payment.validators.spec.ts +++ b/processor/tests/validators/payment.validators.spec.ts @@ -25,6 +25,7 @@ jest.mock('@mollie/api-client', () => ({ dummy: 'dummy', creditcard: 'creditcard', giftcard: 'giftcard', + banktransfer: 'banktransfer', }, })); @@ -445,6 +446,206 @@ describe('checkPaymentMethodSpecificParameters', () => { ); }); + it('should throw an error if the payment method is banktransfer and the billingAddress is not specified', () => { + const paymentRequest = { + description: 'Test', + }; + + const CTPayment: Payment = { + id: '5c8b0375-305a-4f19-ae8e-07806b101999', + version: 1, + createdAt: '2024-07-04T14:07:35.625Z', + lastModifiedAt: '2024-07-04T14:07:35.625Z', + amountPlanned: { + type: 'centPrecision', + currencyCode: 'EUR', + centAmount: 1000, + fractionDigits: 2, + }, + paymentStatus: {}, + transactions: [], + interfaceInteractions: [], + paymentMethodInfo: { + method: 'banktransfer', + }, + custom: { + type: { + typeId: 'type', + id: 'sctm-payment-custom-fields', + }, + fields: { + sctm_create_payment_request: JSON.stringify(paymentRequest), + }, + }, + }; + + try { + checkPaymentMethodSpecificParameters(CTPayment, CTPayment.paymentMethodInfo.method as string); + } catch (error: unknown) { + expect(error).toBeInstanceOf(CustomError); + expect((error as CustomError).message).toBe( + 'SCTM - PAYMENT PROCESSING - email is required for payment method banktransfer. Please make sure you have sent it in billingAddress.email of the custom field', + ); + expect(logger.error).toBeCalledTimes(1); + expect(logger.error).toBeCalledWith( + `SCTM - PAYMENT PROCESSING - email is required for payment method banktransfer. Please make sure you have sent it in billingAddress.email of the custom field`, + { + commerceToolsPayment: CTPayment, + }, + ); + } + }); + + it('should throw an error if the payment method is banktransfer and the billingAddress is specified but does not provide email', () => { + const paymentRequest = { + description: 'Test', + billingAddress: { + title: 'Billing address title' + } + }; + + const CTPayment: Payment = { + id: '5c8b0375-305a-4f19-ae8e-07806b101999', + version: 1, + createdAt: '2024-07-04T14:07:35.625Z', + lastModifiedAt: '2024-07-04T14:07:35.625Z', + amountPlanned: { + type: 'centPrecision', + currencyCode: 'EUR', + centAmount: 1000, + fractionDigits: 2, + }, + paymentStatus: {}, + transactions: [], + interfaceInteractions: [], + paymentMethodInfo: { + method: 'banktransfer', + }, + custom: { + type: { + typeId: 'type', + id: 'sctm-payment-custom-fields', + }, + fields: { + sctm_create_payment_request: JSON.stringify(paymentRequest), + }, + }, + }; + + try { + checkPaymentMethodSpecificParameters(CTPayment, CTPayment.paymentMethodInfo.method as string); + } catch (error: unknown) { + expect(error).toBeInstanceOf(CustomError); + expect((error as CustomError).message).toBe( + 'SCTM - PAYMENT PROCESSING - email is required for payment method banktransfer. Please make sure you have sent it in billingAddress.email of the custom field', + ); + expect(logger.error).toBeCalledTimes(1); + expect(logger.error).toBeCalledWith( + `SCTM - PAYMENT PROCESSING - email is required for payment method banktransfer. Please make sure you have sent it in billingAddress.email of the custom field`, + { + commerceToolsPayment: CTPayment, + }, + ); + } + }); + + it('should throw an error if the payment method is banktransfer and the email is not valid', () => { + const paymentRequest = { + description: 'Test', + billingAddress: { + title: 'Billing address title', + email: 'dummy string' + } + }; + + const CTPayment: Payment = { + id: '5c8b0375-305a-4f19-ae8e-07806b101999', + version: 1, + createdAt: '2024-07-04T14:07:35.625Z', + lastModifiedAt: '2024-07-04T14:07:35.625Z', + amountPlanned: { + type: 'centPrecision', + currencyCode: 'EUR', + centAmount: 1000, + fractionDigits: 2, + }, + paymentStatus: {}, + transactions: [], + interfaceInteractions: [], + paymentMethodInfo: { + method: 'banktransfer', + }, + custom: { + type: { + typeId: 'type', + id: 'sctm-payment-custom-fields', + }, + fields: { + sctm_create_payment_request: JSON.stringify(paymentRequest), + }, + }, + }; + + try { + checkPaymentMethodSpecificParameters(CTPayment, CTPayment.paymentMethodInfo.method as string); + } catch (error: unknown) { + expect(error).toBeInstanceOf(CustomError); + expect((error as CustomError).message).toBe( + 'SCTM - PAYMENT PROCESSING - email must be a valid email address', + ); + expect(logger.error).toBeCalledTimes(1); + expect(logger.error).toBeCalledWith( + `SCTM - PAYMENT PROCESSING - email must be a valid email address`, + { + commerceToolsPayment: CTPayment, + }, + ); + } + }); + + it('should should not throw any error or terminate the process if the payment method is banktransfer and the email is provided correctly', () => { + const paymentRequest = { + description: 'Test', + billingAddress: { + title: 'Billing address title', + email: 'test@gmail.com' + } + }; + + const CTPayment: Payment = { + id: '5c8b0375-305a-4f19-ae8e-07806b101999', + version: 1, + createdAt: '2024-07-04T14:07:35.625Z', + lastModifiedAt: '2024-07-04T14:07:35.625Z', + amountPlanned: { + type: 'centPrecision', + currencyCode: 'EUR', + centAmount: 1000, + fractionDigits: 2, + }, + paymentStatus: {}, + transactions: [], + interfaceInteractions: [], + paymentMethodInfo: { + method: 'banktransfer', + }, + custom: { + type: { + typeId: 'type', + id: 'sctm-payment-custom-fields', + }, + fields: { + sctm_create_payment_request: JSON.stringify(paymentRequest), + }, + }, + }; + + expect(checkPaymentMethodSpecificParameters(CTPayment, CTPayment.paymentMethodInfo.method as string)).toBe( + undefined, + ); + expect(logger.error).toBeCalledTimes(0); + }); + it('should throw an error if the payment method is blik and the currency code is not PLN', () => { const CTPayment: Payment = { id: '5c8b0375-305a-4f19-ae8e-07806b101999', From 8b8956d0e16421d3af270ba85d94301b05b9ede6 Mon Sep 17 00:00:00 2001 From: Nghia Tran Date: Sat, 10 Aug 2024 22:40:40 +0700 Subject: [PATCH 2/2] Fix lint --- processor/src/utils/mollie.utils.ts | 14 ++--- processor/src/validators/env.validators.ts | 14 +++-- .../src/validators/helpers.validators.ts | 13 ++--- .../src/validators/payment.validators.ts | 16 ++++-- processor/tests/utils/config.utils.spec.ts | 5 +- processor/tests/utils/map.utils.spec.ts | 7 ++- processor/tests/utils/mollie.utils.spec.ts | 6 +-- .../validators/helpers.validators.spec.ts | 53 ++++++++++--------- .../validators/payment.validators.spec.ts | 25 ++++----- 9 files changed, 78 insertions(+), 75 deletions(-) diff --git a/processor/src/utils/mollie.utils.ts b/processor/src/utils/mollie.utils.ts index 0fc1e4f..31d7d3b 100644 --- a/processor/src/utils/mollie.utils.ts +++ b/processor/src/utils/mollie.utils.ts @@ -106,13 +106,13 @@ export const calculateDueDate = (input?: string): string => { const match = input.match(DUE_DATE_PATTERN); if (match) { - const days = parseInt(match[1]); - if (!isNaN(days)) { - const today = new Date(); - const futureDate = new Date(today.getTime() + days * 24 * 60 * 60 * 1000); + const days = parseInt(match[1]); + if (!isNaN(days)) { + const today = new Date(); + const futureDate = new Date(today.getTime() + days * 24 * 60 * 60 * 1000); - return futureDate.toISOString().split('T')[0] as string; - } + return futureDate.toISOString().split('T')[0] as string; + } } const errorMessage = `SCTM - calculateDueDate - Failed to calculate the due date, input: ${input}`; @@ -120,4 +120,4 @@ export const calculateDueDate = (input?: string): string => { logger.error(errorMessage); throw new CustomError(400, errorMessage); -} +}; diff --git a/processor/src/validators/env.validators.ts b/processor/src/validators/env.validators.ts index 95d5ef5..3d4e434 100644 --- a/processor/src/validators/env.validators.ts +++ b/processor/src/validators/env.validators.ts @@ -102,14 +102,12 @@ const envValidators = [ max: 4, }, ), - standardDueDate( - ['mollie', 'bankTransferDueDate'], - { - code: 'InvalidBankTransferDueDate', - message: 'Bank transfer due date must be from 1d to 100d, the number must be an integer. If it was not set, the default will be 14d', - referencedBy: 'environmentVariables', - }, - ), + standardDueDate(['mollie', 'bankTransferDueDate'], { + code: 'InvalidBankTransferDueDate', + message: + 'Bank transfer due date must be from 1d to 100d, the number must be an integer. If it was not set, the default will be 14d', + referencedBy: 'environmentVariables', + }), ]; export default envValidators; diff --git a/processor/src/validators/helpers.validators.ts b/processor/src/validators/helpers.validators.ts index 4fe74c9..efb25f8 100644 --- a/processor/src/validators/helpers.validators.ts +++ b/processor/src/validators/helpers.validators.ts @@ -1,7 +1,7 @@ // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-nocheck -import validator, { isInt } from 'validator'; +import validator from 'validator'; import { ValidatorCreator, Wrapper } from '../types/index.types'; import { DUE_DATE_PATTERN } from '../utils/constant.utils'; @@ -34,15 +34,16 @@ export const standardDueDate = (path, message) => [ if (match) { const days = parseInt(match[1]); - + return days >= 1 && days <= 100; } return false; - }), message - ] - ] -] + }), + message, + ], + ], +]; export const standardNaturalNumber = (path, message) => [ path, diff --git a/processor/src/validators/payment.validators.ts b/processor/src/validators/payment.validators.ts index b63d151..f4ab81d 100644 --- a/processor/src/validators/payment.validators.ts +++ b/processor/src/validators/payment.validators.ts @@ -266,11 +266,17 @@ export const checkPaymentMethodSpecificParameters = (ctPayment: CTPayment, metho case MolliePaymentMethods.banktransfer: { if (!paymentCustomFields?.billingAddress || !paymentCustomFields?.billingAddress?.email) { - logger.error(`SCTM - PAYMENT PROCESSING - email is required for payment method banktransfer. Please make sure you have sent it in billingAddress.email of the custom field`, { - commerceToolsPayment: ctPayment, - }); - - throw new CustomError(400, 'SCTM - PAYMENT PROCESSING - email is required for payment method banktransfer. Please make sure you have sent it in billingAddress.email of the custom field'); + logger.error( + `SCTM - PAYMENT PROCESSING - email is required for payment method banktransfer. Please make sure you have sent it in billingAddress.email of the custom field`, + { + commerceToolsPayment: ctPayment, + }, + ); + + throw new CustomError( + 400, + 'SCTM - PAYMENT PROCESSING - email is required for payment method banktransfer. Please make sure you have sent it in billingAddress.email of the custom field', + ); } if (!validateEmail(paymentCustomFields.billingAddress.email)) { diff --git a/processor/tests/utils/config.utils.spec.ts b/processor/tests/utils/config.utils.spec.ts index 3aee51e..4350e26 100644 --- a/processor/tests/utils/config.utils.spec.ts +++ b/processor/tests/utils/config.utils.spec.ts @@ -1,7 +1,6 @@ import { readConfiguration } from '../../src/utils/config.utils'; import CustomError from '../../src/errors/custom.error'; -import { describe, expect, test, beforeEach } from '@jest/globals'; -import * as dotenv from 'dotenv'; +import { describe, expect, test } from '@jest/globals'; const env = process.env; @@ -81,5 +80,5 @@ describe('Test src/utils/config.utils.ts', () => { test('should throw an error when MOLLIE_BANK_TRANSFER_DUE_DATE is invalid', () => { process.env.MOLLIE_BANK_TRANSFER_DUE_DATE = 'dummy'; expect(() => readConfiguration()).toThrow(CustomError); - }) + }); }); diff --git a/processor/tests/utils/map.utils.spec.ts b/processor/tests/utils/map.utils.spec.ts index 87cf5e2..a22a056 100644 --- a/processor/tests/utils/map.utils.spec.ts +++ b/processor/tests/utils/map.utils.spec.ts @@ -12,8 +12,7 @@ jest.mock('../../src/utils/mollie.utils.ts', () => ({ // @ts-expect-error ignore type error ...jest.requireActual('../../src/utils/mollie.utils.ts'), // __esModule: true, - calculateDueDate: jest.fn() - + calculateDueDate: jest.fn(), })); describe('Test map.utils.ts', () => { @@ -276,7 +275,7 @@ describe('createMollieCreatePaymentParams', () => { redirectUrl: 'https://example.com/success', webhookUrl: 'https://example.com/webhook', billingAddress: { - email: 'test@mollie.com' + email: 'test@mollie.com', }, }; @@ -325,7 +324,7 @@ describe('createMollieCreatePaymentParams', () => { webhookUrl: extensionUrl, description: customFieldObject.description, billingAddress: customFieldObject.billingAddress, - dueDate + dueDate, }); }); diff --git a/processor/tests/utils/mollie.utils.spec.ts b/processor/tests/utils/mollie.utils.spec.ts index bca4c80..7863481 100644 --- a/processor/tests/utils/mollie.utils.spec.ts +++ b/processor/tests/utils/mollie.utils.spec.ts @@ -198,13 +198,13 @@ describe('Test mollie.utils.ts', () => { test('should throw error if no matches', () => { try { - calculateDueDate('5') + calculateDueDate('5'); } catch (error: unknown) { expect(logger.error).toBeCalledTimes(1); expect(logger.error).toBeCalledWith('SCTM - calculateDueDate - Failed to calculate the due date, input: 5'); expect(error).toBeInstanceOf(CustomError); } - }) - }) + }); + }); }); diff --git a/processor/tests/validators/helpers.validators.spec.ts b/processor/tests/validators/helpers.validators.spec.ts index eaf3a18..8ee84bf 100644 --- a/processor/tests/validators/helpers.validators.spec.ts +++ b/processor/tests/validators/helpers.validators.spec.ts @@ -1,6 +1,5 @@ -import { standardDueDate } from './../../src/validators/helpers.validators'; -import { describe, test, expect, jest, it } from '@jest/globals'; import { + standardDueDate, array, standardEmail, standardNaturalNumber, @@ -10,7 +9,8 @@ import { getValidateMessages, optional, region, -} from '../../src/validators/helpers.validators'; +} from './../../src/validators/helpers.validators'; +import { describe, test, expect, jest, it } from '@jest/globals'; import { ConnectorEnvVars, Message } from '../../src/types/index.types'; import envValidators from '../../src/validators/env.validators'; @@ -72,10 +72,11 @@ const mockObject = { path: ['./demo/path/dueDate'] as string[], message: { code: 'InvalidBankTransferDueDate', - message: 'Bank transfer due date must be from 1d to 100d, the number must be an integer. If it was not set, the default will be 14d', + message: + 'Bank transfer due date must be from 1d to 100d, the number must be an integer. If it was not set, the default will be 14d', referencedBy: 'environmentVariables', } as Message, - } + }, }; const mockResponse = { @@ -114,7 +115,8 @@ const mockResponse = { [jest.fn()], { code: 'InvalidBankTransferDueDate', - message: 'Bank transfer due date must be from 1d to 100d, the number must be an integer. If it was not set, the default will be 14d', + message: + 'Bank transfer due date must be from 1d to 100d, the number must be an integer. If it was not set, the default will be 14d', referencedBy: 'environmentVariables', }, ], @@ -261,7 +263,7 @@ describe('Test helpers.validators.ts', () => { debug: (process.env.DEBUG ?? '0') as string, profileId: process.env.MOLLIE_PROFILE_ID as string, cardComponent: (process.env.MOLLIE_CARD_COMPONENT ?? '0') as string, - bankTransferDueDate: process.env.MOLLIE_BANK_TRANSFER_DUE_DATE + bankTransferDueDate: process.env.MOLLIE_BANK_TRANSFER_DUE_DATE, }, }; const error = getValidateMessages(envValidators, vars); @@ -285,7 +287,7 @@ describe('Test helpers.validators.ts', () => { debug: (process.env.DEBUG ?? '0') as string, profileId: process.env.MOLLIE_PROFILE_ID as string, cardComponent: (process.env.MOLLIE_CARD_COMPONENT ?? '0') as string, - bankTransferDueDate: process.env.MOLLIE_BANK_TRANSFER_DUE_DATE + bankTransferDueDate: process.env.MOLLIE_BANK_TRANSFER_DUE_DATE, }, }; const error = getValidateMessages(envValidators, vars); @@ -358,11 +360,12 @@ describe('test getValidateMessages', () => { expect(result).toEqual([ { code: 'InvalidBankTransferDueDate', - message: 'Bank transfer due date must be from 1d to 100d, the number must be an integer. If it was not set, the default will be 14d', - referencedBy: 'environmentVariables' - } - ]) - }) + message: + 'Bank transfer due date must be from 1d to 100d, the number must be an integer. If it was not set, the default will be 14d', + referencedBy: 'environmentVariables', + }, + ]); + }); it('should able to return suitable error message when MOLLIE_BANK_TRANSFER_DUE_DATE is invalid', () => { const envVars: ConnectorEnvVars = { @@ -389,11 +392,12 @@ describe('test getValidateMessages', () => { expect(result).toEqual([ { code: 'InvalidBankTransferDueDate', - message: 'Bank transfer due date must be from 1d to 100d, the number must be an integer. If it was not set, the default will be 14d', - referencedBy: 'environmentVariables' - } - ]) - }) + message: + 'Bank transfer due date must be from 1d to 100d, the number must be an integer. If it was not set, the default will be 14d', + referencedBy: 'environmentVariables', + }, + ]); + }); it('should able to return suitable error message when MOLLIE_BANK_TRANSFER_DUE_DATE is more than 100 days', () => { const envVars: ConnectorEnvVars = { @@ -420,9 +424,10 @@ describe('test getValidateMessages', () => { expect(result).toEqual([ { code: 'InvalidBankTransferDueDate', - message: 'Bank transfer due date must be from 1d to 100d, the number must be an integer. If it was not set, the default will be 14d', - referencedBy: 'environmentVariables' - } - ]) - }) -}) + message: + 'Bank transfer due date must be from 1d to 100d, the number must be an integer. If it was not set, the default will be 14d', + referencedBy: 'environmentVariables', + }, + ]); + }); +}); diff --git a/processor/tests/validators/payment.validators.spec.ts b/processor/tests/validators/payment.validators.spec.ts index 4167482..b36918d 100644 --- a/processor/tests/validators/payment.validators.spec.ts +++ b/processor/tests/validators/payment.validators.spec.ts @@ -500,8 +500,8 @@ describe('checkPaymentMethodSpecificParameters', () => { const paymentRequest = { description: 'Test', billingAddress: { - title: 'Billing address title' - } + title: 'Billing address title', + }, }; const CTPayment: Payment = { @@ -554,8 +554,8 @@ describe('checkPaymentMethodSpecificParameters', () => { description: 'Test', billingAddress: { title: 'Billing address title', - email: 'dummy string' - } + email: 'dummy string', + }, }; const CTPayment: Payment = { @@ -590,16 +590,11 @@ describe('checkPaymentMethodSpecificParameters', () => { checkPaymentMethodSpecificParameters(CTPayment, CTPayment.paymentMethodInfo.method as string); } catch (error: unknown) { expect(error).toBeInstanceOf(CustomError); - expect((error as CustomError).message).toBe( - 'SCTM - PAYMENT PROCESSING - email must be a valid email address', - ); + expect((error as CustomError).message).toBe('SCTM - PAYMENT PROCESSING - email must be a valid email address'); expect(logger.error).toBeCalledTimes(1); - expect(logger.error).toBeCalledWith( - `SCTM - PAYMENT PROCESSING - email must be a valid email address`, - { - commerceToolsPayment: CTPayment, - }, - ); + expect(logger.error).toBeCalledWith(`SCTM - PAYMENT PROCESSING - email must be a valid email address`, { + commerceToolsPayment: CTPayment, + }); } }); @@ -608,8 +603,8 @@ describe('checkPaymentMethodSpecificParameters', () => { description: 'Test', billingAddress: { title: 'Billing address title', - email: 'test@gmail.com' - } + email: 'test@gmail.com', + }, }; const CTPayment: Payment = {