mirror of
https://git.hiabuto.net/C3MA/CCMA.git
synced 2026-09-06 03:20:49 +02:00
Add individually agreed membership fees (contribution overrides)
Members are sometimes given a fee that deviates from the regular schedule -- e.g. a reduced rate for students -- for a specific period. Add a per-member "Beitrag" tab where such deviations can be recorded with a month-granular date range (Ab/Bis), a mandatory reason, and either a fixed annual amount or a percentage discount off whichever base rate is in effect at the time. Data model: ContributionData gets a contribution_overrides list, each entry validated (month format, Bis >= Ab, non-overlapping ranges per member, reason required) and CRUD'd through the repository (record/update/delete/get_contribution_override), consistent with how donations already work. Integration: contribution_claims.py now computes each membership-fee claim's amount month by month instead of a single rate for the whole billing period, picking up whichever override (if any) covers each individual month. That handles an override starting or ending mid period correctly (e.g. a semiannual payer whose discount begins in March) without changing behavior for members without overrides. Already-created claims are never recalculated retroactively, matching how changes to the global contribution rates already behave. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 5
parent
44228dd7dd
commit
2484a1631d
@@ -25,6 +25,11 @@ DONATION_STATUS_LABELS = {
|
||||
"overallocated": "ÜBERZUGEORDNET",
|
||||
}
|
||||
|
||||
CONTRIBUTION_OVERRIDE_KIND_LABELS = {
|
||||
"amount": "BETRAG",
|
||||
"percent": "PROZENT",
|
||||
}
|
||||
|
||||
|
||||
def decimal_value(value: Any, field_name: str = "Betrag") -> Decimal:
|
||||
text = str(value).strip().replace(",", ".")
|
||||
@@ -148,6 +153,26 @@ def donation_status(data: ContributionData, donation: dict[str, Any]) -> str:
|
||||
return "open"
|
||||
|
||||
|
||||
def contribution_override_covers_month(override: dict[str, Any], month: str) -> bool:
|
||||
valid_from = str(override.get("valid_from", ""))
|
||||
valid_until = str(override.get("valid_until", "") or "")
|
||||
if valid_from and month < valid_from:
|
||||
return False
|
||||
if valid_until and month > valid_until:
|
||||
return False
|
||||
return True
|
||||
|
||||
|
||||
def contribution_override_ranges_overlap(
|
||||
valid_from: str, valid_until: str, other_from: str, other_until: str
|
||||
) -> bool:
|
||||
"""Month ranges ('YYYY-MM', empty valid_until/other_until = open-ended) overlap
|
||||
if each range starts no later than the other one ends."""
|
||||
starts_before_other_ends = not other_until or valid_from <= other_until
|
||||
other_starts_before_ends = not valid_until or other_from <= valid_until
|
||||
return starts_before_other_ends and other_starts_before_ends
|
||||
|
||||
|
||||
def claim_status(data: ContributionData, claim: dict[str, Any], *, today: date | None = None) -> str:
|
||||
if str(claim.get("status", "")) == "cancelled":
|
||||
return "cancelled"
|
||||
|
||||
Reference in New Issue
Block a user