test: cover portfolio import idempotency
This commit is contained in:
29
backend/src/services/portfolio.integration.test.ts
Normal file
29
backend/src/services/portfolio.integration.test.ts
Normal 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();
|
||||
@@ -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(
|
||||
|
||||
Reference in New Issue
Block a user