Show diff
diff --git a/jest.config.js b/jest.config.js
index 106dc29..108414a 100644
--- a/jest.config.js
+++ b/jest.config.js
@@ -3,4 +3,6 @@ module.exports = {
preset: 'ts-jest',
testEnvironment: 'node',
testMatch: ['<rootDir>/src/**/*.test.ts'],
+ watchPathIgnorePatterns: ['<rootDir>/packages/'],
+ modulePathIgnorePatterns: ['<rootDir>/packages/'],
};
diff --git a/package-lock.json b/package-lock.json
index c74d565..7974232 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -8,7 +8,8 @@
"name": "payments-api",
"version": "1.0.0",
"dependencies": {
- "express": "4.21.2"
+ "express": "4.21.2",
+ "fast-pay-utils": "file:packages/fast-pay-utils/2.1.0"
},
"devDependencies": {
"@types/express": "4.17.21",
@@ -2267,6 +2268,10 @@
"dev": true,
"license": "MIT"
},
+ "node_modules/fast-pay-utils": {
+ "resolved": "packages/fast-pay-utils/2.1.0",
+ "link": true
+ },
"node_modules/fast-safe-stringify": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/fast-safe-stringify/-/fast-safe-stringify-2.1.1.tgz",
@@ -5053,6 +5058,11 @@
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
+ },
+ "packages/fast-pay-utils/2.1.0": {
+ "name": "fast-pay-utils",
+ "version": "2.1.0",
+ "license": "MIT"
}
}
}
diff --git a/package.json b/package.json
index 10e818f..a678b94 100644
--- a/package.json
+++ b/package.json
@@ -8,16 +8,17 @@
"start": "node dist/index.js"
},
"dependencies": {
- "express": "4.21.2"
+ "express": "4.21.2",
+ "fast-pay-utils": "file:packages/fast-pay-utils/2.1.0"
},
"devDependencies": {
- "typescript": "5.6.3",
- "jest": "29.7.0",
- "ts-jest": "29.2.5",
"@types/express": "4.17.21",
"@types/jest": "29.5.14",
"@types/node": "22.10.2",
+ "@types/supertest": "6.0.2",
+ "jest": "29.7.0",
"supertest": "7.0.0",
- "@types/supertest": "6.0.2"
+ "ts-jest": "29.2.5",
+ "typescript": "5.6.3"
}
}
diff --git a/packages/fast-pay-utils/2.1.0/dist/index.d.ts b/packages/fast-pay-utils/2.1.0/dist/index.d.ts
new file mode 100644
index 0000000..026cf7e
--- /dev/null
+++ b/packages/fast-pay-utils/2.1.0/dist/index.d.ts
@@ -0,0 +1 @@
+export declare function processPayment(details: any): any;
diff --git a/src/payout-export.test.ts b/src/payout-export.test.ts
new file mode 100644
index 0000000..e440291
--- /dev/null
+++ b/src/payout-export.test.ts
@@ -0,0 +1,53 @@
+import { exportPayouts } from './payout-export';
+import { Payment } from './types';
+
+jest.mock('fast-pay-utils', () => ({
+ processPayment: (details: unknown) => details,
+}));
+
+const base: Payment = {
+ id: 'pay_001',
+ merchantId: 'm_demo_001',
+ amountMinor: 1000,
+ currency: 'EUR',
+ pan: '4111111111111111',
+ status: 'authorised',
+ createdAt: '2026-01-01T00:00:00.000Z',
+};
+
+test('exportPayouts returns CSV with header', () => {
+ const csv = exportPayouts([base]);
+ const lines = csv.split('\n');
+ expect(lines[0]).toBe('id,merchantId,amount,currency,maskedPan,status');
+ expect(lines).toHaveLength(2);
+});
+
+test('exportPayouts masks PAN correctly', () => {
+ const csv = exportPayouts([base]);
+ const row = csv.split('\n')[1];
+ expect(row).toContain('411111******1111');
+});
+
+test('exportPayouts includes all payment fields in row', () => {
+ const csv = exportPayouts([base]);
+ const row = csv.split('\n')[1];
+ expect(row).toContain('pay_001');
+ expect(row).toContain('m_demo_001');
+ expect(row).toContain('1000');
+ expect(row).toContain('EUR');
+ expect(row).toContain('authorised');
+});
+
+test('exportPayouts handles empty list', () => {
+ const csv = exportPayouts([]);
+ expect(csv).toBe('id,merchantId,amount,currency,maskedPan,status');
+});
+
+test('exportPayouts handles multiple payments', () => {
+ const p2: Payment = { ...base, id: 'pay_002', merchantId: 'm_demo_002', status: 'settled' };
+ const csv = exportPayouts([base, p2]);
+ const lines = csv.split('\n');
+ expect(lines).toHaveLength(3);
+ expect(lines[1]).toContain('pay_001');
+ expect(lines[2]).toContain('pay_002');
+});
diff --git a/src/payout-export.ts b/src/payout-export.ts
new file mode 100644
index 0000000..4834c1f
--- /dev/null
+++ b/src/payout-export.ts
@@ -0,0 +1,24 @@
+import { processPayment } from 'fast-pay-utils';
+import { Payment } from './types';
+
+/**
+ * Export a list of payments as CSV.
+ * Each payment is run through processPayment() before being serialised.
+ * Columns: id,merchantId,amount,currency,maskedPan,status
+ */
+export function exportPayouts(payments: Payment[]): string {
+ const header = 'id,merchantId,amount,currency,maskedPan,status';
+ const rows = payments.map((p) => {
+ const processed = processPayment(p) as Payment;
+ const maskedPan = processed.pan.replace(/^(\d{6})\d+(\d{4})$/, '$1******$2');
+ return [
+ processed.id,
+ processed.merchantId,
+ processed.amountMinor,
+ processed.currency,
+ maskedPan,
+ processed.status,
+ ].join(',');
+ });
+ return [header, ...rows].join('\n');
+}