From 8153f9c4071d6fa2262366ab7e8ee76de60420be Mon Sep 17 00:00:00 2001 From: Sergey Krylov Date: Thu, 5 Nov 2026 07:14:29 +0300 Subject: [PATCH] fix: exclude currency mirror from position shares (WealthLedger/frontend#59) --- src/pages/account/model/positions.test.ts | 26 +++++++++++++++++++---- src/pages/account/model/positions.ts | 2 +- 2 files changed, 23 insertions(+), 5 deletions(-) diff --git a/src/pages/account/model/positions.test.ts b/src/pages/account/model/positions.test.ts index e70943c..e1986d8 100644 --- a/src/pages/account/model/positions.test.ts +++ b/src/pages/account/model/positions.test.ts @@ -23,7 +23,7 @@ function sections(positions: Portfolio["positions"]) { } describe("account position sections", () => { - it("excludes currency instruments only from display, preserving order and share denominators", () => { + it("excludes currency mirrors from display and share denominators", () => { const otherTypes = [ "OPTION", "OTHER", @@ -73,12 +73,30 @@ describe("account position sections", () => { "FIGI-FUND", ...otherTypes.map(type => `FIGI-${type}-NEXT`), ]); - expect(sections[0]?.groups[0]?.positions[0].shareText).toBe("40 %"); - expect(sections[1]?.groups[0]?.positions[0].shareText).toBe("20 %"); - expect(sections[2]?.groups[1]?.positions[0].shareText).toBe("20 %"); + expect(sections[0]?.groups[0]?.positions[0].shareText).toBe("50 %"); + expect(sections[1]?.groups[0]?.positions[0].shareText).toBe("25 %"); + expect(sections[2]?.groups[1]?.positions[0].shareText).toBe("25 %"); expect(snapshot).toEqual(original); }); + it("keeps all-account positions from both accounts without counting mirrored cash", () => { + const result = sections([ + makePosition({ account: { id: "a", name: "Основной" }, currentValue: { currency: "RUB", value: "100" } }), + makePosition({ account: { id: "a", name: "Основной" }, currentValue: { currency: "RUB", value: "50" }, type: "CURRENCY" }), + makePosition({ account: { id: "b", name: "ИИС" }, currentValue: { currency: "RUB", value: "100" } }), + ]); + + const visible = result.flatMap(section => + section.groups.flatMap(group => group.positions)); + + expect(visible) + .toEqual(expect.arrayContaining([ + expect.objectContaining({ account: { id: "a", name: "Основной" }, shareText: "50 %" }), + expect.objectContaining({ account: { id: "b", name: "ИИС" }, shareText: "50 %" }), + ])); + expect(visible).toHaveLength(2); + }); + it("prepares grouped position sections with derived display data", () => { expect( toAccountPagePositionSections(portfolio).map(({ groups, kind }) => ({ diff --git a/src/pages/account/model/positions.ts b/src/pages/account/model/positions.ts index 8fd431f..5019923 100644 --- a/src/pages/account/model/positions.ts +++ b/src/pages/account/model/positions.ts @@ -152,7 +152,7 @@ function toAccountPagePositionSections( const denominators = new Map(); for (const position of portfolio.positions) { - if (!position.currentValue) continue; + if (position.type === "CURRENCY" || !position.currentValue) continue; const currency = position.currentValue.currency; denominators.set( currency,