test: cover portfolio import idempotency

This commit is contained in:
2026-08-20 15:02:47 +03:00
parent e0da7e86ad
commit 6db1312fb1
4 changed files with 39 additions and 3 deletions

View File

@@ -0,0 +1,29 @@
import assert from 'node:assert/strict';
import { pool } from '../db/pool';
import { importPortfolio } from './portfolio';
const payload = {
schemaVersion: 'broker-portfolio-1.0', bank: 'PORTFOLIO_TEST', accountNumber: 'portfolio-test',
reportPeriod: { from: '2026-08-01', to: '2026-08-20' }, reportedAt: '2026-08-20T00:00:00+03:00',
positions: [{ instrument: 'Test Bond', isin: 'RU0000000001', quantity: '1.000', price: '100.123456', valuation: '100.123456' }],
trades: [{ instrument: 'Test Bond', isin: 'RU0000000001', concludedAt: '2026-08-10T10:00:00+03:00', side: 'Покупка', quantity: '1.000', settlementAmount: '100.123456' }],
};
async function run(): Promise<void> {
try {
const first = await importPortfolio(payload);
const second = await importPortfolio(payload);
assert.equal(first.importedTrades, 1);
assert.equal(second.duplicateTrades, 1);
const rows = await pool.query('SELECT COUNT(*)::int AS count FROM portfolio_trades WHERE account_id = $1', [first.accountId]);
assert.equal(rows.rows[0].count, 1);
console.log('portfolio import SQL: OK');
} finally {
await pool.query("DELETE FROM portfolio_trades WHERE account_id IN (SELECT id FROM accounts WHERE bank = 'PORTFOLIO_TEST' AND account_number = 'portfolio-test')");
await pool.query("DELETE FROM portfolio_reports WHERE account_id IN (SELECT id FROM accounts WHERE bank = 'PORTFOLIO_TEST' AND account_number = 'portfolio-test')");
await pool.query("DELETE FROM accounts WHERE bank = 'PORTFOLIO_TEST' AND account_number = 'portfolio-test'");
await pool.end();
}
}
run();

View File

@@ -43,11 +43,11 @@ export function validatePortfolio(body: unknown): asserts body is PortfolioFile
}
}
export async function importPortfolio(body: unknown): Promise<ImportPortfolioResponse> {
export async function importPortfolio(body: unknown, db: Pick<typeof pool, 'connect'> = pool): Promise<ImportPortfolioResponse> {
validatePortfolio(body);
const data = body;
const sourceHash = crypto.createHash('sha256').update(JSON.stringify(data)).digest('hex');
const client = await pool.connect();
const client = await db.connect();
try {
await client.query('BEGIN');
const accountResult = await client.query(