Wiki source code of BMD_Rimo_Invoices

Last modified by Patrizia Gurschka on 2026/10/05 13:48

Hide last authors
Patrizia Gurschka 13.1 1 |(% style="width:772px" %)(((
Patrizia Gurschka 22.1 2 {{box cssClass="floatinginfobox" title="**Auf dieser Seite**"}}
3 {{toc/}}
4 {{/box}}
5
Patrizia Gurschka 20.2 6 = **🧾**BMD → Rimo Invoices (Rechnungsautomatisierung) =
Patrizia Gurschka 5.1 7
Patrizia Gurschka 19.1 8 {{info}}
Patrizia Gurschka 41.1 9 **Zweck: **Automatisierte Übertragung von BMD-Eingangsrechnungen nach Rimo — Download, Upload und Freigabe (Approval), vollständig zustandsbehaftet. Die Lösung läuft stündlich über eine Fabric-Pipeline und meldet fachliche Fehler an die Buchhaltung, technische Auffälligkeiten an die IT.
Patrizia Gurschka 19.1 10
11 **Zielgruppe: **Buchhaltung/Fibu-Team und IT/Fabric-Betrieb.
12 {{/info}}
Patrizia Gurschka 20.1 13 )))
Patrizia Gurschka 19.1 14
Patrizia Gurschka 5.1 15 == Überblick ==
16
17 **BMD → Rimo Invoices** ist eine Fabric-Notebook-gesteuerte Automatisierung mit zwei begleitenden Data-Factory-Pipelines. Die Lösung besteht aus:
18
19 * **Notebook: **Python/PySpark (Microsoft Fabric)
20 * **Datenquelle: **Fabric Lakehouse (Spark SQL)
21 * **Orchestrierung: **2 Data-Factory-Pipelines
22 * **Zielsystem: **Rimo REST-API (Test/Dev)
23
24 == Architektur ==
25
Patrizia Gurschka 39.2 26 [[image:1791200276107-433.png]]
Patrizia Gurschka 5.1 27
28 == Technologiestack ==
29
Patrizia Gurschka 40.2 30 Seit dem 25.09.2026 läuft das Notebook auf Fabric Runtime 2.0 (Spark 4, Python 3.13); die SQL-Abfragen wurden dafür von parametrisierten Abfragen auf f-Strings umgestellt.
Patrizia Gurschka 5.1 31
Patrizia Gurschka 40.2 32 * **Notebook/Backend:** Python, PySpark (Spark SQL), requests, notebookutils, Python-Logging mit eigenem Logger
33 * **Datenplattform:** Fabric Lakehouse, Delta-Tabellen bmd.fibu_erb_buchungen, bmd.fibu_erk_konto, rimo.sdmcompany, rimo.sdmcreditor, rimo.sdmaccount, rimo.sdmsalesorder, rimo.sdmprojectpurchaseorder, spl_gold_lh.bmd.rimo_processed_invoices_log
34 * **Orchestrierung:** Fabric Data Factory (Copy-Data, Notebook-Aktivität, If-Condition, Office-365-Outlook-Aktivität)
35 * **Externe API:** Rimo REST-API (multipart/form-data für Upload, JSON für Approvals)
Patrizia Gurschka 5.1 36
Patrizia Gurschka 40.2 37 == Hauptfunktionen ==
Patrizia Gurschka 5.1 38
Patrizia Gurschka 40.2 39 Jeder Lauf durchläuft nach den Health-Checks drei fachliche Phasen; jede Rechnung trägt ihren Stand in der State-Datei, sodass ein abgebrochener Lauf beim nächsten Mal genau dort weitermacht.
Patrizia Gurschka 5.1 40
41 === 1. Datenerfassung ===
42
Patrizia Gurschka 40.2 43 Buchungszeilen werden aus bmd.fibu_erb_buchungen gelesen: alle Buchungen ohne „Spesen“ im Buchungstext, einschließlich Buchungen **ohne** Buchungstext, mit Erstelldatum ab 27.08.2026, 10:00 Uhr (offenes Zeitfenster). Bereits verarbeitete Zeilen werden per LEFT JOIN gegen spl_gold_lh.bmd.rimo_processed_invoices_log ausgeschlossen; bei mehreren Dateien zum selben Beleg wird die .pdf-Variante bevorzugt. Jede Zeile erhält den Schlüssel //intBelegNr_Firmennr// und wird in die Warteschlange der State-Datei übernommen.
Patrizia Gurschka 5.1 44
Patrizia Gurschka 40.2 45 Buchungen ohne Buchungstext werden ohne userLabel an Rimo übergeben; das Feld fehlt dann im Request.
46
Patrizia Gurschka 5.1 47 === 2. Download-Phase (Belegdokument) ===
48
Patrizia Gurschka 40.2 49 Notebooks können den On-Premises Data Gateway nicht nutzen. Deshalb kopiert die vorgelagerte Copy-Data-Aktivität die Dateien vom Dateiserver (\atwotbmd01\BMDDocs\0\2...) gesammelt ins Lakehouse, anhand eines Abgleichs von bmd.fibu_erb_buchungen mit der Log-Tabelle. Die Download-Phase prüft nur, ob die erwartete Datei im Lakehouse-Zielordner angekommen ist.
Patrizia Gurschka 5.1 50
51 === 3. Upload-Phase (Rechnungsdaten) ===
52
Patrizia Gurschka 40.2 53 BMD-Felder werden auf Rimo-Felder gemappt, Firmen- und Kreditor-IDs per Lakehouse-Lookup ergänzt und Beleg plus Daten per multipart/form-data an POST /v1/invoices übergeben. Ein erfolgreicher Upload liefert die Rimo-externalId.
Patrizia Gurschka 5.1 54
55 === 4. Approval-Phase (Freigaben) ===
56
Patrizia Gurschka 40.2 57 Pro Buchungszeile in bmd.fibu_erk_konto (verknüpft über ErfassNr) wird eine eigene Freigabe an Rimo gesendet, mit mehrstufigem Fallback für die Bestellnummer- und Sales-Order-Zuordnung (siehe Besondere Geschäftslogik). Die Approval-Phase läuft im Modus „all“ mit.
Patrizia Gurschka 5.1 58
Patrizia Gurschka 40.2 59 == Health-Checks und technische Fehlererkennung ==
Patrizia Gurschka 5.1 60
Patrizia Gurschka 40.2 61 Vor jeder Verarbeitung prüft das Notebook Verbindungen, Tabellen und die eigenen SQL-Abfragen. Ein kritischer Fehler bricht den Lauf ab, bevor eine Rechnung angefasst wird; so landen bei Systemumstellungen (z. B. Runtime-Wechsel) keine Rechnungen fälschlich in dead_letter.
Patrizia Gurschka 5.1 62
Patrizia Gurschka 40.2 63 |Check|Schwere|Prüft
64 |Rimo-Token|kritisch|Token-Abruf liefert HTTP 200 und einen Token
65 |Rimo-API erreichbar|kritisch|API antwortet, keine 401/403/5xx
66 |State-Datei|kritisch|Datei lesbar und vollständig; fehlt sie bei befüllter Log-Tabelle → Abbruch (Schutz vor Doppelverarbeitung)
67 |Lakehouse schreibbar|kritisch|Testdatei im Zielordner schreiben und löschen
68 |Stammdatentabellen|kritisch|rimo.sdmcompany, sdmcreditor, sdmaccount, sdmsalesorder, sdmprojectpurchaseorder, bmd.fibu_erk_konto nicht leer
69 |bmd.fibu_erb_buchungen|Warnung|nicht leer; leer ist zulässig, wenn keine Rechnungen anfallen
70 |Schlüsselformat|kritisch|Schlüssel entsprechen //Ziffern_Ziffern// (erkennt Typänderungen im DWH)
71 |BMD-Buchungen aktuell|Warnung|neueste Buchung höchstens 4 Tage alt
72 |Lookup Company|kritisch|echte Lookup-Funktion findet die bekannte Firma 70
Patrizia Gurschka 5.1 73
Patrizia Gurschka 40.2 74 **Während des Laufs** gilt zusätzlich:
Patrizia Gurschka 5.1 75
Patrizia Gurschka 40.2 76 * **Technische Fehler:** Scheitert eine Lookup-Abfrage technisch (SQL-Fehler statt „nicht gefunden“), wird das als technischer Fehler gesammelt und an die IT gemeldet. Ab 5 technischen Fehlern bricht der Lauf ab.
77 * **Lookup-Trefferquote:** Finden Company-, Kreditor-, Account-, Sales-Order- oder Purchase-Order-Lookups bei mindestens 3 Versuchen zu 80 % oder mehr nichts, wird das als vermutliches Daten- oder Abfrageproblem gemeldet.
78 * **Caches:** Lookup-Caches werden zu Beginn jedes Laufs geleert, damit bei wiederverwendeten Sessions keine veralteten Stammdaten verwendet werden.
Patrizia Gurschka 5.1 79
Patrizia Gurschka 40.2 80 == Fehler-Orchestrierung und Benachrichtigungen ==
Patrizia Gurschka 5.1 81
Patrizia Gurschka 40.2 82 Die Pipeline trennt seit Ende September 2026 fachliche Fehler (Mail an die Buchhaltung) von technischen Auffälligkeiten (Mail an die IT); bricht das Notebook ab, geht ein eigener Alarm an die IT.
Patrizia Gurschka 5.1 83
Patrizia Gurschka 40.2 84 [[image:1791200539745-771.png]]
Patrizia Gurschka 5.1 85
Patrizia Gurschka 40.2 86 Fehler-Orchestrierung · drei Mails, zwei Empfängergruppen
Patrizia Gurschka 5.1 87
Patrizia Gurschka 40.2 88 Beide If-Conditions hängen parallel am Erfolgspfad der Notebook-Aktivität und lesen Flags aus dem exitValue.
89
90 |Mail|Auslöser|Inhalt
91 |ErrorMailing (Buchhaltung)|hasFailures = 1|Download-, Upload-, Approval-Fehler und „Lieferperiode ungültig“, je als eigene Tabelle (Feld emailBodyHtml)
92 |TechnicalAlert (IT)|hasTechnicalIssues = 1|Technische Fehler, Health-Check-Warnungen, auffällige Lookups, unklare Uploads (Feld itEmailBodyHtml)
93 |NotebookStopAlert (IT)|Notebook-Aktivität fehlgeschlagen|Extrahierter Fehlertext aus errorValue, Pipeline, Zeitpunkt, Run-ID
94
95 * **Keine Doppelmeldungen:** Gemeldete Fehler werden in der State-Datei markiert (notified_at) und nur einmal gemailt.
96 * **Health-Warnungen mit Schwelle:** Eine leere bmd.fibu_erb_buchungen wird erst nach 3 Läufen in Folge gemeldet, einmal pro Serie; der Zähler steht in der State-Datei und zählt über Tagesgrenzen. Andere Warnungen werden beim ersten Auftreten gemeldet.
97 * **Lieferperiode ungültig:** bleibt in pending statt dead_letter und wird nach Korrektur in BMD automatisch neu versucht.
98 * **Download-Fehler** nach Erreichen der Retry-Grenze erhalten eine verständliche Meldung, z. B. „Datei nach Pipeline-Lauf nicht im Lakehouse gefunden“.
99
100 == Logging, State-Datei und Backups ==
101
102 Jeder Lauf wird als eigener Block oben in rimo_pipeline.log geschrieben, der neueste Lauf steht damit immer am Anfang der Datei.
103
104 === Logging ===
105
106 * Das Notebook nutzt einen eigenen Logger (rimo_pipeline), unabhängig vom Root-Logger der Fabric-Runtime. Hintergrund: Runtime 2.0 konfiguriert den Root-Logger selbst, wodurch seit 25.09.2026 nach 07:08 Uhr keine Einträge mehr in der Logdatei landeten.
107 * Während des Laufs wird lokal nach /tmp geloggt; am Ende fügt das Notebook den Lauf als Block (Kopfzeile //LAUF Start bis Ende//) oben in die Lakehouse-Logdatei ein, innerhalb des Blocks chronologisch.
108 * Das Log wird auch bei einem Abbruch geschrieben (try/finally um den Hauptlauf).
109 * Zeitstempel im Log in Wiener Zeit (Europe/Vienna); Zeitstempel in der State-Datei in UTC.
110
111 === Dateien im Lakehouse ===
112
113 |Datei / Ordner|Pfad|Inhalt
114 |State-Datei|Files/bmd/import/BMD_Invoices/rimo_processed_state.json|Warteschlange (pending), erledigt (succeeded), dead_letter, Zähler der Health-Warnungen
115 |Logdatei|Files/bmd/import/BMD_Invoices/rimo_pipeline.log|Läufe als Blöcke, neuester oben
116 |State-Backups|Files/bmd/import/BMD_Invoices_state_backups/|Tägliche Kopie der State-Datei, 5 Tage aufbewahrt
117 |Log-Tabelle|spl_gold_lh.bmd.rimo_processed_invoices_log|Erledigte und dead_letter-Einträge; Basis für den Ausschluss bei der Datenerfassung
118
119 Die State-Datei wird atomar geschrieben (Temp-Datei, Prüfung, Umbenennen), damit ein Abbruch keine halbe Datei hinterlässt. Die Backups liegen bewusst außerhalb von BMD_Invoices, weil das Cleanup am Ende jedes Laufs dort alle Unterordner löscht; .log- und .json-Dateien bleiben dabei erhalten.
120
121 == Pipelines und Konfiguration ==
122
123 Die wichtigsten Einstellungen stehen als Konstanten in der Konfig-Zelle des Notebooks; Filter und Zugangsdaten sind noch nicht parametrisiert.
124
125 |Bereich|Details
126 |Copy-Pipeline „BMD_Invoices“|Kopiert die benötigten Dateien gesammelt vom Dateiserver ins Lakehouse, vor der Notebook-Aktivität
127 |Orchestrierungs-Pipeline „BMD_Invoices_Error_Handling“|Notebook → If Condition (hasFailures) → ErrorMailing/FallbackAlert; parallel If Condition (hasTechnicalIssues) → IT-Mail; bei Abbruch NotebookStopAlert
128 |Rimo-API-Endpunkt|rimo-api.d-prod.spl-tele.com/v1/invoices
Patrizia Gurschka 25.2 129 |State-Datei|/lakehouse/default/Files/bmd/import/BMD_Invoices/rimo_processed_state.json
Patrizia Gurschka 40.2 130 |Retry-Grenzen|Download/Upload/Approval je max. 5 Versuche; HTTP-Aufrufe je 3 Versuche mit Backoff
131 |Technische Fehler|Abbruch ab 5 technischen Fehlern pro Lauf (MAX_TECH_ERRORS)
132 |Health-Warnung leere Buchungstabelle|Mail erst nach 3 Läufen in Folge, einmal pro Serie
133 |Exit-Details|max. 50 Einträge pro Kategorie im Exit-Wert (MAX_EXIT_DETAILS)
134 |Aktuelle Filterung|Buchungen ohne „Spesen“ (inkl. leerem Buchungstext) + Erstelldatum ab 27.08.2026, 10:00 Uhr; fest im Code. Kein Firmennr-Filter
Patrizia Gurschka 5.1 135
136 == Sicherheit ==
137
Patrizia Gurschka 40.2 138 Die Rimo-Zugangsdaten stehen weiterhin im Klartext im Notebook; die Umstellung auf einen Key Vault ist vorbereitet, aber noch nicht umgesetzt.
139
Patrizia Gurschka 5.1 140 === Authentifizierung ===
141
Patrizia Gurschka 40.2 142 * **Rimo-API-Token:** wird per Benutzer/Passwort über /v1/auth/fetch-token einmal pro Lauf geholt. Der Health-Check bricht den Lauf ab, wenn der Abruf fehlschlägt. Eine automatische Token-Erneuerung bei HTTP 401 gibt es noch nicht.
143 * **Zugangsdaten:** Benutzer und Passwort stehen im Klartext im Notebook und damit auch im Versionsverlauf. Empfehlung: über notebookutils.credentials.getSecret aus einem Key Vault beziehen und das Passwort ändern.
144 * **Fabric-API-Token:** wird nicht mehr verwendet, da der Kopiervorgang vollständig in der vorgelagerten Copy-Data-Aktivität läuft.
Patrizia Gurschka 5.1 145
146 === Datenschutz ===
147
Patrizia Gurschka 40.2 148 Zugriff auf Buchungs- und Stammdaten ausschließlich über die Fabric-Lakehouse-Berechtigungen. Das Notebook greift nicht direkt auf den On-Premises-Dateiserver zu; das läuft ausschließlich über die Gateway-Pipeline.
Patrizia Gurschka 5.1 149
150 == Besondere Geschäftslogik ==
151
Patrizia Gurschka 40.2 152 Vier fachliche Sonderregeln weichen bewusst von einer 1:1-Übernahme der BMD-Daten ab.
Patrizia Gurschka 5.1 153
Patrizia Gurschka 40.2 154 * **Vorzeichen-Korrektur beim Upload:** Ist der Bruttobetrag (grossAmount) positiv, der Nettobetrag (netAmount) aber negativ, wird der Betrag ohne Vorzeichen als netAmount übergeben. Alle anderen Kombinationen bleiben unverändert.
155 * **Mehrstufiger Fallback bei Approvals:**
156 *1. Bestellnummer-Kandidaten (Purchase-/Sales-Order-Paare) einzeln probieren
157 *1. bei Scheitern ein firmenbasierter Sales-Order-Kandidat ohne Bestellung
158 *1. sonst endgültig gescheitert (approval_dead)
159 * **Sales-Order-Ausnahme:** Gibt es für eine Firma keinen Sales Order mit getsalesordernumber = '0000 {4 Ziffern}', wird ersatzweise nach dem Muster „{Firmennummer}000 0001“ gesucht (Firma 68 → „68000 0001“). Dieser Fallback greift nur, wenn die reguläre Suche keine Kandidaten liefert.
160 * **Ungültige Lieferperiode:** Ist eine falsch formatierte Lieferperiode der einzige Fehler, bleibt die Rechnung in pending statt in dead_letter und wird nach Korrektur in BMD automatisch erneut versucht.
Patrizia Gurschka 5.1 161
162 == Server / Umgebung ==
163
Patrizia Gurschka 40.2 164 Notebook und Pipelines laufen im Microsoft Fabric Workspace auf Runtime 2.0; ausgelöst wird stündlich über die Orchestrierungs-Pipeline oder manuell.
Patrizia Gurschka 5.1 165
Patrizia Gurschka 40.2 166 * **Workspace:** wegen des Kapazitätschecks laufen Pipeline und Notebook derzeit über den Fabic_test_workspace, angehängt an das im Fabric Workspace liegende bmd_invoice_execution.
167 * **Runtime:** Fabric Runtime 2.0 seit 25.09.2026. Bei künftigen Runtime-Wechseln vorab in einer Kopie testen; die Health-Checks fangen grundlegende Probleme ab.
168 * **Erreichbarkeit Rimo-API:** über die im Notebook hinterlegten Zugangsdaten.
169 * **Belegquelle:** \atwotbmd01\BMDDocs\0\2..., nur über die On-Premises-Gateway-Pipeline erreichbar.
170
171 == Offene Punkte und bekannte Einschränkungen ==
172
173 Das größte offene Risiko sind doppelte Rechnungen in Rimo bei Timeouts; die Lösung ist ausgearbeitet, aber noch nicht eingebaut.
174
175 * ☐ **Schutz vor doppelten Uploads:** Bei Timeout oder 5xx wiederholt upload_invoice den Upload, obwohl Rimo die Rechnung womöglich schon angelegt hat. Geplant: Status upload_uncertain, kein automatischer Retry, Meldung an die IT, Hilfsfunktion resolve_upload_uncertain.
176 * ☐ **Token-Erneuerung bei HTTP 401** für Upload und Approval, damit lange Läufe nicht abbrechen.
177 * ☐ **Zugangsdaten in Key Vault** verschieben und Passwort ändern.
178 * ☐ **Leere Firmennr im Schlüssel:** CONCAT mit NULL ergibt NULL; COALESCE in der Abfrage ergänzen.
179 * ☐ **Copy-Data-Abfrage angleichen:** Buchungen ohne Buchungstext müssen auch dort mitkopiert werden, sonst scheitert ihr Download.
180 * ☐ **Startdatum parametrisieren** statt fest im SQL.
181 * ☐ **Gleichnamige PDFs** aus verschiedenen BMD-Ordnern überschreiben sich im flachen Lakehouse-Ordner; Copy-Pipeline sollte den relativen Pfad oder den Schlüssel als Dateinamen verwenden.
182 * ☐ **Atomares Schreiben prüfen:** Erscheint im Log „Atomares Ersetzen der State-Datei nicht möglich“, unterstützt der OneLake-Mount os.replace nicht.
183 * ☐ **Health-Check-Werte ergänzen:** bekannten Kreditor und Kontonummer in KNOWN_LOOKUPS eintragen.
184 * ☐ **Approvals bei Timeout:** submit_approval wiederholt bei Timeout und 5xx; im schlimmsten Fall entsteht eine Freigabezeile doppelt.