Timesheets Module Technical Reference
The Timesheets Module governs work hour registration, running task timers, background timer persistence, and Odoo timesheet entry syncing.
Codebase Mapโ
| Layer | Path | Purpose |
|---|---|---|
| Frontend UI | qml/features/timesheets/ | Logs list, manual entry forms, and timer overlays |
| State & Logic | models/timesheet.js | JS timesheet database bindings and manual logging logic |
| Timer Service | models/timer_service.js | JS timer worker coordinating state, notifications, and ticks |
| Backend Service | src/sync_to_odoo.py | Sync worker pushing timesheet entries |
| D-Bus Interface | src/backend.py | D-Bus methods exposing timesheet logging and active timer state |
Database Schemaโ
Timesheet entries are stored locally in the following SQLite table:
account_analytic_line_appโ
id(INTEGER, Primary Key): Unique analytic line ID.name(TEXT): Description/Notes logged by the user.date(TEXT): Date of work registration (YYYY-MM-DD).unit_amount(REAL): Hours spent (represented as decimal, e.g. 1.5 hours = 1h 30m).project_id(INTEGER): References the parent project.task_id(INTEGER): References the parent task.user_id(INTEGER): References the user entering the timesheet.eisenhower_priority(TEXT): Priority scale (Urgent/Important matrix).sync_dirty(INTEGER): Flag for pending remote synchronization (0 = Clean, 1 = Dirty).
Sync Mechanism & Network Protocolโ
Odoo XML-RPC Model Mappingโ
- Remote Model:
account.analytic.line(Odoo Timesheets) - Sync Direction: Bidirectional.
Timer Service & Persistenceโ
The active timer state is governed by models/timer_service.js and persists across app closures.
- When a timer starts, the timestamp
start_timeis written to local storage. - Even if the UI crashes or closes, the Python daemon checks the running timer state on boot and calculates elapsed time using system clock diffs.
Timesheet Operations: models/timesheet.js
Timer Operations: models/timer_service.js
Where the logic is defined:
saveTimesheet(data): Saves/inserts a new timesheet record into SQLite.createTimesheet(instance_id, userid): Instantiates a new empty timesheet record.isRunning(): Checks if the timer is active.getActiveTimesheetId(): Retrieves the active timesheet ID.getStartTime(): Retrieves the timer start timestamp.getElapsedTime(format): Calculates and formats current elapsed tracking duration.stop(): Stops the active timer, calculates the elapsed tracking time, updates the SQLite timesheet entry usingModel.updateTimesheetWithDuration(...), and changes its status.