83 lines
2.1 KiB
Python
83 lines
2.1 KiB
Python
import json
|
||
import os
|
||
from datetime import date, timedelta
|
||
import calendar
|
||
|
||
DATA_DIR = os.path.join(os.path.dirname(__file__), "data")
|
||
BILLS_FILE = os.path.join(DATA_DIR, "bills.json")
|
||
|
||
|
||
def load_bills():
|
||
if os.path.exists(BILLS_FILE):
|
||
with open(BILLS_FILE) as f:
|
||
return json.load(f)
|
||
return []
|
||
|
||
|
||
def save_bills(bills):
|
||
with open(BILLS_FILE, "w") as f:
|
||
json.dump(bills, f, indent=2)
|
||
|
||
|
||
def get_week_label(day):
|
||
if day <= 7:
|
||
return "Week 1 (1–7)"
|
||
elif day <= 14:
|
||
return "Week 2 (8–14)"
|
||
elif day <= 21:
|
||
return "Week 3 (15–21)"
|
||
else:
|
||
return "Week 4 (22–end)"
|
||
|
||
|
||
def get_week_num(day):
|
||
if day <= 7:
|
||
return 1
|
||
elif day <= 14:
|
||
return 2
|
||
elif day <= 21:
|
||
return 3
|
||
else:
|
||
return 4
|
||
|
||
|
||
def bills_for_month(year, month):
|
||
from datetime import datetime
|
||
all_bills = load_bills()
|
||
_, num_days = calendar.monthrange(year, month)
|
||
result = []
|
||
for b in all_bills:
|
||
if not b.get("active", True):
|
||
continue
|
||
# Specific-date bills (BNPL payments)
|
||
if b.get("due_date_str"):
|
||
try:
|
||
d = datetime.strptime(b["due_date_str"], "%Y-%m-%d").date()
|
||
if d.year == year and d.month == month:
|
||
result.append({**b, "due_date": d, "due_day": d.day})
|
||
except ValueError:
|
||
pass
|
||
# Recurring monthly bills
|
||
elif b.get("due_day"):
|
||
due_day = b["due_day"]
|
||
if 1 <= due_day <= num_days:
|
||
result.append({**b, "due_date": date(year, month, due_day)})
|
||
return sorted(result, key=lambda x: x.get("due_day", 0))
|
||
|
||
|
||
def calendar_grid(year, month):
|
||
_, num_days = calendar.monthrange(year, month)
|
||
first_weekday = calendar.monthrange(year, month)[0] # 0=Mon
|
||
# Convert to Sun-first
|
||
first_weekday = (first_weekday + 1) % 7
|
||
|
||
days = []
|
||
for _ in range(first_weekday):
|
||
days.append(None)
|
||
for d in range(1, num_days + 1):
|
||
days.append(d)
|
||
while len(days) % 7 != 0:
|
||
days.append(None)
|
||
|
||
return [days[i:i+7] for i in range(0, len(days), 7)]
|