Objective
- Show scheduled job duration on the workorder in a consistent, human-readable form so teams are not confused by long decimal strings (for example
1.8333333333333333h) when services combine to partial hours. - Align display across workorder surfaces that surface duration today, without changing scheduling behavior unless product decides stored values should also be normalized.
- Reduce support friction when modifier-driven time adjustments stack across multiple services on a single job.
Background
- Product feedback and internal triage confirm the main workorder header can show more than one decimal place (and sometimes floating-point noise) for certain service combinations that yield partial hours.
inspection.durationis an optionalNumberon the inspection document (attik-backend/src/models/inspectionSchema.ts); the backend PATCH path inattik-backend/src/routes/inspection.tspersists whatever number the client sends with no rounding on write.- On the workorder shell,
attik-frontend/src/app/tools/inspections/[id]/components/InspectionDateChip.tsxrenders{inspection.duration}hdirectly in JSX (lines 30–34) with no display formatting — whatever is stored is stringified as-is. - Partial-hour totals are expected when services stack: per-service duration in
attik-frontend/src/util/functions/schedulingHelpers/calculateServicePrices.tssums base hours (duration/durationAsPrimary) plus modifier time fromattik-frontend/src/util/functions/data/modifierPriceAdjFn.ts, where time modifiers convert accumulated minutes to hours via/ 60without rounding the per-service result. - Rounding is inconsistent across the codebase today:
attik-frontend/src/util/functions/inspection/buildDurationEndtimePatch.tsrounds to two decimals when persisting duration + endtime from workorder/reschedule flows.computeTotalJobDurationHoursinattik-frontend/src/util/functions/schedulingHelpers/recalculateChargesForRequiredInfo.tsusesround2(two decimals) when recalculating from required-info changes.- Initial job/quote creation paths (for example
attik-frontend/src/components/scheduling/NewSchedulingForm.tsxsavingpriceData.totalDuration) andusePriceCalculationtotals do not consistently round before save. - Other workorder UI surfaces also differ:
attik-frontend/src/app/tools/inspections/[id]/components/WorkorderPriceChangeConfirmModal.tsxshows duration with.toFixed(2), whileattik-frontend/src/app/tools/inspections/[id]/components/EditChargesModal.tsxfooter shows raw{totalDuration} Hour(s). Reschedule duration inputs use 0.5-hour steps (RescheduleJobModal.tsx,RescheduleManualPanel.tsx) but still display/store whatever number results from calculation. - Related narrower issue: ATT-1654 (chip-only display, one-decimal target). This ticket captures the broader rounding/display inconsistency and partial-hour root cause from modifier stacking.
Scope
Frontend
- Primary display:
attik-frontend/src/app/tools/inspections/[id]/components/InspectionDateChip.tsx— workorder header chip next to date/time; confirmed render path for user-reported behavior. - Secondary display:
attik-frontend/src/app/tools/inspections/[id]/components/EditChargesModal.tsx(footer total duration),WorkorderPriceChangeConfirmModal.tsx(already two-decimal preview — align or reuse formatter). - Duration calculation / persistence touchpoints:
calculateServicePrices.ts,modifierPriceAdjFn.ts,usePriceCalculation.ts,buildDurationEndtimePatch.ts,recalculateChargesForRequiredInfo.ts(computeTotalJobDurationHours), and scheduler save paths (NewSchedulingForm.tsx,attik-frontend/src/app/scheduler/hooks/useDraftSaveOrchestrator.ts,attik-frontend/src/app/scheduler/SchedulerContext.tsx). - Reschedule flows:
RescheduleJobModal.tsxderivestotalDurationfrom charge service definitions and allows manual 0.5-hour edits — regression-check after any formatter or rounding change.
Backend
attik-backend/src/models/inspectionSchema.ts—durationfield type only; no precision constraint.attik-backend/src/routes/inspection.ts— reschedule/PATCH assignsinspection.durationfrom request body without normalization.- Decision needed: display-only rounding vs. canonical rounding on write (create + PATCH + Spectora sync paths) so stored values match what users see.
Product / architecture decisions (for the implementer)
- Decision needed: Target precision — one decimal (e.g.
3.5h), two decimals (matches confirm modal / some save paths), or integers when whole (e.g.3hvs3.5h). - Decision needed: Scope of fix — display formatter only vs. normalize at calculation and save so downstream scheduling, calendar blocks, and exports stay consistent.
- Decision needed: Whether to introduce a shared duration formatter under
attik-frontend/src/util/...reused by chip, Edit Charges, and confirm modal.
References
- Related: ATT-1654 — Duration shows too many decimal places
- Display site:
attik-frontend/src/app/tools/inspections/[id]/components/InspectionDateChip.tsx - Modifier time math:
attik-frontend/src/util/functions/data/modifierPriceAdjFn.ts - Stored field:
attik-backend/src/models/inspectionSchema.ts(duration)