@unchainedshop/plugins
Version:
Official plugin collection for the Unchained Engine with payment, delivery, and pricing adapters
162 lines (161 loc) • 7.9 kB
JavaScript
import { createLogger } from '@unchainedshop/logger';
import { mapOrderDataToGatewayObject, mapUserToGatewayObject } from "./payrexx.js";
import createPayrexxAPI, { GatewayObjectStatus } from "./api/index.js";
import { OrderPricingSheet, PaymentAdapter, PaymentError, } from '@unchainedshop/core';
const logger = createLogger('unchained:payrexx');
export const Payrexx = {
...PaymentAdapter,
key: 'shop.unchained.payment.payrexx',
label: 'Payrexx',
version: '1.0.0',
typeSupported(type) {
return type === 'GENERIC';
},
actions: (config, context) => {
const { modules } = context;
const instance = config.find((c) => c.key === 'instance')?.value;
const adapterActions = {
...PaymentAdapter.actions(config, context),
configurationError() {
if (!process.env.PAYREXX_SECRET) {
return PaymentError.INCOMPLETE_CONFIGURATION;
}
if (!instance) {
return PaymentError.INCOMPLETE_CONFIGURATION;
}
return null;
},
isActive: () => {
if (adapterActions.configurationError() === null)
return true;
return false;
},
isPayLaterAllowed() {
return false;
},
sign: async (transactionContext = {}) => {
const { orderPayment, userId, order } = context;
if (!order)
throw new Error('No order in context, can only sign with order context');
const api = createPayrexxAPI(instance, process.env.PAYREXX_SECRET);
if (orderPayment) {
const pricing = OrderPricingSheet({
calculation: order.calculation,
currencyCode: order.currencyCode,
});
const gatewayObject = mapOrderDataToGatewayObject({ order, orderPayment, pricing }, transactionContext);
const gateway = await api.createGateway(gatewayObject);
return JSON.stringify(gateway);
}
const user = userId && (await modules.users.findUserById(userId));
if (!user)
throw new Error('User not found, can only sign registrations with user context');
const emailAddress = modules.users.primaryEmail(user)?.address;
const gateway = await api.createGateway(mapUserToGatewayObject({
userId,
emailAddress,
currencyCode: order?.currencyCode,
}));
return JSON.stringify(gateway);
},
async register() {
throw new Error('Not implemented');
return null;
},
async confirm() {
const { orderPayment } = context;
if (!orderPayment?.transactionId) {
return false;
}
const { transactionId } = orderPayment;
const api = createPayrexxAPI(instance, process.env.PAYREXX_SECRET);
const gatewayObject = await api.getGateway(transactionId);
if (!gatewayObject) {
return false;
}
if (gatewayObject.status === GatewayObjectStatus.reserved) {
const allTransactions = gatewayObject.invoices?.flatMap((invoice) => invoice.transactions);
await Promise.all(allTransactions.map(async (transaction) => api.chargePreAuthorized(transaction.id, { referenceId: '__IGNORE_WEBHOOK__' })));
return true;
}
if (gatewayObject.status === GatewayObjectStatus.confirmed) {
return true;
}
return false;
},
async cancel() {
const { orderPayment } = context;
if (!orderPayment?.transactionId) {
return false;
}
const { transactionId } = orderPayment;
const api = createPayrexxAPI(instance, process.env.PAYREXX_SECRET);
const gatewayObject = await api.getGateway(transactionId);
if (!gatewayObject) {
return false;
}
if (gatewayObject.status === GatewayObjectStatus.reserved) {
const allTransactions = gatewayObject.invoices?.flatMap((invoice) => invoice.transactions);
await Promise.all(allTransactions.map(async (transaction) => api.deleteReservation(transaction.id)));
return true;
}
if (gatewayObject.status === GatewayObjectStatus.confirmed) {
return false;
}
return true;
},
charge: async ({ gatewayId, paymentCredentials }) => {
if (!gatewayId && !paymentCredentials) {
throw new Error('You have to provide gatewayId or paymentCredentials');
}
const { order, orderPayment } = context;
if (!order)
throw new Error('No order in context, can only charge with order context');
if (!orderPayment)
throw new Error('Order payment not found');
const api = createPayrexxAPI(instance, process.env.PAYREXX_SECRET);
const gatewayObject = await api.getGateway(gatewayId);
if (!gatewayObject) {
throw new Error('Could not load gateway from the Payrexx API');
}
const pricing = OrderPricingSheet({
calculation: order.calculation,
currencyCode: order.currencyCode,
});
const { currencyCode, amount } = pricing.total({ useNetPrice: false });
if (gatewayObject.status === 'reserved' ||
gatewayObject.status === 'confirmed') {
try {
if (gatewayObject.currency !== currencyCode.toUpperCase() ||
gatewayObject.amount !== Math.round(amount)) {
throw new Error('The price has changed since the intent has been created');
}
if (gatewayObject.referenceId !== orderPayment?._id) {
throw new Error('The order payment is different from the initiating intent');
}
logger.info(`Mark as charged, status is ${gatewayObject.status}`, {
orderPaymentId: gatewayObject.referenceId,
});
return {
transactionId: gatewayId,
gatewayObject,
};
}
catch (e) {
if (gatewayObject.status === GatewayObjectStatus.reserved) {
const allTransactions = gatewayObject.invoices?.flatMap((invoice) => invoice.transactions);
await Promise.all(allTransactions.map(async (transaction) => api.deleteReservation(transaction.id)));
}
throw e;
}
}
logger.info('Charge not possible', {
orderPaymentId: gatewayObject.referenceId,
status: gatewayObject.status,
});
throw new Error(`Gateway Status ${gatewayObject.status} does not allow checkout`);
},
};
return adapterActions;
},
};