A cash forecast you can check. It reads what mock-sap says is owed and what mock-bank says the account holds, and says what the account will close at on each of the next business days. Then the clocks are moved, mock-acme's payment run pays what is due each morning, and the bank's statements say whether the forecast was right. Most cash forecasts are never held to anything: by the time the day arrives, nobody looks back.
mock-sap ──open items──────────────▶
acme-treasury ──▶ closing balance, day by day
mock-bank ──camt.052, payments,─────▶
credits, clock, holidays
... a week of mornings and nights ...
mock-bank ──camt.053──▶ the same figure, or the test fails
camt.053 for that day, which has to close where the forecast said, to the cent.EndToEndId and counted once.plan is a small mixed-integer program, written in JuMP and solved by HiGHS: which invoices to hold, and until which business day, so that no day closes under a floor, holding as little as it can for as short a time as it can. plan --apply makes it happen as a user would, with a payment block in SAP on each held invoice, lifted on the morning it should be paid. It lifts only its own blocks.--customers-late-up-to N holds one plan to the floor for every lateness up to N business days, and --late-customers K allows for at most K customers late at once, each on their own, rather than all of them together. The output says what the caution costs. The last film below is one week played both ways.
pip install mock-sap mock-bank mock-acme
git clone https://github.com/rseufert/acme-treasury && cd acme-treasury
julia --project=. -e 'using Pkg; Pkg.instantiate()'
bin/demo # a week's invoices, forecast on Monday
bin/acme-treasury plan --days 8 --floor 10000
GitHub · What it holds to · The payment schedule · What it cannot know
Written in Julia 1.13, against the mocks as published: mock-sap and mock-bank, with the payment run from mock-acme.