mirror of
https://git.hiabuto.net/C3MA/CCMA.git
synced 2026-08-24 22:45:18 +02:00
Stop double-reporting overdue claims and add SEPA-specific followup
The claim-status and reminder-due housekeeper rules used to run
independently, so once a claim was both overdue and past its dunning
grace period, both a generic "überfällig" task and a "Mahnung fällig"
task showed up for the same problem. Rules can't see each other's
output, so the fix is to give reminder-due sole ownership of the whole
overdue lifecycle: a plain overdue notice during the grace period, then
either the dunning escalation or a fallback overdue notice (dunning
hold active, or waiting between reminder levels) -- never both at once.
claim-status now only handles claims that aren't overdue yet ("bald
fällig").
Members with an active SEPA mandate get a new sepa_debit_overdue finding
instead of the postal dunning escalation once a claim is past its grace
period, since mailing a Mahnung makes no sense for a member who pays by
direct debit -- the board needs to check/retrigger the debit instead.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 5
parent
42cde2a0c8
commit
4e4aa22589
@@ -29,11 +29,10 @@ def test_housekeeper_reports_initial_payment_and_open_claims(tmp_path) -> None:
|
||||
)
|
||||
|
||||
findings = Housekeeper(repository).run(today=date(2026, 2, 10))
|
||||
assert {finding.code for finding in findings} == {
|
||||
"initial_payment_overdue",
|
||||
"claim_overdue",
|
||||
"reminder_due",
|
||||
}
|
||||
# Both claims are more than the default 7-day grace period overdue, so the dunning
|
||||
# escalation ("reminder_due") is the single active finding for each -- no separate,
|
||||
# redundant "overdue" finding alongside it.
|
||||
assert {finding.code for finding in findings} == {"reminder_due"}
|
||||
|
||||
|
||||
def test_housekeeper_reports_birthdays_before_today_and_after(tmp_path) -> None:
|
||||
|
||||
+40
-1
@@ -68,7 +68,11 @@ def test_dunning_hold_suppresses_and_then_restores_task(tmp_path) -> None:
|
||||
reason="Betrag wird geklärt",
|
||||
)
|
||||
|
||||
assert not any(item.code == "reminder_due" for item in housekeeper.run(today=date(2026, 2, 10)))
|
||||
findings = housekeeper.run(today=date(2026, 2, 10))
|
||||
assert not any(item.code == "reminder_due" for item in findings)
|
||||
# The claim stays visible as a plain overdue notice instead of disappearing entirely
|
||||
# while the hold suppresses the dunning escalation.
|
||||
assert any(item.code == "claim_overdue" for item in findings)
|
||||
with pytest.raises(RepositoryError, match="Mahnsperre aktiv"):
|
||||
repository.create_reminder_draft(
|
||||
member.member_id,
|
||||
@@ -81,6 +85,41 @@ def test_dunning_hold_suppresses_and_then_restores_task(tmp_path) -> None:
|
||||
assert any(item.code == "reminder_due" for item in housekeeper.run(today=date(2026, 2, 10)))
|
||||
|
||||
|
||||
def test_overdue_claim_and_reminder_finding_are_never_shown_at_once(tmp_path) -> None:
|
||||
repository, member = _overdue_claim_repository(tmp_path)
|
||||
housekeeper = Housekeeper(repository)
|
||||
|
||||
# Still within the 7-day default grace period: only the plain overdue notice, no
|
||||
# dunning escalation yet.
|
||||
within_grace = housekeeper.run(today=date(2026, 2, 4))
|
||||
codes = {item.code for item in within_grace if item.member_id == member.member_id}
|
||||
assert codes == {"claim_overdue"}
|
||||
|
||||
# Past the grace period: the dunning escalation takes over as the single finding,
|
||||
# the redundant plain overdue notice disappears.
|
||||
past_grace = housekeeper.run(today=date(2026, 2, 10))
|
||||
codes = {item.code for item in past_grace if item.member_id == member.member_id}
|
||||
assert codes == {"reminder_due"}
|
||||
|
||||
|
||||
def test_sepa_member_gets_debit_followup_instead_of_reminder(tmp_path) -> None:
|
||||
repository, member = _overdue_claim_repository(tmp_path)
|
||||
member.iban = "DE89370400440532013000"
|
||||
member.mandate_reference = "MANDATE-1"
|
||||
member.mandate_signed_at = "2026-01-01"
|
||||
member.mandate_active = True
|
||||
repository.save_member(member)
|
||||
housekeeper = Housekeeper(repository)
|
||||
|
||||
findings = housekeeper.run(today=date(2026, 2, 10))
|
||||
codes = {item.code for item in findings if item.member_id == member.member_id}
|
||||
|
||||
assert codes == {"sepa_debit_overdue"}
|
||||
sepa_finding = next(item for item in findings if item.code == "sepa_debit_overdue")
|
||||
assert "Lastschrift" in sepa_finding.title
|
||||
assert "SEPA" in sepa_finding.detail
|
||||
|
||||
|
||||
def test_draft_can_be_cancelled_but_sent_reminder_cannot(tmp_path) -> None:
|
||||
repository, member = _overdue_claim_repository(tmp_path)
|
||||
draft = repository.create_reminder_draft(
|
||||
|
||||
Reference in New Issue
Block a user