Skip to content

Prevent overlaps in quick-entry and validate max capacity in a day - #6192

Open
IvanRublev wants to merge 1 commit into
kimai:mainfrom
IvanRublev:BUG-5348-quick-entry-gives-every-row-of-a-day-the
Open

IvanRublev wants to merge 1 commit into
kimai:mainfrom
IvanRublev:BUG-5348-quick-entry-gives-every-row-of-a-day-the

Conversation

@IvanRublev

@IvanRublev IvanRublev commented Sep 15, 2026 •

Copy link
Copy Markdown

Description

Fixes #5348: Quick entry gave every row of a day the same configured default start
time and saved the resulting overlaps, even though overlapping records are forbidden.

Root cause: QuickEntryController stamped every new grid row for every day with the
same default begin time, and the existing TimesheetOverlapping per-row constraint
only queries already-persisted records — it cannot see the other unsaved rows in the
same grid submission, so an overlap created inside one submission was invisible.

Fix: a new App\Validator\Constraints\QuickEntryWeek class-level constraint (with its
QuickEntryWeekValidator), wired into QuickEntryForm, that for each user/day group
in a quick-entry submission:

  • chains new rows back to back, starting after whatever the day already holds
    (TimesheetRepository::findForDay(), including a still-running timer that began an
    earlier day);
  • rejects the day with the same "You already have an entry for this time." message the
    single-entry form uses when a running timer would otherwise be silently overlapped;
  • rejects a day whose total duration (existing + submitted) exceeds that calendar day's
    actual DST-aware length, or whose chained end would cross midnight, naming the day
    (new translations/validators.en.xlf entry).

Existing (already-persisted) rows are never repositioned or checked against each other,
so a pre-existing overlapping pair remains editable without one side blocking the other.
allow_overlapping_records = 1 installations see no behavioural change beyond the new
day-capacity limit. TimesheetService::updateMultipleTimesheets() and the
single-entry/API paths are untouched.

Types of changes

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to change)

Checklist

  • I verified that my code applies to the guidelines (composer code-check: codestyle,
    phpstan level 9, linting all exit 0)
  • I updated the documentation (see here)
  • I agree that this code is used in Kimai (see license)

How this was verified

  • New tests: tests/Validator/Constraints/QuickEntryWeekValidatorTest.php (19 cases —
    chaining, day-sum boundaries, DST spring-forward/fall-back, running-timer block
    (same-day and begun-the-day-before), allow_overlapping_records=1 bypass, cleared
    duration, existing-overlapping-pair tolerance, multi-user isolation, translation
    domain wiring), tests/Repository/TimesheetRepositoryTest.php (new findForDay()
    coverage), tests/Controller/QuickEntryControllerTest.php (end-to-end reproduction +
    billing check via real HTTP submission).
  • All 18 of the task's acceptance criteria are checked off with evidence in
    tasks/BUG-5348-quick-entry-same-start-time-overlap.md.
  • Two rounds of an independent code-review pass found and fixed: a findForDay() gap
    for a still-running timer that began the previous day, a phpstan nullable-call gate
    failure in test code, and a missing translation domain on the day-capacity violation
    message.
  • Regression run: tests/Timesheet/TimesheetServiceTest.php,
    tests/Validator/Constraints/TimesheetOverlappingValidatorTest.php,
    tests/Model/QuickEntryWeekTest.php, tests/Model/QuickEntryModelTest.php,
    tests/Form/Type/QuickEntryTimesheetTypeTest.php,
    tests/Validator/Constraints/QuickEntryModelValidatorTest.php,
    tests/Validator/Constraints/QuickEntryTimesheetValidatorTest.php — all green.

…p overlaps

Co-authored-by: Kaizero <noreply@kaizero.sh>
@kevinpapst

Copy link
Copy Markdown
Member

Thanks.
Please join the discussion first, before posting a solution that includes new features / validations.
Just because some AI thinks a feature would be good, doesn't mean it should/will be included.

@kevinpapst kevinpapst changed the title BUG-5348 Quick entry gives every row of a day the same start time and saves the resulting overlaps although overlapping records are forbidden Prevent overlaps in quick-entry and validate max capacity in a day Sep 15, 2026
@IvanRublev

Copy link
Copy Markdown
Author

Thanks. Please join the discussion first, before posting a solution that includes new features / validations. Just because some AI thinks a feature would be good, doesn't mean it should/will be included.

Hi @kevinpapst thanks for your comment. I'm sorry for pushing the PR without a consensus about the new functionality. Happy to join the discussion.

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.

When using Quick Entry for multiple projects, start time is set the same

2 participants