Skip to content

Commit

Permalink
Merge pull request #8 from mollie/refactor
Browse files Browse the repository at this point in the history
Rearrange validation flow
  • Loading branch information
Tung-Huynh-Shopmacher authored Jul 19, 2024
2 parents fa85610 + 2efd722 commit f146c2a
Show file tree
Hide file tree
Showing 17 changed files with 133 additions and 5,186 deletions.
14 changes: 9 additions & 5 deletions connect.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,13 @@ deployAs:
configuration:
standardConfiguration:
- key: CTP_REGION
description: commercetools Composable Commerce API region
description: Commercetools Composable Commerce API region
required: true
default: "europe-west1.gcp"
- key: DEBUG
description: Debug mode (0 or 1)
required: false
default: "0"
securedConfiguration:
- key: MOLLIE_API_KEY
description: Mollie PSP API key
Expand All @@ -19,14 +23,14 @@ deployAs:
description: Mollie PSP profile ID
required: true
- key: CTP_PROJECT_KEY
description: commercetools Composable Commerce project key
description: Commercetools Composable Commerce project key
required: true
- key: CTP_CLIENT_ID
description: commercetools Composable Commerce client ID
description: Commercetools Composable Commerce client ID
required: true
- key: CTP_CLIENT_SECRET
description: commercetools Composable Commerce client secret
description: Commercetools Composable Commerce client secret
required: true
- key: CTP_SCOPE
description: commercetools Composable Commerce client scope
description: Commercetools Composable Commerce client scope
required: true
2 changes: 1 addition & 1 deletion processor/.env.example
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ CTP_AUTH_URL=https://auth.<YOUR_CTP_REGION>.commercetools.com
CTP_API_URL=https://api.<YOUR_CTP_REGION>.commercetools.com

## Mollie PSP credentials
MOLLIE_DEBUG=<INTEGER_VALUE> ## Either 1 for enable or 0 for disable
DEBUG=<INTEGER_VALUE> ## Either 1 for enable or 0 for disable
MOLLIE_API_KEY=<YOUR_MOLLIE_API_KEY>
MOLLIE_PROFILE_ID=<YOUR_MOLLIE_PROFILE_ID>

Expand Down
2 changes: 1 addition & 1 deletion processor/.env.jest
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,4 @@ CTP_REGION=europe-west1.gcp
## MOLLIE vars
MOLLIE_API_KEY=12345678901234567890123456789012
MOLLIE_PROFILE_ID=pfl_12345
MOLLIE_DEBUG=1
DEBUG=0
2 changes: 1 addition & 1 deletion processor/.nvmrc
Original file line number Diff line number Diff line change
@@ -1 +1 @@
16.16.0
18.12.0
27 changes: 20 additions & 7 deletions processor/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 3 additions & 2 deletions processor/package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "shopmacher-mollie-processor",
"description": "Integration between commercetools and mollie payment service provider",
"version": "0.0.8",
"version": "0.0.11",
"main": "index.js",
"private": true,
"scripts": {
Expand Down Expand Up @@ -30,7 +30,7 @@
"payment provider"
],
"engines": {
"node": ">=18.0.0"
"node": ">=18.0.0 <=20.9.0"
},
"resolutions": {
"axios": "1.6.8"
Expand Down Expand Up @@ -70,6 +70,7 @@
"dotenv": "^16.4.5",
"express": "^4.19.2",
"proxy-from-env": "^1.1.0",
"uuid": "^10.0.0",
"validator": "^13.12.0"
}
}
23 changes: 16 additions & 7 deletions processor/src/controllers/payment.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { PaymentReference, Payment } from '@commercetools/platform-sdk';
import { ConnectorActions } from '../utils/constant.utils';
import { validateCommerceToolsPaymentPayload } from '../validators/payment.validators';
import CustomError from '../errors/custom.error';
import SkipError from '../errors/skip.error';

