Skip to content

Kundenansicht und Signaturen

Die Kundenansicht besteht aus der Parent-Route app/pages/customer-view.vue, der PDF-Vorschau app/pages/customer-view/index.vue und der Signaturseite app/pages/customer-view/signatures.vue.

Der gemeinsame Einstieg liegt in app/composables/protocol/useCustomerViewNavigation.ts.

Dieser Flow wird aus Editor und Top-Bar verwendet und macht vor der Navigation:

  • Acceptance-ID normalisieren
  • gesperrte Acceptances direkt nach /finalize schicken
  • aktuelle Drafts über persistCurrentAcceptanceDrafts() lokal sichern
  • Kündigungsgrund-Workflow über resolveProtocolWorkflowBlockRedirect(...) prüfen
  • optional per useFormSave().saveCurrentAcceptance(...) speichern

Die Runtime-Flags steuern das Verhalten:

  • autoSaveOnCustomerView: speichert vor dem Wechsel automatisch
  • allowUnsavedCustomerView: erlaubt den Wechsel trotz Save-Fehlern oder ausstehenden Änderungen

Wenn der Auto-Save erfolgreich war, hängt der Flow saved=true an die Query. customer-view.vue zeigt daraus einen Erfolgshinweis.

Parent-Route

app/pages/customer-view.vue lädt beim Wechsel der Acceptance:

  1. ausstehende lokale Drafts
  2. acceptanceStore.sync(acceptanceId)
  3. Lock-Status der Acceptance

Wenn die Acceptance gesperrt oder im manuellen Upload-Zustand ist, ersetzt die Route das Ziel durch /finalize?acceptance=<id>.

Die Parent-Route zeigt außerdem Tabs für:

  • Vorschau: /customer-view
  • Signaturen: /customer-view/signatures

Bei Online-Betrieb kann sie ungespeicherte Änderungen blockieren, wenn allowUnsavedCustomerView deaktiviert ist. Offline darf die Kundenansicht weiter geöffnet werden und zeigt einen Hinweis.

PDF-Vorschau

app/pages/customer-view/index.vue erzeugt die PDF-Vorschau über useCustomerPdfPreview().

Unterstützte Varianten:

  • extern: Kundenvorschau
  • intern: interne Vorschau

Die Vorschau nutzt:

  • PdfPreviewFrame.vue für Toolbar, Ladezustand und Viewport
  • PdfPageCanvas.vue für seitenweises Rendering
  • Zoom, Pan-Modus, Seitennavigation, Öffnen und Download

Beim Verlassen der Route wird eine laufende PDF-Generierung über cancelPreviewGeneration() abgebrochen.

Vor dem Wechsel zur Signaturseite prüft die Vorschau erneut den gemeinsamen Workflow-Guard für den Schritt signatures.

Signaturzustand

app/composables/media/pdf/useCustomerSignatureSession.ts kapselt den persistenten Signaturzustand.

Die Signaturseite verwaltet:

  • Mieter-Signatur
  • Vermieter-Signatur
  • dynamische Vertragspartner-Signaturen
  • optionale Dienstleister-Signatur
  • manuelle Signatur als Read-only-/Papiermodus
  • Proxy-Signatur mit Nachweis-Upload
  • optionalen Verweigerungsgrund, wenn für den Protokolltyp globale Vorlagen im Bereich signature_refusal_reasons gepflegt sind

Signaturänderungen werden zuerst lokal über den Signature-Store persistiert. Vor Navigation oder Auto-Save werden pending Draft-Saves geleert, damit der Acceptance-Save den aktuellen Stand sieht.

Verweigerungsgründe werden pro Protokolltyp über Einstellungen > Vorlagen im Bereich Verweigerungsgründe verwaltet. Wenn dort aktive Einträge vorhanden sind, zeigt SignatureInput.vue bei verweigerter Unterschrift eine optionale Auswahl an und speichert ID und Label im Signatur-Payload.

Dienstleister-Signatur

Die Signaturseite lädt Wohnungszuordnungen über:

ts
GET /billing-providers/flat-assignments

Eine Dienstleister-Signatur wird verlangt, wenn:

  • ein aktiver Dienstleister der Wohnung zugeordnet ist
  • dessen Protokolltyp-Regel signatureRequired aktiv ist
  • ein relevanter Zählertyp im Protokoll einen Wert enthält

Wenn die Signatur fehlt, blockiert die Seite die Finalisierung und zeigt einen Warnhinweis.

Finalize-Zugang

Die Signaturseite bietet zwei Wege:

  • manual: Protokoll sperren und später manuell hochladen
  • auto: vollständige Finalisierung mit PDF-Upload starten

Vor dem Wechsel nach /finalize:

  1. Signaturen speichern
  2. Dienstleister-Pflicht prüfen
  3. Finalize-Modus als finalizeMode=auto|manual in die Route schreiben
  4. nach /finalize navigieren

Die Middleware erlaubt /finalize nur mit gesperrter Acceptance oder explizitem finalizeMode-Start. Der fachliche Sperrstatus kommt aus lockedAt und uploadPendingAt, nicht aus Browser Storage.