ZuloOne
English
Sign in
Menu

🏦 The AccountingSettings account profile

Updated

← Developer wiki

IGeneralLedgerService.EntryAsync resolves the legs by code (ChartOfAccounts.Code + IsPostable). The ArAccount, RevenueAccount, … references on the AccountingSettings singleton are what the form shows. On saving, AccountingSettingsEventHandler stamps the paired *AccountCode. An empty reference does not wipe the string: tests and older stands still write the code directly.

Do not rename and do not drop the *AccountCode columns: removing a field from the JSON does not drop the column, and renaming leaves orphans. isVisible: false on the strings; the references are what is visible.

The AccountingAccountProfileTest test (3 cases): the stamp after a reload by MetaId (the event mutates the DataService dictionary, not the same POCO that IDictionaryManager.SaveRecordAsync returned), a string with no reference, a group being rejected.

WipAccount is the same pair. ProductionOrderEventHandler (Production) after posting: on Released the amount is this document's negative ItemCostFifo, Dr WIP / Cr inventory, written as the order's own GL movements (IInventoryCostGLService.PostIssuedCostAsync). Moving to Finished reverses all the order's movements — the WIP leg included — and books only absorbed labour (Dr inventory / Cr LaborAbsorbedAccountCode): materials out and the product in are neutral on the one inventory account. The ProductionWipGLTest test.

PurchasePriceVarianceAccount is the same pair, and it is the one leg that must not be pointed at the inventory account. SupplierInvoiceGLTx books the gap between the supplier's sheet and what the receipts accrued, and the receipt already priced the goods in InventoryValue and in the ItemCostFifo layers. Neither can be revalued afterwards from a script: a layer is addressed by the engine's LotNo, which is absent from the generated entity, and a movement with Quantity = 0 is poison — FifoTotalDriver.CalculateOutcomes hands its whole amount to the next issue whatever that issue's size, while the AVG branch of CostingValuationTotalDriver gives the layer share = 0 and then drops it from the survivors, so the amount never leaves stock. Debiting the inventory ACCOUNT while the registers stay put therefore opens a permanent ledger↔subledger gap and breaks the invariant CostingIssueTotalDriver rests on: the value it writes off is exactly what the engine removed from the layers. The policy is standard costing — stock keeps the receipt price, the gap is a result of the period, and re-costing goods already in a cell stays StockAdjustment's job. An empty code is lawful: no leg, Payable still moves. The SupplierInvoiceVarianceTest test (4 cases) guards both halves — the variance account moved, InventoryValue and ItemCostFifo did not.

Two doors for a document's ledger leg#

Door When Why
EntryAsync in the document's transaction script the amount is known from the document (revenue, payments, payroll, VAT) the leg joins the posting chain: atomic, reversed with the document, compared on re-save
PostForDocumentAsync from OnAfterPost the amount is a fact of the posting (cost the CostingIssue driver took off the layers) GetTransactions is synchronous and runs BEFORE the drivers — the cost is not there yet

Trap: the after-post event can run twice in one posting. A driver that appends movements through the totals manager re-enters the document's events. PostForDocumentAsync takes a legKey (stored as the movement's ScriptMetaId) and skips a leg that is already there. Pass a fixed GUID per leg kind, never Guid.NewGuid() — a fresh key makes the guard useless and the cost doubles silently.

Trap: set all six GL resources. Movement always writes Debit, Credit, ManagementDebit, ManagementCredit, TaxDebit, TaxCredit, zeros included. A hand-built RegisterMovementSpec("GL") that omits one gets a different movement signature from the stored row, and the document re-posts on every save.

Trap: a transaction script's bind row lives in the OWNER's object.json. A new GL tx on SalesRealization is bound in Sales/Documents/SalesRealization/SalesRealization.object.json (subtypeTransactionScripts). Applying the object before the script exists fails with an FK on MetaScripts — apply the script first, then the object.

Same topic for other readers: Analyst · User

Where next#

Was this page helpful?