Skip to content

Commit

Permalink
bal 2663 fix transaction monitoring alert (#2653)
Browse files Browse the repository at this point in the history
  • Loading branch information
liorzam committed Aug 29, 2024
1 parent 11646a3 commit e705fbe
Show file tree
Hide file tree
Showing 4 changed files with 64 additions and 11 deletions.
2 changes: 1 addition & 1 deletion services/workflows-service/prisma/data-migrations
45 changes: 41 additions & 4 deletions services/workflows-service/src/alert/alert.service.intg.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,13 @@ const createTransactionsWithCounterpartyAsync = async (
return baseTransactionFactory;
};

const createFutureDate = (daysToAdd: number) => {
const currentDate = new Date();
const futureDate = new Date(currentDate);
futureDate.setDate(currentDate.getDate() + daysToAdd);
return futureDate;
};

describe('AlertService', () => {
let prismaService: PrismaService;
let alertService: AlertService;
Expand Down Expand Up @@ -429,7 +436,7 @@ describe('AlertService', () => {
});
});

it.only('When there are more than or equal to 15 chargeback transactions, an alert should be created', async () => {
it('When there are more than or equal to 15 chargeback transactions, an alert should be created', async () => {
// Arrange
const business1Transactions = await baseTransactionFactory
.withBusinessOriginator()
Expand Down Expand Up @@ -1003,8 +1010,8 @@ describe('AlertService', () => {
.withBusinessBeneficiary()
.direction(TransactionDirection.inbound)
.paymentMethod(PaymentMethod.credit_card)
.amount(2)
.count(ALERT_DEFINITIONS.PAY_HCA_CC.inlineRule.options.amountThreshold + 1)
.amount(ALERT_DEFINITIONS.PAY_HCA_CC.inlineRule.options.amountThreshold + 1)
.count(1)
.create();

// Act
Expand All @@ -1015,7 +1022,7 @@ describe('AlertService', () => {
expect(alerts).toHaveLength(1);
expect(alerts[0]?.alertDefinitionId).toEqual(alertDefinition.id);
expect(alerts[0] as any).toMatchObject({
executionDetails: { executionRow: { transactionCount: '1001', totalAmount: 2002 } },
executionDetails: { executionRow: { transactionCount: '1', totalAmount: 1001 } },
});
});

Expand Down Expand Up @@ -1067,6 +1074,36 @@ describe('AlertService', () => {
expect(ALERT_DEFINITIONS.PAY_HCA_APM.inlineRule.options.excludePaymentMethods).toBe(true);
});

it('When there more than 1k credit card transactions, an alert should be created', async () => {
// Arrange
await baseTransactionFactory
.withBusinessBeneficiary()
.direction(TransactionDirection.inbound)
.paymentMethod(PaymentMethod.debit_card)
.amount(ALERT_DEFINITIONS.PAY_HCA_APM.inlineRule.options.amountThreshold + 1)
.count(1)
.create();

await baseTransactionFactory
.withBusinessBeneficiary()
.direction(TransactionDirection.inbound)
.paymentMethod(PaymentMethod.apple_pay)
.amount(ALERT_DEFINITIONS.PAY_HCA_APM.inlineRule.options.amountThreshold + 1)
.transactionDate(createFutureDate(1))
.count(1)
.create();
// Act
await alertService.checkAllAlerts();

// Assert
const alerts = await prismaService.alert.findMany();
expect(alerts).toHaveLength(1);
expect(alerts[0]?.alertDefinitionId).toEqual(alertDefinition.id);
expect(alerts[0] as any).toMatchObject({
executionDetails: { executionRow: { transactionCount: '1', totalAmount: 1001 } },
});
});

it('When there more than 1k credit card transactions, an alert should be created', async () => {
// Arrange
await baseTransactionFactory
Expand Down
16 changes: 12 additions & 4 deletions services/workflows-service/src/alert/alert.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -466,13 +466,17 @@ export class AlertService {

buildTransactionsFiltersByAlert(alert: Alert & { alertDefinition: AlertDefinition }) {
const filters: {
endDate: Date;
endDate: Date | undefined;
startDate: Date | undefined;
} = {
endDate: alert.updatedAt || alert.createdAt,
endDate: undefined,
startDate: undefined,
};

const endDate = alert.updatedAt || alert.createdAt;
endDate.setHours(23, 59, 59, 999);
filters.endDate = endDate;

const inlineRule = alert?.alertDefinition?.inlineRule as InlineRule;

// @ts-ignore - TODO: Replace logic with proper implementation for each rule
Expand All @@ -491,7 +495,7 @@ export class AlertService {
}
}

const startDate = new Date(filters.endDate);
let startDate = new Date(endDate);

let subtractValue = 0;

Expand All @@ -516,8 +520,12 @@ export class AlertService {
}

startDate.setHours(0, 0, 0, 0);
startDate = new Date(startDate.getTime() - subtractValue);

const oldestDate = new Date(Math.min(startDate.getTime(), new Date(alert.createdAt).getTime()));

filters.startDate = new Date(startDate.getTime() - subtractValue);
oldestDate.setHours(0, 0, 0, 0);
filters.startDate = oldestDate;

return filters;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -278,6 +278,7 @@ export class DataAnalyticsService {
Prisma.sql`"transactionDate" >= CURRENT_DATE - INTERVAL '${Prisma.raw(
`${timeAmount} ${timeUnit}`,
)}'`,
Prisma.sql`"transactionDate" <= NOW()`,
];

if (!isEmpty(transactionType)) {
Expand Down Expand Up @@ -396,6 +397,7 @@ export class DataAnalyticsService {
AND "transactionDate" >= CURRENT_DATE - INTERVAL '${Prisma.raw(
`${timeAmount} ${timeUnit}`,
)}'
AND "transactionDate" <= NOW()
GROUP BY
"${Prisma.raw(subjectColumn)}"
)
Expand Down Expand Up @@ -454,6 +456,7 @@ export class DataAnalyticsService {
WHERE
"tr"."projectId" = ${projectId}
AND "tr"."counterpartyBeneficiaryId" IS NOT NULL
AND "tr"."transactionDate" <= NOW()
GROUP BY
"tr"."counterpartyBeneficiaryId"
)
Expand Down Expand Up @@ -492,9 +495,10 @@ export class DataAnalyticsService {
Prisma.sql`"tr"."businessId" IS NOT NULL`,
// TODO: should we use equation instead of IN clause?
Prisma.sql`"tr"."transactionType"::text IN (${Prisma.join(transactionType, ',')})`,
Prisma.sql`"transactionDate" >= CURRENT_DATE - INTERVAL '${Prisma.raw(
Prisma.sql`"tr"."transactionDate" >= CURRENT_DATE - INTERVAL '${Prisma.raw(
`${timeAmount} ${timeUnit}`,
)}'`,
Prisma.sql`"tr"."transactionDate" <= NOW()`,
];

if (Array.isArray(paymentMethods.length)) {
Expand All @@ -516,7 +520,7 @@ export class DataAnalyticsService {

switch (havingAggregate) {
case AggregateType.COUNT:
havingClause = `${AggregateType.COUNT}(id)`;
havingClause = `${AggregateType.COUNT}("id")`;
break;
case AggregateType.SUM:
havingClause = `${AggregateType.SUM}("tr"."transactionBaseAmount")`;
Expand Down Expand Up @@ -555,6 +559,7 @@ export class DataAnalyticsService {
Prisma.sql`"tr"."paymentMethod"::text ${Prisma.raw(paymentMethod.operator)} ${
paymentMethod.value
}`,
Prisma.sql`"transactionDate" <= NOW()`,
!!timeAmount &&
!!timeUnit &&
Prisma.sql`"tr"."transactionDate" >= CURRENT_DATE - INTERVAL '${Prisma.raw(
Expand Down Expand Up @@ -633,6 +638,7 @@ export class DataAnalyticsService {
paymentMethod.value
}`,
historicalTransactionClause,
Prisma.sql`"transactionDate" <= NOW()`,
];

return await this._executeQuery<Array<{ counterpartyId: string }>>(
Expand Down Expand Up @@ -672,6 +678,7 @@ export class DataAnalyticsService {
Prisma.sql`"tr"."projectId" = ${projectId}`,
Prisma.sql`"tr"."counterpartyOriginatorId" IS NOT NULL`,
Prisma.sql`"cpOriginator"."correlationId" LIKE '%****%'`,
Prisma.sql`"tr"."transactionDate" <= NOW()`,
!!timeAmount &&
!!timeUnit &&
Prisma.sql`"tr"."transactionDate" >= CURRENT_DATE - INTERVAL '${Prisma.raw(
Expand Down Expand Up @@ -733,6 +740,7 @@ export class DataAnalyticsService {
paymentMethod.value
}`,
!!customerType && Prisma.sql`b."businessType" = ${customerType}`,
Prisma.sql`"tr"."transactionDate" <= NOW()`,
].filter(Boolean);

const sqlQuery = Prisma.sql`WITH tx_by_business AS
Expand Down

0 comments on commit e705fbe

Please sign in to comment.