Advanced: Time Tracking
For users who already know the basics β this guide covers the rate hierarchy in depth, CSV import best practices, payroll locking mechanics, bulk correction strategies, and how the hour balance is actually calculated.
The Hourly Rate Hierarchy
Three tiers determine which rate appears on an invoice line item when unbilled hours are imported:
- Per-member project rate β set on the project's Team tab for a specific employee. This is the most specific and always wins.
- Project default rate β set on the project itself. Applies to all team members who don't have a per-member override.
- Employee default rate β set on the employee's profile under the Hourly Rate field. This is the fallback when neither of the above is set.
If all three are blank, the line item imports with a rate of zero β you'll need to edit the invoice manually. The most common mistake is forgetting to set the employee default for new hires before their first billing cycle.
Changing rates mid-project: The rate is resolved and stored on each time entry when it is created (at clock-in or when a manual entry is saved), not at invoice-import time. That resolved value is the hourly_rate_applied column, which InvoiceService::resolveRate() reads first. If you change a project rate in week 3, hours already logged in weeks 1 and 2 will keep their captured rate when imported β they do not retroactively pick up the new rate. Editing a time entry's times or project doesn't re-resolve the rate either. To propagate a new rate to older entries you must either delete and re-create them, or set a custom rate on the invoice line at billing time.
CSV Import Best Practices
The import is all-or-nothing: if any row fails validation, nothing is imported. Run the Analyze step every time before committing.
Common failure causes and how to avoid them:
- Wrong date format β use
YYYY-MM-DDexactly;DD.MM.YYYYwill fail. - Duration vs. start/end time β the template expects start + end (and optional break minutes), not a pre-computed duration. Supply both columns.
- Unknown project name β the import matches projects by exact name. A trailing space or different capitalisation will cause a "project not found" error on every row referencing it. Export the project list from the app and paste names directly.
- Duplicates β the pre-import analysis flags entries where the same employee, date, start time, and end time already exist. Review these carefully; the system won't auto-merge.
- Importing for other employees β only users with the Create entries for others permission can import rows assigned to colleagues. If you're an employee importing your own history, remove the "Employee" column entirely and the system will default to you.
After a large import, do a spot-check on the Team view immediately: confirm totals look right before payroll runs.
Understanding Payroll Locking
When payroll is generated for a period, every time entry consumed by that run receives a lock β both payroll_id and payroll_locked_at are set on the entry. Locked entries become read-only (canBeEdited() / canBeDeleted() both return false) and they disappear from the Add unbilled hours tab on draft invoices.
This is by design. Payroll is the formal sign-off on worked hours. Once the payroll report is issued, the underlying data must be immutable for audit purposes.
There is no per-entry unlock UI or permission. The only way to make a locked entry editable again is to delete the parent payroll itself β the payroll_id foreign key is onDelete('set null'), so removing the payroll immediately unlocks every entry it consumed (because isLockedInPayroll() requires both payroll_id AND payroll_locked_at to be non-null).
What to do when a locked entry is wrong:
- Prefer a forward adjustment. Do nothing to the locked entry. Create a corrected entry (or an offsetting correction) in the current open period. It will appear as an adjustment in the NEXT payroll run β this is what Swiss payroll law expects for issued reports.
- Only delete the payroll if the correction can't wait β e.g., the error was significant enough to invalidate the issued report and you haven't sent it yet. Deleting the payroll unlocks ALL its entries at once, so be surgical: fix the specific entries, then re-run payroll for that period.
Never delete a payroll just to edit a single entry unless you also plan to re-issue the payroll report. The forward-adjustment path (step 1) is the norm.
Bulk Corrections
When you have many entries to fix (e.g., an import batch went in with the wrong project), the fastest approach is:
- Export the period using the Team view's export function β you'll get a CSV of all entries for the date range.
- Delete the batch β filter to the wrong project in the Team view and bulk-delete (admin only, before payroll lock).
- Fix the CSV β update the project column.
- Re-import β run the Analyze step, then commit.
If entries are already payroll-locked, you cannot delete them in bulk. You must unlock each one individually, correct it, and let it flow into the next payroll run as a correction.
How the Hour Balance Is Calculated
The Stundenguthaben (hour balance) widget compares hours worked against hours owed for the current or selected week.
Hours owed = contracted weekly hours Γ (work percentage / 100), adjusted for:
- Public holidays in the employee's canton that fall on working days.
- Approved leave (vacation, special, parental) β these days reduce the target, not the worked count.
- Sick leave β sick days also reduce the weekly target once the sick leave is acknowledged.
Hours worked = sum of all completed time entries in the week.
Common misreadings:
- An employee on 80% working MondayβThursday will show a lower weekly target than a full-time colleague β that's correct.
- A day off for a cantonal holiday reduces the owed hours automatically. If the balance looks odd after a holiday, check that the employee's canton is set correctly on their profile.
- Leave that's still in pending status does not reduce the target. The manager needs to approve it first.
Related Guides
- Advanced: Projekte β rate hierarchy from the project side, historical rate tracking
- Modules-Zeiterfassung β basic setup and daily workflow
Was this article helpful?
Still need help?
Contact support