Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/mol 186/pict 225 #35

Merged
merged 7 commits into from
Aug 9, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 9 additions & 2 deletions connect.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,20 @@ deployAs:
description: Enable Mollie cart component (0 or 1)
required: false
default: "0"
- key: CONNECTOR_MODE
description: Either test or live
required: true
default: "test"
- key: DEBUG
description: Debug mode (0 or 1)
required: false
default: "0"
securedConfiguration:
- key: MOLLIE_API_KEY
description: Mollie PSP API key
- key: MOLLIE_API_TEST_KEY
description: Mollie PSP test API key
required: true
- key: MOLLIE_API_LIVE_KEY
description: Mollie PSP live API key
required: true
- key: MOLLIE_PROFILE_ID
description: Mollie PSP profile ID
Expand Down
4 changes: 3 additions & 1 deletion processor/.env.example
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,9 @@ CTP_API_URL=https://api.<YOUR_CTP_REGION>.commercetools.com

## Mollie PSP credentials
DEBUG=<INTEGER_VALUE> ## Either 1 for enable or 0 for disable
MOLLIE_API_KEY=<YOUR_MOLLIE_API_KEY>
CONNECTOR_MODE=<YOUR_CONNECTOR_MODE> ## Either test or live
MOLLIE_API_TEST_KEY=<YOUR_MOLLIE_API_TEST_KEY>
MOLLIE_API_LIVE_KEY=<YOUR_MOLLIE_API_LIVE_KEY>
MOLLIE_PROFILE_ID=<YOUR_MOLLIE_PROFILE_ID>
MOLLIE_CARD_COMPONENT=0 ## Either 1 for enable or 0 for disable

Expand Down
4 changes: 3 additions & 1 deletion processor/.env.jest
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,11 @@ CTP_PROJECT_KEY=TEST
CTP_SCOPE=TEST
CTP_REGION=europe-west1.gcp
## MOLLIE vars
MOLLIE_API_KEY=12345678901234567890123456789012
MOLLIE_PROFILE_ID=pfl_12345
DEBUG=0
MOLLIE_CARD_COMPONENT=0
CONNECTOR_MODE=test ## Either test or live
MOLLIE_API_TEST_KEY=test_12345
MOLLIE_API_LIVE_KEY=live_12345

CONNECT_SERVICE_URL=http://localhost:3000/processor
4 changes: 2 additions & 2 deletions processor/package-lock.json

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

16 changes: 11 additions & 5 deletions processor/src/client/mollie.client.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,22 @@
import createMollieClient, { MollieClient } from '@mollie/api-client';
import { readConfiguration } from '../utils/config.utils';
import { LIBRARY_NAME, LIBRARY_VERSION } from '../utils/constant.utils';
import { getApiKey, readConfiguration } from '../utils/config.utils';
import { VERSION_STRING } from '../utils/constant.utils';

/**
* Initializes the Mollie client using the API key from the configuration.
*
* @return {MollieClient} Returns the initialized Mollie client.
*/
export const initMollieClient = (): MollieClient => {
const { mollie } = readConfiguration();
return createMollieClient({
apiKey: mollie.apiKey,
versionStrings: `${LIBRARY_NAME}/${LIBRARY_VERSION}`,
apiKey: getApiKey(),
versionStrings: `${VERSION_STRING}`,
});
};

