Add ILogger<ViewService> and log the match-count summary at the end
of MatchOpenBankTransactions: "Matched {Matched} of {Total} open bank
transactions". Completes item 18.
Also drop the ISettingsService [Inject] from Home.razor.cs that was
declared but never referenced.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Replace the hand-rolled model.Copy(target) pattern in every SaveXxx
with FindIndex -> in-place replace (or Add on new). Move the two
hidden defaults out of the deleted Copy bodies: Currency = "CHF"
default now lives in AccountRepository.SaveAccount; BookingDate =
ValueDate default now lives in TransactionRepository.SaveTransaction.
Delete Copy from Account, BookingRule, BookingText, SubClass, and
SplitPredefinition. Keep Transaction.Clone() (renamed from Copy, and
now includes RelatedParty) for the defensive copy in GetTransaction
and ViewService.WithDisplaySign.
Fixes a pre-existing bug where Transaction.Copy silently dropped
RelatedParty on every update save.
42 tests total, all passing.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
New IFxConverter.ConvertToChf(amount, fromCurrency) and FxConverter
wrap the vendor IFxService and the FixerIo API key so callers stop
threading the key through every conversion. ViewService drops
IFxService and ISettingsService from its constructor and takes
IFxConverter instead; GetAccountViewList and GetBalanceSheetView no
longer read settingsService.GetSettings() per method.
FxConverterTestShould locks in the target-currency + API-key routing.
40 tests total, all passing.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
BaseRepository takes an ILogger via its constructor and logs the
failing file path and exception in Save's catch block before
rethrowing. Every concrete repository takes ILogger<ThisRepo> and
passes it up so failures are categorised by repository type.
Pulls Microsoft.Extensions.Logging.Abstractions into the Db project.
TransactionRepositoryTestShould and AccountRepositoryTestShould pass
NullLogger<T>.Instance.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
FileService.ImportAccountStatementFile now emits Information on the
file being processed and on each account's import count, Warning on
mandator-mismatch skips, and Error on vendor-parser failures. UI-facing
MessageDataset behaviour is unchanged.
Pulls Microsoft.Extensions.Logging.Abstractions into the Services
project; FileServiceTestShould uses NullLogger<FileService>.Instance.
Rest of item 18 (repository logging, MatchOpenBankTransactions
summary) tracked as a follow-up.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Add Schaad.Accounting.Tests (xUnit + NSubstitute + Shouldly, net9.0)
wired into Accounting.sln with a direct Reference to
Schaad.Finance.Api.dll so it flows into the test binary.
Naming convention: file/class is <Subject>TestShould, each test method
is DoThisWhenThat. Reads as a sentence:
"ViewService test should sum activa and passiva totals separately when
getting balance view". All assertions use Shouldly (.ShouldBe,
.ShouldBeNull, .ShouldContain, ...) rather than xUnit Assert.*.
38 tests across seven files:
- ViewServiceTestShould: balance math (activa/passiva totals, per-
account balance from start balance + credits - debits, FX conversion
to CHF) and bank-transaction auto-matching (booking-rule text,
value-matching preference, same-accounts-last-month fallback,
open-transaction filter).
- TransactionRepositoryTestShould: FX round-trip against a temp XML
directory, unknown-id -> null, and the mutation-on-read regression
from PR A (a second Get on the same FX transaction used to divide
by FxRate again).
- FormattingTestShould: Swiss thousands separator, two-decimal
rounding, culture independence.
- RepositoryCacheTestShould: loader called once, per-key isolation,
invalidation forces reload, case-insensitive keys.
- AccountRepositoryTestShould: id assignment, in-place update,
currency defaulting, delete, bank-account lookup, bank-balance
update, and constructor re-run against an existing file.
- ChartServiceTestShould: honours settingsService.GetYear() without
mutating it (locks in PR E), account vs sub-class grouping
heuristic, skips empty accounts.
- FileServiceTestShould: CSV header + running balance for debit and
credit lines, ordering by BookingDate/ValueDate/Value, no in-place
value mutation (locks in PR A).
CLAUDE.md gains a `dotnet test` line. IMPROVEMENT_PLAN.md notes that
this landed as three PRs (G, H, I) and was squashed on request.
Also add `*.DotSettings.user` to .gitignore so Rider's per-user
solution settings don't get accidentally staged.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>