from __future__ import annotations from decimal import Decimal from quartermaster import month_service, service from quartermaster.models import Section def test_add_entry_stores_notes(db): entry = service.add_entry( db, Section.sinking_fund, "Emergency", Decimal("500.00"), notes="Target: 3 months of expenses", ) assert entry.notes == "Target: 3 months of expenses" def test_add_entry_strips_and_nulls_empty_notes(db): entry = service.add_entry( db, Section.other, "Gift", Decimal("25.00"), notes=" " ) assert entry.notes is None def test_set_entry_notes_updates(db): entry = service.add_entry(db, Section.food, "Groceries", Decimal("400.00")) updated = service.set_entry_notes(db, entry.id, "weekly Costco run") assert updated is not None assert updated.notes == "weekly Costco run" def test_set_entry_notes_missing_returns_none(db): assert service.set_entry_notes(db, 9999, "oops") is None def test_snapshot_copies_notes(db): service.add_entry( db, Section.sinking_fund, "Emergency", Decimal("500.00"), notes="3 months expenses", ) month = month_service.create_month(db, "2026-04") emergency = next(e for e in month.entries if e.origin_name == "Emergency") assert emergency.notes == "3 months expenses" def test_month_notes_edit_does_not_change_deviation_state(db): service.add_entry( db, Section.fixed_bill, "Rent", Decimal("1200.00"), notes="auto-pay" ) month = month_service.create_month(db, "2026-04") rent = next(e for e in month.entries if e.origin_name == "Rent") # unchanged initially assert ( month_service.deviation_state(rent) == month_service.DeviationState.unchanged ) # update notes only month_service.update_month_entry( db, month, rent.id, notes="auto-pay; renew July 2027" ) db.refresh(rent) assert rent.notes == "auto-pay; renew July 2027" assert ( month_service.deviation_state(rent) == month_service.DeviationState.unchanged ) def test_update_month_entry_notes_to_empty_nulls(db): service.add_entry(db, Section.other, "Parking", Decimal("25.00"), notes="work") month = month_service.create_month(db, "2026-04") entry = next(e for e in month.entries if e.origin_name == "Parking") assert entry.notes == "work" month_service.update_month_entry(db, month, entry.id, notes="") db.refresh(entry) assert entry.notes is None # --- route-level ----------------------------------------------------------- def test_create_entry_route_accepts_notes(client): response = client.post( "/sections/sinking_fund/entries", data={"name": "Emergency", "amount": "500.00", "notes": "3 mo cushion"}, ) assert response.status_code == 200 assert "3 mo cushion" in response.text def test_update_entry_notes_route(client): client.post( "/sections/food/entries", data={"name": "Groceries", "amount": "400.00"}, ) response = client.post("/entries/1/notes", data={"notes": "weekly"}) assert response.status_code == 200 assert "weekly" in response.text def test_update_entry_notes_empty_clears(client): client.post( "/sections/food/entries", data={"name": "Groceries", "amount": "400.00", "notes": "weekly"}, ) response = client.post("/entries/1/notes", data={"notes": ""}) assert response.status_code == 200 # the input's value="" still renders but the placeholder kicks in; # specifically, no literal "weekly" anymore assert "value=\"weekly\"" not in response.text def test_create_month_entry_route_accepts_notes(client): client.post("/month/2026-04/create") response = client.post( "/month/2026-04/sections/other/entries", data={"name": "Gift", "planned": "25.00", "notes": "birthday"}, ) assert response.status_code == 200 assert "birthday" in response.text def test_update_month_entry_route_accepts_notes(client): client.post( "/sections/fixed_bill/entries", data={"name": "Rent", "amount": "1200.00"}, ) client.post("/month/2026-04/create") response = client.post( "/month/2026-04/entries/1", data={"notes": "auto-pay"} ) assert response.status_code == 200 assert "auto-pay" in response.text def test_budget_page_renders_notes_inputs(client): client.post( "/sections/fixed_bill/entries", data={"name": "Rent", "amount": "1200.00", "notes": "due 1st"}, ) response = client.get("/") assert response.status_code == 200 assert "entry-notes-row" in response.text assert "due 1st" in response.text def test_month_page_renders_notes_inputs(client): client.post( "/sections/fixed_bill/entries", data={"name": "Rent", "amount": "1200.00", "notes": "auto-pay"}, ) client.post("/month/2026-04/create") response = client.get("/month/2026-04") assert response.status_code == 200 # notes input lives inside the expandable entry body now assert 'name="notes"' in response.text assert "auto-pay" in response.text