diff --git a/src/ccma/domain/contributions.py b/src/ccma/domain/contributions.py index c731f2e..4aab558 100644 --- a/src/ccma/domain/contributions.py +++ b/src/ccma/domain/contributions.py @@ -76,6 +76,13 @@ def allocated_total(data: ContributionData, claim_id: str) -> Decimal: ) +def claim_settled_total(data: ContributionData, claim: dict[str, Any]) -> Decimal: + allocated = allocated_total(data, str(claim.get("claim_id", ""))) + if claim_total(claim) < 0: + return abs(allocated).quantize(CENT) + return allocated.quantize(CENT) + + def payment_allocated_total(data: ContributionData, payment_id: str) -> Decimal: return sum( ( diff --git a/src/ccma/services/documents.py b/src/ccma/services/documents.py index af80139..31733e1 100644 --- a/src/ccma/services/documents.py +++ b/src/ccma/services/documents.py @@ -15,9 +15,9 @@ from xml.etree import ElementTree from ccma.domain.contributions import ( CLAIM_STATUS_LABELS, - allocated_total, claim_balance, claim_items, + claim_settled_total, claim_status, claim_total, money_text, @@ -257,7 +257,7 @@ def _template_values( ), "claim.created_at": _display_timestamp(str(claim.get("created_at", ""))), "claim.total": f"{money_text(claim_total(claim))} EUR", - "claim.paid": f"{money_text(allocated_total(data, claim_id))} EUR", + "claim.paid": f"{money_text(claim_settled_total(data, claim))} EUR", "claim.balance": f"{money_text(claim_balance(data, claim))} EUR", "claim.status": CLAIM_STATUS_LABELS.get(status, status), "claim.items": "; ".join(item_lines), diff --git a/src/ccma/ui/claim_tab.py b/src/ccma/ui/claim_tab.py index 97e0263..1f84bb1 100644 --- a/src/ccma/ui/claim_tab.py +++ b/src/ccma/ui/claim_tab.py @@ -12,6 +12,7 @@ from ccma.domain.contributions import ( allocated_total, claim_balance, claim_items, + claim_settled_total, claim_status, claim_total, credit_allocated_total, @@ -166,7 +167,7 @@ class ClaimTab(ttk.Frame): messagebox.showerror("Forderung konnte nicht geladen werden", str(exc), parent=self) return total = claim_total(self.claim) - paid = allocated_total(self.data, self.claim_id) + paid = claim_settled_total(self.data, self.claim) balance = claim_balance(self.data, self.claim) status = claim_status(self.data, self.claim) self.title_var.set(str(self.claim.get("title") or "Forderung")) diff --git a/tests/test_contributions.py b/tests/test_contributions.py index 0905700..992cba1 100644 --- a/tests/test_contributions.py +++ b/tests/test_contributions.py @@ -3,8 +3,10 @@ from decimal import Decimal import pytest from ccma.domain.contributions import ( + allocated_total, claim_balance, claim_items, + claim_settled_total, claim_status, claim_total, payment_allocated_total, @@ -102,6 +104,25 @@ def test_payment_can_be_split_across_multiple_claims(tmp_path) -> None: ) +def test_credit_claim_settlement_is_displayed_as_positive_amount() -> None: + claim = {"claim_id": "claim-1", "title": "Kautionsrückzahlung", "amount": "-25.00"} + data = ContributionData( + claims=[claim], + credits=[{"credit_id": "credit-1", "amount": "25.00"}], + allocations=[ + { + "allocation_id": "allocation-1", + "claim_id": "claim-1", + "credit_id": "credit-1", + "amount": "25.00", + } + ], + ) + + assert allocated_total(data, "claim-1") == Decimal("-25.00") + assert claim_settled_total(data, claim) == Decimal("25.00") + + def test_reminder_fee_increases_claim_and_is_audited(tmp_path) -> None: repository, member = _repository_with_claim(tmp_path) diff --git a/tests/test_documents.py b/tests/test_documents.py index 8677c72..9f15944 100644 --- a/tests/test_documents.py +++ b/tests/test_documents.py @@ -58,6 +58,28 @@ def test_document_and_claim_creation_time_placeholders() -> None: assert values["claim.created_at"] == "21.06.2026 14:35" +def test_credit_claim_paid_placeholder_is_positive() -> None: + member = Member("member-1", "CCMA-1", "Ada", "Lovelace") + claim = {"claim_id": "claim-1", "title": "Kautionsrückzahlung", "amount": "-25.00"} + data = ContributionData( + claims=[claim], + credits=[{"credit_id": "credit-1", "amount": "25.00"}], + allocations=[ + { + "allocation_id": "allocation-1", + "claim_id": "claim-1", + "credit_id": "credit-1", + "amount": "25.00", + } + ], + ) + + values, _repeats = _template_values(member, data=data, claim=claim) + + assert values["claim.paid"] == "25.00 EUR" + assert values["claim.balance"] == "0.00 EUR" + + def test_claim_item_loop_clones_formatted_table_row() -> None: source = b"""