Objective
- Ship wide service fee columns in Reports Hub so finance can see one column per active catalog service on each inspection row — charge amount or $0 — without pivoting charges in Excel.
- Users opt in via a single “All Service Fee Breakdown” control when charges are linked on an Inspections-base report, then save and re-run that report like any other custom export.
Background
- Andy and Erin need job-level revenue visibility: which services were charged on each job and for how much. Today, Line items (
charges base + linked inspections) exports one row per charge — not one row per job with service-named columns.
- Wide service columns do not exist today. Reports Hub has aggregation pivot /
addOnServiceName groupBy for upsell-by-ancillary reports, but not dynamic flat-export columns keyed by catalog service.
- Related fields already available (not part of this ticket): finance can add
baseFee, addOnTotal, address, datetime, etc. from the existing inspections column picker (exportFieldDefinitions.ts, documentResolution.ts). Value aggregations on baseFee / addOnTotal already work via the standard aggregation UI when configured.
- Epic context: Child of Reports Hub update for Finance (ATT-1862). Identifying columns from siblings remain optional add-ons in the builder.
- No prebuilt report for v1. Users assemble the finance view manually and save it.
Locked product decisions (v1)
Wide service fee columns
- Column set: All active services in the company catalog, ordered like the Services List settings page — business segments sorted by
order, then services within each segment sorted by order (ServiceSettingsList.tsx; order on serviceSchema.ts and business segments). Exclude inactive/deactivated services (active: false).
- Scope: Include all active catalog services in that order (primary and add-on). No separate add-on-only subset.
- Stability: Column headers do not change when filters or date range change. They only change when services are added, removed, reordered, renamed, or activated/deactivated on the Services List page.
- Multiple charges for same service on one job: Sum all charge amounts for that service into the single column for that service.
- Duplicate display names: Services with the same name remain distinct columns (keyed by service id internally). Column order follows Services List so category context disambiguates. Optional enhancement (not required for v1): append category abbreviation in brackets when names collide, e.g.
Termite (CI).
- Max columns: No maximum in preview or export — full active-catalog width is acceptable.
Charge amount source
- Use charge
amount summed per _serviceId on the job. Wide columns reflect what was charged; they do not recalculate base vs add-on logic (originalBasePrice ?? amount on primary remains on existing baseFee field).
Builder UX
- Opt-in via a single “All Service Fee Breakdown” option in the charges collection (linked from inspections). Selecting it adds the full set of wide service fee columns for the company’s active catalog — users do not pick individual service columns one by one.
Done when
- On an Inspections-base report with charges linked, a user can enable All Service Fee Breakdown and:
- See one column per active catalog service on each job row, Services List order, with $0 where the job has no charge for that service.
- See wide columns in preview (horizontal scroll; no column cap).
- Export matches preview for wide columns.
- Save and re-run the report with wide columns persisted in the report config.
Scope
Backend
- Wide service fee columns (new behavior): extend flat export in
joinedReport.ts and/or runDataExportJob.ts to emit dynamic columns keyed by catalog service id (header = service display name), ordered per company Services List. Load column set from active company services only — not from distinct service names in the filtered result set.
- Sum charge
amount per _serviceId when multiple charges match the same service on one job; resolve display name via _serviceId / catalogName (chargeFields.catalogName in exportFieldDefinitions.ts).
- Expose All Service Fee Breakdown in export/report config so saved reports persist the opt-in (exact config shape: decision left to implementer).
Frontend
- Report builder — All Service Fee Breakdown opt-in under linked charges on inspections-base reports (
CreateReportForm.tsx, column-picker components).
ReportPreviewSection.tsx — render dynamic wide columns; horizontal scroll; no column cap.
- Export run path — wide columns included when config has breakdown enabled.
- Services List order reference:
attik-frontend/src/app/tools/settings/services/ServiceSettingsList.tsx.
Out of scope
- Job-level add-on names computed field (delimited list) — wide columns supersede for finance; open a follow-up only if a compact text column is still wanted.
baseFee / addOnTotal / addOnCount — already exportable; not modified by this ticket.
- Value aggregations on
baseFee / addOnTotal or per-wide-column totals — existing aggregation UI; not part of this ticket.
- New prebuilt in
prebuiltReports.ts
- Global category columns: ATT-1857
- Convenience / PAC fees: ATT-1859
- Client name, county, full address: ATT-1858
- Business segments / linking: ATT-1861
- Split date/time columns: ATT-1863
References
- Parent epic: Reports Hub update for Finance
- Charge rollup (existing base/add-on fields):
attik-backend/src/util/functions/dataExports/documentResolution.ts
- Field defs:
attik-backend/src/config/exportFieldDefinitions.ts
- Report builder:
attik-frontend/src/app/tools/data-exports/CreateReportForm.tsx
- Services List ordering:
attik-frontend/src/app/tools/settings/services/ServiceSettingsList.tsx
Diagram
flowchart LR
subgraph catalog [Active company catalog]
BL[Services List order\nsegment.order → service.order]
S1[Service A]
S2[Service B]
S3[Service C]
BL
BL
BL
end
subgraph job [Inspection job charges]
AC1[Charge Service A]
AC2[Charge Service A duplicate]
AC3[Charge Service B]
end
subgraph export [Wide export row same job]
WA[Service A column\nsum amounts]
WB[Service B column]
WC[Service C column\n$0 if none]
end
AC1
AC2
AC3
S1 -. column header .-> WA
S2 -. column header .-> WB
S3 -. column header .-> WC