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..31d7d3b 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..3d4e434 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,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', + }), ]; export default envValidators; diff --git a/processor/src/validators/helpers.validators.ts b/processor/src/validators/helpers.validators.ts index 528f2c0..efb25f8 100644 --- a/processor/src/validators/helpers.validators.ts +++ b/processor/src/validators/helpers.validators.ts @@ -3,6 +3,7 @@ import validator 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,30 @@ 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..f4ab81d 100644 --- a/processor/src/validators/payment.validators.ts +++ b/processor/src/validators/payment.validators.ts @@ -264,6 +264,32 @@ 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..4350e26 100644 --- a/processor/tests/utils/config.utils.spec.ts +++ b/processor/tests/utils/config.utils.spec.ts @@ -2,6 +2,8 @@ import { readConfiguration } from '../../src/utils/config.utils'; import CustomError from '../../src/errors/custom.error'; import { describe, expect, test } from '@jest/globals'; +const env = process.env; + describe('Test src/utils/config.utils.ts', () => { test('should return the correct configuration when all env vars are valid', () => { const config = readConfiguration(); @@ -20,6 +22,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 +76,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..a22a056 100644 --- a/processor/tests/utils/map.utils.spec.ts +++ b/processor/tests/utils/map.utils.spec.ts @@ -1,13 +1,20 @@ -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 +274,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 +308,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 +323,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..7863481 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..8ee84bf 100644 --- a/processor/tests/validators/helpers.validators.spec.ts +++ b/processor/tests/validators/helpers.validators.spec.ts @@ -1,5 +1,5 @@ -import { describe, test, expect, jest } from '@jest/globals'; import { + standardDueDate, array, standardEmail, standardNaturalNumber, @@ -9,8 +9,9 @@ import { getValidateMessages, optional, region, -} from '../../src/validators/helpers.validators'; -import { Message } from '../../src/types/index.types'; +} 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'; const mockObject = { @@ -67,6 +68,15 @@ 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 +108,20 @@ 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 +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, }, }; const error = getValidateMessages(envValidators, vars); @@ -262,6 +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, }, }; const error = getValidateMessages(envValidators, vars); @@ -299,4 +325,109 @@ 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..b36918d 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,201 @@ 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',