Group payments into ISO-week buckets
Python · Python · advanced · greenfield
Adds the ISO-week bucketing for the revenue report. The key comes straight from `date.isocalendar()` — both the week and, crucially, the ISO week-year, so the December/January boundary lands in the week finance expects. Keys are zero-padded so lexicographic order is chronological order, and the result dict is built in sorted key order.
Requirements
- Implement `iso_week_key(day)` and `weekly_totals(payments)` for the revenue report. `day` is a `datetime.date`; each payment is `{'paid_on': date, 'amount_cents': int}` (amounts are integer cents, may be negative for refunds).
- Buckets follow **ISO-8601 week numbering**, including its year boundary: the key uses the ISO week-**year**, not the calendar year — e.g. 2025-12-29 falls in `2026-W01`, and 2027-01-01 falls in `2026-W53`. Finance reconciles against ISO weeks; calendar-year keys are wrong.
- Key format `YYYY-Www`: the ISO week-year zero-padded to four digits, the week to two (`2026-W03`). Payment dates are real payment data — years 1970 through 9999.
- `weekly_totals` returns a dict whose keys iterate in chronological order.
- An empty payment list returns an empty dict.
Files touched
- app/reports/weekly_revenue.py
--- app/reports/weekly_revenue.py
+from collections import defaultdict
+
+
+def iso_week_key(day):
+ """ISO-8601 week key for a date, e.g. ``2026-W03``."""
+ year, week, _ = day.isocalendar()
+ return f"{year:04d}-W{week:02d}"
+
+
+def weekly_totals(payments):
+ """Sum payment amounts (integer cents) into ISO-week buckets, oldest first."""
+ totals = defaultdict(int)
+ for payment in payments:
+ totals[iso_week_key(payment["paid_on"])] += payment["amount_cents"]
+ return dict(sorted(totals.items()))
+