Skip to content

Fix Weekly Timesheet Total Rounding Mismatch - #507

Open
SarkarShubhdeep wants to merge 2 commits into
mainfrom
fix/434-weekly-total-rounding
Open

Fix Weekly Timesheet Total Rounding Mismatch#507
SarkarShubhdeep wants to merge 2 commits into
mainfrom
fix/434-weekly-total-rounding

Conversation

@SarkarShubhdeep

@SarkarShubhdeep SarkarShubhdeep commented Sep 1, 2026

Copy link
Copy Markdown
Collaborator

Fixes #434

Summary

  • Weekly Total Hours summed raw session seconds, then rounded once. Each row already rounded to the nearest minute on its own, so leftover seconds across days could add an extra minute to the card (40h 1m) while the visible sessions still added to 40h 0m.
  • Session data is unchanged. Only the display total now rounds each session to the nearest minute first, then sums those values, matching the rows.
  • Personal and admin timesheets both use sumRoundedDurationsForDisplay for Total Hours only. Break Hours / Avg Session are unchanged.

Rounding rule

Leftover 0–29s → round down, 30–59s → round up (Math.round(seconds / 60) * 60).

Before vs after (#434)

Five sessions at 8h 0m 12s each:

Total
Rows (each rounded) 8h 0m × 5 = 40h 0m
Old card (sum raw, round once) 40h 1m
New card (round each, then sum) 40h 0m

Out of scope (separate PRs if needed)

  • Admin day-header vs expanded work-row mismatches (break/midnight segment rounding)
  • Total Hours vs day-header sum when those formulas differ
  • Clock timestamp vs duration ±1m (minute-only clocks, rounded durations)
  • Wall-clock vs work-seconds fallback when accumulatedTime is missing
  • Exact seconds display / ~ nearest-minute cards
  • Break Hours / Avg Session alignment

Test plan

  • Personal timesheet: several ~8h days with leftover seconds → Total Hours matches sum of visible session minutes
  • Admin timesheet Total Hours uses the same round-then-sum rule
  • npx vitest run src/features/clock/timesheetUtils.test.ts

Copilot AI balanced review requested due to automatic review settings September 1, 2026 15:33
@github-actions

github-actions Bot commented Sep 1, 2026

Copy link
Copy Markdown

🚀 Preview Deployment Ready

Service URL
App https://mieweb-timehuddle-fix-434-weekly-total-rounding.os.mieweb.org
API (Meteor) https://mieweb-timehuddle-fix-434-weekly-total-rounding-api.os.mieweb.org

Preview auto-deletes when this PR is closed.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Updates timesheet display aggregation so totals sum per-session rounded durations.

Changes:

  • Adds a shared duration aggregation helper and unit tests.
  • Applies it to personal and admin summaries.
  • Adds an end-to-end regression test.

Reviewed changes

Copilot reviewed 5 out of 5 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
src/features/clock/timesheetUtils.ts Adds rounded-duration summation.
src/features/clock/timesheetUtils.test.ts Tests rounding behavior.
src/features/clock/PersonalTimesheetPanel.tsx Updates personal summary calculations.
src/features/teams/AdminTimesheetPanel.tsx Updates admin total calculation.
tests/e2e/timesheet/timesheet-calculation-fixes.spec.ts Verifies displayed row and total agreement.
Suppressed comments (1)

src/features/clock/PersonalTimesheetPanel.tsx:453

  • Break Hours now rounds one aggregate per session rather than each visible break row. Two 30-second breaks in one session render as two 1m Break Period rows, but getSessionBreakSeconds returns 60 seconds and this helper reports 1m. Round the individual break durations used by TimesheetRow, or retain the prior Break Hours behavior if this PR is intended to change only Total Hours.
    const totalBreakSeconds = sumRoundedDurationsForDisplay(
      filteredSessions.map((s) => getSessionBreakSeconds(s, currentTime)),

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread src/features/clock/PersonalTimesheetPanel.tsx
Comment thread src/features/clock/PersonalTimesheetPanel.tsx Outdated
Comment thread src/features/teams/AdminTimesheetPanel.tsx
@SarkarShubhdeep
SarkarShubhdeep marked this pull request as ready for review September 1, 2026 19:46
@SarkarShubhdeep SarkarShubhdeep self-assigned this Sep 1, 2026

@Dharp02 Dharp02 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a lot of code for simple rounding error.

@SarkarShubhdeep

SarkarShubhdeep commented Sep 2, 2026

Copy link
Copy Markdown
Collaborator Author

This is a lot of code for simple rounding error.

@Dharp02 fair point — this got bigger than the bug.

What #434 asked for: rows already show nearest-minute durations (8h × 5 = 40h), but Total Hours summed raw seconds first and rounded once, so leftover seconds across the week could surface as 40h 1m. Expected: the card matches the visible minutes (40h 0m).

What landed: two different fixes.

  1. First commit (7efb10d) was the small one: round each session to the nearest minute, then sum. That matches the rows and closes Weekly total shows 40h 1m instead of 40h #434.
  2. After Copilot’s review (break/midnight segments, Break Hours, Avg Session, admin day rows) I switched models: show exact seconds on timesheet rows/cards, and put a ~ nearest-minute line under the total. That also pulled TimesheetRow’s break/midnight splitting into timesheetTimeline.ts so cards and rows share one path.
    That’s a display redesign, not the rounding bug. For the reported week the card still reads 40h 1m 0s / ~40h 1m — the extra minute is “honest” now because rows show 8h 0m 12s, but it is not the 40h 0m the issue asked for. Most of the +557/−300 is that second pass (extraction, new formatters, DurationStat, admin/break/avg surfaces, tests).

Proposal: keep this PR scoped to only #434.

Revert the seconds / ~ / shared-timeline work.
Restore round-then-sum for Total Hours only (personal + admin), so five visible 8h rows total 40h.
Leave Break Hours, Avg Session, clock-in/out format, and TimesheetRow internals alone.
If we still want exact seconds + ~ on cards, that should be a separate issue/PR so it can be reviewed as a UX change.

Copilot’s break-split edge case (30s + break + 30s rounding to 1m+1m vs session 1m) is real but not what #434 reported. I’d leave it out of this PR unless we hit it in the wild.

@SarkarShubhdeep

Copy link
Copy Markdown
Collaborator Author

Restoring that path should take this from +557 / −300 (13 files) down to about +220 / −20 (5 files) — roughly 60% fewer additions and ~70% less churn.

Of that +220, about 200 are tests (≈90 unit, ≈110 e2e) and ~20 are product code (the helper plus the two Total Hours cards). The Playwright case alone is half the leftover diff.

Round each session to the nearest minute before summing so leftover
seconds cannot add an extra minute to the weekly total (#434).

Co-authored-by: Cursor <cursoragent@cursor.com>
@SarkarShubhdeep
SarkarShubhdeep force-pushed the fix/434-weekly-total-rounding branch from 1ebcfbf to 6fd1c6d Compare September 2, 2026 18:04
@SarkarShubhdeep

SarkarShubhdeep commented Sep 2, 2026

Copy link
Copy Markdown
Collaborator Author

@Dharp02

I shrunk the PR back to the original #434 fix only:

  • Round each session to the nearest minute, then sum for Total Hours (personal + admin)
  • Removed the seconds display, ~ approximation line, shared timeline extraction, and the extra e2e case
  • Diff is now 4 files, +59 / −6

Break Hours / Avg Session are unchanged. Admin day-row vs expanded-row mismatches (breaks/midnight), clock-vs-duration ±1m, and wall-clock vs work-seconds fallbacks are out of scope here and can be separate PRs if we want them next.

Happy to re-review when you have a minute.

Co-authored-by: Cursor <cursoragent@cursor.com>

@Dharp02 Dharp02 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review: no breaking changes found.

Checked out the PR branch and verified:

  • sumRoundedDurationsForDisplay() unit tests pass (including the new #434 regression cases: 40h 0m vs old 40h 1m).
  • ESLint clean on all 4 changed files.
  • Both display sites (PersonalTimesheetPanel.tsx, AdminTimesheetPanel.tsx) render totalSeconds directly without re-wrapping in roundDurationSecondsForDisplay, so there's no double-rounding.
  • averageSessionSeconds correctly still uses the raw (unrounded) sum — unchanged, matches issue scope.

Diff is small and tightly scoped to #434. Minor non-blocking nit: both panels iterate filteredSessions twice (once for rawWorkSeconds, once inside sumRoundedDurationsForDisplay's .map) — trivial for typical session counts, not worth blocking on.

LGTM.

@Dharp02
Dharp02 requested a review from horner September 3, 2026 22:32
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Weekly total shows 40h 1m instead of 40h

3 participants