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>
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>
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>