From e00b4ae57268828ed9dad47e7cf8b7e0df840a9f Mon Sep 17 00:00:00 2001 From: Claude Date: Tue, 6 Oct 2026 10:03:25 +0000 Subject: [PATCH] =?UTF-8?q?Spezifikation:=20Auftragsbest=C3=A4tigung=20und?= =?UTF-8?q?=20projektbezogene=20Rechnungen?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Entwurf aus dem Brainstorming vom 06.10.2026 (Abschnitte im Chat freigegeben): Projektkonto, Rechnungsarten Anzahlung/Schluss/Aufwand/Festbetrag über Stripe, Auftragsbestätigung als eigenes PDF mit Bestätigungsklick und Verbraucher-Variante, zwei Pläne. Co-Authored-By: Claude Opus 5.5 --- ...6-10-06-auftraege-und-rechnungen-design.md | 402 ++++++++++++++++++ 1 file changed, 402 insertions(+) create mode 100644 docs/superpowers/specs/2026-10-06-auftraege-und-rechnungen-design.md diff --git a/docs/superpowers/specs/2026-10-06-auftraege-und-rechnungen-design.md b/docs/superpowers/specs/2026-10-06-auftraege-und-rechnungen-design.md new file mode 100644 index 0000000..8faba6a --- /dev/null +++ b/docs/superpowers/specs/2026-10-06-auftraege-und-rechnungen-design.md @@ -0,0 +1,402 @@ +# Aufträge und Rechnungen: Auftragsbestätigung und projektbezogene Rechnungen + +Stand: 2026-10-06 · Status: Entwurf zur Freigabe (Abschnitte im Chat einzeln freigegeben) + +Grundlage: Wunsch des Nutzers vom 06.10.2026 („Auftragsbestätigung und Rechnungen bei uns, wenn wir auf Kunden gehen; +Projekt auswählen, Zusammenfassung sehen, Festbeträge möglich“), Recherche im selben Gespräch (Quellen am Ende), +Bestand: Finanzen-Spezifikation `2026-10-01-finanzen-design.md` (Stripe-Rechnungen aus WOMS, live seit 01.10.2026). + +## Ziel + +Im Ticketsystem (WOMS) legt ein Admin beim Kunden **Auftragsbestätigungen (AB)** und **Rechnungen zu einem Projekt** an. +Nach der Projektwahl zeigt eine **Zusammenfassung**, was vereinbart ist, was schon berechnet und bezahlt ist, was noch +offen ist und wie viel Zeit im Projekt steckt. Die Rechnung entsteht als Anzahlung, Schlussrechnung, nach Aufwand oder +als frei gewählter **Festbetrag** – auch wenn die erfasste Zeit mehr wert wäre (Beispiel: Frau Wolf, 500 € laut +mündlicher Absprache). + +Erfolg: +- Eine Projektrechnung (Festbetrag oder Aufwand) ist in unter zwei Minuten geschrieben und versendet. +- Eine AB geht mit PDF an den Kunden, der sie per Klick bestätigt; bei Privatkunden ist sie widerrufsrechtlich korrekt. +- Kein Arbeitsblatt wird doppelt berechnet, keine Anzahlung wird in der Schlussrechnung vergessen. +- Jede Rechnung erfüllt § 34a UStDV, jede gesendete AB liegt unveränderlich mit Prüfsumme vor. + +## Feststehende Rahmenbedingungen (geprüft) + +- **WEBklar GbR, Kleinunternehmer nach § 19 UStG.** Rechnungen müssen nach **§ 34a UStDV** (seit 01.01.2025) enthalten: + Name und Anschrift beider Seiten, **Steuernummer** (oder USt-IdNr./Kleinunternehmer-IdNr.), Ausstellungsdatum, Art + und Umfang der Leistung, Entgelt in einer Summe mit Hinweis auf die Kleinunternehmerbefreiung. Leistungszeitpunkt und + Rechnungsnummer sind für Kleinunternehmer keine Pflicht; § 33 UStDV (Kleinbetrag bis 250 €) bleibt unberührt. + **Befund:** Der heutige Rechnungsfuß (`config.stripe.invoiceFooter`) enthält keine Steuernummer. +- **Aufbewahrung:** Rechnungsdoppel 8 Jahre (§ 14b UStG seit 2025), Auftragsbestätigungen als Beleg 8 bzw. als + Geschäftsbrief 6 Jahre. E-Rechnungen muss ein Kleinunternehmer nicht ausstellen. +- **Verbraucher:** Bei Fernabsatzverträgen (Telefon, E-Mail, Chat) muss der Unternehmer den Vertrag auf einem + dauerhaften Datenträger bestätigen, spätestens bevor er mit der Leistung beginnt (§ 312f Abs. 2 BGB), samt der Angaben + nach Art. 246a EGBGB und Widerrufsbelehrung. Ohne Belehrung läuft die Widerrufsfrist bis zu 12 Monate und 14 Tage; ohne + ausdrückliches Verlangen des Verbrauchers vor Fristende schuldet er bei Widerruf keinen Wertersatz. +- **Kostenschätzung:** Zeichnet sich eine wesentliche Überschreitung eines Kostenanschlags ab, muss der Unternehmer den + Besteller unverzüglich informieren (§ 649 Abs. 2 BGB). +- **AGB (webklar.com/agb):** Vergütung „ergibt sich aus dem Angebot“, Aufwand in 15-Minuten-Schritten, Unterstützung + zur Hälfte (Nr. 9), Mitwirkung (Nr. 7), Abnahme (Nr. 8), „Projektleistungen sind nach Vereinbarung fällig“. + Stundensatz in den Abo-Bedingungen: 100 € pro Stunde (Endpreis, § 19 UStG). +- **Stripe** (SDK `stripe@19`, API 2025-10-29.clover): Rechnungen mit bis zu **4 Zusatzfeldern** im Kopf (Name ≤ 40, + Wert ≤ 140 Zeichen), Seitengröße per `rendering.pdf.page_size` (Standard außerhalb Japans: US-Letter), Rechnungsposten + mit **negativem `amount`** (mindert den Betrag), Steuer-IDs des Kontos im Dashboard (Einstellungen → Billing → + Rechnungen → „Steuerinformationen für Rechnungen“). Stripe-„Quotes“ taugen nicht als AB (Aufpreis, PDF-Titel + „Angebot“, keine Verbraucher-Variante). +- **Bestand im Portal-Server:** `createProjectInvoice` in `server/services/finance/stripeFinance.js` (Entwurf/Senden, + Adress-Sperre über 250 €, Doppel-Schutz), Finanzen-API `/api/admin/finanzen/*` mit `requireAppwriteStaff` (Admin, + zweiter Faktor), Mailer `sendCustomerMail` mit Anhängen, Fristenlogik `deadlines.js` (`withdrawalDeadline`), + Frühbeginn-Erklärungen nach Muster Terminplaner/Webshop, öffentliche Widerrufsseite `widerrufen.html` + (`/api/abo/public/withdraw`), Kundenansicht-Sperre (fail-closed), Arbeitszeit-Regeln `worksheetMinutes.js`. +- **Bestand im WOMS:** Reiter „Rechnungen“ am Kunden (nur Admins), Dialog „Rechnung schreiben“ (freie Positionen), + Finanzen-Seite. Projekte (`websiteProjects`) hängen an genau einem Ticket (`ticketId`), Arbeitsblätter + (`worksheets.totalTime`, `supporters`, `countsToPlan`) an Tickets. +- **WOMS-Redesign** (weißes Design, Pakete P4 Kunden und P7 Finanzen) baut parallel genau die betroffenen Dateien um. + +## Entscheidungen des Nutzers (06.10.2026) + +1. **Abrechnungsarten:** Festpreis, nach Aufwand (Arbeitsblätter × Stundensatz) und Anzahlung mit Schlussrechnung; ein + freier Festbetrag geht immer. +2. **Auch Privatkunden:** Kunden bekommen die Kundenart *Unternehmen / Privatperson*. Bei Privatpersonen enthält die AB + Widerrufsbelehrung und Muster-Widerrufsformular; Arbeitsbeginn vor Fristende nur auf ausdrückliches Verlangen. +3. **AB-Versand:** Mail mit PDF und Knopf „Auftrag bestätigen“ (Link ohne Anmeldung, auch im Portal sichtbar); der + Klick wird protokolliert. +4. **Ansatz A:** Rechnungen bleiben Stripe-Rechnungen (erweitert); die AB ist ein eigenes Dokument des Portal-Servers. +5. **Abschnitte 1–4 dieses Entwurfs** (Oberfläche, AB, Rechnungen, Technik/Livegang) wie unten beschrieben. +6. **Reihenfolge:** Portal-Server und Kundenseiten zuerst; WOMS-Oberfläche im neuen weißen Design, sobald die + Redesign-Stränge Kunden (P4) und Finanzen (P7) zusammengeführt sind. **Zwei Pläne** (siehe unten). + +## Begriffe + +| Begriff | Bedeutung | +|---|---| +| **Auftrag / AB** | Eine Auftragsbestätigung an einen Kunden, meist zu einem Projekt. Art *Festpreis* (Positionen) oder *Aufwand* (Stundensatz, Schätzung). | +| **Projektkonto** | Zusammenfassung je Projekt: vereinbart, berechnet, bezahlt, noch offen, Zeit erfasst. | +| **Zeitquelle** | Die Tickets, deren Arbeitsblätter zu einem Projekt/Auftrag zählen (Standard: das mit dem Projekt verknüpfte Ticket). | +| **Rechnungsart** | `anzahlung`, `schluss`, `aufwand`, `festbetrag` (mit Projekt) oder `frei` (ohne Projekt, wie heute). | +| **Abo-Zeit** | Arbeitsblätter mit `countsToPlan = true`; sie laufen über das Abo-Stundenkonto und werden nie projektbezogen berechnet. | + +## 1. Oberfläche in WOMS + +**Ort:** Kunde → Reiter **„Aufträge und Rechnungen“** (bisher „Rechnungen“, `id` bleibt `invoices`), nur für Admins. +Gebaut im neuen weißen Design (Komponenten des Redesigns, z. B. ``). + +Von oben nach unten: + +1. **Projekte (Projektkonto):** je Projekt des Kunden eine Zeile mit Name, Art und Ticketnummer; Spalten *Vereinbart* + (Summe der gültigen Festpreis-ABs bzw. „nach Aufwand, 100 €/Std.“ bzw. „keine AB“), *Berechnet* (darunter „bezahlt + x €“), *Noch offen*, *Zeit erfasst* (Stunden, darunter „Wert x €“). Knöpfe **„Auftragsbestätigung“** und + **„Rechnung“**. Eine letzte Zeile **„Ohne Projekt“** sammelt Rechnungen ohne Projektbezug. +2. **Aufträge:** Liste der ABs (Nummer, Projekt/Titel, Datum, Summe bzw. „nach Aufwand“, Status, Aktionen: PDF, + Erinnerung senden, Neue Fassung, Stornieren, Entwurf bearbeiten/löschen). +3. **Rechnungen:** die bestehende Rechnungsliste mit den zusätzlichen Spalten *Projekt* und *Art*. + +Der neue Dialog „Rechnung schreiben“ ersetzt den bisherigen überall. Seine Projektliste endet mit **„Ohne Projekt“** +(Art `frei`: freie Positionen wie bisher), so bleibt eine Rechnung ohne Projekt möglich. + +**Kundenart:** In der Kunden-Übersicht ein Feld „Kundenart: Unternehmen / Privatperson“ (leer = unbekannt). Ist es +leer, fragt der AB-Dialog im ersten Schritt danach und speichert die Antwort am Kunden. + +**Finanzen-Seite:** „Rechnung schreiben“ öffnet denselben neuen Dialog, mit Kundenwahl davor. Die Rechnungstabelle +bekommt die Spalten Projekt und Art. + +**Arbeitsblätter (Ticketseite):** Ein abgerechnetes Arbeitsblatt zeigt das Abzeichen „abgerechnet (Rechnungsnummer)“. +Ändert jemand dessen Zeit, warnt der Dialog: „Dieses Arbeitsblatt ist abgerechnet (WEBKLAR-0009). Eine Änderung ändert +die Rechnung nicht.“ (Keine harte Sperre: WOMS schreibt Arbeitsblätter direkt in Appwrite.) Das Abzeichen sehen alle +Mitarbeiter (ohne Beträge). + +### Dialog „Rechnung schreiben“ (neu) + +1. **Projekt** (vorausgewählt, wenn vom Projektkonto geöffnet) oder „Ohne Projekt“. +2. **Zusammenfassung** des Projektkontos (siehe Abschnitt 4) und **Art**: Anzahlung, Schlussrechnung, Nach Aufwand, + Festbetrag. Anzahlung und Schlussrechnung sind nur mit gültiger Festpreis-AB wählbar (Hinweis statt Sperre ohne + Erklärung: „Anzahlung und Schlussrechnung brauchen eine Auftragsbestätigung.“). +3. **Positionen** (je Art vorausgefüllt, änderbar), **Leistungszeitraum** (optional, bei Aufwand vorausgefüllt), + Zahlungsziel (Standard 14 Tage), Notiz; Summe mit § 19-Hinweis. +4. **„Als Entwurf speichern“** oder **„Senden“** (mit Rückfrage wie heute; Adress-Sperre über 250 € wie heute). + +### Dialog „Auftragsbestätigung“ (neu) + +1. **Projekt** (oder freier Titel, wenn es noch kein Projekt gibt; später zuordenbar) und, falls leer, **Kundenart**. +2. **Auftrag:** Datum der Absprache und Weg (mündlich, telefonisch, per E-Mail, vor Ort, im Chat). Art **Festpreis** + (Positionen: Beschreibung, Menge, Einzelpreis; Grenzen wie bei Rechnungen) oder **Nach Aufwand** (Stundensatz, + Standard 100 €; Schätzung in Stunden, optional, in 15-Minuten-Schritten). +3. **Zahlung und Termine:** Zahlungsplan „Alles nach Abnahme“ · „Anzahlung x % bei Auftrag, Rest nach Abnahme“ + (Standard 50 %) · „Monatlich nach Aufwand“ (nur Aufwand) · „Frei“ (Text, höchstens 500 Zeichen); Zahlungsziel + (Standard 14 Tage); Start und voraussichtliche Fertigstellung (optional); Zeitquelle (Tickets des Kunden, Standard: + Ticket des Projekts). +4. **Vorschau** (PDF, nicht gespeichert) → „Als Entwurf speichern“ oder „Senden“ (mit Rückfrage). + +## 2. Auftragsbestätigung (AB) + +### Nummer und Status + +- Nummer **`AB-JJJJ-NNNN`**, fortlaufend je Kalenderjahr (Berliner Datum des Sendens), vergeben erst beim Senden unter + einer Sperre im Portal-Server (eine Instanz). Entwürfe haben keine Nummer. Scheitert das Senden vor dem Speichern des + PDFs, wird keine Nummer verbraucht. +- Status: `entwurf` → `versendet` → `bestaetigt` → `abgerechnet` (nach finalisierter Schlussrechnung); außerdem + `storniert` (von Hand, ohne Mail), `ersetzt` (durch eine neue Fassung) und `widerrufen` (Privatperson). +- **Unveränderlich nach dem Senden.** Änderung = „Neue Fassung“: Kopie als neuer Entwurf mit Vermerk + „Ersetzt AB-… vom …“; beim Senden der neuen AB wird die alte `ersetzt`. Rechnungen der alten AB wandern intern mit + (`projektRechnungen.auftragId` und Stripe-Metadaten auf die neue AB); der auf finalisierten Rechnungen aufgedruckte + Bezug bleibt unverändert. + +### Inhalt des PDFs (A4) + +- Kopf: WEBklar-Logo, WEBklar GbR, Anschrift, Kontakt, **Steuernummer** (Einstellung `financeSettings.steuernummer`). +- Empfänger: Firma bzw. Name, Anschrift (Straße, PLZ, Ort Pflicht für das Senden – auch unter 250 €). +- Titel „Auftragsbestätigung“, Nummer, Datum, Projekt bzw. Titel, Kundennummer (falls vorhanden). +- Einleitung: „Vielen Dank für Ihren Auftrag vom TT.MM.JJJJ (telefonisch). Wir bestätigen ihn wie folgt:“ +- Leistungsumfang: Positionen mit Menge, Einzelpreis, Summe und Gesamtpreis **oder** Aufwandsregel („100 € pro + Stunde in Schritten von 15 Minuten; unterstützt eine weitere Person, berechnen wir für sie die Hälfte der + Arbeitszeit (AGB Nr. 9). Geschätzter Umfang: etwa X Stunden (unverbindlich). Zeichnet sich eine deutliche + Überschreitung ab, melden wir uns vorher.“); Hinweis „Gemäß § 19 UStG wird keine Umsatzsteuer berechnet.“ +- Zahlungsplan mit Beträgen (z. B. „Anzahlung 50 % (400,00 €) nach Auftragsbestätigung, Rest (400,00 €) nach Abnahme; + zahlbar jeweils innerhalb von 14 Tagen nach Rechnung“), Termine. +- Mitwirkung und Abnahme laut AGB Nr. 7 und 8; „Es gelten unsere Allgemeinen Geschäftsbedingungen in der Fassung vom + …, die dieser Bestätigung beiliegen.“ +- **Privatperson:** zusätzliche Seiten „Widerrufsbelehrung“ (Projektauftrag) und „Muster-Widerrufsformular“. +- Fuß: Bankverbindung (`financeSettings.bankDetailsText`), Kontakt, Seitenzahl. +- Texte und Fassung kommen aus einer Konstante im Server (`texteFassung`, Muster wie `config.termine`), die AB merkt sich + die Fassung. + +### Erzeugung und Ablage + +- PDF mit **pdfkit** (reines JavaScript; kein Chrome zur Laufzeit wegen knappem Arbeitsspeicher), Schrift Figtree aus + `public/fonts`, Logo aus `public/img`. +- Beim Senden einmal erzeugt und unter `upload-data/auftraege//.pdf` abgelegt, SHA-256 im Dokument; + danach wird nur noch diese Datei ausgeliefert. Die Datei liegt in der Hetzner-Serversicherung; jede Mail geht zudem + per BCC an das Team-Postfach. +- Die **AGB** werden als versionierte PDF-Datei ins Portal gedruckt (`public/rechtliches/agb-.pdf` mit + `.sha256`, über `scripts/build-legal-pdfs.sh`, Quelle: Website-AGB). Jede AB merkt sich `agbFassung`. + +### Versand + +- Mail **K31 „Auftragsbestätigung“** (Kunde, Design der Mailvorlagen, BCC Team): kurzer Text, Anhänge AB-PDF und + AGB-PDF, Knopf **„Auftrag bestätigen“** → `https://project.webklar.com/auftrag.html?t=`; bei Privatpersonen + Hinweis auf Widerrufsbelehrung und Frühbeginn. +- Token: 32 Zufallsbytes (base64url), gespeichert nur als SHA-256, gültig 60 Tage ab dem letzten Versand. + **„Erinnerung senden“** (WOMS, von Hand) schickt K31 erneut mit Erinnerungs-Hinweis und neuem Token (der alte gilt + nicht mehr). +- Mail-Status am AB (`mailStatus`: gesendet / nicht zugestellt + Zeitpunkt); bei Fehler „Erneut senden“. + +### Bestätigung + +- **Öffentliche Seite** `auftrag.html?t=…` (ohne Anmeldung, `noindex`, Ratenbegrenzung je IP im Arbeitsspeicher wie + bei der Widerrufsseite): Zusammenfassung (Nummer, Datum, Projekt, Positionen bzw. Aufwandsregel, Summe, + Zahlungsplan, Termine), Links auf AB-PDF und AGB-PDF, Häkchen „Ich bestätige den Auftrag zu diesen Bedingungen.“, + Knopf „Auftrag bestätigen“. Nach der Bestätigung zeigt die Seite „Bestätigt am …“. Ungültiger oder abgelaufener Link: + Erklärung und Kontaktweg. +- **Privatperson:** zweites, freiwilliges Häkchen mit der Frühbeginn-Erklärung (Wortlaut aus der Rechtsrunde, Muster + der Funktionen). Ohne Häkchen zeigt WOMS „Arbeitsbeginn frühestens am TT.MM.“ = Tag nach + `withdrawalDeadline(gesendetAm)`. +- **Im Portal** (angemeldet): Reiter Rechnungen → Abschnitt „Aufträge“ mit Status, PDF und demselben Bestätigen-Ablauf. +- **Kundenansicht:** Bestätigen ist gesperrt (Erklärung im Namen des Kunden; der Endpunkt steht nicht auf der + Freigabeliste der Kundenansicht-Sperre). +- **Protokoll am AB:** `bestaetigtAm`, `bestaetigtUeber` (`link` | `portal`), `bestaetigtPdfSha256` (muss + `pdfSha256` entsprechen), `texteFassung`, `fruehbeginn` (ja/nein) und dessen Textfassung. **Keine IP-Adresse.** + Eine zweite Bestätigung ändert nichts (die erste zählt). +- Danach: Mail **K32 „Auftrag bestätigt“** an den Kunden (Eingangsbestätigung mit Datum, Uhrzeit, Frühbeginn ja/nein) + und **T22 „Auftrag bestätigt“** an das Team. + +### Widerruf (Privatperson) + +- `widerrufen.html` bekommt die Vertragsart **„Projektauftrag (Auftragsbestätigung)“** mit Feld AB-Nummer. Die + Erklärung läuft über den bestehenden Weg (Eingangsbestätigung an den Kunden, Team-Mail); passt die AB zu Nummer und + E-Mail-Adresse, wird sie `widerrufen` und WOMS zeigt es. Erstattung und Wertersatz bleiben Handarbeit. + +## 3. Rechnungen + +Alle Projektrechnungen bleiben **Stripe-Rechnungen** (`collection_method: send_invoice`, Mail mit PDF und Zahlungsseite, +Karte/SEPA, Bankabgleich und Finanzen-Übersicht unverändert). + +### Arten + +| Art | Voraussetzung | Positionen | +|---|---|---| +| `anzahlung` | AB *Festpreis*, Status `versendet` oder `bestaetigt` | Eine Zeile „Anzahlung 50 % gemäß Auftragsbestätigung AB-2026-0002 vom 06.10.2026 (Projekt)“; Betrag aus dem Zahlungsplan, änderbar in % oder €, höchstens AB-Summe minus bereits Berechnetes. Bezeichnung änderbar (auch „Teilrechnung“). | +| `schluss` | AB *Festpreis*, Status `versendet` oder `bestaetigt`; kein offener Entwurf zur AB | Alle AB-Positionen, zusätzliche Positionen (Nachträge) möglich, dann je früherer finalisierter, nicht stornierter Rechnung zur AB eine **Minuszeile** („abzüglich Anzahlung, Rechnung WEBKLAR-0007 vom 08.10.2026“, negativer `amount`). Summe muss > 0 sein, sonst „Nichts mehr offen“. Nach dem Finalisieren: AB `abgerechnet` (Storno setzt zurück). | +| `aufwand` | Projekt; Zeitquelle mit noch nicht abgerechneten Arbeitsblättern | Alle offenen Arbeitsblätter der Zeitquelle (ohne Abo-Zeit, ohne reine Kommentare, ohne 0 Minuten) sind vorausgewählt und abwählbar; **eine Zeile je Tag**: „06.10.2026: Startseite, Kontaktformular – 2,25 Std. à 100,00 €“ (Menge 1, Betrag = Stunden × Satz). Minuten je Arbeitsblatt wie `worksheetMinutes` (inkl. Unterstützung), je Eintrag auf 15 Minuten aufgerundet. Zeilentext = Kurzfassungen der Arbeitsblätter des Tages, gefiltert wie in der Kundenansicht (`customerProjectView`: ohne Git-Anhänge, SHAs, Kontonamen), auf 200 Zeichen gekürzt, im Dialog änderbar. Satz aus der jüngsten gültigen Aufwands-AB des Projekts, sonst 100 €. | +| `festbetrag` | Projekt | Freie Positionen wie heute (Frau Wolf: „Erstellung der Website anelia-wolf.com, Pauschalpreis laut Absprache“, 500 €). | +| `frei` | „Ohne Projekt“ gewählt | Freie Positionen wie bisher, ohne Zusatzfelder „Projekt“/„Auftrag“ (aber A4). | + +Grenzen wie heute (1–20 Positionen inkl. Minuszeilen; Beschreibung ≤ 200 Zeichen). Ergäbe eine Aufwandsrechnung mehr +als 20 Zeilen (zusätzliche Positionen zählen mit), werden die ältesten Tage zu Kalenderwochen zusammengefasst +(„KW 41/2026: … – 6,5 Std. à 100,00 €“), bis höchstens 20 Zeilen bleiben. + +### Auf jeder Projektrechnung + +- **Zusatzfelder** (`custom_fields`): „Projekt“ (Name, auf 140 Zeichen gekürzt), „Auftrag“ („AB-2026-0002 vom + 06.10.2026“, nur mit AB), „Leistungszeitraum“ (bei Aufwand erster bis letzter Tag, sonst optional; immer änderbar). +- **Metadaten:** `webklarCustomerId`, `quelle`, `erstelltVon` (wie heute) plus `projektId`, `projektName`, `auftragId`, + `auftragNummer`, `art`. +- **`rendering.pdf.page_size = 'a4'`** – auch im bisherigen Dialog. +- Fuß unverändert (§ 19-Hinweis, Bankverbindung, Verwendungszweck). + +### Abgerechnete Arbeitsblätter, Storno + +- Jede Projektrechnung bekommt ein Dokument in `projektRechnungen` (Kennung = Stripe-Rechnungs-ID) mit Projekt, AB, + Art, Betrag und den **abgerechneten Arbeitsblatt-IDs**. Beim Anlegen prüft der Server, dass keines der Blätter in einer + aktiven Projektrechnung steckt (sonst 409 „Arbeitsblatt bereits abgerechnet“). +- Entwurf löschen oder Rechnung stornieren setzt das Dokument auf `aktiv = false`: die Blätter sind wieder frei, der + Betrag zählt nicht mehr als berechnet; eine Schlussrechnung setzt die AB auf den vorigen Status zurück. + +### Steuernummer + +- **Sofort, unabhängig vom Bau (Nutzer):** Steuernummer der GbR im Stripe-Dashboard (Einstellungen → Billing → + Rechnungen → „Steuerinformationen für Rechnungen“) hinterlegen und als Standard setzen – dann steht sie auf allen + Rechnungen, auch Abo-Rechnungen. +- Beim Livegang an einem Entwurfs-PDF prüfen, wie Stripe sie beschriftet. Ist die Beschriftung unpassend, kommt sie + stattdessen in den Rechnungsfuß (`invoiceFooter`, und per Skript in `invoice_settings.footer` bestehender + Stripe-Kunden). +- Für das AB-PDF: neues Einstellungsfeld `steuernummer` in WOMS Finanzen → Einstellungen. + +### Kundenportal + +- Die Rechnungsliste zeigt zusätzlich das Projekt (`metadata.projektName`). + +## 4. Projektkonto (Rechenregeln) + +Je Projekt, berechnet im Portal-Server bei jeder Anfrage (Stripe-Daten aus dem bestehenden 60-Sekunden-Zwischenspeicher; +fehlt eine Rechnung dort, wird sie einzeln gelesen): + +| Feld | Regel | +|---|---| +| Vereinbart | Summe `summeCents` aller Festpreis-ABs des Projekts mit Status `versendet`, `bestaetigt` oder `abgerechnet`. Aufwands-ABs: Text „nach Aufwand, €/Std.“ (mit Schätzung). Ohne AB: „keine AB“. | +| Berechnet | Summe der Rechnungen aus aktiven `projektRechnungen` des Projekts, die finalisiert sind (offen, überfällig, bezahlt, uneinbringlich); Entwürfe und Stornos zählen nicht. | +| davon bezahlt | Summe `amount_paid` dieser Rechnungen. | +| Noch offen | Festpreis: Vereinbart − Berechnet (nie unter 0). Aufwand: Wert der noch nicht abgerechneten Zeit. Ohne AB: „–“. | +| Zeit erfasst | Minuten aller Arbeitsblätter der Zeitquelle ohne Abo-Zeit (Regeln wie Aufwand), darunter „Wert x €“ zum Satz der AB bzw. 100 €; Abo-Zeit getrennt als „über Abo: y Std.“. | + +Zeitquelle eines Projekts: Vereinigung der Zeitquellen seiner ABs, sonst das Ticket des Projekts; im Rechnungsdialog +können weitere Tickets des Kunden dazugenommen werden. „Ohne Projekt“: Stripe-Rechnungen des Kunden ohne aktive +`projektRechnungen`. + +## 5. Daten (Appwrite `woms-database`, nur Server-Schlüssel) + +Neue Collections (Setup-Skript `scripts/auftraege-setup.mjs`, idempotent wie `setup-finanzen.mjs`): + +- **`auftraege`**: `nummer`, `jahr`, `laufnummer`, `status`, `kundenId`, `kundeJson` (Name, Firma, Anschrift, E-Mail, + Kundenart zum Zeitpunkt des Sendens), `projektId`, `titel`, `zeitquelleTicketIds` (string[]), `art` + (`festpreis` | `aufwand`), `positionenJson`, `stundensatzCents`, `schaetzungMinuten`, `summeCents`, + `zahlungsplanJson`, `zahlungszielTage`, `auftragVom`, `auftragWeg`, `startAm`, `fertigBis`, `texteFassung`, + `agbFassung`, `pdfDatei`, `pdfSha256`, `gesendetAm`, `gesendetAn`, `mailStatus`, `mailFehler`, `tokenHash`, + `tokenGueltigBis`, `bestaetigtAm`, `bestaetigtUeber`, `bestaetigtPdfSha256`, `fruehbeginn`, `fruehbeginnFassung`, + `ersetztId`, `ersetztDurchId`, `storniertAm`, `widerrufenAm`, `erstelltVon`, `erstelltAm`, `geaendertAm`. + Indizes: `kundenId`, `projektId`, `nummer` (unique), `tokenHash`. +- **`projektRechnungen`**: Dokument-ID = Stripe-Rechnungs-ID; `kundenId`, `projektId`, `auftragId`, `art`, + `betragCents`, `arbeitsblattIds` (string[]), `aktiv` (bool), `erstelltVon`, `erstelltAm`. Indizes: `kundenId`, + `projektId`, `auftragId`. + +Neue Attribute: `customers.kundenart` (`''` | `unternehmen` | `privat`), `financeSettings.steuernummer`. + +Stripe-Rechnungen werden weiter nicht gespiegelt. + +## 6. Schnittstellen (Portal-Server) + +Admin (unter dem bestehenden Finanzen-Router, `requireAppwriteStaff`): + +| Methode, Pfad | Zweck | +|---|---| +| GET `/api/admin/finanzen/projektkonten?kunde=` | Projektkonten des Kunden inkl. „Ohne Projekt“ | +| GET `/api/admin/finanzen/projektkonten/:projektId` | Ein Projektkonto mit ABs, Rechnungen, offenen Arbeitsblättern | +| GET, POST `/api/admin/finanzen/auftraege` (`?kunde=`) | ABs lesen, Entwurf anlegen | +| GET, PATCH, DELETE `/api/admin/finanzen/auftraege/:id` | Lesen; Entwurf ändern/löschen | +| GET `/api/admin/finanzen/auftraege/:id/pdf` | Gespeichertes PDF bzw. Vorschau eines Entwurfs | +| POST `/api/admin/finanzen/auftraege/:id/senden` | Nummer, PDF, Ablage, Mail | +| POST `/api/admin/finanzen/auftraege/:id/erinnern` | K31 erneut, neuer Token | +| POST `/api/admin/finanzen/auftraege/:id/neue-fassung` | Kopie als Entwurf | +| POST `/api/admin/finanzen/auftraege/:id/stornieren` | Status `storniert` | +| POST `/api/admin/finanzen/rechnungen` | erweitert: `{ customerId, projektId?, auftragId?, art, items, arbeitsblattIds?, leistungszeitraum?, daysUntilDue, memo, senden, idempotencyKey }`; Positionen für `anzahlung`/`schluss`/`aufwand` baut der Server nach (Minuszeilen nur serverseitig) | +| PATCH `/api/admin/finanzen/einstellungen` | erweitert um `steuernummer` | + +Alle Mitarbeiter (`/api/team`, `requireStaffJwt`): GET `/api/team/arbeitsblaetter/abgerechnet?ticketId=` → +`{ worksheetId: rechnungsnummer }` (ohne Beträge). + +Kunden: GET `/api/auftraege` (eigene ABs), GET `/api/auftraege/:id/pdf`, POST `/api/auftraege/:id/bestaetigen` +(Portal-Sitzung; in der Kundenansicht gesperrt). + +Öffentlich (Token): GET `/api/auftrag/:token`, GET `/api/auftrag/:token/pdf`, POST `/api/auftrag/:token/bestaetigen` +(`{ bestaetigt: true, fruehbeginn }`). + +Widerruf: `/api/abo/public/withdraw` akzeptiert `order = projekt` mit `abNummer`. + +Kundenart: WOMS schreibt `customers.kundenart` direkt (wie die übrigen Kundenfelder). + +## 7. Mails + +Nächste freie Kennungen zum Zeitpunkt des Baus prüfen (derzeit K31, K32, T22): + +- **K31 Auftragsbestätigung** (Kunde; Anhänge AB-PDF und AGB-PDF; Variante Erinnerung; Variante Privatperson). +- **K32 Auftrag bestätigt** (Kunde; Eingangsbestätigung, Frühbeginn ja/nein). +- **T22 Auftrag bestätigt** (Team). +- Widerruf eines Projektauftrags nutzt die bestehenden Widerrufs-Mails (K04/T09) mit der neuen Vertragsart. + +## 8. Rechtsrunde (vor dem Livegang von Plan 2) + +Der Nutzer gibt frei; danach lädt Claude die Fassungen in WOMS → Rechtliches hoch: +- Textbausteine der AB (Einleitung, Aufwandsregel, Zahlungsplan, Mitwirkung/Abnahme, AGB-Satz). +- Widerrufsbelehrung für Projektaufträge und Muster-Widerrufsformular (Bauart wie `widerrufsbelehrung-funktionen`). +- Frühbeginn-Erklärung (Wortlaut nach Muster der Funktionen, passende Norm prüfen). +- Datenschutzerklärung: neuer Abschnitt „Auftragsbestätigungen“ (verarbeitete Daten, Bestätigungslink, keine IP, + Aufbewahrung 6 bzw. 8 Jahre) und Ergänzung des Widerrufs-Abschnitts. +- AGB als PDF (Fassung, aus der Website gedruckt). + +## 9. Fehlerverhalten + +| Fall | Verhalten | +|---|---| +| Stripe nicht erreichbar | Rechnung scheitert mit „Stripe ist gerade nicht erreichbar.“; ABs und Projektkonto (ohne Stripe-Teil, markiert) gehen weiter | +| PDF-Erzeugung scheitert | AB bleibt Entwurf, keine Nummer verbraucht, Meldung im Dialog | +| Mail scheitert | AB ist `versendet`, `mailStatus` „nicht zugestellt“, Knopf „Erneut senden“ | +| Link ungültig/abgelaufen | Seite erklärt es, nennt den Kontaktweg; WOMS kann per „Erinnerung senden“ einen neuen Link schicken | +| Doppelte Bestätigung | folgenlos, die erste zählt | +| Arbeitsblatt schon abgerechnet | 409 mit Rechnungsnummer | +| Schlussrechnung mit offenem Entwurf zur AB | 409 „Erst den Entwurf … senden oder löschen.“ | +| Fehlende Anschrift beim AB-Senden | 409 „Adresse des Kunden unvollständig“ | +| Kundenart leer beim AB-Senden | 400 (der Dialog fragt vorher) | + +## 10. Tests + +- **Unit** (`node --test`): Projektkonto-Regeln; Positionsbau je Art (Minuszeilen, Tageszeilen, 15-Minuten-Rundung, + Unterstützung, Wochen-Zusammenfassung über 20 Tage); AB-Nummern (Jahreswechsel, Sperre); Token (Hash, Ablauf, + Erneuerung); Frühbeginn-Datum; PDF enthält Pflichtangaben (Text aus dem PDF gelesen) und bei Privatpersonen die + Belehrung; Stripe-Parameter (`custom_fields`, `page_size`, Metadaten) gegen das Fake-Stripe. +- **Server-Ablauf** mit Appwrite-Nachbau, Fake-Stripe und SMTP-Senke (Rezept `kundenportal-testing`): AB anlegen → + senden → bestätigen (Link und Portal) → Anzahlung → Schlussrechnung; Aufwand mit Arbeitsblättern; Storno gibt frei; + Kundenansicht kann nicht bestätigen; Widerruf eines Projektauftrags. +- **WOMS:** Lib-Tests der Ansichtslogik; Bildschirmfotos über das Prüfwerkzeug des Redesigns (Desktop und Handy). +- **Kundenseiten:** Playwright (Handy, Desktop) gegen Fixture-Server. +- **Live:** nur Entwürfe mit dem Testkunden des Nutzers; nichts an echte Kunden. + +## 11. Pläne und Livegang + +- **Plan 1 – Rechnungen mit Projektkonto:** `projektRechnungen`, Projektkonto, Arten `aufwand`, `festbetrag` und + `frei`, Zusatzfelder, Metadaten, A4, Abzeichen „abgerechnet“, Projekt in der Kunden-Rechnungsliste, + WOMS-Oberfläche (Projektkonto, neuer Rechnungsdialog, Reiter umbenannt). In Plan 1 zeigt *Vereinbart* immer + „keine AB“. Keine Rechtsrunde nötig. +- **Plan 2 – Auftragsbestätigung:** `auftraege`, Kundenart, Steuernummer-Einstellung, PDF, Mails, Bestätigungsseite + und Portal-Abschnitt, Verbraucher-Variante, Widerruf, Arten `anzahlung` und `schluss` (mit Minuszeilen), + WOMS-Dialog und -Liste, Rechtsrunde. +- **Reihenfolge je Plan:** Portal-Server und Kundenseiten zuerst; WOMS-Oberfläche im neuen Design auf Basis der + zusammengeführten Redesign-Stränge Kunden (P4) und Finanzen (P7). Sind die Stränge beim Start der WOMS-Aufgaben noch + nicht zusammengeführt, wird mit dem Nutzer entschieden (warten oder auf `test` bauen und eine Mitnahme-Notiz für das + Redesign hinterlegen). +- **Livegang:** (0) Nutzer hinterlegt die Steuernummer in Stripe; (1) Setup-Skript; (2) Nutzer pusht Portal `main`; + (3) Nutzer pusht WOMS `test`; (4) Prüfung mit Testkunde (Entwürfe, PDF-Ansicht); bei Plan 2 vorher Rechtsrunde und + Upload in Rechtliches. + +## Nicht im Umfang + +Angebote vor dem Auftrag, Mahnwesen (Stripe-Erinnerungen wie heute), E-Rechnung, Abrechnung des Abo-Mehraufwands +(`hourLedger`), Nachlass-/Rabattzeilen, eigene Archivkopien der Stripe-PDFs, englische ABs, mehrere Währungen, +Projektmarge und Auswertungen, automatische Erinnerungen. + +## Quellen + +- § 34a UStDV: https://lxgesetze.de/ustdv/34a +- § 14b UStG: https://lxgesetze.de/ustg/14b +- § 312f BGB: https://www.haufe.de/id/norm/buergerliches-gesetzbuch-312f-abschriften-und-bestaetigungen-HI1049155_p312f.html +- Auftragsbestätigung (Inhalt): https://www.lexware.de/wissen/faktura-warenwirtschaft/auftragsbestaetigung-bedeutung-und-inhalt/ +- Stripe Rechnungen anpassen: https://docs.stripe.com/invoicing/customize +- Agentur-Abrechnung (Festpreis/Aufwand): https://everhour.com/de/invoices/rechnungssoftware-fuer-digitalagenturen