summaryrefslogtreecommitdiff
path: root/tests
diff options
context:
space:
mode:
authorSomhairle H. Marisol <[email protected]>2026-09-22 13:23:34 +0800
committerSomhairle H. Marisol <[email protected]>2026-09-22 13:23:34 +0800
commit9bdc062e99b8de10700036a13a6e07a1d45411bd (patch)
treedd6857e299c58507fc21f0a9f99709b214aafe9d /tests
parent2dedc30358d1724f60ab646b7a24e93f3672dff1 (diff)
downloadfund-lab-9bdc062e99b8de10700036a13a6e07a1d45411bd.tar.gz
Prove manual stock sells credit cash with a single ledger event (3d-35)
Diffstat (limited to 'tests')
-rw-r--r--tests/FundLab.Api.Tests/CashReconciliationTests.fs44
1 files changed, 44 insertions, 0 deletions
diff --git a/tests/FundLab.Api.Tests/CashReconciliationTests.fs b/tests/FundLab.Api.Tests/CashReconciliationTests.fs
index 6fb761e..e969472 100644
--- a/tests/FundLab.Api.Tests/CashReconciliationTests.fs
+++ b/tests/FundLab.Api.Tests/CashReconciliationTests.fs
@@ -248,6 +248,13 @@ type CashReconciliationTests(fixture: PostgresFixture) =
command.Parameters.AddWithValue("fund_id", fundId) |> ignore
command.ExecuteScalar() :?> int64
+ let tableCount (table: string) fundId =
+ use connection = new NpgsqlConnection(fixture.ConnectionString)
+ connection.Open()
+ use command = new NpgsqlCommand(sprintf "SELECT count(*) FROM %s WHERE fund_id = @fund_id" table, connection)
+ command.Parameters.AddWithValue("fund_id", fundId) |> ignore
+ command.ExecuteScalar() :?> int64
+
[<Fact>]
member _.``cash reconciliation balances across every source category``() =
let fundId = createFund 10000.00m
@@ -427,3 +434,40 @@ type CashReconciliationTests(fixture: PostgresFixture) =
Assert.Contains("\"closingCash\":\"1000.00\"", body)
Assert.Contains("\"difference\":\"0.00\"", body)
Assert.Equal(0, eventCount body "bond_buy")
+
+ // the rolled-back transaction must not leave trades, positions or dirty ledger rows behind
+ Assert.Equal(0L, tableCount "bond_trades" fundId)
+ Assert.Equal(0L, tableCount "bond_positions" fundId)
+ Assert.Equal(0L, ledgerEventCount fundId)
+
+ [<Fact>]
+ member _.``manual stock sell credits available cash and records a stock_sell event``() =
+ let fundId = createFund 10000.00m
+ buyStock fundId "600519" 100m 10.00m (fixture.Key "cash-sell-buy")
+ sellStock fundId "600519" 40m 12.00m (fixture.Key "cash-sell-partial")
+
+ let status, body = reconciliation fundId
+ Assert.Equal(200, status)
+ Assert.Contains("\"openingCash\":\"10000.00\"", body)
+ Assert.Contains("\"closingCash\":\"9480.00\"", body)
+ Assert.Contains("\"ledgerBalance\":\"9480.00\"", body)
+ Assert.Contains("\"difference\":\"0.00\"", body)
+ Assert.Equal("-1000.00", (sourceEntry body "stock_buy").GetProperty("netAmount").GetString())
+ Assert.Equal("480.00", (sourceEntry body "stock_sell").GetProperty("netAmount").GetString())
+ Assert.Equal(1, eventCount body "stock_sell")
+
+ [<Fact>]
+ member _.``replaying a stock sell credits cash and the ledger only once``() =
+ let fundId = createFund 10000.00m
+ let sellKey = fixture.Key "cash-sell-replay"
+ buyStock fundId "600519" 100m 10.00m (fixture.Key "cash-sell-replay-buy")
+
+ sellStock fundId "600519" 40m 12.00m sellKey
+ sellStock fundId "600519" 40m 12.00m sellKey
+
+ let status, body = reconciliation fundId
+ Assert.Equal(200, status)
+ Assert.Contains("\"closingCash\":\"9480.00\"", body)
+ Assert.Contains("\"difference\":\"0.00\"", body)
+ Assert.Equal(1, eventCount body "stock_sell")
+ Assert.Equal(1L, tableCount "stock_sells" fundId)