import {
Payment,
PaymentStatus,
PaymentProcessingState,
PaymentFilters,
} from '../types';
import { convertFromPrisma } from '../converters';
import { prisma } from '../prisma';
import { tracer } from '@capchase/tracer';
import { callLog } from '../call_log';
/**
* Default page size for listing.
*
* @const
* @memberOf module:payments/actions
* @access private
*/
const DEFAULT_PAGE_SIZE = 100;
const internalListPayments = async (
args: PaymentFilters | null,
actionBy: string
): Promise<Payment[]> => {
await callLog({
callName: 'listPayments',
actionBy,
args: [args, actionBy],
});
const span = tracer?.scope()?.active();
// TODO(SHI-1454): Validate actual user permissions
if (actionBy.length === 0) {
throw new Error('Action by should be set');
}
span?.addTags({
action_by: actionBy,
});
const grouped = await prisma.payment.groupBy({
by: ['key'],
_max: {
id: true,
},
where: {
contractName: args?.contractName || undefined,
direction: args?.direction || undefined,
currency: args?.currency || undefined,
effectiveDate: args?.effectiveDate || undefined,
amount: args?.amount || undefined,
actionBy: args?.actionBy && {
contains: args?.actionBy,
},
// Get the unprocessed ones
processingState: PaymentProcessingState.UNPROCESSED,
},
});
const { offset, limit } = args || { offset: 0, limit: 100 };
// If limit is not set, use the default page size
const take = limit || DEFAULT_PAGE_SIZE;
// Skip based on given offset or begin from start
const skip = offset || 0;
return (
await prisma.payment.findMany({
where: {
id: { in: grouped.map(({ _max: { id } }) => id) as number[] },
status: args?.status
? {
in: args?.status as PaymentStatus[],
}
: undefined,
},
orderBy: {
id: 'desc',
},
skip,
take,
})
).map(convertFromPrisma);
};
/**
* Returns a list of all the payments with possible
* filtering based on the `args`.
*
* @param {PaymentFilters | null} args Fitlering parameters
* @param {string} actionBy Action executor
* @return {Promise<Payment[]>}
*
* @async
* @function
* @memberOf module:payments/actions
* @access public
*/
const listPayments =
tracer?.wrap('payments.listPayments', internalListPayments) ||
internalListPayments;
const internalCountPayments = async (
args: PaymentFilters | null,
actionBy: string
): Promise<number> => {
await callLog({
callName: 'countPayments',
actionBy,
args: [args, actionBy],
});
const span = tracer?.scope()?.active();
// TODO(SHI-1454): Validate actual user permissions
if (actionBy.length === 0) {
throw new Error('Action by should be set');
}
span?.addTags({
action_by: actionBy,
});
const grouped = await prisma.payment.groupBy({
by: ['key'],
_max: {
id: true,
},
where: {
contractName: args?.contractName || undefined,
direction: args?.direction || undefined,
currency: args?.currency || undefined,
effectiveDate: args?.effectiveDate || undefined,
amount: args?.amount || undefined,
actionBy: args?.actionBy && {
contains: args?.actionBy,
},
processingState: PaymentProcessingState.UNPROCESSED,
},
});
return await prisma.payment.count({
where: {
id: { in: grouped.map(({ _max: { id } }) => id) as number[] },
status: args?.status
? {
in: args?.status as PaymentStatus[],
}
: undefined,
},
});
};
/**
* Returns the total number of payments based on the `args` filtering.
*
* This is used for pagination purposes.
*
* @param {PaymentFilters} args Fitlering parameters
* @param {string} actionBy Action executor
* @return {Promise<number>}
*
* @async
* @function
* @memberOf module:payments/actions
* @access public
*/
const countPayments =
tracer?.wrap('payments.countPayments', internalCountPayments) ||
internalCountPayments;
const internalGetPaymentHistory = async (
paymentKey: string,
actionBy: string
): Promise<Payment[]> => {
await callLog({
callName: 'getPaymentHistory',
actionBy,
args: [paymentKey, actionBy],
});
const span = tracer?.scope()?.active();
// TODO(SHI-1454): Validate actual user permissions
if (actionBy.length === 0) {
throw new Error('Action by should be set');
}
span?.addTags({
action_by: actionBy,
});
return (
await prisma.payment.findMany({
where: {
key: paymentKey,
processingState: PaymentProcessingState.UNPROCESSED,
},
orderBy: [
{
id: 'desc',
},
],
})
).map(convertFromPrisma);
};
/**
* Given a `paymentKey` it returns the history of all payment associated with
* that given key, ordered by in decreasing order by its additions.
*
* Note that only the unprocessed payments will be returned so that
* a clean history is kept.
*
* @param {string} paymentKey Payment key
* @param {string} actionBy Action executor
* @return {Promise<Payment[]>} History of the payment as a list of payments
*
* @async
* @function
* @memberOf module:payments/actions
* @access public
*/
const getPaymentHistory =
tracer?.wrap('payments.getPaymentHistory', internalGetPaymentHistory) ||
internalGetPaymentHistory;
const internalGetPaymentProcessingHistory = async (
paymentKey: string,
processingKey: string,
actionBy: string
): Promise<Payment[]> => {
await callLog({
callName: 'getPaymentProcessingHistory',
actionBy,
args: [paymentKey, processingKey, actionBy],
});
const span = tracer?.scope()?.active();
// TODO(SHI-1454): Validate actual user permissions
if (actionBy.length === 0) {
throw new Error('Action by should be set');
}
span?.addTags({
action_by: actionBy,
});
return (
await prisma.payment.findMany({
where: {
key: paymentKey,
processingKey,
},
orderBy: [
{
id: 'desc',
},
],
})
).map(convertFromPrisma);
};
/**
* Given a `paymentKey` and a `processingKey` it returns the processing history.
*
* @param {string} paymentKey Payment key
* @param {string} processingKey Payment processing key
* @param {string} actionBy Action executor
* @return {Promise<Payment[]>}
*
* @throws {Error} If no payment for the given key are found
*
* @async
* @function
* @memberOf module:payments/actions
* @access public
*/
const getPaymentProcessingHistory =
tracer?.wrap(
'payments.getPaymentProcessingHistory',
internalGetPaymentProcessingHistory
) || internalGetPaymentProcessingHistory;
const internalGetLastPayment = async (
paymentKey: string,
actionBy: string
): Promise<Payment> => {
await callLog({
callName: 'getLastPayment',
actionBy,
args: [paymentKey, actionBy],
});
const span = tracer?.scope()?.active();
// TODO(SHI-1454): Validate actual user permissions
if (actionBy.length === 0) {
throw new Error('Action by should be set');
}
span?.addTags({
action_by: actionBy,
});
return convertFromPrisma(
(
await prisma.payment.findMany({
where: {
key: paymentKey,
processingState: PaymentProcessingState.UNPROCESSED,
},
orderBy: [
{
id: 'desc',
},
],
take: 1,
})
)[0]
);
};
/**
* Given a `paymentKey` it returns the last unprocessed payment associated with
* that given key.
*
* @param {string} paymentKey Payment key
* @param {string} actionBy Action executor
* @return {Promise<Payment>} The last payment for the given key
*
* @throws {Error} If no payment for the given key are found
*
* @async
* @function
* @memberOf module:payments/actions
* @access public
*/
const getLastPayment =
tracer?.wrap('payments.getLastPayment', internalGetLastPayment) ||
internalGetLastPayment;
export {
getLastPayment,
getPaymentHistory,
getPaymentProcessingHistory,
listPayments,
countPayments,
};