# Reporting: Setup-Prüfung und Fehleranalyse


## Aufgabe 4: Auslieferung der Info-Dateien

### Ergebnis

Die neuen und überarbeiteten RTF-Dateien werden sowohl vom normalen Setup als auch vom Update erfasst. Eine Änderung der Inno-Setup-Skripte ist dafür nicht erforderlich.

### Nachweis

- Zentrale Quelldefinition:
  - `C:\Source\Setup6\Setup.iss:46`
  - `C:\Source\Setup6\Setup_Intern.iss:46`
  - `C:\Source\Setup6\Update.iss:46`
  - `C:\Source\Setup6\Update_Intern.iss:46`
  - Alle vier Skripte verwenden `C:\Source\SourceVB\DevData\Portalum` als `SourceDataPath`.
- Normales Setup:
  - `C:\Source\Setup6\Setup.iss:593` und `C:\Source\Setup6\Setup_Intern.iss:600` binden `Setup_Files.iss` ein.
  - `C:\Source\Setup6\Setup_Files.iss:246` übernimmt `Reporting\Info\*` rekursiv in den Datenpfad.
- Update:
  - `C:\Source\Setup6\Update.iss:461` und `C:\Source\Setup6\Update_Intern.iss:462` binden `Update_Files.iss` ein.
  - `C:\Source\Setup6\Update_Files.iss:182` übernimmt `Reporting\Info\*` rekursiv in den Datenpfad.
- Der aktuelle Quellordner enthält 83 RTF-Dateien: 82 nummerierte Berichtsdokumentationen und `Vorlage.rtf`.
- Ein isolierter Testlauf mit Inno Setup 6 und exakt derselben `[Files]`-Regel wurde erfolgreich kompiliert.
- Das Compilerprotokoll enthielt alle 83 RTF-Dateien; es fehlte keine Datei.

### Zu beachten

- Beim normalen Setup gehört die Auslieferung zur Komponente `datafiles`. Diese ist für die Typen `server` und `workstation` ausgewählt, nicht für einen reinen `client`.
- Beim Update gehört die Auslieferung ebenfalls zur Komponente `datafiles`. Sie ist im Typ `full` ausgewählt und kann bei einer benutzerdefinierten Installation abgewählt werden.
- `DeleteReporting('Info')` ersetzt den vorhandenen Info-Ordner vor dem Kopieren. Beim Update wird eine Sicherung nur angelegt, wenn die Komponente `reportingbackup` ausgewählt ist. Kundenspezifische Änderungen im Info-Ordner können ansonsten überschrieben werden.
- Empfehlung: Die standardisierten Info-Dateien ausschließlich als ausgelieferten Standard behandeln. Kundenspezifische Ergänzungen sollten langfristig in einem getrennten, updatefesten Ordner liegen.

## Aufgabe 5: Fehleranalyse

### Gesamtbewertung

Das Reporting funktioniert grundsätzlich, aber die Fehlerbehandlung ist historisch gewachsen und uneinheitlich. Die größten Risiken sind nicht fehlende Meldungsfenster, sondern:

- ein Vorgang läuft nach einem Fehler weiter;
- ein Fehler wird nur im Entwicklermodus sichtbar;
- ein Rückgabewert von List & Label wird nicht geprüft;
- ein Benutzerabbruch wird wie ein technischer Fehler oder sogar wie ein Erfolg behandelt;
- ein automatischer Auftrag verwendet unbemerkt einen anderen Drucker;
- ein leerer oder unvollständiger Bericht wird erzeugt, ohne die Ursache zu nennen.

## Priorität 1: Zuerst beheben

### 1. PDF-Fehler kann auf den Standarddrucker ausweichen

Fundstellen:

- `Frontends\Portalum\Reporting\LuLReporting.frm:6996`
- `Frontends\Portalum\Reporting\LuLDirectPrint.frm:171`

