feat(performance): investment performance vs Moscow Exchange index (WealthLedger/main#54) (#200)
Backend verify / commits (push) Skipped
Backend verify / security (push) Successful in 1m7s
Backend verify / verify (push) Failing after 7m19s

This commit was merged in pull request #200.
This commit is contained in:
2026-11-08 16:45:29 +03:00
parent 84433ee207
commit fee61537b6
28 changed files with 1507 additions and 4 deletions
@@ -0,0 +1,15 @@
import { isCompleteValuation } from './complete-valuation';
describe('isCompleteValuation', () => {
it('requires an actual currency total and every position value', () => {
expect(isCompleteValuation({ totalsByCurrency: [], positions: [] })).toBe(false);
expect(isCompleteValuation({
totalsByCurrency: [{ currency: 'RUB', value: '100' }],
positions: [{ currentValue: null }],
})).toBe(false);
expect(isCompleteValuation({
totalsByCurrency: [{ currency: 'RUB', value: '100' }],
positions: [{ currentValue: { currency: 'RUB', value: '0' } }],
})).toBe(true);
});
});
@@ -0,0 +1,13 @@
type Valuation = {
positions: { currentValue: unknown }[];
totalsByCurrency: unknown[];
};
const MIN_TOTALS_COUNT = 0;
export function isCompleteValuation(
snapshot: Valuation,
): boolean {
return snapshot.totalsByCurrency.length > MIN_TOTALS_COUNT &&
snapshot.positions.every((position) => position.currentValue !== null);
}
@@ -11,6 +11,8 @@ import { toJson } from '#src/prisma/to-json';
import type { PortfolioDto } from '../presentation/portfolio.dto';
import { isCompleteValuation } from '../domain/complete-valuation';
const EXPECTED_UPDATED_ACCOUNTS = 1;
type PortfolioAttempt = {
@@ -140,10 +142,7 @@ export class PortfolioRepository {
});
// Value history points require a fully valued snapshot; the attempt
// identity deduplicates repeated or late publications of one attempt.
if (
snapshot.totalsByCurrency.length > Number.MIN_VALUE &&
snapshot.positions.every((position) => position.currentValue !== null)
) {
if (isCompleteValuation(snapshot)) {
await tx.tbankPortfolioValueHistory.upsert({
where: {
userId_accountId: { userId: attempt.userId, accountId },
@@ -1,5 +1,6 @@
export { ForecastService } from './application/forecast.service';
export { PortfolioService } from './application/portfolio.service';
export { isCompleteValuation } from './domain/complete-valuation';
// Public cross-module surface. Nest providers are exported by the matching module.
export {