Tell members which reference to put on a transfer

A data-review mail that lists the payment frequency but not how to pay leaves the
board matching anonymous transfers by hand. The mail now closes with the
reference to quote -- member number and full name, joined only where both exist
so a missing half cannot leave a dangling dash. Both are offered because either
identifies the payment on its own: a member who has forgotten their number falls
back on the name, and two members sharing a name are told apart by the number.

The note about the shortened IBAN moved out of the fixed template text into
{{data.iban_hint}}, filled only for members whose bank details are actually
listed -- it used to explain a masked IBAN to members who pay by transfer and see
no IBAN at all. It sits directly under the record as a parenthesised footnote,
which also keeps the dropped line from leaving a blank one behind.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Marcel Peterkau
2026-09-04 22:08:40 +02:00
co-authored by Claude Opus 5
parent 9e9bb7d668
commit 31c1646571
6 changed files with 81 additions and 7 deletions
+26
View File
@@ -4,11 +4,13 @@ from email.policy import default
import pytest
from ccma.domain.models import Member
from ccma.services.member_data_mail import (
data_review_recipients,
generate_data_review_mails,
mask_iban,
member_data_fields,
payment_reference,
)
from ccma.storage.repository import MemberRepository, RepositoryError
@@ -75,6 +77,13 @@ def test_the_mail_lists_the_stored_record_of_that_member(tmp_path):
assert "Telefon: 0621 123456" in content
assert "PLZ und Ort: 68159 Mannheim" in content
assert "Mitglied seit: 01.01.2026" in content
assert "Zahlweise: Halbjährlich" in content
# Both halves identify a transfer on their own, so both are offered.
assert "deine Mitgliedsnummer und/oder deinen vollen Namen" in content
assert f"{member.member_number} Ada Lovelace" in content
# Nothing bank-related is stored, so the note about the shortened IBAN is left
# out instead of pointing at a line that is not there.
assert "verkürzt" not in content
assert content.rstrip().endswith("Der Vorstand")
@@ -123,6 +132,23 @@ def test_bank_details_are_listed_with_a_masked_iban(tmp_path):
assert "DE98670505050038907751" not in content
assert "Mandatsreferenz: MANDAT-42" in content
assert "Lastschriftmandat: aktiv, erteilt am 01.02.2026" in content
assert "(Die IBAN zeigen wir absichtlich nur verkürzt an" in content
def test_the_transfer_reference_joins_number_and_name():
member = Member(
member_id="1", member_number="CCMA-0007", first_name="Ada", last_name="Lovelace"
)
assert payment_reference(member) == "CCMA-0007 Ada Lovelace"
# The store insists on a member number, but a record read from elsewhere may not
# have one -- the name then carries the reference without a dangling dash.
assert (
payment_reference(
Member(member_id="1", member_number="", first_name="Ada", last_name="Lovelace")
)
== "Ada Lovelace"
)
def test_mask_iban_keeps_country_and_last_four_digits():