refactor!: support RUB only (WealthLedger/main#55)
Backend verify / commits (pull_request) Successful in 1m38s
Backend verify / security (pull_request) Successful in 1m28s
Backend verify / verify (pull_request) Successful in 8m40s

Filter non-RUB data at ingest and collapse per-currency collections
into a single RUB Money. Drop currency from TbankPortfolioValuePoint,
remove NON_RUB_ACTIVITY and the screener currency filter.

BREAKING CHANGE: per-currency API fields replaced with single RUB Money.
This commit is contained in:
2026-11-11 09:40:25 +03:00
parent 85d65f8997
commit 83df5f0be6
61 changed files with 617 additions and 735 deletions
+7 -14
View File
@@ -103,7 +103,6 @@ describe('local income completeness and exact money (SQLite)', () => {
for (const [id, units, nano, currency, type] of [
['same', '10', 1, 'rub', 'OPERATION_TYPE_COUPON'],
['negative', '-2', -500000000, 'rub', 'OPERATION_TYPE_DIVIDEND'],
['usd', '3', 0, 'usd', 'OPERATION_TYPE_COUPON'],
] as const) {
await prisma.tbankOperation.create({
data: {
@@ -130,11 +129,8 @@ describe('local income completeness and exact money (SQLite)', () => {
assert(result.data);
expect(result.meta.availability).toBe('available');
expect(result.meta.completeness).toBe('complete');
expect(result.data.totalsByCurrency.map((row) => row.total)).toEqual([
{ currency: 'RUB', value: '15.000000002' },
{ currency: 'USD', value: '6' },
]);
expect(result.data.entries).toHaveLength(6);
expect(result.data.total.total).toEqual({ currency: 'RUB', value: '15.000000002' });
expect(result.data.entries).toHaveLength(4);
expect(
result.data.entries
.filter((row) => row.id === 'same')
@@ -185,7 +181,7 @@ describe('local income completeness and exact money (SQLite)', () => {
assert(after.data);
expect(after.data.entries.find((entry) => entry.account?.id === 'a' && entry.id === 'same')?.logoName).toBe('bond.png');
expect(after.data.entries.find((entry) => entry.account?.id === 'b' && entry.id === 'same')?.logoName).toBeNull();
expect(after.data.totalsByCurrency).toEqual(base.totalsByCurrency);
expect(after.data.total).toEqual(base.total);
expect(after.data.calculatedAt).toBe(base.calculatedAt);
expect(upstream.getOperationsByCursor).not.toHaveBeenCalled();
});
@@ -205,8 +201,8 @@ describe('local income completeness and exact money (SQLite)', () => {
new Date('2025-03-31T21:00:00Z'),
);
expect(
(await read('a', 'from=2025-03-01&to=2025-03-31')).data?.totalsByCurrency,
).toEqual([]);
(await read('a', 'from=2025-03-01&to=2025-03-31')).data?.total.total,
).toEqual({ currency: 'RUB', value: '0' });
expect(upstream.getOperationsByCursor).toHaveBeenCalledWith(
'synthetic', expect.objectContaining({ accountId: 'b' }),
);
@@ -225,11 +221,8 @@ describe('local income completeness and exact money (SQLite)', () => {
});
const result = await read();
assert(result.data);
expect(result.data.entries).toHaveLength(6);
expect(
result.data.totalsByCurrency.find(({ currency }) => currency === 'RUB')
?.total,
).toEqual({ currency: 'RUB', value: '25.000000002' });
expect(result.data.entries).toHaveLength(4);
expect(result.data.total.total).toEqual({ currency: 'RUB', value: '25.000000002' });
});
it('preserves the complete financial result and timestamp through failed atomic reconciliation', async () => {
const before = await read();