diff --git a/plants/templates/plants/pruning_calendar.html b/plants/templates/plants/pruning_calendar.html index ab5446a..c0dcdb3 100644 --- a/plants/templates/plants/pruning_calendar.html +++ b/plants/templates/plants/pruning_calendar.html @@ -1,2 +1,68 @@ {% extends "plants/base.html" %} -{% block content %}

Pruning calendar coming soon.

{% endblock %} +{% block title %}Pruning Calendar — PlantDB{% endblock %} +{% block content %} +
✂️ Pruning Calendar
+ +{% if overdue %} +
⚠ Overdue
+
+ {% for plant in overdue %} + +
+
{{ plant.name }}
+ {{ plant.location }} +
+ Overdue +
+ {% endfor %} +
+{% endif %} + +{% if due_this_month %} +
This month — {{ month_name }}
+
+ {% for plant in due_this_month %} + +
+
{{ plant.name }}
+ {{ plant.location }} +
+ This month +
+ {% endfor %} +
+{% endif %} + +{% if next_month_plants %} +
Next — {{ next_month_name }}
+
+ {% for plant in next_month_plants %} + +
+
{{ plant.name }}
+ {{ plant.location }} +
+ {{ next_month_name }} +
+ {% endfor %} +
+{% endif %} + +{% if later %} +
+ Later this year ({{ later|length }}) +
+ {% for plant in later %} + +
{{ plant.name }}
+ {{ plant.location }} · Months: {{ plant.pruning_months|join:", " }} +
+ {% endfor %} +
+
+{% endif %} + +{% if not overdue and not due_this_month and not next_month_plants and not later %} +

No pruning schedules set. Add pruning months to your plants.

+{% endif %} +{% endblock %} diff --git a/plants/tests/test_views.py b/plants/tests/test_views.py index 97fd218..1b72c4c 100644 --- a/plants/tests/test_views.py +++ b/plants/tests/test_views.py @@ -215,3 +215,28 @@ class TestPlantDelete: plant = Plant.objects.create(name='Fern', location='Office') client.post(reverse('plant_delete', args=[plant.pk])) assert not Plant.objects.filter(pk=plant.pk).exists() + + +@pytest.mark.django_db +class TestPruningCalendar: + def test_returns_200(self, client): + resp = client.get(reverse('pruning_calendar')) + assert resp.status_code == 200 + + def test_overdue_plant_in_context(self, client): + plant = Plant.objects.create(name='Rose', location='Garden', pruning_months=[3]) + resp = client.get(reverse('pruning_calendar')) + assert plant in resp.context['overdue'] + + def test_due_this_month_in_context(self, client): + from datetime import date + today = date.today() + plant = Plant.objects.create(name='Apple', location='Garden', pruning_months=[today.month]) + resp = client.get(reverse('pruning_calendar')) + assert plant in resp.context['due_this_month'] + + def test_no_schedule_plants_excluded(self, client): + plant = Plant.objects.create(name='Fern', location='Office', pruning_months=[]) + resp = client.get(reverse('pruning_calendar')) + assert plant not in resp.context['overdue'] + assert plant not in resp.context['due_this_month'] diff --git a/plants/views/pruning.py b/plants/views/pruning.py index 28aac4a..6804ab9 100644 --- a/plants/views/pruning.py +++ b/plants/views/pruning.py @@ -5,4 +5,36 @@ from plants.utils.pruning import pruning_status def pruning_calendar(request): - return render(request, 'plants/pruning_calendar.html', {}) + today = date.today() + next_month_num = today.month % 12 + 1 + next_month_year = today.year + (1 if today.month == 12 else 0) + next_month_date = date(next_month_year, next_month_num, 1) + + all_plants = list( + Plant.objects.select_related('species').prefetch_related('pruning_logs') + ) + + overdue, due_this_month, next_month_plants, later = [], [], [], [] + + for plant in all_plants: + if not plant.pruning_months: + continue + status = pruning_status(plant, today) + if status == 'overdue': + overdue.append(plant) + elif status == 'due_this_month': + due_this_month.append(plant) + elif next_month_num in plant.pruning_months: + next_month_plants.append(plant) + else: + later.append(plant) + + return render(request, 'plants/pruning_calendar.html', { + 'overdue': overdue, + 'due_this_month': due_this_month, + 'next_month_plants': next_month_plants, + 'later': later, + 'today': today, + 'month_name': today.strftime('%B'), + 'next_month_name': next_month_date.strftime('%B'), + })