This is the walkthrough I actually give new developers on a project before I hand them their first report ticket — not a feature tour, but the sequence of decisions that gets you from "client wants a custom packing slip" to a deployed .rpx that survives the next upgrade. If you've read the deep-dive on report internals elsewhere on this site, treat this one as the practical companion: the order of operations, not the theory.
Start in the Schema Builder, not the layout canvas
The single biggest mistake new report developers make is opening the layout canvas first and dragging fields onto a page before the data source is right. Work backwards from the finished report: list every field that needs to appear, trace each one back to its DAC, and build the relations in the Schema Builder before you place a single TextBox. A report with a clean schema — proper joins, filters that map to parameters, only the fields you'll actually use — takes half the time to lay out, because you're not fighting a dataset that's missing a field or duplicating rows from an unnecessary join.
Relations: SOShipment (root) -> SOShipLine (detail, inner join on ShipmentNbr)
Filters: SOShipment.ShipmentNbr Equal =[@ShipmentNbr] (parameter, pushed to SQL)
Fields: only what the layout references — resist "select everything, just in case"
Understand the band model before you nest anything
A report is a stack of bands: Report Header/Footer (once per report), Page Header/Footer (once per page), Group Header/Detail/Group Footer (once per group, repeated per row respectively). New developers usually get tripped up putting summary calculations in the wrong band — a running total belongs in the group footer with a Sum() expression scoped to that group, not computed manually in the detail band with a running variable, which breaks the moment someone reorders columns or adds a page break mid-group.
Wire parameters to the Report Viewer, deliberately
Every parameter you declare shows up as a prompt when the report runs standalone from the sitemap, but when a report is invoked from a screen action (Print Invoice, Print Packing Slip) the graph passes parameter values programmatically and the user never sees a prompt at all. Decide on day one whether a given report is meant to run interactively with prompts, or exclusively from a screen action with values supplied in code — that decision changes whether you need sensible defaults and validation on the parameter, or can assume it's always populated correctly by the calling graph.
A report that only ever gets invoked via PXReportRequiredException from a graph action will still appear in the report catalogue and can be run directly by anyone with access rights. If it assumes a parameter is always populated and doesn't handle a blank prompt gracefully, someone will eventually run it standalone, hit a blank or broken report, and file a bug against something you never tested that way.
Package it in the customization project from the start
Don't build a report loose on the instance and add it to the customization project later — deploy it into the project as your very first step, even before the schema is finished. Reports added late to a project have a habit of getting missed when the project is exported and handed to another environment, and you end up with a report that works in dev and is quietly absent in staging.
Wrapping up
Schema before layout, understand which band each calculation belongs in before you place it, decide up front whether the report is interactive or action-invoked, and package it in the customization project from the first save, not the last. Follow that order and most of the rework I see junior developers redo — a report built beautifully against the wrong dataset — never happens in the first place.
Independent software engineer in Nairobi specialising in Acumatica customisations, Laravel backends, and tax fiscalisation integrations across East and Southern Africa.