Ist das PDF-Zielverzeichnis ungültig, wird zwar ein Fehlertext gesetzt, anschließend aber der Windows-Standarddrucker ausgewählt und der Vorgang fortgesetzt. Ein geplanter PDF-Auftrag kann dadurch unbeabsichtigt auf Papier ausgegeben werden. Sind bei `PrinterDevicename = "PDF"` Dateiname oder Ordner leer, wird der PDF-Zweig ebenfalls nicht sicher betreten.

Vorschlag:

- Bei einer expliziten PDF-Ausgabe niemals auf einen Drucker zurückfallen.
- Ordner, Dateiname, Schreibrecht und vorhandene Zieldatei vor dem Start prüfen.
- Bei einem Fehler den Auftrag eindeutig beenden und einen Fehlerstatus zurückgeben.
- Meldung: `Die PDF-Datei konnte nicht erstellt werden. Auf den Zielordner '<Pfad>' kann nicht geschrieben werden. Es wurde nichts gedruckt.`

### 2. Der zentrale Direktdruck-Fehlerhandler setzt den Vorgang fort

Fundstelle:

- `Frontends\Portalum\Reporting\LuLReporting.frm:7101`

Der Handler zeigt den Laufzeitfehler an und verwendet danach `Resume Next`. Dadurch kann der Druckjob mit einem unvollständigen Zustand weiterlaufen. Weitere Fehler, doppelte Abschlussaufrufe oder falsche Erfolgsrückgaben sind möglich.

Vorschlag:

- Fehlerdaten sofort lokal sichern.
- In einem gemeinsamen Abschlussblock einen eventuell offenen Druckjob genau einmal beenden.
- Danach die Funktion mit einem definierten Fehlerergebnis verlassen.
- Kein `Resume Next` nach einem Fehler im Druckablauf.

### 3. Bericht 6004 enthält mehrere sichere Laufzeit- und Datenfehler

Fundstellen:

- `Frontends\Portalum\Reporting\LuLDruckRoutinenA4.cls:2099`
- `Frontends\Portalum\Reporting\LuLDruckRoutinenA4.cls:2107`
- `Frontends\Portalum\Reporting\LuLDruckRoutinenA4.cls:2114`
- `Frontends\Portalum\Reporting\LuLDruckRoutinenA4.cls:2129`

Probleme:

- Wenn `DRP Is Nothing` ist, wird trotzdem `DRP.ReadLastError` aufgerufen.
- Danach wird außerhalb des `Else` zusätzlich `DRP.CloseRS` aufgerufen.
- Das Feld `Direct,Event.DateTime` enthält ein Komma statt eines Punktes.
- `V(i)` verwendet den alten Schleifenzähler der Filterliste statt des Veranstaltungsfeldes `V(1)`.

Vorschlag:

- Queryfehler aus der Query- oder Datenbankschicht lesen, ohne den nicht vorhandenen Pointer anzusprechen.
- Nach einem fehlgeschlagenen Query sofort aus der Routine aussteigen.
- Feldname und Veranstaltungsindex korrigieren.
- Meldung mit Bericht 6004, Zeitraum, Zone und technischem Queryfehler protokollieren.

### 4. Drei Berichtstypen sind technisch unvollständig

Fundstellen:

- Bericht 3530:
  - `Frontends\Portalum\Reporting\LuLDruckRoutinenA4.cls:164`
  - `Frontends\Portalum\Reporting\LuLDruckRoutinenA4.cls:840`
- Bericht 9503:
  - `Frontends\Portalum\Reporting\LuLDruckRoutinenBon.cls:36`
- Bericht 9505:
  - `Frontends\Portalum\Reporting\LuLReporting.frm:4466`

Probleme:

