Parent: #130 (Report Builder) · Hanging item from #608
Story
As a company admin, I want the Group Header / Group Footer bands to repeat per group of line items (e.g. per project, per product category), so long invoices read as grouped sections with per-group subtotals instead of one flat item table.
Current state (as of PR #608)
Modules/Core/Services/ReportRenderer.php renders every band exactly once, in ReportBand::ordered() order. The group_header and group_footer bands exist in the five-band model and are editable in the builder, but nothing ever repeats them — grouping is not configurable anywhere.
Spec to settle in this issue
- A
group_by setting — either in the template manifest or as per-details-band config (decide: manifest band_options.details.group_by fits the existing band-options pattern used by keep_together).
- The whitelist of valid group keys: which item attributes may be grouped on (candidates from
ReportDataMapper::itemData(): none today — grouping keys like project_id/category must first be added to the item data array; enumerate them explicitly, never accept arbitrary strings).
- Per-group data exposure: Group Header bricks receive the current group key/label; Group Footer bricks receive per-group totals (
subtotal, tax, total computed over the group's items) alongside the document-level totals.
- Renderer loop: for each group — group_header bands → details (group's items only) → group_footer bands; header/footer bands stay document-level.
Acceptance criteria
Parent: #130 (Report Builder) · Hanging item from #608
Story
As a company admin, I want the Group Header / Group Footer bands to repeat per group of line items (e.g. per project, per product category), so long invoices read as grouped sections with per-group subtotals instead of one flat item table.
Current state (as of PR #608)
Modules/Core/Services/ReportRenderer.phprenders every band exactly once, inReportBand::ordered()order. Thegroup_headerandgroup_footerbands exist in the five-band model and are editable in the builder, but nothing ever repeats them — grouping is not configurable anywhere.Spec to settle in this issue
group_bysetting — either in the template manifest or as per-details-band config (decide: manifestband_options.details.group_byfits the existing band-options pattern used bykeep_together).ReportDataMapper::itemData(): none today — grouping keys likeproject_id/categorymust first be added to the item data array; enumerate them explicitly, never accept arbitrary strings).subtotal,tax,totalcomputed over the group's items) alongside the document-leveltotals.Acceptance criteria
bands.json/manifest carry an optional, enum-validatedgroup_by(unknown keys rejected on load, same pattern asReportTemplateStorage::sanitizeBands())group_byunset, rendering is byte-identical to today (golden fixtures unchanged)group_byset, Group Header/Footer bands repeat per group and the details band iterates only that group's items