From a16aedcfd880171a27dc6ad8c524460261c64117 Mon Sep 17 00:00:00 2001 From: Claudio Schaad Date: Sat, 23 May 2026 16:08:01 +0200 Subject: [PATCH] Display transactions and balances in account currency - Transaction amounts, totals, and sidebar badges in the Transactions page now show in the account's native currency (EUR, USD, etc.) instead of always CHF - Fixed FX conversion in SaveTransaction/GetTransaction to fire when either the origin or target account is a foreign-currency account, not only the origin side Co-Authored-By: Claude Sonnet 4.6 --- CLAUDE.md | 64 +++++++++++++++++++ .../Repositories/TransactionRepository.cs | 17 ++--- .../Components/Pages/Transactions.razor | 8 ++- 3 files changed, 78 insertions(+), 11 deletions(-) create mode 100644 CLAUDE.md diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 0000000..ef821b9 --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,64 @@ +# CLAUDE.md + +This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. + +## Commands + +```bash +# Build +dotnet build + +# Run (dev server at http://localhost:5225) +cd Schaad.Accounting.UI && dotnet run + +# Publish +dotnet publish -c Release +``` + +There are no automated tests or lint commands. + +## Architecture + +**AccountingNext** is a Swiss personal accounting app built with ASP.NET Core 9 + Blazor (interactive server-side rendering) and Microsoft Fluent UI. Data is stored as XML files on disk — no database. + +### Projects + +| Project | Role | +|---|---| +| `Schaad.Accounting.UI` | Blazor web app — pages, dialogs, layout | +| `Schaad.Accounting.Services` | Business logic — balances, FX conversion, file import, charts | +| `Schaad.Accounting.Db` | Repository layer — XML serialization/deserialization | +| `Schaad.Accounting.Common` | Shared models, DTOs, interfaces | + +### Data flow + +``` +Blazor Pages/Dialogs (UI) + → Services (ViewService, FileService, ChartService) + → Repositories (AccountRepository, TransactionRepository, …) + → XML files: {DataPath}/{year}/{mandator}/Data/*.xml +``` + +Data is multi-year and multi-mandator. Each combination has its own directory under `DataPath` (configured in `appsettings.Development.json`). When a new year is opened, the previous year's data is copied as the starting point. + +### Key services + +- **ViewService** — aggregates account balances, applies FX rates, builds datasets for the UI +- **FileService** — imports bank statements (MT940, CAMT053 via external `Schaad.Finance.dll`), parses PDFs, manages backups +- **ChartService** — produces data for Plotly charts (assets, spendings over time) +- **SettingsService** — manages the active year, mandator, and file paths + +### UI structure + +Pages live in `Schaad.Accounting.UI/Components/Pages/`. Each page typically has a companion `Dialogs/` subfolder with Fluent UI dialog components for CRUD operations. The app is hardcoded to the `de-CH` culture. + +### Key external dependencies + +- `Microsoft.FluentUI.AspNetCore.Components` — UI components (FluentDataGrid, FluentDialog, etc.) +- `Plotly.Blazor` — charts +- `FreeSpire.PDF` — PDF parsing for bank statement imports +- `Schaad.Finance.dll` / `Schaad.Finance.Api.dll` — proprietary DLLs for MT940/CAMT053 parsing and FX rate lookups (FixerIo API key in `appsettings.Development.json`) + +### Domain constants + +`ClassIds` in `Schaad.Accounting.Common` defines the Swiss accounting chart-of-accounts classes: Activa=1000, Passiva=2000, Income=3000, Expenses=4000. diff --git a/Schaad.Accounting.Db/Repositories/TransactionRepository.cs b/Schaad.Accounting.Db/Repositories/TransactionRepository.cs index 8689e7d..de9021c 100644 --- a/Schaad.Accounting.Db/Repositories/TransactionRepository.cs +++ b/Schaad.Accounting.Db/Repositories/TransactionRepository.cs @@ -31,18 +31,18 @@ namespace Schaad.Accounting.Repositories public void SaveTransaction(Transaction transaction) { transaction.Value = Math.Abs(transaction.Value); - - // prevent saving fxrate for chf account - var isFxAccount = accountRepository.GetAccount(transaction.OriginAccountId).IsFxAccount; - // if source account is fx account, we pass a foreign value -> calc to chf + var originIsFx = accountRepository.GetAccount(transaction.OriginAccountId).IsFxAccount; + var targetIsFx = accountRepository.GetAccount(transaction.TargetAccountId).IsFxAccount; + var isFxAccount = originIsFx || targetIsFx; + + // user enters amount in the foreign account's currency -> convert to CHF for storage if (isFxAccount && transaction.FxRate != 0) { transaction.Value = transaction.Value * transaction.FxRate.Value; } - isFxAccount |= accountRepository.GetAccount(transaction.TargetAccountId).IsFxAccount; - if (isFxAccount == false) + if (!isFxAccount) { transaction.FxRate = null; } @@ -69,8 +69,9 @@ namespace Schaad.Accounting.Repositories var transactions = GetTransactionList(); var transaction = transactions.FirstOrDefault(t => t.Id == id); - // if source account is fx account, we save in chf currency -> calc to foreign currency for display - var isFxAccount = accountRepository.GetAccount(transaction.OriginAccountId).IsFxAccount; + // value is stored in CHF -> convert back to foreign currency for display/editing + var isFxAccount = accountRepository.GetAccount(transaction.OriginAccountId).IsFxAccount + || accountRepository.GetAccount(transaction.TargetAccountId).IsFxAccount; if (isFxAccount && transaction.FxRate != 0) { transaction.Value = transaction.Value / transaction.FxRate.Value; diff --git a/Schaad.Accounting.UI/Components/Pages/Transactions.razor b/Schaad.Accounting.UI/Components/Pages/Transactions.razor index ddb84f6..38f0c02 100644 --- a/Schaad.Accounting.UI/Components/Pages/Transactions.razor +++ b/Schaad.Accounting.UI/Components/Pages/Transactions.razor @@ -17,7 +17,7 @@
- @Math.Abs(account.BalanceCHF).ToString("C2") + @Math.Abs(account.Balance).ToString("N2") @account.Currency
@@ -34,7 +34,7 @@ @selectedAccount.Name - Total @Math.Abs(selectedAccount.Balance).ToString("C2") in @transactionList?.Count() Transaktionen + Total @Math.Abs(selectedAccount.Balance).ToString("N2") @selectedAccount.Currency in @transactionList?.Count() Transaktionen Neue Transaktion hinzufügen @@ -49,7 +49,9 @@ @GetAccountName(context) - + + @context.GetValue(selectedAccount.IsFxAccount).ToString("N2") @selectedAccount.Currency +