- 3530 besitzt eine leere Sammelroutine. Der Router verwendet außerdem zweimal `lulTypBWEingang`; `lulTypBWEingangsListe` wird nicht erreicht.
- 9503 besitzt Layoutdateien, aber der Router meldet nur im Entwicklermodus `Fehlt noch`.
- 9505 steht im Berichtsbaum, besitzt aber keine Filter-, Router-, Sammelroutinen- oder Layoutimplementierung.

Vorschlag:

- Bis zur Implementierung diese Berichte in Produktion deaktivieren oder sichtbar als `noch nicht verfügbar` kennzeichnen.
- Ein unbekannter oder nicht implementierter Berichtstyp muss den Auftrag abbrechen und darf keinen leeren Ausdruck starten.
- Die vollständige Implementierung jeweils als eigene Aufgabe behandeln.

### 5. List-&-Label-Rückgabewerte werden nur teilweise geprüft

Fundstellen:

- `Frontends\Portalum\Reporting\LuLReporting.frm:6328`
- `Frontends\Portalum\Reporting\LuLReporting.frm:6925`
- `Frontends\Portalum\Reporting\LuLReporting.frm:7024`
- `Frontends\Portalum\Reporting\LuLControl.frm:416`
- `Frontends\Portalum\Reporting\LuLControl.frm:454`

Nur der Startwert wird an einigen Stellen geprüft. Rückgaben von Druckerkonfiguration, Exportparametern, Datensatzübergabe, Druckende und Vorschau werden überwiegend ignoriert. `CommitRow` und `CommitVar` unterscheiden nur Benutzerabbruch und Nicht-Abbruch; andere negative Fehlercodes können als Erfolg weiterlaufen.

Vorschlag:

- Einen zentralen Prüfer für alle List-&-Label-Rückgabewerte einführen.
- `0`, Wiederholungsstatus, Benutzerabbruch und technische Fehler getrennt behandeln.
- Jeden technischen Fehler mit API-Schritt, Fehlernummer und Berichtskontext protokollieren.
- Benutzerabbruch ohne Warnfenster als eigenen Status `Abgebrochen` zurückgeben.

### 6. Ein Benutzerabbruch wird nicht durch den gesamten Job weitergegeben

Fundstellen:

- `Frontends\Portalum\Reporting\LuLControl.frm:418`
- `Frontends\Portalum\Reporting\LuLControl.frm:456`
- `Frontends\Portalum\Reporting\LuLReporting.frm:6940`
- `Frontends\Portalum\Reporting\LuLReporting.frm:7081`

`CommitRow` beendet bei Abbruch bereits den List-&-Label-Job. Die aufrufende Sammelroutine beendet zwar meistens ihre Schleife, die darüberliegende Ausgaberoutine ruft danach aber weiterhin `LlPrintFieldsEnd` und `LlPrintEnd` auf.

Vorschlag:

- Jobweiten Status `Running`, `Cancelled`, `Failed`, `Completed` führen.
- Nach `Cancelled` keine weiteren List-&-Label-Aufrufe ausführen.
- Druckjob zentral und genau einmal schließen.

## Priorität 2: Danach stabilisieren

### 7. CSV-Export verwendet für `%D2` das Von-Datum

Fundstelle:

- `Frontends\Portalum\Reporting\LuLReporting.frm:7570`

`%D2` wird mit `mySelParamD1` ersetzt. Erwartet wird `mySelParamD2`.

Zusätzlich sind `Kill`, `Open`, `Print` und `Close` nicht lokal abgesichert. Als Dateinummer wird fest `#1` statt `FreeFile` verwendet.

Vorschlag:

- Datumsersetzung korrigieren.
- Zielpfad und Schreibrecht vorab prüfen.
- `FreeFile` verwenden und den Dateihandle im Fehlerfall sicher schließen.
- CSV-Fehler dürfen den eigentlichen Druck nur dann stoppen, wenn der Export ausdrücklich verpflichtend ist.

### 8. Druck- und PDF-Zähler steigen auch bei Fehler oder Abbruch

Fundstelle:

