Wiki source code of BMD_Rimo_Invoices

Version 40.2 by Patrizia Gurschka on 2026/10/05 13:43

Show last authors
1 |(% style="width:772px" %)(((
2 {{box cssClass="floatinginfobox" title="**Auf dieser Seite**"}}
3 {{toc/}}
4 {{/box}}
5
6 = **đŸ§Ÿ**BMD → Rimo Invoices (Rechnungsautomatisierung) =
7
8 {{info}}
9 **Zweck: **Automatisierte Übertragung von BMD-Eingangsrechnungen nach Rimo — Download, Upload und Freigabe (Approval), vollstĂ€ndig zustandsbehaftet.
10
11 **Zielgruppe: **Buchhaltung/Fibu-Team und IT/Fabric-Betrieb.
12 {{/info}}
13 )))
14
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
26 [[image:1791200276107-433.png]]
27
28 == Technologiestack ==
29
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.
31
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)
36
37 == Hauptfunktionen ==
38
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.
40
41 === 1. Datenerfassung ===
42
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.
44
45 Buchungen ohne Buchungstext werden ohne userLabel an Rimo ĂŒbergeben; das Feld fehlt dann im Request.
46
47 === 2. Download-Phase (Belegdokument) ===
48
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.
50
51 === 3. Upload-Phase (Rechnungsdaten) ===
52
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.
54
55 === 4. Approval-Phase (Freigaben) ===
56
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.
58
59 == Health-Checks und technische Fehlererkennung ==
60
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.
62
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
73
74 **WÀhrend des Laufs** gilt zusÀtzlich:
75
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.
79
80 == Fehler-Orchestrierung und Benachrichtigungen ==
81
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.
83
84 [[image:1791200539745-771.png]]
85
86 Fehler-Orchestrierung · drei Mails, zwei EmpfÀngergruppen
87
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
129 |State-Datei|/lakehouse/default/Files/bmd/import/BMD_Invoices/rimo_processed_state.json
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
135
136 == Sicherheit ==
137
138 Die Rimo-Zugangsdaten stehen weiterhin im Klartext im Notebook; die Umstellung auf einen Key Vault ist vorbereitet, aber noch nicht umgesetzt.
139
140 === Authentifizierung ===
141
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.
145
146 === Datenschutz ===
147
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.
149
150 == Besondere GeschÀftslogik ==
151
152 Vier fachliche Sonderregeln weichen bewusst von einer 1:1-Übernahme der BMD-Daten ab.
153
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.
161
162 == Server / Umgebung ==
163
164 Notebook und Pipelines laufen im Microsoft Fabric Workspace auf Runtime 2.0; ausgelöst wird stĂŒndlich ĂŒber die Orchestrierungs-Pipeline oder manuell.
165
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.