Artikelmatching
Problembeschreibung
Beim Auslesen von PDF-Rechnungen können bisher nie Artikelnummern
erfasst werden. Diese werden derzeit immer durch ein Matching mittels
regex in der jeweiligen Scriptdatei ermittelt.
Bisher diente die Zuordnung mittels regex vorrangig der Zuordnung
eines Produkttypen (productcomponentidentifier). Mit der Weiterung auf
Artikelnummern kam hier eine neue Komplexität hinzu.
- Artikelnummern gehören in der Regel zu bestimmten Verzeichnissen bzw. Nummernkreisen. So verwendet der BDEW in der Netznutzung andere Artikelnummern als EDNA in der Endkundenabrechnung. Einige Kunden wie z.B. Daimler AG erwarten zudem einen selbstdeinifierten Artikelnumemrnsatz.
- Artikelnummern und Prodtuktypen müssen zusätzlich in der Handerfassung zugeordnet werden. Eine Zuordnung innerhalb eines Importscriptes ist damit weitgehend ausgeschlossen.
- Es soll eine einheitliche Lösung geschaffen werden, welche sowohl für die automatische als auch die manuelle Verarbeitung nutzbar ist.
- Artikeltexte sind oft nicht eindeutig genug, um eine sichere Zuordnung für eine Artikelnummer zu treffen (je nach Kundenanforderung - siehe Daimler AG).
- Im Fall von srukturierten elektronischen Rechnungen (z.B. ZUGFeRD, XRechnung oder INVOIC) soll ein Mapping der eingehenden Artikelnummern auf interne Produkttypen und Artikelnummern möglich sein.
Multiple Regex-Regeln
Eine alternative und vermutlich flexiblere Lösung wäre ein Set an Vergleichsausdrücken zu erstellen, bei dem jeder Vergleich mit dem entsprechenden Attribute in der Rechnungszeilen-JSON korrespondiert.
| Rechnungszeile der Import- oder Export-JSON | JSON-Struktur mit Matching-Regeln in den korrespondierenden Attributen |
|---|---|
| ```JSON | |
| { |
"linenr":1,
"globalid":"9990001990001",
"globaldir":"DAG",
"start":"01.12.2020",
"end":"31.12.2020",
"text":"Verbrauch HT (T)",
"text_standard":"Wirkarbeit HT (Hochtarif)",
"productType":"Lieferung",
"days":31,
"amount":805,
"unit":"kWh",
"price":4.469,
"priceunit":"cts/khWh",
"basefactor":100,
"net_amount":35.98,
"tax_rate":16,
"tax_amount":null,
"gross_amount":null,
"total":35.98,
"currency":"EUR",
"toSubstitute":false,
"variant":"1"
}
|JSON
{
// “linenr”:1,
// “globalid”:“9990001990001”,
// “globaldir”:“DAG”,
// “start”:“01.12.2020”,
// “end”:“31.12.2020”,
“text”: value => value.matches(Verbrauch\s+HT.*),
// “text_standard”:“Wirkarbeit HT (Hochtarif)”,
// “productType”:“Lieferung”,
// “days”:31,
// “amount”:805,
“unit”: value => value.matches(.*),
“price”: value => {5.0 > value > 4,4},
“priceunit”: value => value.matches(.*),
// “basefactor”:100,
// “net_amount”:35.98,
// “tax_rate”:16,
// “tax_amount”:null,
// “gross_amount”:null,
// “total”:35.98,
// “currency”:“EUR”,
// “toSubstitute”:false,
// “variant”:“1”
}
Die Prüfung auf Entsprechung erfolgt durch die JSON mit den
Matching-Regeln. Diese wird durchlaufen und dabei für jeden Key der
entsprechende Wert in der JSON der Rechnungszeile validiert. Wenn alle
Validierung mit `UND` verknüpft `true` ergeben, gilt der Match als
erfolgreich.
## Eingliederung der Matching-Regeln
In der GUI sollten die Matching-Regeln zunächst direkt hinter den
Artikelnummern angeordnet werden. Dies dürfte der geringste
Anpassungsaufwnad sein.
------------------------------------------------------ ------------------------------------------------------
 
schematisches Datenmodell Anzeige/Bearbeitung in der GUI
------------------------------------------------------ ------------------------------------------------------
Um eine bessere Übersicht über alle Artikel eines Nummernkreises zu
schaffen, sollte hierfür ein **neues Level-1** eingeführt werden, in dem
die Nummernkreise separat aufgeführt werden.\
Unterhalb des Nummernkreises sollten dann die Artikelnummern und
dahinter die angelegten Matching-Regeln angezeigt werden.\
Zusätzlich zur Anzeige der Artikelnummern sollte auch unbedingt eine
Anzeige der angelegten Macthing-Regeln eingeführt werden. Dies scheint
dringend geboten, damit eine bessere Übersicht über alle Regeln gegeben
ist.
**[WICHTIG:]{style="color:green;"}** An den Matching-Regeln muss immer
der Lieferant/Kreditor gefiltert werden können, damit man sich leicht
einen Überblick zu den spezifischen Regeln eines Lieferanten/Kreditor
verschaffen kann.
--------------------------------------------------------------------------------

schematischer Entwurf einer UI für die Artikelnummernkreise und Macthig-Regeln
--------------------------------------------------------------------------------
## Implementierung
### Prototypische Umsetzung
#### Funktionen zur Beschreibung der Validierungsregeln
Nach Diskussion der Lösungsansätze wurde Variante 2 als elegante, wenn
auch nicht ganz triviale Lösung ausgewählt.\
Diese Lösung ist zunächst für die "Energieversorgung Leverkusen"
prototypisch umgesetzt.\
Die Umsetzung erfolgte im Rahmen des Exports, da hier ein einfacher
Eingriff ohne eine Änderung des Java-Codes und ein Update möglich ist.
Die Grundidee der Umsetzung besteht darin, dass eine Struktur aus
Validierungsregeln aufgebaut wird. Die Regelstruktur wird dann auf eine
Rechnungszeile angewendet.\
Die Ansätze hierzu sind weiter oben beschrieben.
In der Datei `LineArticleMatcher.scr` sind dazu folgende Funktionen
implementiert:
------------------------------------
einfache Funktionen zum Validieren
------------------------------------
Zur logischen Verknüpfung von Ergebnissen ist noch ein logischen `UND`
sowie `ODER` implementiert:
--------------------------------------
Funktionen zur logischen Verknüpfung
--------------------------------------
#### Artikelnummerndatensatz mit Validierungsregeln
Grundansatz ist, dass für jede Artikelnummer Validierungsregeln angelegt
werden, welche dann insgesamt auf eine Rechnungszeile angewendet
werden.\
Ergebnis ist dann eine Liste der möglichen Treffer, also Artikelnummern,
deren Validierungsregeln für die jeweilige Rechnungzeile ein positives
Ergebnis geliefert haben (`type == "SUCCESS"`).\
Da grundsätzlich mehrer Treffer möglich sind, wird zusätzlich noch eine
Wertigkeit der Regeln angegeben.\
Regeln, die einen geringen Einschränkingsgrad haben, werden mit einer
niedrigen `selectivity` bewertet.
Ein einfaches Beispiel ist eine Regeln, welche ausschließlich nach dem
regulären Ausdruck '.**Leistung.**' sucht. Diese Regel nicht sonderlich
spezifisch, kann jedoch für einzelne Rechnungssteller erforderlich
sein.\
Eine deutlich selektivere Regel wie z.B. '.\*abschaltbare.**Leistung.**'
muss eine höhere Wertigkeit erhalten, da hier zweifelsfrei klar ist, um
welche Art Rechnungszeile es sich handelt.\
Sicher wäre es auch möglich die Zeilen "Leistung" und "abschaltbare
Leistung" durch eine Regel in dem regulären Ausdruck für die
tatsächliche Leistung zu trenne. Dies würde jedoch bedeuten, dass eine
alternative Zeichenkette wie 'abschaltbare' für die Leistung
ausgeschlossen werden muss. Da dies nicht für alle möglichen
Konfigurationen möglich sein wird, wurde hier eine Wertigkeit der
Artikelregeln gewählt.\
So können allgemeine Artikelnummern-Regeln definiert werden und davon
abweichende Regeln für jeden einzelnen Lieferanten ergänzt werden.
Insgesamt soll somit der Anzahl der benötigten Regel möglichst gering
gehalten werden.
Für einen prototypischen Testlauf wurden Artikelnummernregeln als Array
auf Script-Ebene angelegt. Diese Regeln sollen dannzukünftig in der DB
an den jeweiligen Artikeln hinterlegt werden.
Als Ersatz für die bisher verwendeten Texte zur Zuordnung von
Produkttypen wird jetzt im Attribut `typeKey` ein Schlüssel angegenen,
der unabhängig von der konkreten Benennung eines Produkttypen eine
sichere Zuordnung ermöglicht.