Add a club legal address, used for invoices/referee forms ahead of the home ground

New Club.legal_address/legal_zip_code/legal_city, editable from the
identity page (management:club_settings). Official document headers
(the dues invoice, the referee payment form) previously borrowed the
club's home Location for this -- conflating "where we play" with "our
registered address", which aren't always the same place. New
club.services.invoicing.resolve_document_address(club) picks the club's
own legal address when set, falling back to the home Location exactly as
before when it isn't, so nothing breaks for a club that hasn't set one
yet. Location.is_home now means only what it always should have: telling
a home game from an away one.

Renamed the shared "home_location" template/context variable to
"document_address" on both PDFs to match -- it was never accurate once a
legal address could win instead.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01ECGMEwrc2k4D8VQuwjstj9
This commit is contained in:
2026-08-21 17:50:08 +02:00
parent 80fda6a4a4
commit c7887637ff
12 changed files with 159 additions and 27 deletions

View File

@@ -40,7 +40,7 @@ from .services.access import (
teams_staffed_by,
)
from .services.fees import mark_as_paid, record_payment, remaining_balance
from .services.invoicing import create_or_resend_invoice, invoice_pdf, invoices_due_for_reminder, recipient_for
from .services.invoicing import create_or_resend_invoice, invoice_pdf, invoices_due_for_reminder, recipient_for, resolve_document_address
from .services.onboarding import (
annotate_onboarding_status,
approve_all_clean,
@@ -1683,6 +1683,48 @@ class InvoicePdfTests(TestCase):
self.assertIn(self.invoice.number, html)
def test_the_legal_address_takes_precedence_over_the_home_location(self):
Location.objects.create(club=self.club, name="Sports Hall", address="Sportlaan 1", zip_code="1000", city="Brussels", is_home=True)
self.club.legal_address = "Registered Office 5"
self.club.legal_zip_code = "9000"
self.club.legal_city = "Ghent"
self.club.save(update_fields=["legal_address", "legal_zip_code", "legal_city"])
html = self.render()
self.assertIn("Registered Office 5", html)
self.assertNotIn("Sportlaan 1", html)
class ResolveDocumentAddressTests(TestCase):
"""club.services.invoicing.resolve_document_address -- the club's own
legal_address when set, else its home Location, else None."""
@classmethod
def setUpTestData(cls):
cls.club = Club.objects.create(name="Ajax United", slug="ajax-united")
def test_returns_none_with_neither_set(self):
self.assertIsNone(resolve_document_address(self.club))
def test_falls_back_to_the_home_location(self):
home = Location.objects.create(club=self.club, name="Sports Hall", address="Sportlaan 1", zip_code="1000", city="Brussels", is_home=True)
self.assertEqual(resolve_document_address(self.club), home)
def test_legal_address_wins_over_the_home_location(self):
Location.objects.create(club=self.club, name="Sports Hall", address="Sportlaan 1", zip_code="1000", city="Brussels", is_home=True)
self.club.legal_address = "Registered Office 5"
self.club.legal_zip_code = "9000"
self.club.legal_city = "Ghent"
self.club.save(update_fields=["legal_address", "legal_zip_code", "legal_city"])
address = resolve_document_address(self.club)
self.assertEqual(address.address, "Registered Office 5")
self.assertEqual(address.zip_code, "9000")
self.assertEqual(address.city, "Ghent")
class InvoicesDueForReminderTests(TestCase):
"""club.services.invoicing.invoices_due_for_reminder -- sent, unpaid, past