Commit graph

8 commits

Author SHA1 Message Date
8f5232d1fe
Fix weekly summary crash on open entries
print_summary_weekly, print_summary_weekly_totals and _aggregate summed
raw duration_hours, which is None for open (unfinished) entries, raising
TypeError: float + NoneType. Skip open entries from the weekly totals,
matching to_csv_entries and parser.aggregate. Add regression tests.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-02 09:31:17 +02:00
de46399010
Add ~ marker to exclude entries from CSV export
Prefix the project name or note column with ~ to mark an entry as
count-but-don't-export. Marked entries are included in summary and
status totals but omitted from all csv output (both --raw and
aggregated, single-day and weekly).

  | 09:00 | 17:00 | 8:00 | ~Leave |  | Day off  |
  | 09:00 | 17:00 | 8:00 |  Leave |  | ~Day off |

The ~ is stripped from whichever field carries it before any
downstream processing, so project map resolution is unaffected.

Implementation:
- parse_table sets skip_csv=True on marked rows and strips the ~
- new filter_skip_csv() helper in parser.py
- to_csv_entries() skips skip_csv rows
- _cmd_csv calls filter_skip_csv() before aggregate_rows()
2026-06-02 09:31:16 +02:00
cd8ca789aa
Add --weekly flag to csv command
- Add `write_csv_weekly()` to output.py: writes entries from multiple
  days as a single CSV with one header row, correct date per row
- Add `-w`/`--weekly` flag to csv subparser
- _cmd_csv branches on args.weekly: fetches week sections, formats
  per-day date strings, calls write_csv_weekly; --raw is honoured
- Add TestWriteCsvWeekly with 6 tests
- Update README with weekly csv usage examples
2026-06-02 09:31:14 +02:00
985ee28113
Add --raw flag to csv command to skip aggregation
- Add `to_csv_entries()` to output.py: converts raw rows to write_csv
  entries one-for-one, without merging by (project, description)
- Add `--raw` flag to the csv subparser; _cmd_csv branches on it
- Add TestToCsvEntries with 6 tests
- Update README with --raw usage example
- Add .coverage and htmlcov/ to .gitignore
2026-06-02 09:31:13 +02:00
2d60624e0e
feat(stories): add stories subcommand
- Add stories subcommand listing stories worked on, grouped by project
- Preserve story_raw in parser row dicts alongside the stripped story,
  so markdown links are available for display
- print_stories() filters to rows with a non-empty story field,
  deduplicates by stripped story text (preferring the linked version),
  sums hours per story, and outputs an indented Markdown list
- Project names resolved through project_map (same as csv/summary)
- -w/--weekly flag aggregates stories across the full week
- Add tests for print_stories covering deduplication, link preservation,
  grouping, empty rows, and story-less row exclusion
- Fix flex daily target in status: use projected hours per prior day
  rather than fixed 8h when computing remaining hours for today
2026-06-02 09:31:09 +02:00
f372a691d4
feat(status): add status subcommand with day and week metrics
- Add status.py with compute_day_status() and compute_week_status()
- Add projected_hours_for_day(): for each entry, use its duration if
  closed, or the next entry's start time as the close time if open
- Open entries (start present, end absent) are preserved by the parser
  instead of being skipped; aggregate_rows() skips them for summaries
- Expected end is computed by filling remaining hours into available
  time slots from the open entry's start; clamped to latest_end if a
  pre-logged entry ends later, with a note explaining why
- Projected week total sums projected_hours_for_day() across all days
- Add status subcommand to cli.py with shared source/day arguments
- Add [work] daily_hours / weekly_hours config keys (default 8 / 40)
- Add timesheets.example.toml [work] section
- Add tests for projected_hours_for_day, compute_day_status,
  compute_week_status and all DayStatus/WeekStatus fields
2026-06-02 09:31:08 +02:00
ac1e9f959a
feat(summary): add --weekly/-w and --short/-s flags
--weekly (-w): show the summary for the entire week containing the
given day, fetching from Joplin or parsing all tables in the file

--short (-s, repeatable):
  -s alone:       one line per project label + total
  -s --weekly:    per-day project totals with day subtotals
  -ss --weekly:   one line per day with right-aligned date + week total

Add filter_week_sections() to parser.py to split a document into
(date, rows) pairs for a given ISO week. Add print_summary_short(),
print_summary_weekly(), print_summary_weekly_short(), and
print_summary_weekly_totals() to output.py.
2026-06-02 09:31:07 +02:00
7bea08ddac
feat: set up modularized version of project with testing 2026-06-02 09:31:01 +02:00