Python program to automate exporting my Markdown timesheets to Odoo
| src/timesheets | ||
| tests | ||
| .coverage | ||
| .gitignore | ||
| .python-version | ||
| AGENTS.md | ||
| project_map.json | ||
| pyproject.toml | ||
| README.md | ||
| timesheets.example.toml | ||
| uv.lock | ||
Timesheets
A Python CLI tool that parses markdown pipe-delimited timesheet tables and exports them to CSV for import into Odoo. It also supports a human-readable summary view, a stories list, a work status dashboard, and can fetch notes directly from Joplin.
Package layout
timesheets/
├── pyproject.toml # package metadata, entry point, dev dependencies
├── timesheets.example.toml # example config file
└── src/timesheets/
├── cli.py # argument parsing, main() entry point
├── parser.py # markdown table parsing, aggregation, date filtering
├── projects.py # project_map.json loading and key resolution
├── output.py # CSV writing, summary, stories, and status printing
├── config.py # TOML config file loading and key extraction
├── joplin.py # Joplin API integration (notebook traversal, note fetching)
├── status.py # day/week status calculations
└── utils.py # shared low-level helpers (duration parsing, formatting, etc.)
Installation
cd timesheets
uv sync
Subcommands
| Command | Description |
|---|---|
summary |
Human-readable summary of time spent per project |
csv |
Export timesheet entries as CSV for Odoo import |
stories |
List stories worked on, grouped by project |
status |
Show hours remaining today and projected week total |
All subcommands accept the same source and day arguments:
# Source: Joplin (recommended) or a local file
uv run timesheets <cmd> --joplin
uv run timesheets <cmd> --input timesheet.md
# Day: defaults to today, accepts YYYY-MM-DD, MM-DD, natural language
uv run timesheets <cmd> 2026-05-22 --joplin
uv run timesheets <cmd> yesterday --joplin
uv run timesheets <cmd> 3 days ago --joplin
summary
uv run timesheets summary --joplin # today, full detail
uv run timesheets summary -w --joplin # full week
uv run timesheets summary -s --joplin # short: one line per project
uv run timesheets summary -w -s --joplin # weekly short: per-day project totals
uv run timesheets summary -w -ss --joplin # weekly totals only: one line per day
csv
uv run timesheets csv --joplin # stdout
uv run timesheets csv --joplin -o output.csv # write to file
stories
uv run timesheets stories --joplin # today
uv run timesheets stories -w --joplin # full week
status
uv run timesheets status --joplin
Config file
Copy timesheets.example.toml to timesheets.toml in the working directory
(or pass --config /path/to/file.toml):
[joplin]
token = "your_api_token_here"
[projects]
map = "/path/to/project_map.json"
[work]
daily_hours = 8.0
weekly_hours = 40.0
Priority order: CLI flag > config file > environment variable > default.
Joplin notebook structure
Work/
└── Timesheets/
└── YYYY/
└── YYYY - WNN ← note per week, one table per day
Each table is preceded by a heading of the form # <weekday> - YYYY-MM-DD.
Open entries (start time present, end time absent) are used by the status
command to calculate expected end time.