- `Frontends\Portalum\Reporting\LuLAusgabe.cls:705`

Bei Rechnungen werden `CounterPDF` oder `CounterPrint` nach dem Aufruf immer erhöht. Der Rückgabewert der Ausgabe und `R.Store` werden nicht auf Erfolg geprüft.

Vorschlag:

- Zähler ausschließlich bei einem bestätigten Ergebnis `Completed` erhöhen.
- Für Vorschau und Benutzerabbruch keinen Druckzähler erhöhen.
- Einen fehlgeschlagenen `Store` getrennt melden und protokollieren.

### 9. Info-RTF-Fehler bleiben unsichtbar

Fundstellen:

- `Frontends\Portalum\Reporting\LuLReporting.frm:7647`
- `Frontends\Portalum\Reporting\LuLReporting.frm:7964`
- `Frontends\Portalum\Reporting\LuLReporting.frm:7973`

Ein Fehler beim Laden löscht den sichtbaren Text kommentarlos. Beim Speichern fehlt ein lokaler Fehlerhandler. Ursachen wie defekte RTF-Datei, fehlendes Leserecht oder schreibgeschützter Datenpfad sind nicht unterscheidbar.

Vorschlag:

- Fehlende Datei, ungültiges RTF und Zugriffsfehler getrennt behandeln.
- Im Info-Tab einen kurzen Hinweis anzeigen, statt nur eine leere Fläche zu zeigen.
- Speichern zunächst in eine temporäre Datei, danach atomar ersetzen.
- Nur Entwickler dürfen speichern; Schreibfehler mit Pfad und Windows-Fehler protokollieren.

### 10. Fehlende Pflichtfilter werden nicht benannt

Fundstellen:

- `Frontends\Portalum\Reporting\LuLReporting.frm:3522`
- `Frontends\Portalum\Reporting\LuLReporting.frm:7555`

Die Prüfung stoppt beim ersten fehlenden Filter und meldet nur, dass mindestens ein Filter fehlt. Der Benutzer erfährt nicht, welcher Filter gemeint ist.

Vorschlag:

- Alle fehlenden Pflichtfilter sammeln.
- Den Filter-Tab öffnen und die betroffenen Zeilen markieren.
- Meldung: `Der Bericht kann noch nicht gestartet werden. Bitte setzen Sie: Sitzung, Zeitraum und Arbeitsstation.`

### 11. Leere Ergebnismengen werden nicht zentral erkannt

Es gibt keinen jobweiten Datensatzzähler. Dadurch können ein legitimer Zeitraum ohne Treffer, eine unvollständige Sammelroutine und ein Datenfehler alle zu einem leeren Bericht führen.

Vorschlag:

- Erfolgreiche `CommitRow`- und `CommitVar`-Aufrufe pro Job zählen.
- Vor Ausgabe unterscheiden:
  - `Keine Daten für die gewählten Filter`
  - `Datensammlung fehlgeschlagen`
  - `Berichtstyp nicht implementiert`
- Für Berichte, die absichtlich ohne Tabellenzeilen arbeiten, eine explizite Ausnahme definieren.

### 12. Ungültige Drucker fallen still auf den Standarddrucker zurück

Fundstellen:

- `Frontends\Portalum\Reporting\LuLReporting.frm:7006`
- `Frontends\Portalum\Reporting\LuLDirectPrint.frm:179`

Wird ein gespeicherter oder übergebener Drucker nicht gefunden, wird der Windows-Standarddrucker verwendet. Bei automatischen Aufträgen kann dies die Ausgabe an ein falsches Gerät senden.

Vorschlag:

- Interaktive Ausgabe: Druckerauswahl anbieten.
- Unbeaufsichtigte Ausgabe: Auftrag abbrechen und `Drucker nicht gefunden` zurückgeben.
- Meldung muss angeforderten Drucker und verfügbare Ersatzaktion nennen.

### 13. Layout-Metadatenfehler werden weitgehend verschluckt

