feat(notes): service-layer support for notes on entry and month_entry
add_entry and add_month_entry accept an optional notes keyword. A new set_entry_notes function updates a single budget entry's notes. update_month_entry gains a notes parameter guarded by a sentinel so callers can distinguish "do not touch notes" from "clear to NULL". create_month copies entry.notes into each freshly snapshotted month_entry. Blank / whitespace notes normalise to NULL. Refs #13 Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
4d40843e24
commit
034a8d65f5
2 changed files with 48 additions and 2 deletions
|
|
@ -112,6 +112,7 @@ def create_month(db: Session, year_month: str) -> Month:
|
|||
name=e.name,
|
||||
planned=e.amount,
|
||||
applied=Decimal("0.00"),
|
||||
notes=e.notes,
|
||||
origin_name=e.name,
|
||||
origin_planned=e.amount,
|
||||
source_entry_id=e.id,
|
||||
|
|
@ -203,12 +204,20 @@ def section_view(month: Month, section: Section, label: str) -> MonthSectionView
|
|||
)
|
||||
|
||||
|
||||
def _clean_notes(raw: str | None) -> str | None:
|
||||
if raw is None:
|
||||
return None
|
||||
stripped = raw.strip()
|
||||
return stripped if stripped else None
|
||||
|
||||
|
||||
def add_month_entry(
|
||||
db: Session,
|
||||
month: Month,
|
||||
section: Section,
|
||||
name: str,
|
||||
planned: Decimal,
|
||||
notes: str | None = None,
|
||||
) -> MonthEntry:
|
||||
entry = MonthEntry(
|
||||
month_id=month.id,
|
||||
|
|
@ -216,6 +225,7 @@ def add_month_entry(
|
|||
name=name.strip(),
|
||||
planned=planned,
|
||||
applied=Decimal("0.00"),
|
||||
notes=_clean_notes(notes),
|
||||
origin_name=None,
|
||||
origin_planned=None,
|
||||
source_entry_id=None,
|
||||
|
|
@ -243,6 +253,9 @@ def delete_month_entry(db: Session, month: Month, entry_id: int) -> Section | No
|
|||
return section
|
||||
|
||||
|
||||
_NOTES_SENTINEL = object()
|
||||
|
||||
|
||||
def update_month_entry(
|
||||
db: Session,
|
||||
month: Month,
|
||||
|
|
@ -251,6 +264,7 @@ def update_month_entry(
|
|||
name: str | None = None,
|
||||
planned: Decimal | None = None,
|
||||
applied: Decimal | None = None,
|
||||
notes: str | None | object = _NOTES_SENTINEL,
|
||||
) -> MonthEntry | None:
|
||||
entry = get_month_entry(db, month, entry_id)
|
||||
if entry is None:
|
||||
|
|
@ -261,6 +275,8 @@ def update_month_entry(
|
|||
entry.planned = planned
|
||||
if applied is not None:
|
||||
entry.applied = applied
|
||||
if notes is not _NOTES_SENTINEL:
|
||||
entry.notes = _clean_notes(notes) # type: ignore[arg-type]
|
||||
db.commit()
|
||||
db.refresh(entry)
|
||||
return entry
|
||||
|
|
|
|||
|
|
@ -87,14 +87,44 @@ def budget_zero(db: Session) -> Decimal:
|
|||
return (total_income - total_non_income).quantize(Decimal("0.01"))
|
||||
|
||||
|
||||
def add_entry(db: Session, section: Section, name: str, amount: Decimal) -> Entry:
|
||||
entry = Entry(section=section, name=name.strip(), amount=amount)
|
||||
def add_entry(
|
||||
db: Session,
|
||||
section: Section,
|
||||
name: str,
|
||||
amount: Decimal,
|
||||
notes: str | None = None,
|
||||
) -> Entry:
|
||||
entry = Entry(
|
||||
section=section,
|
||||
name=name.strip(),
|
||||
amount=amount,
|
||||
notes=_clean_notes(notes),
|
||||
)
|
||||
db.add(entry)
|
||||
db.commit()
|
||||
db.refresh(entry)
|
||||
return entry
|
||||
|
||||
|
||||
def _clean_notes(raw: str | None) -> str | None:
|
||||
if raw is None:
|
||||
return None
|
||||
stripped = raw.strip()
|
||||
return stripped if stripped else None
|
||||
|
||||
|
||||
def set_entry_notes(
|
||||
db: Session, entry_id: int, notes: str | None
|
||||
) -> Entry | None:
|
||||
entry = db.get(Entry, entry_id)
|
||||
if entry is None:
|
||||
return None
|
||||
entry.notes = _clean_notes(notes)
|
||||
db.commit()
|
||||
db.refresh(entry)
|
||||
return entry
|
||||
|
||||
|
||||
def delete_entry(db: Session, entry_id: int) -> Entry | None:
|
||||
entry = db.get(Entry, entry_id)
|
||||
if entry is None:
|
||||
|
|
|
|||
Loading…
Reference in a new issue