diff options
| author | Somhairle H. Marisol <[email protected]> | 2026-09-22 11:59:00 +0800 |
|---|---|---|
| committer | Somhairle H. Marisol <[email protected]> | 2026-09-22 11:59:00 +0800 |
| commit | 8d98ba88f75852f5cc4b5d66c5b30210b7eefe6c (patch) | |
| tree | aba9aa2210103460935fd1a9baa0b9f4e69efdca /tests | |
| parent | 4ff91444dc9f29acf6f8459572a6cbf7db676b59 (diff) | |
| download | fund-lab-8d98ba88f75852f5cc4b5d66c5b30210b7eefe6c.tar.gz | |
Backfill cash ledger from historical transactions and add reconciliation QA (3d-32)
Diffstat (limited to 'tests')
| -rw-r--r-- | tests/FundLab.Api.Tests/CashReconciliationTests.fs | 43 |
1 files changed, 43 insertions, 0 deletions
diff --git a/tests/FundLab.Api.Tests/CashReconciliationTests.fs b/tests/FundLab.Api.Tests/CashReconciliationTests.fs index 59f6fd6..d8dc7bb 100644 --- a/tests/FundLab.Api.Tests/CashReconciliationTests.fs +++ b/tests/FundLab.Api.Tests/CashReconciliationTests.fs @@ -2,6 +2,7 @@ namespace FundLab.Api.Tests open System open System.Text.Json +open Npgsql open Xunit open FundLab.Api open FundLab.Domain @@ -201,6 +202,20 @@ type CashReconciliationTests(fixture: PostgresFixture) = |> Seq.filter (fun entry -> entry.GetProperty("source").GetString() = source) |> Seq.length + let deleteLedgerEvents fundId = + use connection = new NpgsqlConnection(fixture.ConnectionString) + connection.Open() + use command = new NpgsqlCommand("DELETE FROM cash_ledger_events WHERE fund_id = @fund_id", connection) + command.Parameters.AddWithValue("fund_id", fundId) |> ignore + command.ExecuteNonQuery() |> ignore + + let ledgerEventCount fundId = + use connection = new NpgsqlConnection(fixture.ConnectionString) + connection.Open() + use command = new NpgsqlCommand("SELECT count(*) FROM cash_ledger_events WHERE fund_id = @fund_id", 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 @@ -252,3 +267,31 @@ type CashReconciliationTests(fixture: PostgresFixture) = let status, body = reconciliation (Guid.NewGuid()) Assert.Equal(404, status) Assert.Contains("FUND_NOT_FOUND", body) + + [<Fact>] + member _.``backfill rebuilds the ledger for history written before it existed``() = + let fundId = createFund 10000.00m + deposit fundId 5000.00m (fixture.Key "cash-backfill-deposit") + buyStockDebit fundId "600519" 100m 10.00m (fixture.Key "cash-backfill-buy") + sellStock fundId "600519" 40m 10.00m (fixture.Key "cash-backfill-sell") + buyBond fundId "110075" 10m 100.00m + recordBondCoupon fundId "110075" 50.00m (fixture.Key "cash-backfill-coupon") + subscribe fundId (seedInstrument ()) 1000.00m (fixture.Key "cash-backfill-subscribe") + + // deposit + stock buy + stock sell + bond coupon + subscription settle + let expected = 5L + + // simulate a database that predates the ledger: drop the hook-written events + deleteLedgerEvents fundId + Assert.Equal(0L, ledgerEventCount fundId) + + repository().BackfillCashLedger() |> ignore + + Assert.Equal(expected, ledgerEventCount fundId) + Assert.Equal(0.00m, (repository().GetCashReconciliation fundId |> Result.defaultWith failwith).Difference) + + // re-running must be a no-op: same event count, same reconciled balance + repository().BackfillCashLedger() |> ignore + + Assert.Equal(expected, ledgerEventCount fundId) + Assert.Equal(0.00m, (repository().GetCashReconciliation fundId |> Result.defaultWith failwith).Difference) |