export const initMollieClientForApplePaySession = (): MollieClient => {
return createMollieClient({
apiKey: readConfiguration().mollie.liveApiKey,
versionStrings: `${VERSION_STRING}`,
});
};
24 changes: 24 additions & 0 deletions processor/src/commercetools/customFields.commercetools.ts
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,30 @@ export async function createCustomPaymentType(): Promise<void> {
},
inputHint: 'MultiLine',
},
{
name: CustomFields.applePay.session.request,
label: {
en: 'The request object for inquiring the Apple Pay payment session',
de: 'Das Anfrageobjekt für die Abfrage der Apple Pay-Zahlungssitzung',
},
required: false,
type: {
name: 'String',
},
inputHint: 'MultiLine',
},
{
name: CustomFields.applePay.session.response,
label: {
en: 'The response object holding the Apple Pay payment session',
de: 'Das Antwortobjekt zur Speicherung der Apple Pay-Zahlungssitzung',
},
required: false,
type: {
name: 'String',
},
inputHint: 'MultiLine',
},
],
},
})
Expand Down
4 changes: 4 additions & 0 deletions processor/src/controllers/payment.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import {
handleCancelPayment,
handleCreatePayment,
handleCreateRefund,
handleGetApplePaySession,
handleListPaymentMethodsByPayment,
handlePaymentCancelRefund,
} from '../service/payment.service';
Expand Down Expand Up @@ -56,6 +57,9 @@ export const paymentController = async (
case ConnectorActions.CancelRefund:
logger.debug('SCTM - payment processing - paymentController - handlePaymentCancelRefund');
return await handlePaymentCancelRefund(ctPayment);
case ConnectorActions.GetApplePaySession:
logger.debug('SCTM - payment processing - paymentController - getApplePaySession');
return await handleGetApplePaySession(ctPayment);
default:
logger.debug('SCTM - payment processing - paymentController - No payment actions matched');
throw new SkipError('No payment actions matched');
Expand Down
33 changes: 25 additions & 8 deletions processor/src/mollie/payment.mollie.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,13 @@ import {
PaymentCreateParams,
PaymentEmbed,
} from '@mollie/api-client';
import { initMollieClient } from '../client/mollie.client';
import { initMollieClient, initMollieClientForApplePaySession } from '../client/mollie.client';
import CustomError from '../errors/custom.error';
import { logger } from '../utils/logger.utils';
import { readConfiguration } from '../utils/config.utils';
import { LIBRARY_NAME, LIBRARY_VERSION } from '../utils/constant.utils';
import { CustomPayment } from '../types/mollie.types';
import { ApplePaySessionRequest, CustomPayment } from '../types/mollie.types';
import ApplePaySession from '@mollie/api-client/dist/types/src/data/applePaySession/ApplePaySession';
import { getApiKey } from '../utils/config.utils';
import { VERSION_STRING } from '../utils/constant.utils';
import fetch from 'node-fetch';

/**
Expand Down Expand Up @@ -107,12 +108,10 @@ export const createPaymentWithCustomMethod = async (paymentParams: PaymentCreate
let errorMessage;

try {
const { mollie } = readConfiguration();

const headers = {
'Content-Type': 'application/json',
Authorization: `Bearer ${mollie.apiKey}`,
versionStrings: `${LIBRARY_NAME}/${LIBRARY_VERSION}`,
Authorization: `Bearer ${getApiKey()}`,
versionStrings: `${VERSION_STRING}`,
};

const response = await fetch('https://api.mollie.com/v2/payments', {
Expand Down Expand Up @@ -149,3 +148,21 @@ export const createPaymentWithCustomMethod = async (paymentParams: PaymentCreate
throw new CustomError(400, errorMessage);
}
};

export const getApplePaySession = async (options: ApplePaySessionRequest): Promise<ApplePaySession> => {
try {
return await initMollieClientForApplePaySession().applePay.requestPaymentSession(options);
} catch (error: unknown) {
let errorMessage;
if (error instanceof MollieApiError) {
errorMessage = `SCTM - getApplePaySession - error: ${error.message}, field: ${error.field}`;
} else {
errorMessage = `SCTM - getApplePaySession - Failed to get ApplePay session with unknown errors`;
}

logger.error(errorMessage, {
error,
});
throw new CustomError(400, errorMessage);
}
};
23 changes: 22 additions & 1 deletion processor/src/service/payment.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import {
cancelPayment,
createMolliePayment,
createPaymentWithCustomMethod,
getApplePaySession,
getPaymentById,
listPaymentMethods,
} from '../mollie/payment.mollie';
Expand Down Expand Up @@ -54,7 +55,9 @@ import {
import { getPaymentExtension } from '../commercetools/extensions.commercetools';
import { HttpDestination } from '@commercetools/platform-sdk/dist/declarations/src/generated/models/extension';
import { cancelPaymentRefund, createPaymentRefund, getPaymentRefund } from '../mollie/refund.mollie';
import { CustomPayment } from '../types/mollie.types';
import { ApplePaySessionRequest, CustomPayment } from '../types/mollie.types';
import { parseStringToJsonObject } from '../utils/app.utils';
import ApplePaySession from '@mollie/api-client/dist/types/src/data/applePaySession/ApplePaySession';

/**
* Handles listing payment methods by payment.
Expand Down Expand Up @@ -527,3 +530,21 @@ export const handleCancelPayment = async (ctPayment: Payment): Promise<Controlle
actions: [],
};
};

export const handleGetApplePaySession = async (ctPayment: Payment): Promise<ControllerResponseType> => {
const requestOptions: ApplePaySessionRequest = parseStringToJsonObject(
ctPayment.custom?.fields[CustomFields.applePay.session.request],
CustomFields.applePay.session.request,
'SCTM - handleGetApplePaySession',
ctPayment.id,
);

const session: ApplePaySession = await getApplePaySession(requestOptions);

const ctActions: UpdateAction[] = [setCustomFields(CustomFields.applePay.session.response, JSON.stringify(session))];

return {
statusCode: 200,
actions: ctActions,
};
};
3 changes: 2 additions & 1 deletion processor/src/types/controller.types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,5 @@ export type DeterminePaymentActionType =
| 'cancelPayment'
| 'createRefund'
| 'cancelRefund'
| 'noAction';
| 'noAction'
| 'getApplePaySession';
4 changes: 3 additions & 1 deletion processor/src/types/index.types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,9 @@ export type ConnectorEnvVars = {
region: string;
};
mollie: {
apiKey: string;
testApiKey: string;
liveApiKey: string;
mode: string;
profileId: string;
debug: string;
cardComponent: string;
Expand Down
4 changes: 4 additions & 0 deletions processor/src/types/mollie.types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,10 @@ export type ParsedMethodsRequestType = {
sequenceType?: string;
};

export type ApplePaySessionRequest = {
domain: string;
validationUrl: string;
};
export enum CustomPaymentMethod {
blik = 'blik',
}
Expand Down
11 changes: 10 additions & 1 deletion processor/src/utils/config.utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,9 @@ export const readConfiguration = () => {
region: process.env.CTP_REGION as string,
},
mollie: {
apiKey: process.env.MOLLIE_API_KEY as string,
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,
Expand All @@ -36,3 +38,10 @@ export const readConfiguration = () => {

return envVars;
};

export const getApiKey = (): string => {
if (process.env.CONNECTOR_MODE === 'test') {
return process.env.MOLLIE_API_TEST_KEY as string;
}
return process.env.MOLLIE_API_LIVE_KEY as string;
};
9 changes: 9 additions & 0 deletions processor/src/utils/constant.utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ export const LIBRARY_NAME = 'ShopmacherCommercetoolsMollieConnector';

export const LIBRARY_VERSION = PACKAGE_VERSION;

export const VERSION_STRING = `${LIBRARY_NAME}/${LIBRARY_VERSION}`;

export const CustomFields = {
payment: {
error: 'sctm_payment_methods_error',
Expand All @@ -17,6 +19,12 @@ export const CustomFields = {
interfaceInteraction: 'sctm_interface_interaction_type',
},
paymentCancelReason: 'sctm_payment_cancel_reason',
applePay: {
session: {
request: 'sctm_apple_pay_session_request',
response: 'sctm_apple_pay_session_response',
},
},
};

export enum ConnectorActions {
Expand All @@ -26,6 +34,7 @@ export enum ConnectorActions {
CreateRefund = 'createRefund',
CancelRefund = 'cancelRefund',
NoAction = 'noAction',
GetApplePaySession = 'getApplePaySession',
}

export const ErrorMessages = {
Expand Down
8 changes: 8 additions & 0 deletions processor/src/utils/paymentAction.utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,14 @@ export const determinePaymentAction = (ctPayment?: Payment): DeterminePaymentAct
return ConnectorActions.GetPaymentMethods;
}

const shouldGetAppleSession =
ctPayment.custom?.fields?.[CustomFields.applePay.session.request] &&
ctPayment.custom?.fields?.[CustomFields.applePay.session.request].length > 0;

if (shouldGetAppleSession) {
return ConnectorActions.GetApplePaySession;
}

const { transactions } = ctPayment;
const groups = getTransactionGroups(transactions);

Expand Down
25 changes: 22 additions & 3 deletions processor/src/validators/env.validators.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,9 +46,15 @@ const envValidators = [
referencedBy: 'environmentVariables',
}),

standardKey(['mollie', 'apiKey'], {
code: 'InvalidMollieApiKey',
message: 'Mollie API key should be a valid string.',
standardKey(['mollie', 'testApiKey'], {
code: 'InvalidMollieTestApiKey',
message: 'Mollie test API key should be a valid string.',
referencedBy: 'environmentVariables',
}),

standardKey(['mollie', 'liveApiKey'], {
code: 'InvalidMollieLiveApiKey',
message: 'Mollie live API key should be a valid string.',
referencedBy: 'environmentVariables',
}),

Expand Down Expand Up @@ -83,6 +89,19 @@ const envValidators = [
max: 1,
},
),

standardString(
['mollie', 'mode'],
{
code: 'InvalidMode',
message: 'Mode should be a valid string of either "test" or "live".',
referencedBy: 'environmentVariables',
},
{
min: 1,
max: 4,
},
),
];

export default envValidators;
Loading