Fundstellen:

- `Frontends\Portalum\Reporting\DruckDatei.cls:81`
- `Frontends\Portalum\Reporting\LuLReporting.frm:5544`
- `Frontends\Portalum\Reporting\LuLReporting.frm:5616`

`ReadVariablen` verwendet für die gesamte Datei `On Error Resume Next`. Ein beschädigtes oder gesperrtes Layout kann dadurch mit teilweise gelesenen Metadaten weiterverwendet werden. Die Layoutliste protokolliert Fehler und setzt danach mit `Resume Next` fort.

Vorschlag:

- Dateizugriff und Metadatenparser getrennt absichern.
- Dateihandle in jedem Fall schließen.
- Defekte Layouts in der Liste rot markieren und für die Ausgabe sperren.
- Technische Details protokollieren; dem Benutzer eine kurze, handlungsorientierte Meldung zeigen.

### 14. Initialisierung der Control-Instanz verwendet die falsche Bedingung

Fundstelle:

- `Frontends\Portalum\Reporting\LuLAusgabe.cls:156`

Die Instanz wird neu erzeugt, wenn sie bereits vorhanden ist. Erwartbar ist eine Erzeugung, wenn `myFrmC Is Nothing` gilt. Die Reporting-Formen gleichen dies später teilweise aus, dennoch ist die Lebensdauer der zentralen Instanz inkonsistent.

Vorschlag:

- Bedingung korrigieren.
- Initialisierung idempotent gestalten.
- Initialisierungsfehler als strukturiertes Ergebnis von `EngineInit` zurückgeben.

### 15. Fehlender Meldungsparameter

Fundstelle:

- `Frontends\Portalum\Reporting\LuLAusgabe.cls:961`

Die Meldung enthält `%1`, übergibt aber den Dateinamen nicht an `Tools.Msg`.

Vorschlag:

- `PrtFile` als Meldungsparameter übergeben.
- Einen automatischen statischen Test für Meldungsplatzhalter ergänzen.

### 16. Doppelte Parameterdefinition für Bericht 6001

Fundstellen:

- `Frontends\Portalum\Reporting\LuLReporting.frm:5733`
- `Frontends\Portalum\Reporting\LuLReporting.frm:5932`

`lulTypAufenthaltsdauer` kommt in demselben `Select Case` zweimal vor. Der zweite Zweig ist nicht erreichbar. Dadurch können erwartete Standardwerte oder Parameter fehlen.

Vorschlag:

- Beide Definitionen fachlich zusammenführen.
- Berichtstypen in Router-, Filter-, Parameter-, Sortier- und Baumdefinition automatisiert auf Eindeutigkeit prüfen.

### 17. Bon-Zahlungsfortschritt verwendet einen möglicherweise alten oder nullen Divisor

Fundstelle:

- `Frontends\Portalum\Reporting\LuLDruckRoutinenBon.cls:231`

Im Container `Payment` wird `100 * i / Menge` verwendet. `Menge` wird dort nicht aus den Zahlungsarten gesetzt und kann vom vorherigen Container stammen oder null sein.

Vorschlag:

- Anzahl der Zahlungszeilen vor der Schleife bestimmen.
- Bei null Zeilen keinen Quotienten bilden.
- Fortschrittsberechnung in eine sichere Hilfsfunktion verlagern.

## Priorität 3: Meldungen vereinheitlichen

### Aktuelle Schwächen

- Teilweise deutsche, teilweise englische Rückgaben wie `No Database` oder `Missing User`.
- Technische API-Texte werden direkt dem Benutzer gezeigt.
- Mehrere Schreibfehler und alte Trennungen wie `ge-funden`, `Druck Ausgabe` oder `initalisiert`.
- `Tools.Msg`, `MsgBox`, Funktionsrückgaben, Entwicklerstopps und Logdateien werden uneinheitlich eingesetzt.
- Die vorhandene Fehlercodetabelle nennt häufig die List-&-Label-Funktion, aber selten eine konkrete Lösung.
- Unbekannte Fehlernummern werden ohne die eigentliche Nummer ausgegeben.

