{% import "bausteine/bausatz.html" as b %} {#- **Die Beitragsrechnungen als Makro**, weil sie an zwei Stellen stehen: im Grundriss mit zwei Spalten und unter der Meldung, wenn die Abrechnung ausfällt oder hier nicht eingerichtet ist. Ihr Abruf ist eigenständig; fällt nur die Abrechnung aus, bleibt der Einzahlungsschein trotzdem erreichbar (Codeprüfung 07.10.2026). -#} {%- macro rechnungsblock() %} {#- **Die Beitragsrechnungen mit Einzahlungsschein** (QR-Rechnung, Block 5.4k). Rechte Spalte, zwischen Abrechnung und Konto: Sie sagen, was zu zahlen ist, das Konto darunter, wohin. Welche Rechnungen hier stehen, entscheidet die Gegenseite (Verhältnis von heute, laufendes Jahr und Vorjahr); die Seite zeigt nur an. **Der Grund für eine fehlende Rechnung steht nicht da.** Er ist eine Arbeitsanweisung an die Verwaltung («Kontoinhaber fehlt»); hier steht nur, dass sie noch nicht bereitsteht und wen man fragt. -#} {%- if rechnungen_gestoert %} {{ b.meldung("achtung", "Ihre Beitragsrechnungen sind zurzeit nicht abrufbar. Bitte versuchen Sie es später noch einmal.") }} {%- endif %} {%- for r in rechnungen %} {%- call b.kasten("Beitragsrechnung " ~ (r.get('jahr') or '') ~ (" · " ~ r.get('einheit') if r.get('einheit') else ""), klasse="bereichskarte rechnung", icon="franken") %} {%+ if r.get('liegenschaft') %}

{{ r.liegenschaft }}{% if rechnungen_mandanten and r.get('mandant') %} · {{ r.mandant }}{% endif %}

{% endif +%} {#- **Je Rate eine Zeile mit dem offenen Betrag**, nicht der gestellte: Wer eine Teilzahlung geleistet hat, will wissen, was noch fehlt. Bei bezahlten Raten steht das Wort, kein Betrag «0.00». **«noch offen» steht ausgeschrieben davor.** «1'600.00 von 2'000.00» allein las die Laienprüfung (07.10.2026) als «1'600 bezahlt» und hätte 400 statt 1'600 überwiesen. Ist die Fälligkeit vorbei, heisst es «war fällig am»: ein Zeitpunkt, kein Vorwurf. -#}
{%- for rate in r.get('raten') or [] %} {%- set stand = rate.get('stand') %}
Rate {{ rate.get('nummer') }} von {{ rate.get('von') }}{% if rate.get('faellig') %}, {% if stand != "bezahlt" and rate.faellig < heute_iso %}war fällig am{% else %}fällig{% endif %} {{ datum_kurz(rate.faellig) }}{% endif %}
{% if stand == "bezahlt" %}bezahlt{% else %}noch offen {{ betrag(rate.get('offen')) }}{% if stand == "teilweise bezahlt" %} von {{ betrag(rate.get('betrag')) }}{% endif %}{% endif %}
{%- endfor %}
{#- Nur, wenn etwas offen ist: Bei lauter bezahlten Raten hat das PDF keinen Einzahlungsschein, und der Satz läse sich als Aufforderung. -#} {%+ if (r.get('raten') or []) | rejectattr('stand', 'equalto', 'bezahlt') | list %}

Die Rechnung enthält für jede offene Rate einen Einzahlungsschein mit QR-Code über den Betrag, der beim Herunterladen offen ist.

{% endif +%} {#- Miteigentümer sehen dieselbe Rechnung; ohne diesen Satz zahlen beide (Laienprüfung 07.10.2026). -#} {%+ if r.get('gemeinsam') %}

Diese Rechnung gilt für alle Eigentümer der Wohnung zusammen und ist nur einmal zu bezahlen.

{% endif +%}
{{ b.knopf("Rechnung herunterladen", "zweit", klasse="breit") }}
{%- endcall %} {%- endfor %} {%- for f in rechnungen_fehlen %} {{ b.meldung("info", "Die Beitragsrechnung " ~ (f.get('jahr') or '') ~ (" für " ~ f.get('einheit') if f.get('einheit') else "") ~ (" (" ~ f.get('liegenschaft') ~ ")" if f.get('liegenschaft') else "") ~ " steht noch nicht bereit. Die Raten sind trotzdem zu ihren Terminen fällig. Ihre Verwaltung nennt Ihnen Beträge und Termine.") }} {%- endfor %} {%- endmacro %} {# Der Bereich «Zahlungen»: die eingegangenen Akontozahlungen links, die Abrechnung rechts (am Telefon: die Abrechnung zuoberst). **Zwei Kästen, nicht einer.** Sie beantworten zwei verschiedene Fragen: «Muss ich nachzahlen?» und «Ist meine Zahlung angekommen?». Der zweite ist der häufigere Anlass, im Portal nachzusehen, und der einzige, den die Abrechnung nicht beantwortet. **Die vier Zustände bleiben vier** (wie Ablage und Revision). Eine leere Seite kann heissen: Bereich nicht eingerichtet, Gegenseite weg, Konto nicht verknüpft, oder es ist wirklich nichts da. Drei davon gehören der Verwaltung gemeldet statt der Eigentümerin angelastet — und bei Geld wiegt das schwerer als bei Dokumenten: Wer «keine Zahlung eingegangen» liest, überweist womöglich ein zweites Mal. #} {#- **Der Banner steht vor allem anderen und in JEDEM Zustand.** Auch wenn die Abrechnung gerade nicht abrufbar ist, gilt die angeheftete Mitteilung — sie hat mit dem Ausfall nichts zu tun. -#} {{ banner }} {%- if zustand == "aus" %} {{ b.leerzustand("bestand", "Dieser Bereich ist hier nicht eingerichtet.", hinweis="Wenden Sie sich an Ihre Verwaltung, wenn Sie Ihre Abrechnung erwarten.") }} {{ rechnungsblock() }} {%- elif zustand == "ausfall" %} {{ b.meldung("achtung", "Ihre Abrechnung ist zurzeit nicht abrufbar. Bitte versuchen Sie es später noch einmal.") }} {{ rechnungsblock() }} {%- elif zustand == "unbekannt" %} {{ b.meldung("achtung", "Ihr Konto ist noch keiner Eigentümerin zugeordnet. Bitte melden Sie sich bei Ihrer Verwaltung.") }} {#- **Das Zahlungsziel hält die Seite offen.** Wer diesen Sommer gekauft hat, hat bis zur ersten Jahresabrechnung weder Abrechnung noch Zahlung — einbezahlen muss er trotzdem. Ohne diese dritte Bedingung fiele er in den Leerzustand, und die Seite verschwiege ihm genau die Auskunft, die er braucht. -#} {#- **Eine Störung der Rechnungen hält die Seite ebenfalls offen.** Sonst stünde «noch keine Abrechnung freigegeben» da, und die Meldung, dass die Rechnungen gerade nicht abrufbar sind, fiele weg. -#} {%- elif not abrechnungen and not zahlungen and not zahlungsziele and not rechnungen and not rechnungen_fehlen and not rechnungen_gestoert %} {{ b.leerzustand("bestand", "Für Sie ist noch keine Abrechnung freigegeben.", hinweis="Sobald die Jahresabrechnung abgeschlossen ist, steht sie hier.") }} {%- else %} {#- **Zwei Spalten, derselbe Grundriss wie die Meldungsseite** (Vorgabe des Auftraggebers, 07.09.2026). Bis dahin standen die beiden Kästen untereinander, und auf einem breiten Schirm lag rechts daneben die halbe Seite leer. **Welcher wohin, entscheidet die Regel aus `docs/gestaltung.md`:** Wo die grosse Fläche eine Arbeitsfläche ist, steht sie links; die Angaben stehen rechts in fester Breite. Die Zahlungsliste ist ein Verzeichnis mit einer Zeile je Zahlung, also links. Die Abrechnung ist eine Eckwerteliste aus sechs Zeilen; in einer breiten Spalte stünde hinter jedem Betrag eine Handbreit Weiss. **Am Telefon dreht sich die Reihenfolge um** (`order: -1` im Stil), wie bei der Meldungsseite: Einspaltig stünde die Abrechnung sonst unter der Zahlungsliste, und sie trägt die Zahl, wegen der jemand kommt. -#}
{%- call b.kasten("Ihre Zahlungen", klasse="bereichskarte", icon="franken") %} {#- **Die Liste steht auch dann da, wenn sie leer ist.** Sie ist die einzige Stelle im Portal, an der jemand sieht, ob sein Geld angekommen ist; sie wegzulassen hiesse, die Frage unbeantwortet zu lassen, die öfter gestellt wird als die nach dem Saldo. -#} {%- if unzuordenbar %} {#- **Der Fall, den die Gegenseite ausdrücklich meldet.** Bei Miteigentum liegt Akontogeld ohne Personenbezug auf der Einheit — es lässt sich niemandem einzeln zuschreiben und geht darum an niemanden. Ohne diesen Satz stünde «keine Zahlungen» über einer Wohnung, für die pünktlich überwiesen wurde. -#} {{ b.meldung("info", "Für Ihre Wohnung sind Zahlungen eingegangen, die sich nicht einzeln einer Person zuordnen lassen. Sie erscheinen darum nicht in dieser Liste. Ihre Verwaltung kann Ihnen den Stand nennen.") }} {%- endif %} {%- if zahlungen %} {% if mehrere %}{% endif %} {%- for z in zahlungen %} {#- **Eine stornierte Zahlung bleibt stehen und wird benannt.** Eine, die aus der Reihe verschwindet, sieht für den Zahler aus wie ein Fehler — und dann ruft er an. Der GRUND der Stornierung steht bewusst nicht da: Dass storniert wurde, gehört dem Zahler, warum, ist eine interne Sache. -#} {%- if mehrere %}{% endif %} {%- endfor %} {#- **Die Summe steht in der Tabelle, nicht darunter** (Vorgabe des Auftraggebers, 08.09.2026: «die Summe aller geleisteten Zahlungen auf der untersten Zeile»). Als `tfoot`, damit sie in der Spalte «Betrag» steht und ein Vorleseprogramm sie als Fusszeile ansagt. **Sie sagt, worüber sie summiert.** «Summe» allein hiesse: alles. Zwei Fälle machen diese Aussage falsch, und beide nennt die Seite selbst: eine gekappte Liste («es werden die neuesten gezeigt») und nicht zuordenbare Zahlungen («sie erscheinen darum nicht in dieser Liste»). In beiden steht «Summe der gezeigten Zahlungen» — sonst behauptete die Zahl eine Vollständigkeit, der die Seite selbst zwei Zentimeter weiter oben widerspricht (`/code-review` 08.09.2026). **Stornierte sind nicht darin** (`_zahlungssumme`), und wenn welche in der Liste stehen, sagt die Zeile das auch. Sonst zählt jemand nach und kommt auf einen anderen Wert. -#} {%- if zahlungssumme %} {%- endif %}
DatumZahlungWohnungBetrag
{{ datum_kurz(z.get('datum') or '') }}{{ z.get('bezeichnung') or 'Zahlung' }}{% if z.get('storniert') %} {{ b.kapsel("storniert", "neutral") }}{% endif %}{{ z.get('einheit') or '' }}{{ betrag(z.get('betrag')) }}
{{ "Summe der gezeigten Zahlungen" if (gekappt or unzuordenbar) else "Summe" }} {%- if storniert_dabei %} (ohne stornierte){% endif %} {{ zahlungssumme }}
{%- if gekappt %}

Es werden die neuesten Zahlungen gezeigt. Für ältere wenden Sie sich an Ihre Verwaltung.

{%- endif %} {%- elif not unzuordenbar %} {{ b.leerzustand("bestand", "Für Sie ist noch keine Zahlung erfasst.", hinweis="Eingegangene Akontozahlungen erscheinen hier, sobald sie verbucht sind.") }} {%- endif %} {%- endcall %}
{#- **Die Abrechnung trägt die Zahl, wegen der jemand kommt:** ob er etwas schuldet. Sie stand darum bis zum 07.09.2026 zuoberst. Seit dem Umbau auf zwei Spalten steht sie rechts und am Telefon weiterhin zuoberst — dasselbe Versprechen, nur nicht mehr über die Reihenfolge im Rumpf eingelöst. -#} {%- for a in abrechnungen %} {%- set wort = saldowort(a.get('saldo')) %} {%- call b.kasten("Abrechnung " ~ (a.get('jahr') or '') ~ (" · " ~ a.get('einheit') if mehrere and a.get('einheit') else ""), klasse="bereichskarte abrechnung", icon="franken") %} {#- Art und Zeitraum als Unterzeile: «Eigentümerabrechnung» sagt, welche Art Abrechnung das ist, und der Zeitraum, wofür sie gilt. Beides steht klein, weil es die Frage «muss ich zahlen» nicht beantwortet. -#} {%+ if a.get('art') or a.get('von') %}

{{ a.get('art') or '' }}{% if a.get('von') and a.get('bis') %}{% if a.get('art') %} · {% endif %}{{ datum_kurz(a.von) }} bis {{ datum_kurz(a.bis) }}{% endif %}

{% endif +%}
{#- **Der Kostenanteil ENTHÄLT die beiden «davon»-Zeilen.** Wer die drei addiert, zählt doppelt — die Namen sagen es, und die Einrückung zeigt es. Ohne dieses Wort stünden drei Beträge untereinander, die wie eine Rechnung aussehen. -#}
Ihr Kostenanteil
{{ betrag(a.get('kostenanteil_gesamt')) }}
{%- if hat_betrag(a.get('davon_ef_anteil')) %}
davon Erneuerungsfonds
{{ betrag(a.davon_ef_anteil) }}
{% endif %} {%- if hat_betrag(a.get('davon_sonderbeitrag')) %}
davon Sonderbeitrag
{{ betrag(a.davon_sonderbeitrag) }}
{% endif %} {#- **«Ihr Akonto», nie «bezahlt»** (Vorgabe des Auftraggebers, 06.09.2026: «Akonto vorgeschrieben passt vom Wording her nicht»). Die Zahl ist nicht das Eingegangene — das steht im Kasten darunter. Der Saldo rechnet mit ihr, und wer nie gezahlt hat, hätte darin sonst ein Guthaben. **Warum kein Wort, das die Herkunft nennt.** Die Zahl bedeutet drüben nicht immer dasselbe: Im Regelfall sind es die gebuchten Vorschreibungen des Jahres (Sollbuchungen auf dem Forderungskonto), bei fehlenden Buchungen aber der Budgetbeschluss der Versammlung, und ein von Hand erfasster Wert schlägt beides. «In Rechnung gestellt» wäre im zweiten Fall falsch, «beschlossen» im ersten. Was in allen Fällen stimmt, ist «Ihr Akonto». **Die Jahreszahl gehört dazu und ist nicht Zierrat**: Drüben filtert die Abfrage auf das Kalenderjahr. Eine Rate, die im Januar fürs Vorquartal eingeht, zählt in diesem Jahr mit, ihre Vorschreibung aber nicht. Ohne die Zahl läse man die Zeile als «mein Akonto überhaupt». -#}
Ihr Akonto{% if a.get('jahr') %} {{ a.jahr }}{% endif %}
{{ betrag(a.get('akonto_vorgeschrieben')) }}
{#- **Vier Zustände, und `_ausstand` entscheidet sie an EINER Stelle.** Kein Wert heisst «nicht ermittelbar»: keine Zeile. Eine echte Null heisst «nichts mehr offen», in Worten. Ein negativer Wert bekommt AUCH keine Zeile — er belegt keine Überzahlung, sondern kann aus einer Zahlung fürs Vorquartal oder aus einer Vorschreibung im Entwurf stammen, und beides kann die Leserin nicht auflösen. Alles andere ist der Betrag. Warum die Entscheidung nicht hier in der Vorlage steht: Sie war in der ersten Fassung dieses Blocks eine Bedingung im Markup und kannte nur drei der vier Fälle. Der vierte hätte «davon noch offen: −250.00» ergeben. Die Gründe zu jedem Fall stehen bei `_ausstand` in `portal/main.py`. -#} {%- set offen_wort, offen_wert, offen_klasse = ausstand(a.get('akonto_offen')) %} {%- if offen_wort %}
{{ offen_wort }}
{{ offen_wert }}
{% endif %} {#- **Der Saldo mit einem WORT, nicht nur mit einem Vorzeichen.** «−319.20» sagt einer Eigentümerin nichts; sie will wissen, ob sie zahlen muss. Positiv heisst Nachzahlung, negativ Guthaben — die Lesart kommt von der Gegenseite und steht im Kopf von `api/features/portal_bewohner/abrechnung.py`. **Als gewöhnliche Zeile, nicht als Kapsel** (Vorgabe des Auftraggebers, 06.09.2026: «Guthaben in normal und linksbündig»). Das Wort steht jetzt links wie jede andere Beschriftung, der Betrag rechts in der Spalte der übrigen — die Zeile liest sich als Fortsetzung der Rechnung darüber, weil sie genau das ist. **Damit fällt die Farbe weg**, und das ist vertretbar: Sie war Verstärkung, nie Träger. `docs/gestaltung.md` §1 sagt, dass Farbe nie etwas allein sagen darf — die Aussage steckte immer im Wort «Nachzahlung» oder «Guthaben», und das steht unverändert da. Die Trennlinie bleibt: Sie sagt, dass hier gerechnet wurde und nicht weiter aufgezählt wird. -#} {%+ if hat_saldo(a.get('saldo')) %}
{{ wort or 'Saldo' }}
{{ saldobetrag(a.saldo) }}
{% endif +%}
{%+ if mehrere and a.get('mandant') %}

{{ a.mandant }}

{% endif +%} {%- endcall %} {%- endfor %} {{ rechnungsblock() }} {#- **Wohin einbezahlt wird — in der rechten Spalte, unter der Abrechnung.** Es ist eine Eckwerteliste aus drei Zeilen, keine Arbeitsfläche; die Regel aus `docs/gestaltung.md` weist sie damit derselben Spalte zu wie die Abrechnung. **Das Zeichen ist das Haus und nicht der Franken**, obwohl es um Geld geht: Es gibt je Liegenschaft ein Konto, und wer zwei Wohnungen in zwei Gemeinschaften hat, sieht hier zwei Kästen. Das Zeichen sagt, wonach sie sich unterscheiden. -#} {#- **Der Hausname steht IMMER im Titel, nicht erst ab zwei Karten.** Wer in zwei Gemeinschaften Eigentümer ist und für die eine keine eindeutige Verbindung hat, sähe sonst eine einzige Karte «Wohin Sie einzahlen» und läse sie als «das Konto» — das Akonto der einen Liegenschaft ginge an die andere (Befund `/code-review` 07.09.2026). Der Mandant kommt dazu, sobald mehrere im Spiel sind: Zwei Gemeinschaften verschiedener Mandanten können gleich heissen. -#} {%- for z in zahlungsziele %} {%- call b.kasten("Wohin Sie einzahlen" ~ (" · " ~ z.get('liegenschaft') if z.get('liegenschaft') else ""), klasse="bereichskarte", icon="haus") %} {%- if z.get('unklar') %} {#- **«Keine gesicherte Verbindung» ist eine eigene Auskunft, keine leere Karte.** Die Gegenseite meldet den Fall ausdrücklich; er hat drei Ursachen (gar keine Verbindung erfasst, mehrere verschiedene, oder zwei Speicher, die sich widersprechen). Der Satz nennt keine davon, weil er für alle drei gelten muss: «nicht eindeutig» wäre für den Fall ohne jedes Konto schlicht falsch (Befund `/code-review` 07.09.2026, dritter Durchgang). Eine geratene IBAN wäre hier der teuerste Ausweg: Die Zahlung käme an, nur bei der falschen Gemeinschaft. -#} {{ b.meldung("achtung", "Für diese Liegenschaft ist hier keine gesicherte Bankverbindung hinterlegt. Bitte fragen Sie bei Ihrer Verwaltung nach, bevor Sie einzahlen.") }} {%- else %}
{%- if z.get('empfaenger') %}
Empfänger
{{ z.empfaenger }}
{% endif %} {#- **Die IBAN in Vierergruppen und in fester Schrift.** Sie wird abgetippt; 21 Zeichen am Stück verliest sich jeder einmal. **Und nur, wenn eine da ist.** `unklar` ist gegen ein fehlendes Feld gehärtet, `iban` war es nicht: Fehlte sie, stand «IBAN» leer da, darunter die Aufforderung einzuzahlen (Befund `/code-review` 07.09.2026). -#} {%- if z.get('iban') %}
IBAN
{{ iban_anzeigen(z.iban) }}
{% endif %} {%- if z.get('bank') %}
Bank
{{ z.bank }}
{% endif %} {#- **Die Währung steht nur da, wenn sie NICHT Franken ist.** «Währung: CHF» ist auf einer Schweizer Abrechnung keine Auskunft, sondern eine Zeile mehr; eine abweichende Währung dagegen ist genau die, wegen der eine Zahlung schiefgeht. -#} {%- if z.get('waehrung') and z.waehrung != 'CHF' %}
Währung
{{ z.waehrung }}
{% endif %}
{#- **Der Hinweis auf die Mitteilung ist keine Höflichkeit.** Bis es eine Referenznummer gibt (eigenes Vorhaben, Entscheid des Auftraggebers 07.09.2026), ist der Mitteilungstext das einzige, woran die Verwaltung eine Zahlung erkennt. Auf Dev lagen am 06.09.2026 45 Akontozahlungen auf Einheiten mit mehreren Eigentümern, ohne dass jemand sagen konnte, von wem sie stammen. Seit 5.4k (07.10.2026) trägt der Einzahlungsschein der Beitragsrechnung eine Referenz. Wer von dieser Karte abtippt, hat sie nicht; für ihn bleibt der Satz der einzige Weg. -#} {#- **Mit Rechnung zwei Wege, ohne Rechnung einer.** Unter einer Rechnung mit Einzahlungsschein las die Laienprüfung (07.10.2026) den alten Satz als Pflicht für jede Zahlung und hätte IBAN und Betrag abgetippt, um die Mitteilung schreiben zu können; die Referenz wäre verloren. -#} {#- Nur, wenn eine Rechnung DIESER Liegenschaft dasteht. Gleicht der Name nicht (Unterobjekt), bleibt der alte Satz; der stimmt in jedem Fall. -#} {%- if rechnungen | selectattr('liegenschaft', 'equalto', z.get('liegenschaft')) | list %}

Mit dem Einzahlungsschein aus der Beitragsrechnung müssen Sie nichts weiter angeben. Zahlen Sie ohne Einzahlungsschein, etwa per Dauerauftrag, geben Sie bitte Ihren Namen und Ihre Wohnung an.

{%- else %}

Bitte geben Sie bei der Zahlung Ihren Namen und Ihre Wohnung an, damit Ihr Geld zugeordnet werden kann.

{%- endif %} {%- endif %} {%+ if mehrere_mandanten and z.get('mandant') %}

{{ z.mandant }}

{% endif +%} {%- endcall %} {%- endfor %}
{%- endif %}