Objective
- Let Reports Hub users exclude one or more services from job-level inspection and quote report results without manually selecting every other service or exporting data for cleanup.
- Make recurring office workflows like “all inspections except mold tests” practical inside the report builder.
- Extend the existing Service name filter (when Charges is linked) with an Include / Exclude mode — the control lives in Reports Hub, not in service settings.
Background
- Product feedback (Ashley): staff need to pull broad inspection sets while leaving out a small number of services (e.g. mold tests).
- Today the workable paths are selecting all other services manually or exporting and deleting rows outside Attik — both painful for a recurring task.
- When Charges is linked on inspection or quote reports, a Service name filter appears via
charges:catalogName.
- That filter is include-only today: it returns jobs with at least one matching charge line. Selecting “everything except mold” still keeps jobs that have mold plus another included service.
- There is no exclude / not-in path for this filter in the report builder or filter pipeline today.
- Follow-on to include-style service filtering shipped in ATT-1307.
Scope
Product behavior (v1)
- Report types: Job-level inspections and quotes only, when Charges is linked. Not charge-line base reports, aggregation-only paths, or other entities in v1.
- Exclude semantics: Excluding a service removes jobs that have any charge line for that service — including add-ons. Example: Home Inspection (primary) + Mold Testing (add-on) → excluded when Mold Testing is in the exclude list.
- UX: Add an Include / Exclude control on the existing Service name filter in Reports Hub (
ReportFiltersSection). Users pick mode and select service(s); include and exclude modes are mutually exclusive on this filter.
- Persistence: Include/exclude mode and selected services must save and restore on saved report definitions like other filter rules today.
Done when
- User can set Service name to Exclude → Mold Testing on an inspections report (Charges linked) and get jobs with no mold charge lines — including jobs where mold was only an add-on.
- User can still use Include mode with the same control (today’s behavior).
- Saved report reopens with the same include/exclude mode and service selections.
Backend (attik-backend)
- Service name filter definition:
src/config/exportFieldDefinitions.ts (charges:catalogName, DEFAULT_FILTER with defaultOperator: 'in').
- Filter API when Charges linked:
GET /data-exports/filters/:entity in src/routes/dataExport.ts.
- Filter execution:
src/util/functions/dataExports/filterBuilders.ts (buildRuleClause, getRelatedIdsMatchingLinkedFilter, getBaseFilterForJoinedReport, buildChargeDocMatchFromFilters) and join metadata in src/util/functions/dataExports/metadata.ts (reverseLookupConfig).
- Extend this linked Service name path so exclude mode resolves excluded service names to charge
_serviceIds and removes matching inspection/quote IDs from the result set (any matching charge line on the job).
Frontend (attik-frontend)
- Report builder filters UI:
src/app/tools/data-exports/components/ReportFiltersSection.tsx — add Include / Exclude mode for the Service name filter; persist mode + values through existing filter rule shape / saved report config.
Out of scope for v1
- Exclude controls on Settings → Services or anywhere outside Reports Hub.
- Generalizing exclude / none-of across unrelated report dimensions.
- Simultaneous include-and-exclude on the same service filter.
- Charge-line base reports, events, or other entities beyond job-level inspections and quotes with Charges linked.
References
- ATT-1307 — shipped include-style service/charge name filters
attik-backend/src/config/exportFieldDefinitions.ts
attik-backend/src/util/functions/dataExports/filterBuilders.ts
attik-backend/src/routes/dataExport.ts
attik-frontend/src/app/tools/data-exports/components/ReportFiltersSection.tsx