222 lines
7.0 KiB
TypeScript
222 lines
7.0 KiB
TypeScript
/**
|
|
* Unit tests for Payment Identity Map Service
|
|
*/
|
|
|
|
import { PaymentIdentityMapService } from '@/exports/identity-map';
|
|
import { TestHelpers } from '../../utils/test-helpers';
|
|
import { PaymentRepository } from '@/repositories/payment-repository';
|
|
import { MessageRepository } from '@/repositories/message-repository';
|
|
import { PaymentStatus } from '@/models/payment';
|
|
import { MessageType, MessageStatus } from '@/models/message';
|
|
import { v4 as uuidv4 } from 'uuid';
|
|
|
|
describe('PaymentIdentityMapService', () => {
|
|
let paymentRepository: PaymentRepository;
|
|
let messageRepository: MessageRepository;
|
|
|
|
beforeAll(async () => {
|
|
paymentRepository = new PaymentRepository();
|
|
messageRepository = new MessageRepository();
|
|
// Clean database before starting
|
|
await TestHelpers.cleanDatabase();
|
|
}, 10000); // Increase timeout for database setup
|
|
|
|
beforeEach(async () => {
|
|
await TestHelpers.cleanDatabase();
|
|
});
|
|
|
|
afterAll(async () => {
|
|
await TestHelpers.cleanDatabase();
|
|
// Close database connections
|
|
const pool = TestHelpers.getTestDb();
|
|
await pool.end();
|
|
}, 10000);
|
|
|
|
describe('buildForPayment', () => {
|
|
it('should build identity map for payment with all identifiers', async () => {
|
|
// Create test operator
|
|
const operator = await TestHelpers.createTestOperator('TEST_ID_MAP', 'MAKER' as any);
|
|
|
|
// Create payment
|
|
const paymentRequest = TestHelpers.createTestPaymentRequest();
|
|
const paymentId = await paymentRepository.create(
|
|
paymentRequest,
|
|
operator.id,
|
|
`TEST-PAY-${Date.now()}`
|
|
);
|
|
|
|
const uetr = uuidv4();
|
|
const internalTxnId = 'TXN-12345';
|
|
|
|
// Update payment with identifiers
|
|
await paymentRepository.update(paymentId, {
|
|
internalTransactionId: internalTxnId,
|
|
uetr,
|
|
status: PaymentStatus.LEDGER_POSTED,
|
|
});
|
|
|
|
// Create ledger posting
|
|
const { query } = require('@/database/connection');
|
|
await query(
|
|
`INSERT INTO ledger_postings (
|
|
internal_transaction_id, payment_id, account_number, transaction_type,
|
|
amount, currency, status, posting_timestamp, reference
|
|
) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9)`,
|
|
[
|
|
internalTxnId,
|
|
paymentId,
|
|
paymentRequest.senderAccount,
|
|
'DEBIT',
|
|
paymentRequest.amount,
|
|
paymentRequest.currency,
|
|
'POSTED',
|
|
new Date(),
|
|
paymentId,
|
|
]
|
|
);
|
|
|
|
// Create ISO message
|
|
const messageId = uuidv4();
|
|
const msgId = 'MSG-12345';
|
|
const xmlContent = `<?xml version="1.0" encoding="UTF-8"?>
|
|
<Document xmlns="urn:iso:std:iso:20022:tech:xsd:pacs.008.001.10">
|
|
<FIToFICstmrCdtTrf>
|
|
<GrpHdr>
|
|
<MsgId>${msgId}</MsgId>
|
|
<CreDtTm>${new Date().toISOString()}</CreDtTm>
|
|
</GrpHdr>
|
|
<CdtTrfTxInf>
|
|
<PmtId>
|
|
<EndToEndId>E2E-123</EndToEndId>
|
|
<TxId>TX-123</TxId>
|
|
<UETR>${uetr}</UETR>
|
|
</PmtId>
|
|
</CdtTrfTxInf>
|
|
</FIToFICstmrCdtTrf>
|
|
</Document>`;
|
|
|
|
await messageRepository.create({
|
|
id: messageId,
|
|
messageId: messageId,
|
|
paymentId,
|
|
messageType: MessageType.PACS_008,
|
|
uetr,
|
|
msgId,
|
|
xmlContent,
|
|
xmlHash: 'test-hash',
|
|
status: MessageStatus.VALIDATED,
|
|
});
|
|
|
|
// Build identity map
|
|
const identityMap = await PaymentIdentityMapService.buildForPayment(paymentId);
|
|
|
|
expect(identityMap).toBeDefined();
|
|
expect(identityMap?.paymentId).toBe(paymentId);
|
|
expect(identityMap?.uetr).toBe(uetr);
|
|
expect(identityMap?.endToEndId).toBe('E2E-123');
|
|
expect(identityMap?.txId).toBe('TX-123');
|
|
expect(identityMap?.ledgerJournalIds.length).toBeGreaterThan(0);
|
|
expect(identityMap?.internalTransactionIds).toContain(internalTxnId);
|
|
});
|
|
|
|
it('should return null for non-existent payment', async () => {
|
|
const identityMap = await PaymentIdentityMapService.buildForPayment(uuidv4());
|
|
expect(identityMap).toBeNull();
|
|
});
|
|
});
|
|
|
|
describe('findByUETR', () => {
|
|
it('should find payment by UETR', async () => {
|
|
const operator = await TestHelpers.createTestOperator('TEST_UETR', 'MAKER' as any);
|
|
const paymentRequest = TestHelpers.createTestPaymentRequest();
|
|
const paymentId = await paymentRepository.create(
|
|
paymentRequest,
|
|
operator.id,
|
|
`TEST-UETR-${Date.now()}`
|
|
);
|
|
|
|
const uetr = uuidv4();
|
|
await paymentRepository.update(paymentId, {
|
|
uetr,
|
|
status: PaymentStatus.LEDGER_POSTED,
|
|
});
|
|
|
|
const identityMap = await PaymentIdentityMapService.findByUETR(uetr);
|
|
|
|
expect(identityMap).toBeDefined();
|
|
expect(identityMap?.paymentId).toBe(paymentId);
|
|
expect(identityMap?.uetr).toBe(uetr);
|
|
});
|
|
|
|
it('should return null for non-existent UETR', async () => {
|
|
const identityMap = await PaymentIdentityMapService.findByUETR(uuidv4());
|
|
expect(identityMap).toBeNull();
|
|
});
|
|
});
|
|
|
|
describe('buildForPayments', () => {
|
|
it('should build identity maps for multiple payments', async () => {
|
|
const operator = await TestHelpers.createTestOperator('TEST_MULTI', 'MAKER' as any);
|
|
const paymentIds: string[] = [];
|
|
|
|
// Create multiple payments
|
|
for (let i = 0; i < 3; i++) {
|
|
const paymentRequest = TestHelpers.createTestPaymentRequest();
|
|
const paymentId = await paymentRepository.create(
|
|
paymentRequest,
|
|
operator.id,
|
|
`TEST-MULTI-${Date.now()}-${i}`
|
|
);
|
|
paymentIds.push(paymentId);
|
|
}
|
|
|
|
const identityMaps = await PaymentIdentityMapService.buildForPayments(paymentIds);
|
|
|
|
expect(identityMaps.size).toBe(3);
|
|
paymentIds.forEach((id) => {
|
|
expect(identityMaps.has(id)).toBe(true);
|
|
});
|
|
});
|
|
});
|
|
|
|
describe('verifyUETRPassThrough', () => {
|
|
it('should verify valid UETR format', async () => {
|
|
const operator = await TestHelpers.createTestOperator('TEST_VERIFY', 'MAKER' as any);
|
|
const paymentRequest = TestHelpers.createTestPaymentRequest();
|
|
const paymentId = await paymentRepository.create(
|
|
paymentRequest,
|
|
operator.id,
|
|
`TEST-VERIFY-${Date.now()}`
|
|
);
|
|
|
|
const uetr = uuidv4();
|
|
await paymentRepository.update(paymentId, {
|
|
uetr,
|
|
status: PaymentStatus.LEDGER_POSTED,
|
|
});
|
|
|
|
const isValid = await PaymentIdentityMapService.verifyUETRPassThrough(paymentId);
|
|
expect(isValid).toBe(true);
|
|
});
|
|
|
|
it('should return false for invalid UETR', async () => {
|
|
const operator = await TestHelpers.createTestOperator('TEST_INVALID', 'MAKER' as any);
|
|
const paymentRequest = TestHelpers.createTestPaymentRequest();
|
|
const paymentId = await paymentRepository.create(
|
|
paymentRequest,
|
|
operator.id,
|
|
`TEST-INVALID-${Date.now()}`
|
|
);
|
|
|
|
await paymentRepository.update(paymentId, {
|
|
uetr: 'invalid-uetr',
|
|
status: PaymentStatus.LEDGER_POSTED,
|
|
});
|
|
|
|
const isValid = await PaymentIdentityMapService.verifyUETRPassThrough(paymentId);
|
|
expect(isValid).toBe(false);
|
|
});
|
|
});
|
|
});
|
|
|