# Django Accounting UI Formatting Former skill: `django-accounting-ui-formatting`. Use this when changing how money, balances, invoices, payments, totals, or differences are displayed in a Django accounting/reconciliation webapp. ## Core rule Accounting amounts must be formatted deliberately and consistently. Do not rely on ad-hoc `floatformat:2` everywhere if the app has locale-specific expectations. For Danish Radix accounting/reconciliation UIs, render amounts with: - thousands separator: `.` - decimal separator: `,` - exactly 2 decimals - minus sign before the formatted number Example: ```text 1234567.89 -> 1.234.567,89 -1234567.89 -> -1.234.567,89 0 -> 0,00 ``` ## Recommended Django implementation Create a shared template filter in a common app, e.g.: ```text backend/apps/common/templatetags/amount_format.py ``` Example filter: ```python from decimal import Decimal, InvalidOperation, ROUND_HALF_UP from django import template register = template.Library() @register.filter def amount_dk(value): if value is None or value == "": return "0,00" try: amount = Decimal(str(value)).quantize(Decimal("0.01"), rounding=ROUND_HALF_UP) except (InvalidOperation, ValueError, TypeError): return value sign = "-" if amount < 0 else "" amount = abs(amount) formatted = f"{amount:,.2f}" return sign + formatted.replace(",", "X").replace(".", ",").replace("X", ".") ``` Ensure `templatetags/__init__.py` exists. In templates: ```django {% load amount_format %} {{ amount|amount_dk }} kr ``` ## What to update Search all relevant templates for amount displays, especially: - `floatformat:2` - table columns named Beløb, Sum, Difference, Rest, Betalt - dashboard cards - report tables - invoice/payment status pages - transaction detail pages Replace monetary `floatformat:2` with the shared amount filter. Leave percentages, scores, counts, and raw JSON/raw imported data alone unless the user explicitly asks otherwise. ## Tests Follow TDD for behavior changes: 1. Add a failing unit/template test for the filter: ```python template = Template("{% load amount_format %}{{ value|amount_dk }}") assert template.render(Context({"value": Decimal("1234567.89")})) == "1.234.567,89" ``` 2. Add at least one rendered-page regression test for the main UI path, asserting: - formatted amount is present, e.g. `1.234.567,89` - raw unformatted amount is absent, e.g. `1234567.89` 3. Run the relevant app tests and system check in the project runtime, usually Docker Compose for Radix internal apps: ```bash docker compose exec -T web python manage.py test apps.core --settings=config.settings.test -v 2 docker compose exec -T web python manage.py check ``` ## Verification Before finalizing: - Confirm there are no remaining monetary `|floatformat:2` usages in the changed templates. - Confirm templates that use `amount_dk` include `{% load amount_format %}`. - Restart the web container if the running app needs to load a new template tag module: ```bash docker compose restart web ``` ## Pitfalls - Do not alter raw JSON/raw import displays; those are audit data and should preserve original values. - Do not apply money formatting to percentages or match scores. - Avoid Python float math for money formatting; use `Decimal` to avoid binary rounding surprises. - If the app already has a localization/formatting utility, extend that instead of adding a second competing filter.