mirror of
https://git.hiabuto.net/C3MA/CCMA.git
synced 2026-08-24 22:45:18 +02:00
Fix housekeeper false-positive overdue errors and ended-member birthday/anniversary noise
An overdue claim whose reminder had already been sent, with that reminder's own payment deadline still running, fell through to the plain "überfällig" error finding whenever reminder_due's escalation check returned None to signal "not yet time for the next Mahnstufe" -- that None was indistinguishable from "never handled at all" to the caller, so it looked neglected even though a reminder was already out. Give that case its own low-priority "reminder_awaiting_deadline" finding instead of silently falling back to the overdue-error path. Birthday and membership-anniversary findings also kept firing for members whose status is "ended", which doesn't make sense once the membership itself is over. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 5
parent
4ecdf87d05
commit
56a3f5f037
@@ -61,6 +61,35 @@ def test_reminder_rule_progresses_only_after_sent_deadline(tmp_path) -> None:
|
||||
assert "Erste Mahnung" in next_task.title
|
||||
|
||||
|
||||
def test_overdue_claim_awaiting_reminder_deadline_is_not_reported_as_error(tmp_path) -> None:
|
||||
repository, member = _overdue_claim_repository(tmp_path)
|
||||
housekeeper = Housekeeper(repository)
|
||||
draft = repository.create_reminder_draft(
|
||||
member.member_id,
|
||||
"claim-1",
|
||||
level=1,
|
||||
name="Zahlungserinnerung",
|
||||
payment_deadline_days=14,
|
||||
items=[],
|
||||
)
|
||||
sent = repository.mark_reminder_sent(member.member_id, "claim-1", draft["reminder_id"])
|
||||
deadline = date.fromisoformat(sent["payment_deadline"])
|
||||
|
||||
findings = [
|
||||
item
|
||||
for item in housekeeper.run(today=deadline - timedelta(days=1))
|
||||
if item.member_id == member.member_id
|
||||
]
|
||||
|
||||
# A reminder was already sent and its own deadline hasn't expired yet -- this is
|
||||
# being handled, so it must not appear as an unaddressed "error"-severity overdue
|
||||
# claim, only as a low-priority note that the existing deadline is still running.
|
||||
assert not any(item.code == "claim_overdue" for item in findings)
|
||||
awaiting = next(item for item in findings if item.code == "reminder_awaiting_deadline")
|
||||
assert awaiting.severity == "info"
|
||||
assert "Zahlungserinnerung" in awaiting.title
|
||||
|
||||
|
||||
def test_dunning_hold_suppresses_and_then_restores_task(tmp_path) -> None:
|
||||
repository, member = _overdue_claim_repository(tmp_path)
|
||||
housekeeper = Housekeeper(repository)
|
||||
|
||||
@@ -236,6 +236,39 @@ def test_housekeeper_does_not_create_claims_due_after_membership_end(tmp_path) -
|
||||
assert "membership-fee:2027:annual" not in claim_keys
|
||||
|
||||
|
||||
def test_housekeeper_skips_birthday_and_anniversary_for_ended_members(tmp_path) -> None:
|
||||
repository = MemberRepository(tmp_path)
|
||||
repository.initialize()
|
||||
active = repository.create_member(first_name="Active", last_name="Member", birth_date="1990-06-21")
|
||||
active.status = "active"
|
||||
active.accepted_at = "2025-06-21"
|
||||
active.membership_started_at = "2025-06-21"
|
||||
repository.save_member(active)
|
||||
ended = repository.create_member(first_name="Ended", last_name="Member", birth_date="1990-06-21")
|
||||
ended.status = "ended"
|
||||
ended.accepted_at = "2025-06-21"
|
||||
ended.membership_started_at = "2025-06-21"
|
||||
ended.membership_ended_at = "2025-12-31"
|
||||
repository.save_member(ended)
|
||||
|
||||
settings = housekeeper_module.HousekeeperSettings.from_values(
|
||||
birthday_days_before=0,
|
||||
birthday_days_after=0,
|
||||
anniversary_days_before=0,
|
||||
anniversary_days_after=0,
|
||||
anniversary_intervals="1Y",
|
||||
)
|
||||
|
||||
findings = Housekeeper(repository, settings).run(today=date(2026, 6, 21))
|
||||
codes_by_member = {}
|
||||
for item in findings:
|
||||
codes_by_member.setdefault(item.member_id, set()).add(item.code)
|
||||
|
||||
assert "birthday" in codes_by_member.get(active.member_id, set())
|
||||
assert "membership_anniversary" in codes_by_member.get(active.member_id, set())
|
||||
assert codes_by_member.get(ended.member_id, set()).isdisjoint({"birthday", "membership_anniversary"})
|
||||
|
||||
|
||||
def test_housekeeper_resolves_tasks_not_seen_in_current_run(tmp_path) -> None:
|
||||
repository = MemberRepository(tmp_path)
|
||||
repository.initialize()
|
||||
|
||||
Reference in New Issue
Block a user