A BOM cost rollup report answers one question that sounds simple and isn't: "what does this assembly actually cost to build, all the way down?" Acumatica already computes rolled-up standard costs via the Cost Rollup process on the Bill of Material screen (AM208000) and stores the result, but a lot of clients want a printable report that shows the rollup with the tree structure — material, labor, and overhead broken out per level, not just the final number. That's a report you build, not one Acumatica ships, and building it well means respecting how BOMs actually nest.
Read the stored rollup, don't recompute it in the report
The temptation is to have the report walk the BOM tree itself and sum component costs live. Don't — that's reimplementing the Cost Rollup engine's logic (including phantom BOM handling, scrap factors, and effective-dated revisions) inside a report schema, and you will get it subtly wrong the first time someone uses a phantom assembly. Instead, the report should read INSiteCostStatus / the cost rollup result tables (the specific DACs vary by version — AMBomCost-family tables hold the exploded cost detail after a rollup run) that already contain the computed per-component cost. Your report's job is presentation of an existing number, not recalculation.
Cost Rollup is a batch process, not a live trigger — if a component's purchase cost changed yesterday and nobody re-ran the rollup for the parent assembly, your report prints a stale number that looks authoritative. Put the rollup's last run date on the report header so nobody mistakes a three-month-old number for today's cost. I've had this exact gap cause a client to quote a job off a rolled-up cost that hadn't accounted for a resin price increase.
Printing the indented tree
For the "show me every level" version, the self-referencing subreport pattern is the right tool — the report passes the current component's InventoryID and a Level counter down to itself, indenting the description by [@Level] and suppressing further recursion past a sane depth (I use 8; real BOMs rarely nest deeper and it guards against a bad data cycle recursing forever). The report only needs read access to the exploded cost table per level — it does not need to re-derive costs, only to walk the existing parent/component relationships and print the number that's already there.
ReportName: KGAMBOMCostP
Parameters:
ParentInventoryID = [AMBomItem.InventoryID]
Level = [@Level] + 1
VisibleExpr on subreport control: =[@Level] < 8
Splitting material, labor, and overhead cleanly
Clients almost always want the three cost buckets shown separately, not just a total — it's the difference between "why is this so expensive" being answerable versus not. The rollup tables carry the split (material cost, labor cost from routing operations, and applied overhead) as separate columns; make sure your report's group footer sums each bucket independently rather than summing a pre-blended total field, otherwise you can't show the breakdown at all without going back to raw component data — and by then you've lost the point of using the stored rollup in the first place.
Wrapping up
Build the BOM cost rollup report as a presentation layer over Acumatica's own Cost Rollup output, not a live recalculation — print the last-rollup date prominently, use a bounded self-referencing subreport for the indented tree, and keep material/labor/overhead as separate summed columns from the start. The report that recomputes costs from scratch is the one that eventually disagrees with what Manufacturing sees on-screen, and that disagreement is always a support ticket.
Independent software engineer in Nairobi specialising in Acumatica customisations, Laravel backends, and tax fiscalisation integrations across East and Southern Africa.