feat(joplin): add --joplin flag to fetch weekly timesheet note from Joplin
- Add joplin.py with fetch_week_note() that walks Work > Timesheets > YYYY and returns the body of the matching YYYY-WNN note via joppy ClientApi - Add filter_rows_by_date() to parser.py to extract only rows belonging to a specific day based on '# ... YYYY-MM-DD' headings in the document - Update cli.py: input and --joplin are now a mutually exclusive required group; add --token flag with JOPLIN_TOKEN env var fallback; --date is parsed into a real date object used for both output and day filtering - Add joppy as a runtime dependency (lazy-imported in cli.py) - Add tests for filter_rows_by_date and full mocked coverage of joplin.py - Update AGENTS.md with Joplin usage, notebook structure, and test rules The actual Joplin structure has notes directly inside the year notebook (Work > Timesheets > YYYY), not in per-week sub-notebooks as initially assumed. fetch_week_note() reflects this flat structure.
This commit is contained in:
parent
d6689a6c83
commit
ecdd28e8a3
8 changed files with 513 additions and 17 deletions
44
AGENTS.md
44
AGENTS.md
|
|
@ -4,7 +4,7 @@
|
|||
|
||||
A Python CLI tool that parses markdown pipe-delimited timesheet tables and
|
||||
exports them to CSV for import into Odoo (or similar tools). It also supports
|
||||
a human-readable summary view.
|
||||
a human-readable summary view and can fetch notes directly from Joplin.
|
||||
|
||||
### Package layout
|
||||
|
||||
|
|
@ -14,9 +14,10 @@ timesheets/
|
|||
├── AGENTS.md
|
||||
└── src/timesheets/
|
||||
├── cli.py # argument parsing, main() entry point
|
||||
├── parser.py # markdown table parsing and row aggregation
|
||||
├── parser.py # markdown table parsing, aggregation, date filtering
|
||||
├── projects.py # project_map.json loading and key resolution
|
||||
├── output.py # CSV writing and summary printing
|
||||
├── joplin.py # Joplin API integration (notebook traversal, note fetching)
|
||||
└── utils.py # shared low-level helpers (duration parsing, formatting, etc.)
|
||||
```
|
||||
|
||||
|
|
@ -27,7 +28,8 @@ tests/
|
|||
├── test_utils.py
|
||||
├── test_parser.py
|
||||
├── test_projects.py
|
||||
└── test_output.py
|
||||
├── test_output.py
|
||||
└── test_joplin.py
|
||||
```
|
||||
|
||||
---
|
||||
|
|
@ -57,7 +59,7 @@ uv run timesheets input.md
|
|||
uv run timesheets input.md -o output.csv
|
||||
|
||||
# Override the date (DD/MM/YY)
|
||||
uv run timesheets input.md --date 22/03/26
|
||||
uv run timesheets input.md --date 22/05/26
|
||||
|
||||
# Use a specific project map file
|
||||
uv run timesheets input.md --map /path/to/project_map.json
|
||||
|
|
@ -67,13 +69,44 @@ uv run timesheets input.md --summary
|
|||
|
||||
# Read from stdin
|
||||
cat input.md | uv run timesheets -
|
||||
|
||||
# Fetch today's entries from Joplin (token via env var)
|
||||
JOPLIN_TOKEN=your_token uv run timesheets --joplin
|
||||
|
||||
# Fetch entries for a specific date from Joplin
|
||||
uv run timesheets --joplin --date 22/05/26 --token your_token
|
||||
```
|
||||
|
||||
The `--joplin` flag and the file `input` argument are mutually exclusive.
|
||||
When `--joplin` is used, only entries matching the target date (from `--date`,
|
||||
or today) are returned, filtered by the `# ... YYYY-MM-DD` day heading in the note.
|
||||
|
||||
The API token can be provided via:
|
||||
- `--token <token>` CLI flag
|
||||
- `JOPLIN_TOKEN` environment variable
|
||||
|
||||
`project_map.json` is auto-discovered in the current working directory if
|
||||
`--map` is not provided.
|
||||
|
||||
---
|
||||
|
||||
## Joplin notebook structure
|
||||
|
||||
The `--joplin` flag expects the following notebook hierarchy in Joplin:
|
||||
|
||||
```
|
||||
Work/
|
||||
└── Timesheets/
|
||||
└── YYYY/
|
||||
└── YYYY - WNN/ ← notebook per week
|
||||
└── YYYY - WNN ← note with the same title as the notebook
|
||||
```
|
||||
|
||||
The note body contains one markdown table per day, each preceded by a heading
|
||||
of the form `# <weekday> - YYYY-MM-DD`.
|
||||
|
||||
---
|
||||
|
||||
## Testing
|
||||
|
||||
The test suite uses **pytest** with **pytest-cov** for coverage reporting.
|
||||
|
|
@ -110,3 +143,6 @@ uv run pytest tests/test_parser.py::TestParseTable::test_empty_input
|
|||
|
||||
4. `cli.py` is intentionally excluded from unit tests — it is thin glue code.
|
||||
All logic worth testing belongs in the other modules.
|
||||
|
||||
5. Joplin integration tests in `test_joplin.py` must mock `ClientApi` — do not
|
||||
require a live Joplin instance.
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue