feat(logging): seed month + posting events (#27)

This commit is contained in:
Jeff Smith 2026-04-19 11:42:32 -06:00
parent 41ee888d3b
commit 7340a66988
2 changed files with 112 additions and 0 deletions

View file

@ -1,5 +1,6 @@
from __future__ import annotations
import logging
import re
from dataclasses import dataclass
from datetime import date, datetime, timezone
@ -28,6 +29,8 @@ from quartermaster.models import (
Section,
)
logger = logging.getLogger("quartermaster.month_service")
YEAR_MONTH_RE = re.compile(r"^\d{4}-(0[1-9]|1[0-2])$")
@ -148,6 +151,10 @@ def create_month(db: Session, year_month: str) -> Month:
)
db.commit()
db.refresh(month)
logger.info(
"created month snapshot",
extra={"event": "month_created", "year_month": month.year_month},
)
return month
@ -314,6 +321,15 @@ def add_posting(
db.add(posting)
db.commit()
db.refresh(posting)
logger.info(
"added posting",
extra={
"event": "posting_added",
"posting_id": posting.id,
"month_entry_id": posting.month_entry_id,
"amount": str(posting.amount),
},
)
return posting
@ -368,6 +384,10 @@ def delete_posting(
entry = posting.entry
db.delete(posting)
db.commit()
logger.info(
"deleted posting",
extra={"event": "posting_deleted", "posting_id": posting_id},
)
return entry
@ -428,6 +448,10 @@ def close_month(db: Session, month: Month) -> Month:
month.closed_at = datetime.now(timezone.utc)
db.commit()
db.refresh(month)
logger.info(
"closed month",
extra={"event": "month_closed", "year_month": month.year_month},
)
return month

View file

@ -3,8 +3,14 @@ from __future__ import annotations
import io
import json
import logging
from datetime import date
from decimal import Decimal
import pytest
from quartermaster import month_service, service
from quartermaster.logging_config import LOG_CONFIG
from quartermaster.models import Section
def _build_formatter():
@ -89,3 +95,85 @@ def test_log_config_loads_via_dictconfig():
from quartermaster.logging_config import LOG_CONFIG
logging.config.dictConfig(LOG_CONFIG)
@pytest.fixture(autouse=True)
def _reset_quartermaster_logger():
"""Ensure the quartermaster logger propagates to root so caplog can capture records.
logging.config.dictConfig (called in test_log_config_loads_via_dictconfig) sets
propagate=False on the quartermaster logger. caplog injects its handler into the
root logger, so records only reach it when propagation is enabled. This fixture
temporarily re-enables propagation for every test in this module and restores the
original value on teardown.
"""
qm_logger = logging.getLogger("quartermaster")
original_propagate = qm_logger.propagate
qm_logger.propagate = True
yield
qm_logger.propagate = original_propagate
def _make_debt_minimum(db, name="Loan", amount=Decimal("100.00")):
from quartermaster.models import Entry
entry = Entry(section=Section.debt_minimum, name=name, amount=amount)
db.add(entry)
db.commit()
db.refresh(entry)
return entry
def test_create_month_logs_month_created_event(db, caplog):
caplog.set_level(logging.INFO, logger="quartermaster")
month_service.create_month(db, "2026-05")
events = [r for r in caplog.records if getattr(r, "event", None) == "month_created"]
assert len(events) == 1
assert events[0].levelname == "INFO"
def test_close_month_logs_month_closed_event(db, caplog):
month = month_service.create_month(db, "2026-06")
# move through active → closed with a zero-applied budget (no entries yet)
month_service.activate_month(db, month)
caplog.clear()
caplog.set_level(logging.INFO, logger="quartermaster")
month_service.close_month(db, month)
events = [r for r in caplog.records if getattr(r, "event", None) == "month_closed"]
assert len(events) == 1
def test_add_posting_logs_posting_added_event(db, caplog):
_make_debt_minimum(db)
month = month_service.create_month(db, "2026-07")
entry = month.entries[0]
caplog.set_level(logging.INFO, logger="quartermaster")
month_service.add_posting(
db, month, entry.id,
occurred_on=date(2026, 7, 15),
amount=Decimal("25.00"),
)
events = [r for r in caplog.records if getattr(r, "event", None) == "posting_added"]
assert len(events) == 1
def test_delete_posting_logs_posting_deleted_event(db, caplog):
_make_debt_minimum(db)
month = month_service.create_month(db, "2026-08")
entry = month.entries[0]
posting = month_service.add_posting(
db, month, entry.id,
occurred_on=date(2026, 8, 15),
amount=Decimal("10.00"),
)
caplog.clear()
caplog.set_level(logging.INFO, logger="quartermaster")
month_service.delete_posting(db, month, posting.id)
events = [r for r in caplog.records if getattr(r, "event", None) == "posting_deleted"]
assert len(events) == 1