### Empfohlenes Ergebnis-Modell

Jeder Ausgabeweg sollte genau einen strukturierten Status liefern:

- `Completed`
- `Cancelled`
- `NoData`
- `ConfigurationError`
- `DataError`
- `OutputError`
- `ListLabelError`
- `InternalError`

Zusätzliche Felder:

- Berichtstyp und Berichtsname
- Layoutdatei
- Ausgabeart
- angeforderter Drucker oder PDF-Ziel
- Fehlernummer und technische Beschreibung
- Benutzeraktion
- Support-ID oder Zeitstempel

### Aufbau einer Benutzermeldung

1. Kurze Überschrift: Was ist fehlgeschlagen?
2. Konkreter Bezug: Welcher Bericht und welche Ausgabe?
3. Handlung: Was kann der Benutzer jetzt tun?
4. Optional: Support-ID für die Logsuche.

Beispiel:

`PDF-Ausgabe nicht möglich`

`Der Bericht 5002 "Sitzungsliste" konnte nicht als PDF gespeichert werden. Auf den Ordner "D:\Export" kann nicht geschrieben werden. Bitte wählen Sie einen anderen Ordner oder prüfen Sie die Berechtigung. Es wurde nichts gedruckt. Support-ID: REP-20260727-143015.`

### Technisches Protokoll

Das Log sollte zusätzlich enthalten:

- Prozedur und Verarbeitungsschritt
- List-&-Label-Fehlercode
- `Err.Number`, `Err.Source` und `Err.Description`
- Berichtstyp, Layoutpfad und Ausgabeziel
- kompakte Filter- und Parameterzusammenfassung
- Bediener, Arbeitsstation und Datenbankkennung
- Startzeit, Endzeit, Dauer und Anzahl ausgegebener Datensätze

Sensible Inhalte wie vollständige Kundendaten, Ticketcodes oder Zahlungsdaten dürfen nicht ungefiltert protokolliert werden.

## Empfohlene Umsetzungsreihenfolge

1. PDF- und Drucker-Fallbacks entfernen.
2. Fehlerhandler und jobweiten Abbruchstatus einführen.
3. Bericht 6004 sowie die Typen 3530, 9503 und 9505 korrigieren oder deaktivieren.
4. Alle List-&-Label-Rückgabewerte zentral prüfen.
5. CSV-, RTF- und Layout-Dateizugriffe absichern.
6. Einheitliches Ergebnisobjekt und Meldungssystem einführen.
7. Jobweiten Datensatzzähler und `NoData`-Behandlung ergänzen.
8. Automatischen Reporting-Preflight aufbauen.

## Empfohlener Reporting-Preflight

Vor einem Release sollte ein Prüfwerkzeug automatisch kontrollieren:

- Jeder Baumtyp besitzt genau einen Datenrouter.
- Jeder Router verweist auf eine nicht leere Sammelroutine.
- Jeder Typ besitzt passende Filter-, Parameter- und Sortierdefinitionen.
- Für produktive Typen existiert mindestens ein Layout.
- Alle in Layouts verwendeten Felder werden in der Konfigurationsphase definiert.
- Feldnamen zwischen Konfigurations- und Datenphase sind identisch.
- Alle Info-RTFs existieren und lassen sich laden.
- Meldungsplatzhalter besitzen die erforderlichen Parameter.
- Inno Setup erfasst alle ausgelieferten Info-Dateien.

## Abgrenzung

Für Aufgabe 5 wurden noch keine Laufzeitänderungen am Reporting vorgenommen. Dieses Dokument ist die fachliche und technische Grundlage, um die Korrekturen anschließend in kleinen, kontrollierten Aufgaben umzusetzen.
