mirror of
https://git.hiabuto.net/C3MA/CCMA.git
synced 2026-08-24 22:45:18 +02:00
Run the housekeeper for a single member, optionally retroactively
Add a "Hausmeister für dieses Mitglied" button to the member view. It runs every rule scoped to just that member -- e.g. after editing a contribution override or payment frequency, to recompute their claims on demand instead of waiting for or triggering a full run over every member. A checkbox lets the board force retroactive claim creation for just that one run, without changing the application-wide default setting. Housekeeper.run() gained member_id and retroactive_claims parameters. Scoping to one member skips the asset checks and leaves every other member's tasks completely untouched, since their rules never ran this pass and so fall outside the resolved-scope set that _resolve_stale_tasks uses to decide what to clear. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 5
parent
c07bdff04e
commit
ee99577b20
+65
-1
@@ -8,7 +8,7 @@ import pytest
|
||||
import ccma.services.housekeeper as housekeeper_module
|
||||
from ccma.rules.loader import RuleLoadError
|
||||
from ccma.services.housekeeper import Housekeeper
|
||||
from ccma.storage.repository import MemberRepository
|
||||
from ccma.storage.repository import MemberRepository, RepositoryError
|
||||
|
||||
|
||||
def test_housekeeper_optionally_waits_between_members(tmp_path, monkeypatch) -> None:
|
||||
@@ -381,3 +381,67 @@ def test_housekeeper_removes_items_for_deleted_member_directory(tmp_path) -> Non
|
||||
|
||||
assert findings == []
|
||||
assert not any(item.get("member_id") == member.member_id for item in state["items"])
|
||||
|
||||
|
||||
def test_housekeeper_run_can_target_a_single_member(tmp_path) -> None:
|
||||
repository = MemberRepository(tmp_path)
|
||||
repository.initialize()
|
||||
member_a = repository.create_member(first_name="Alpha", last_name="Member")
|
||||
member_b = repository.create_member(first_name="Beta", last_name="Member")
|
||||
housekeeper = Housekeeper(repository)
|
||||
housekeeper.run(today=date(2026, 6, 21))
|
||||
state_before = json.loads((repository.root / "housekeeper.json").read_text(encoding="utf-8"))
|
||||
b_task_before = next(
|
||||
item for item in state_before["items"] if item.get("member_id") == member_b.member_id
|
||||
)
|
||||
|
||||
member_a.birth_date = "1990-01-01"
|
||||
repository.save_member(member_a)
|
||||
findings = housekeeper.run(today=date(2026, 6, 21), member_id=member_a.member_id)
|
||||
|
||||
a_findings = [item for item in findings if item.member_id == member_a.member_id]
|
||||
assert not any(item.code == "missing_birth_date" for item in a_findings)
|
||||
state_after = json.loads((repository.root / "housekeeper.json").read_text(encoding="utf-8"))
|
||||
b_task_after = next(
|
||||
item for item in state_after["items"] if item.get("member_id") == member_b.member_id
|
||||
)
|
||||
assert b_task_after == b_task_before
|
||||
|
||||
|
||||
def test_housekeeper_run_rejects_unknown_member_id(tmp_path) -> None:
|
||||
repository = MemberRepository(tmp_path)
|
||||
repository.initialize()
|
||||
housekeeper = Housekeeper(repository)
|
||||
|
||||
with pytest.raises(RepositoryError, match="nicht gefunden"):
|
||||
housekeeper.run(today=date(2026, 6, 21), member_id="does-not-exist")
|
||||
|
||||
|
||||
def test_housekeeper_run_retroactive_override_applies_only_to_that_run(tmp_path) -> None:
|
||||
repository = MemberRepository(tmp_path)
|
||||
repository.initialize()
|
||||
member = repository.create_member(first_name="Retro", last_name="Member", birth_date="1990-01-01")
|
||||
member.status = "active"
|
||||
member.accepted_at = "2024-04-15"
|
||||
member.membership_started_at = "2024-04-15"
|
||||
member.payment_frequency = "annual"
|
||||
repository.save_member(member)
|
||||
housekeeper = Housekeeper(repository)
|
||||
|
||||
housekeeper.run(today=date(2026, 6, 21), member_id=member.member_id, retroactive_claims=True)
|
||||
|
||||
claim_keys = {claim["claim_key"] for claim in repository.get_contributions(member.member_id).claims}
|
||||
assert "membership-fee:2024:annual" in claim_keys
|
||||
assert housekeeper.settings.retroactive_claims is False
|
||||
|
||||
other = repository.create_member(first_name="NoRetro", last_name="Member", birth_date="1990-01-01")
|
||||
other.status = "active"
|
||||
other.accepted_at = "2024-04-15"
|
||||
other.membership_started_at = "2024-04-15"
|
||||
other.payment_frequency = "annual"
|
||||
repository.save_member(other)
|
||||
housekeeper.run(today=date(2026, 6, 21), member_id=other.member_id)
|
||||
|
||||
other_claim_keys = {claim["claim_key"] for claim in repository.get_contributions(other.member_id).claims}
|
||||
assert "membership-fee:2024:annual" not in other_claim_keys
|
||||
assert "membership-fee:2026:annual" in other_claim_keys
|
||||
|
||||
Reference in New Issue
Block a user