Write postings
Updated
Which registers a document writes, with which dimensions, analytics, resources,
and signs, is read entirely from its posting script:
transactions.Add(new RegisterMovementSpec(…).Dim(…).An(…).Res(…)). A service
may compute the number. It must not assemble the movement.
Note
The engine replaces movements on a subtype change (Mix). It drops every movement the document already has and runs the scripts of the target subtype only. Early-state postings do not travel forward unless those scripts are also bound on the later subtype.
How to#
A subtype may have any number of posting scripts, one per accounting goal
(stock, cost, turnover). They run as a horizontal list, executionOrder then
creation time — not as Chain of Command. Bind each script on the document
with subtypeTransactionScripts. A script in the pool that is not bound does
not run.
The platform generates the base. You write:
public partial class ReceiptStockTx
{
protected override void GetTransactions(
GoodsReceipt document,
TransactionPairCollection transactionPairs,
TransactionCollection transactions)
{
foreach (var line in document.Lines)
{
transactions.Add(new Stock
{
Warehouse = document.Warehouse,
Item = line.Item ?? Guid.Empty,
Quantity = line.Quantity ?? 0m
});
}
}
}
Double-entry is transactionPairs.Add(minus, plus). Dynamic analytics:
new RegisterMovementSpec("Stock").Dim(…).An(…).Res(…).
GetTransactions is a pure calculation of movements. No lookups that
belong in a service, no spawned documents (those are OnAfterPostAsync).
A GL leg whose amount is known before posting is
IGeneralLedgerService.EntryAsync(…) inside the posting script. A leg whose
amount is a fact of posting (cost pulled by a driver) is
OnAfterPost + IGeneralLedgerService.PostForDocumentAsync(docId, legKey, …)
with a fixed legKey so a repeated event does not double the book. Do not
spawn a JournalEntry per source document.
Tip
To adjust somebody else's posting script, wrap that script with Chain of Command. Do not add a second posting on the subtype "on top" of theirs unless you own a new register.
A test of a posting side effect must create the balance with a receipt
document, not PostMovementAsync("Stock"). The latter does not start the
costing driver, and the test stays green while production doubles the book.
What's not there yet#
There is no builder service that returns a ready RegisterMovementSpec for
several documents to share. Similar movements in different documents are
normal.