bloombase/plants/utils/pruning.py

61 lines
2.3 KiB
Python

from datetime import date
def months_before(d, n):
"""Return a date on the 1st of the month n months before d."""
m = (d.month - 1 - n) % 12 + 1
y = d.year + (d.month - 1 - n) // 12
return date(y, m, 1)
def pruning_status(plant, today=None):
"""
Returns one of: 'overdue', 'due_this_month', 'upcoming', 'no_schedule'.
Checks the most recent past pruning month within 12 months. If it was
not logged the plant is overdue. Uses a 12-month rolling window so
December is correctly caught when checked in January.
"""
if today is None:
today = date.today()
months = plant.pruning_months or []
if not months:
return 'no_schedule'
logs = plant.pruning_logs.all()
logged = {(log.pruned_on.year, log.pruned_on.month) for log in logs}
# Check if this month is scheduled
if today.month in months:
if (today.year, today.month) not in logged:
return 'due_this_month'
else:
# This month is scheduled and already logged -> upcoming
return 'upcoming'
# Look for any scheduled month in the past 12 months (excluding this month, which we handled above).
# Stop at the first scheduled month we encounter going backwards.
for i in range(1, 13):
past = months_before(today, i)
if past.month in months:
# Found a past scheduled month
if (past.year, past.month) not in logged:
# Determine if this past month represents an actual overdue condition
if past.year == today.year:
# Same year, past month -> overdue
return 'overdue'
else:
# Previous year. It's overdue if:
# - past.month < today.month (e.g., Aug 2025 when today >= Aug)
# - OR wrap-around: today is early (1-3) and past.month >= some threshold
if past.month < today.month:
return 'overdue'
# Wrap-around when today is early and we're looking at previous year
# Consider any month in previous year as overdue if today is Jan-Mar
elif today.month <= 3:
return 'overdue'
return 'upcoming'
# No past scheduled month found
return 'upcoming'