summaryrefslogtreecommitdiff
path: root/tests/FundLab.Domain.Tests
diff options
context:
space:
mode:
Diffstat (limited to 'tests/FundLab.Domain.Tests')
-rw-r--r--tests/FundLab.Domain.Tests/DomainTests.fs81
1 files changed, 81 insertions, 0 deletions
diff --git a/tests/FundLab.Domain.Tests/DomainTests.fs b/tests/FundLab.Domain.Tests/DomainTests.fs
index 63bcab2..c3d4551 100644
--- a/tests/FundLab.Domain.Tests/DomainTests.fs
+++ b/tests/FundLab.Domain.Tests/DomainTests.fs
@@ -880,3 +880,84 @@ module DividendPolicyTests =
Assert.Equal("dividend:7c9e6679-7425-40de-944b-e07fc1f90ae7", DividendPolicy.recordKey recordId)
Assert.Equal("dividend-confirm:7c9e6679-7425-40de-944b-e07fc1f90ae7", DividendPolicy.confirmKey recordId)
+
+module CashLedgerTests =
+
+ open System
+ open Xunit
+ open FundLab.Domain
+
+ let private event source amount : CashLedger.CashLedgerEvent =
+ {
+ Source = source
+ EventDate = DateOnly(2026, 9, 21)
+ Amount = amount
+ ReferenceType = "test"
+ ReferenceId = Guid.NewGuid().ToString("D")
+ Note = None
+ }
+
+ [<Fact>]
+ let ``cash source text roundtrips through parse`` () =
+ let sources =
+ [
+ CashLedger.Subscription
+ CashLedger.Redemption
+ CashLedger.Dividend
+ CashLedger.Sip
+ CashLedger.StockBuy
+ CashLedger.StockSell
+ CashLedger.BondBuy
+ CashLedger.BondSell
+ CashLedger.BondCoupon
+ CashLedger.BondMaturity
+ CashLedger.CapitalDeposit
+ ]
+
+ for source in sources do
+ Assert.Equal(Some source, CashLedger.parseSource (CashLedger.sourceText source))
+
+ Assert.Equal(None, CashLedger.parseSource "unknown")
+
+ [<Fact>]
+ let ``scheduled contribution keys are tagged as sip`` () =
+ Assert.Equal(CashLedger.Sip, CashLedger.subscriptionSourceForKey "sip:plan:2026-09-21")
+ Assert.Equal(CashLedger.Sip, CashLedger.subscriptionSourceForKey "investment-plan:abc:2026-09-21")
+ Assert.Equal(CashLedger.Subscription, CashLedger.subscriptionSourceForKey "manual-key")
+ Assert.Equal(CashLedger.Subscription, CashLedger.subscriptionSourceForKey null)
+
+ [<Fact>]
+ let ``reconciliation groups sources and balances`` () =
+ let events =
+ [
+ event CashLedger.CapitalDeposit 5000.00m
+ event CashLedger.StockBuy -1000.00m
+ event CashLedger.StockSell 400.00m
+ event CashLedger.StockSell 100.00m
+ ]
+
+ let reconciliation = CashLedger.reconcile 10000.00m 14500.00m events
+
+ Assert.Equal(10000.00m, reconciliation.OpeningCash)
+ Assert.Equal(4500.00m, reconciliation.NetInflow)
+ Assert.Equal(14500.00m, reconciliation.ClosingCash)
+ Assert.Equal(14500.00m, reconciliation.LedgerBalance)
+ Assert.Equal(0m, reconciliation.Difference)
+
+ let bySource =
+ reconciliation.Sources |> List.map (fun total -> CashLedger.sourceText total.Source, total.NetAmount, total.EventCount)
+
+ Assert.Equal<(string * decimal * int) list>(
+ [ ("capital_deposit", 5000.00m, 1); ("stock_buy", -1000.00m, 1); ("stock_sell", 500.00m, 2) ],
+ bySource
+ )
+
+ [<Fact>]
+ let ``reconciliation reports a non-zero difference`` () =
+ let reconciliation = CashLedger.reconcile 10000.00m 9000.00m [ event CashLedger.StockBuy -500.00m ]
+ Assert.Equal(9500.00m, reconciliation.ClosingCash)
+ Assert.Equal(500.00m, reconciliation.Difference)
+
+ let empty = CashLedger.reconcile 100.00m 100.00m []
+ Assert.Equal(0m, empty.Difference)
+ Assert.Empty(empty.Sources)