Skip to content

Commit 3286ce2

Browse files
committed
fix(transaction): throw HttpException when originator or beneficiary is missing in TransactionEntityMapper
fix(transaction): throw HttpException when counterparty has neither business nor end user data in TransactionEntityMapper fix(transaction): throw HttpException when counterparty has both business and end user data in TransactionEntityMapper fix(transaction.service): map transactionsPayload to mappedTransactions before creating transactions in bulk
1 parent bd44aeb commit 3286ce2

File tree

3 files changed

+102
-13
lines changed

3 files changed

+102
-13
lines changed

services/workflows-service/src/transaction/transaction.controller.external.intg.test.ts

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -489,5 +489,87 @@ describe('#TransactionControllerExternal', () => {
489489
message: [expect.any(String)],
490490
});
491491
});
492+
493+
it('returns 400 when counterparty is missing from the body', async () => {
494+
// Arrange
495+
const apiKey = (customer.authenticationConfiguration as { authValue: string }).authValue;
496+
const validTransaction = getBaseTransactionData();
497+
const transactions = [
498+
{
499+
...validTransaction,
500+
originator: undefined as unknown as TransactionCreateDto['originator'],
501+
},
502+
] as const satisfies readonly TransactionCreateDto[];
503+
504+
// Act
505+
const response = await request(app.getHttpServer())
506+
.post('/external/transactions/bulk')
507+
.send(transactions)
508+
.set('authorization', `Bearer ${apiKey}`);
509+
510+
// Assert
511+
expect(response.status).toBe(400);
512+
expect(response.body).toEqual({
513+
statusCode: 400,
514+
message: 'Originator and beneficiary are required.',
515+
});
516+
});
517+
518+
it('returns 400 when counterparty is missing an entity', async () => {
519+
// Arrange
520+
const apiKey = (customer.authenticationConfiguration as { authValue: string }).authValue;
521+
const validTransaction = getBaseTransactionData();
522+
const transactions = [
523+
{
524+
...validTransaction,
525+
beneficiary: {
526+
correlationId: faker.datatype.uuid(),
527+
// Missing endUserData or businessData
528+
},
529+
},
530+
] as const satisfies readonly TransactionCreateDto[];
531+
532+
// Act
533+
const response = await request(app.getHttpServer())
534+
.post('/external/transactions/bulk')
535+
.send(transactions)
536+
.set('authorization', `Bearer ${apiKey}`);
537+
538+
// Assert
539+
expect(response.status).toBe(400);
540+
expect(response.body).toEqual({
541+
statusCode: 400,
542+
message: 'Counterparty must have either business or end user data.',
543+
});
544+
});
545+
});
546+
547+
it('returns 400 when counterparty has both business and end user', async () => {
548+
// Arrange
549+
const apiKey = (customer.authenticationConfiguration as { authValue: string }).authValue;
550+
const validTransaction = getBaseTransactionData();
551+
const transactions = [
552+
{
553+
...validTransaction,
554+
originator: getBusinessCounterpartyData(),
555+
beneficiary: {
556+
...getBusinessCounterpartyData(),
557+
...getEndUserCounterpartyData(),
558+
},
559+
},
560+
] as const satisfies readonly TransactionCreateDto[];
561+
562+
// Act
563+
const response = await request(app.getHttpServer())
564+
.post('/external/transactions/bulk')
565+
.send(transactions)
566+
.set('authorization', `Bearer ${apiKey}`);
567+
568+
// Assert
569+
expect(response.status).toBe(400);
570+
expect(response.body).toEqual({
571+
statusCode: 400,
572+
message: 'Counterparty must have either business or end user data.',
573+
});
492574
});
493575
});

services/workflows-service/src/transaction/transaction.mapper.ts

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,10 @@ import { HttpException } from '@nestjs/common';
55

66
export class TransactionEntityMapper {
77
static toCreateData({ dto, projectId }: { dto: TransactionCreateDto; projectId: TProjectId }) {
8+
if (!dto.originator || !dto.beneficiary) {
9+
throw new HttpException('Originator and beneficiary are required.', 400);
10+
}
11+
812
return {
913
transactionCorrelationId: dto.correlationId,
1014
transactionDate: dto.date,
@@ -92,16 +96,17 @@ export class TransactionEntityMapper {
9296
counterpartyInfo,
9397
projectId,
9498
}: {
95-
counterpartyInfo: CounterpartyInfo | undefined;
99+
counterpartyInfo: CounterpartyInfo;
96100
projectId: string;
97101
}):
98102
| Prisma.TransactionRecordCreateInput['counterpartyOriginator']
99103
| Prisma.TransactionRecordCreateInput['counterpartyBeneficiary'] {
104+
if (!counterpartyInfo?.businessData && !counterpartyInfo?.endUserData) {
105+
throw new HttpException('Counterparty must have either business or end user data.', 400);
106+
}
107+
100108
if (counterpartyInfo?.businessData && counterpartyInfo?.endUserData) {
101-
throw new HttpException(
102-
'Counterparty must have either business or end user data, not both.',
103-
400,
104-
);
109+
throw new HttpException('Counterparty must have either business or end user data.', 400);
105110
}
106111

107112
return counterpartyInfo

services/workflows-service/src/transaction/transaction.service.ts

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -24,16 +24,18 @@ export class TransactionService {
2424
transactionsPayload: TransactionCreateDto[];
2525
projectId: TProjectId;
2626
}) {
27+
const mappedTransactions = transactionsPayload.map(transactionPayload =>
28+
TransactionEntityMapper.toCreateData({
29+
dto: transactionPayload,
30+
projectId,
31+
}),
32+
);
33+
2734
const response: Array<TransactionCreatedDto | { error: Error; correlationId: string }> = [];
2835

29-
for (const transactionPayload of transactionsPayload) {
36+
for (const transactionPayload of mappedTransactions) {
3037
try {
31-
const transaction = await this.repository.create({
32-
data: TransactionEntityMapper.toCreateData({
33-
dto: transactionPayload,
34-
projectId,
35-
}),
36-
});
38+
const transaction = await this.repository.create({ data: transactionPayload });
3739

3840
response.push({
3941
id: transaction.id,
@@ -50,7 +52,7 @@ export class TransactionService {
5052

5153
response.push({
5254
error: errorToLog,
53-
correlationId: transactionPayload.correlationId,
55+
correlationId: transactionPayload.transactionCorrelationId,
5456
});
5557
}
5658
}

0 commit comments

Comments
 (0)