/**
* Handle the cart controller according to the action
Expand All @@ -19,20 +20,28 @@ export const paymentController = async (
): Promise<ControllerResponseType> => {
const ctPayment: Payment = JSON.parse(JSON.stringify(resource)).obj;

validateCommerceToolsPaymentPayload(action, ctPayment);

const controllerAction = determinePaymentAction(ctPayment);

if (controllerAction.errorMessage !== '') {
throw new CustomError(400, controllerAction.errorMessage as string);
}

if (controllerAction.action === ConnectorActions.NoAction) {
throw new SkipError('SCTM - No payment actions matched');
}

validateCommerceToolsPaymentPayload(action, controllerAction.action, ctPayment);

switch (controllerAction.action) {
case ConnectorActions.GetPaymentMethods:
return await handleListPaymentMethodsByPayment(ctPayment);
case ConnectorActions.CreatePayment:
return await handleCreatePayment(ctPayment);
case ConnectorActions.NoAction:
return {
statusCode: 200,
};
default:
throw new CustomError(400, controllerAction.errorMessage ?? '');
if (controllerAction.errorMessage === '') {
throw new SkipError('SCTM - No payment actions matched');
}

throw new CustomError(400, controllerAction.errorMessage as string);
}
};
5 changes: 3 additions & 2 deletions processor/src/controllers/processor.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { paymentController } from './payment.controller';
import CustomError from '../errors/custom.error';
import SkipError from '../errors/skip.error';
import { apiError } from '../api/error.api';
import { formatErrorResponse } from '../errors/mollie.error';

/**
* Exposed service endpoint.
Expand Down Expand Up @@ -44,8 +45,8 @@ export const post = async (request: Request, response: Response, next: NextFunct
}
if (error instanceof CustomError) {
return apiError(response, error.errors);
} else {
next(error);
}

return apiError(response, formatErrorResponse(error).errors);
}
};
3 changes: 1 addition & 2 deletions processor/src/service/payment.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,15 +42,14 @@ export const handleListPaymentMethodsByPayment = async (ctPayment: Payment): Pro
try {
const mollieOptions = await mapCommercetoolsPaymentCustomFieldsToMollieListParams(ctPayment);
const methods: List<Method> = await listPaymentMethods(mollieOptions);

const availableMethods = JSON.stringify({
count: methods.length,
methods: methods.length ? methods : [],
});

const ctUpdateActions: UpdateAction[] = [setCustomFields(CustomFields.payment.response, availableMethods)];

const hasCardPayment = methods.findIndex((method: Method) => method.id === PaymentMethod.creditcard);
const hasCardPayment = methods.find((method: Method) => method.id === PaymentMethod.creditcard);

if (hasCardPayment) {
ctUpdateActions.push(setCustomFields(CustomFields.payment.profileId, readConfiguration().mollie.profileId));
Expand Down
2 changes: 1 addition & 1 deletion processor/src/utils/config.utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ export const readConfiguration = () => {
},
mollie: {
apiKey: process.env.MOLLIE_API_KEY as string,
debug: process.env.MOLLIE_DEBUG as string,
debug: process.env.DEBUG as string,
profileId: process.env.MOLLIE_PROFILE_ID as string,
},
};
Expand Down
6 changes: 3 additions & 3 deletions processor/src/utils/paymentAction.utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ export const determinePaymentAction = (ctPayment?: Payment): DeterminePaymentAct
};
}

const { key, transactions } = ctPayment;
const { id, key, transactions } = ctPayment;

const initialChargeTransactions: CTTransaction[] = [];
const pendingChargeTransactions: CTTransaction[] = [];
Expand Down Expand Up @@ -70,15 +70,15 @@ export const determinePaymentAction = (ctPayment?: Payment): DeterminePaymentAct
break;

// Create Payment
case !!key &&
case (!!key || !!id) &&
initialChargeTransactions.length === 1 &&
!successChargeTransactions.length &&
!pendingChargeTransactions.length:
action = ConnectorActions.CreatePayment;
break;
default:
action = ConnectorActions.NoAction;
errorMessage = 'SCTM - No payment actions matched';
logger.warn('SCTM - No payment actions matched');
}

return {
Expand Down
23 changes: 15 additions & 8 deletions processor/src/validators/payment.validators.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { PaymentMethod as MolliePaymentMethods } from '@mollie/api-client';
import SkipError from '../errors/skip.error';
import CustomError from '../errors/custom.error';
import { logger } from '../utils/logger.utils';
import { CustomFields } from '../utils/constant.utils';
import { ConnectorActions, CustomFields } from '../utils/constant.utils';

/**
* Checks if the given action is either 'Create' or 'Update'.
Expand Down Expand Up @@ -51,12 +51,12 @@ export const hasValidPaymentMethod: (method: string | undefined) => boolean = (m
/**
* Checks the payment method input of a Commercetools Payment object.
*
* @param {CTPayment} CTPayment - The Commercetools Payment object to check.
* @return {true | CustomError} An object containing the validation result.
* The `isInvalid` property indicates if the payment method input is invalid.
* The `errorMessage` property contains the error message if the input is invalid.
* @param ctPayment
*/
export const checkPaymentMethodInput = (ctPayment: CTPayment): true | CustomError => {
export const checkPaymentMethodInput = (connectorAction: string, ctPayment: CTPayment): true | CustomError => {
const CTPaymentMethod = ctPayment.paymentMethodInfo?.method ?? '';
const [method] = CTPaymentMethod.split(',');

Expand Down Expand Up @@ -128,16 +128,23 @@ export const checkAmountPlanned = (ctPayment: CTPayment): true | CustomError =>
/**
* Validates the payload of a CommerceTools payment based on the provided action and payment object.
*
* @param {string} action - The action to perform on the payment.
* @param {CTPayment} CTPayment - The CommerceTools payment object to validate.
* @param {string} extensionAction - The action to perform on the payment.
* @param {string} controllerAction - The determined action that need to be done with the payment.
* @param {CTPayment} ctPayment - The CommerceTools payment object to validate.
* @return {void} - An object containing the validated action and an error message if validation fails.
*/
export const validateCommerceToolsPaymentPayload = (action: string, ctPayment: CTPayment): void => {
checkExtensionAction(action);
export const validateCommerceToolsPaymentPayload = (
extensionAction: string,
connectorAction: string,
ctPayment: CTPayment,
): void => {
checkExtensionAction(extensionAction);

checkPaymentInterface(ctPayment);

checkPaymentMethodInput(ctPayment);
if (connectorAction === ConnectorActions.CreatePayment) {
checkPaymentMethodInput(connectorAction, ctPayment);
}

checkAmountPlanned(ctPayment);
};
8 changes: 7 additions & 1 deletion processor/tests/controllers/payment.controller.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,11 @@ describe('Test payment.controller.ts', () => {
} as unknown as Payment,
} as PaymentReference;

(determinePaymentAction as jest.Mock).mockReturnValue({
action: ConnectorActions.GetPaymentMethods,
errorMessage: '',
});

(validateCommerceToolsPaymentPayload as jest.Mock).mockImplementationOnce(() => {
throw new CustomError(400, 'dummy message');
});
Expand All @@ -61,7 +66,8 @@ describe('Test payment.controller.ts', () => {
expect(error).toBeInstanceOf(CustomError);
expect(error.statusCode).toBe(400);
expect(error.message).toBe('dummy message');
expect(determinePaymentAction).toBeCalledTimes(0);
expect(determinePaymentAction).toBeCalledTimes(1);
expect(validateCommerceToolsPaymentPayload).toBeCalledTimes(1);
expect(handleListPaymentMethodsByPayment).toBeCalledTimes(0);
expect(handleCreatePayment).toBeCalledTimes(0);
});
Expand Down
6 changes: 3 additions & 3 deletions processor/tests/utils/config.utils.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ describe('Test src/utils/config.utils.ts', () => {
},
mollie: {
apiKey: process.env.MOLLIE_API_KEY,
debug: process.env.MOLLIE_DEBUG,
debug: process.env.DEBUG,
profileId: process.env.MOLLIE_PROFILE_ID,
},
});
Expand Down Expand Up @@ -51,8 +51,8 @@ describe('Test src/utils/config.utils.ts', () => {
expect(() => readConfiguration()).toThrow(CustomError);
});

test('should throw an error when MOLLIE_DEBUG is not defined', () => {
delete process.env.MOLLIE_DEBUG;
test('should throw an error when DEBUG is not defined', () => {
delete process.env.DEBUG;
expect(() => readConfiguration()).toThrow(CustomError);
});
});
4 changes: 2 additions & 2 deletions processor/tests/validators/helpers.validators.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -234,7 +234,7 @@ describe('Test helpers.validators.ts', () => {
},
mollie: {
apiKey: process.env.MOLLIE_API_KEY as string,
debug: (process.env.MOLLIE_DEBUG ?? '0') as string,
debug: (process.env.DEBUG ?? '0') as string,
profileId: process.env.MOLLIE_PROFILE_ID as string,
},
};
Expand All @@ -254,7 +254,7 @@ describe('Test helpers.validators.ts', () => {
},
mollie: {
apiKey: process.env.MOLLIE_API_KEY as string,
debug: (process.env.MOLLIE_DEBUG ?? '0') as string,
debug: (process.env.DEBUG ?? '0') as string,
profileId: process.env.MOLLIE_PROFILE_ID as string,
},
};
Expand Down
Loading

0 comments on commit f146c2a

Please sign in to comment.