Inventory, costing and payroll
These two families are where a manufacturing book is either right or quietly wrong, because both turn a stream of small events into a unit cost that everything downstream believes.The costing chain runs one way
RECEIPT → ISSUE → PRODUCTION_IN → SHIP, and every movement’s unit cost is stamped immutably on the movement at post time.
Because a movement’s cost is frozen when it posts, a later price change cannot retroactively move both the WIP-in and the WIP-out leg.
That tautology is exactly what the source workbook could not avoid - its stock-movement cost column was a live formula - and it is why the equivalent check there had no teeth.
Stock on hand, the weighted-average unit cost, the WIP balance, the GRNI balance and the
627 pool are all derived from movements plus the GL.
None of them is a stored total that can drift from the rows it summarises.The 627 overhead pool must equal what was absorbed
The pool is sourced from real expenses and absorbed into WIP, and the two sides are checked against each other.
Depreciation lines are recorded with
source_type: ASSET_REGISTER, so the pool can be checked against an independent re-derivation from each asset’s cost and life rather than against itself.
A pool that does not equal the overhead absorbed into 154 is a Close-list break.
An inventory adjustment always carries its stock movement
A signed adjustment on a stock account posts its GL legs at the positive magnitude and a matching stock movement with the signed quantity and value. An adjustment to a stock account with no stock movement behind it is a break, by design: a value change with no quantity story is how inventory quietly stops matching the warehouse.Payroll: one person, one bracket, three bills
Employment terms are a time series. The payroll for a period reads the contract in effect as of that period, exactly as FX reads the rate as of the transaction date - the applicable term, not the latest one.
Two identities hold by construction and are checked:
employer_cost = gross + employer social insurancenet = gross - employee social insurance - PIT
154, which is what ties the payroll sub-ledger to the costing sub-ledger - the same number, reached two ways.
Reversing a 13th-month accrual for someone who left is real information, not an error to hide.
A negative allocation keeps the reconciliation tied, which is why the reversal is a first-class operation rather than a deletion.
computed == paid + carried.
Where it is enforced
The test that would fail if it broke
backend/tests/test_costing.py drives the chain end to end and asserts a stamped cost does not move.
backend/tests/test_payroll.py covers the identities, the allocation reconciliation and the PIT conservation.
The payroll Close family runs only when a period is supplied, and its bill-level checksums appear only once that period’s payroll bills are raised.
That is another reason a live run’s executed count differs from the 104 defined checksums.
Related
- Inventory and costing - the sub-ledger, its movements and its derived balances
- Payroll - the family in full
- Derived balances - why a unit cost is not a stored column
- The Close checksums - how these families are run