Rechnungsstellung mit QR-Codes

In einem meiner letzten Artikel zum Thema Rechnungsstellung habe ich erwähnt, dass manche Kundenüberweisungen aufgrund von Zahlendrehern in Rechnungsnummern nicht automatisiert zuordenbar waren. Dazu habe ich mir eine Alternative überlegt, wie ich die Zuordnungsquote erhöhen kann.

QR-Code auf der Rechnung – Warum?

Eines Tages las ich einen Artikel über QR-Codes, die vor allem im Paymentbereich in der Schweiz sehr verbreitet sind und eine Menge Vorteile bieten. Da kam mir die Idee, die QR-Code-Technologie für die Weiterentwicklung meines eigenes Rechnungsprogramm einzusetzen und so die Rechnungen automatisch mit QR-Codes auszustatten. Beim Einscannen des Codes aus einer BankingApp heraus werden alle Daten ins Überweisungsformular automatisch übernommen, sodass dieses nur noch zu kontrollieren und freizugeben ist. Davon würden beide Seiten profitieren – meine Kunden könnten sich das Abtippen oder Kopieren von Überweisungsdaten sparen und ich hätte dann keine Zuordnungsprobleme bei Überweisungen.

Auch hier stand ich dann vor der Überlegung, ob ich eine der verfügbaren freien Bibliotheken, bzw. WebAPIs für die Erzeugung von QR-Codes nutzen möchte. Man sagt ja, es gibt keinen Grund, das Rad nochmal zu erfinden:-). Und normallerweise stimme ich dem auch zu, es sei denn, man betrachtet das ganze aus einer anderen Perspektive – kurz gesagt, getrieben vom Forschungsdrang entschied ich mich dafür, einen QR-Code Generator selbst zu programmieren.

Informationsbeschaffung

Bei der Recherche zum Thema QR-Codes wurde mir schnell klar, dass viele Webseiten es relativ oberflächlich behandeln und nur einen groben Überblick über die Struktur, Aufbau und Funktionsweise geben, ohne jedoch stark in die Tiefe zu gehen. Es war also absehbar, dass ich für die komplexeren Teilgebiete, wie zum Beispiel Fehlerkorrektur oder Maskierung von QR-Codes ganz andere Informationstiefe benötige. Dazu bin ich erst im englischsprachigen Raum fündig geworden (QR-Code-Tutorial).

Auswahl der Technologie – VBA oder C#

Obwohl ich meinen QR-Code Generator eigentlich nur für den Einsatz in der ACCESS-Rechnungsdatenbank (also in der VBA-Welt) vorgesehen habe, entschied ich mich, diesen nicht als ein VBA-Modul oder Add-In, sondern als eine Klassenbibliothek mit C# unter Visual Studio zu entwickeln. Eine allgemeine Klassenbibliothek hätte den Charme, dass sich diese auch in eine Konsolen- oder auch in eine GUI-Anwendung integrieren ließe. Auch die geplante Verwendung aus der VBA-Welt heraus wäre durch die COM-Technologie ebenfalls abgedeckt.

Programmierung

Grundstruktur

Am Anfang des Projektes habe ich relativ schnell die ersten Erfolge erzielt und die statische Grundstruktur aufgebaut. So war die erste Version des QR Code Generators in der Lage, anhand des übergebenen Textes und des gewählten Korrekturlevels die benötigte Matrixgröße zu errechnen und die ganzen Pattern

  • Finderpattern
  • Alignmentpattern
  • Timingpattern

in der Matrix abzubilden und in Bildform zu visualisieren. Mathematisch und programmiertechnisch war dies relativ einfach zu bewerkstelligen.

Die QRCode-Spezifikation gibt viele Parameter vor, die je nach gewähltem Fehlerkorrekturlevel und QRCode-Größe mit unterschiedlichen Ausprägungen zu verwenden sind. Für die Verwaltung dieser Parameter habe ich mich für XML entschieden, obwohl man die wahrscheinlich genauso gut direkt im Quellcode mit Strukturen hätte abbilden können. Denn genau genommen handelt es sich nicht wirklich um dynamische Parameter, sondern eher um Konstanten, die sich vermutlich nie ändern werden. Das ist aber auch das Tolle an der Programmierung – es gibt einfach unterschiedliche Möglichkeiten ans Ziel zu kommen.

Um ein Gefühl für die Vielfalt der Parameterausprägungen zu bekommen, zeige ich hier einen kleinen Auszug aus dieser Konfigurationsdatei. Darin sieht man allgemeine Parameter für QR-Codes in der Version 11 und spezielle Parameter für den Fehlerkorrekturlevel L in der Version 11. Insgesamt sieht die Spezifikation insgesamt 40 Versionen und 4 Fehlerkorrekturlevel vor – am Ende bin ich da bei stolzen 3.500 Zeilen allein an Parameterdaten hinausgelaufen. Für den Zugriff auf diese Parameterdatei habe ich eine separate Klasse implementiert, die auf einem Singleton-Entwurfsmuster basiert – so wird die Konfigurationsdatei physisch tatsächlich nur einmalig von der Festplatte gelesen. Das macht vor allem dann Sinn, wenn der Generator für eine Batchverarbeitung eingesetzt wird, wo mehrere Tausend QR-Codes zu erzeugen sind. Diese Klasse stellt dann über fachliche Methoden den lesenden Zugriff auf die einzelnen Parameter bereit.

XMLD-Datei mit Parametern für die Erstellung von QR-Codes
XML-Datei mit QR-Code-Parametern

Fehlerkorrektrurcodes

Das nächste Teilgebiet des Projektes forderte mich so richtig heraus. Es ging dabei um die Erzeugung von Fehlerkorrekturcodes. QR-Codes können nämlich auch dann eingescannt und dekodiert werden, wenn ein gewisser Teil des Codes nicht lesbar ist. Beim höchsten Fehlerkorrkturlevel reichen gar 70% des QR-Codes aus, ohne dass es dabei zu Dekodierproblemen kommt. Diese Fehlerkorrekturen werden, aus meiner Sicht als Nichtmathematiker, nach einem sehr komplizierten Verfahren namens Reed-Solomon (benannt nach zwei Überfliegern vom Massachusetts Institute of Technology) generiert.

Ohne die ausführlichen und für die Nichtdoktoren der Mathematik aufbereiteten Informationen aus dem Tutorial, hätte ich die Generierung der Fehlerkorrekturcodes nicht umsetzen können. Allerdings auch den vereinfacht dargestellten Ablauf in den Code zu gießen, war nicht ohne – wie oft hat man schon als Anwendungsentwickler eine Methode für die Polynomdivision zweier Gleichungen 78en Grades zu programmieren 🙂

Maskierung

Das letzte Teilgebiet mit der Darstellung der kodierten Daten in der Matrix und deren Maskierung für ein besseres maschinelles Einscannen war verglichen mit dem vorherigen Teil schon fast zu einfach. Das hat mich auch richtig motiviert, dass ich den komplizierten Teil schon hinter mir habe und kurz vor der Fertigstellung stehe. Tja, und dann kam das Testen:-)

Testen

Einem QR-Code sieht man mit unbewaffnetem Auge in der Regel nicht an, ob es richtig aufgebaut ist. Für den Schnelltest nutzte ich dabei mein Handy – beim Einscannen hatte ich dann direkt die Rückmeldung, ob der QR-Code richtig war oder zumindest eingescannt werden konnte. Wenn jedoch der erzeugte QR-Code nicht lesbar war, dann ging die Suche nach dem Fehler erst richtig los.

Einen guten Dienst hat mir dabei diese Webseite https://www.nayuki.io/page/creating-a-qr-code-step-by-step geleistet. Im Gegensatz zu anderen webbasierten QR-Code Generatoren, erlaubt der Betreiber hier einen Blick in den „Maschinenraum“. So ist es zum Beispiel möglich, sich die generierten Korrekturwörter oder die Penaltyscores der einzelnen Masken anzeigen zu lassen. Durch den Vergleich mit dem Output meiner Klasse konnte ich den Fehler zumindest ganz grob lokalisieren. Der Löwenanteil aller Fehler lag in der Klasse für die Erzeugung der Fehlerkorrekturcodes – mit Sicherheit habe ich für die Fehlersuche und deren Behebung fast genauso lang gebraucht wie für die Entwicklung . Aufgrund deren Komplexität auch nicht weiter verwunderlich – aus sprachlicher Sicht dennoch amüsant:-). Alle anderen Klassen waren da deutlich robuster und wiesen kaum Fehler auf.

Projektergebnis

Herausgekommen ist aus diesem Projekt, wie erwähnt, ein Generator in Form einer dll-Datei und einer Parameter-XML-Datei mit QR-Code-Spezifikationen. Um eine bessere Vorstellung über die Struktur des QR Code Generators zu bekommen, zeige ich hier die entwickelten Klassen mit deren öffentlichen Signaturen als Klassendiagramm. Darüber hinaus gibt es noch einige Structs und Enums, die aber eine untergeordnete Rolle spielen und für das Verständnis der Funktionsweise nicht relevant sind.

Klassendiagramm der Bibliothek QR-Code-Generator
Klassendiagramm der Bibliothek QR-Code Generator

Alle Klassen bis auf QRCodeGenerator haben die Sichtbarkeit internal und treten somit nicht in Erscheinung. Die Klasse QRCodeGenerator ist public und fungiert somit als die Schnittstelle nach außen und erlaubt Erstellung von Objekten, denen man den zu verschlüsselnden Text sowie den gewünschten Fehlerkorrekturlevel übergibt. Anschließend kann mit einer der beiden SaveAs-Methoden der QR-Code auf die Festplatte gespeichert werden. Die Nutzung dieser Klasse in anderen Anwendungen (beispielsweise in einer GUI- oder einer Konsolenanwendung) ist wirklich sehr einfach, weil nahezu alle Parameter entweder von der Klasse selbst errechnet oder in der Parameterdatei „nachgeschlagen“ werden.

QRCodeGenerator generator = new QRCodeGenerator(text, correctionLevel);
generator.SaveAsSVG(qrFilePath);

Das geht natürlich etwas auf die Kosten der Flexibilität, sodass man beispielsweise keinen Einfluss auf die QR-Code-Größe hat – die Einfachheit in der Nutzung war mir persönlich aber am wichtigsten. Zumal im Fall der Fälle sich der Generator ohne Probleme erweitern lässt, um gewisse Parameter manuell vorgeben zu können.

Anbindung des QR-Code Generators an die Rechnungsstellung

Um den QR-Code Generator auch unter ACCESS nutzen zu können, war es erforderlich, ihn von einer Wrapperklasse aufzurufen zu lassen, welche die COM-Schnittstelle implementiert. Diese enthält tatsächlich keinerlei Verarbeitungslogik, sondern macht den Generator „lediglich“ für die VBA-Welt aufrufbar. Dafür ist eine einmalige Registrierung auf dem Zielrechner erforderlich.

Nun war auf der technischen Seite alles fertig, um den ersten QR-Code für eine Überweisung erstellen zu können. Ein kurzer Ausflug zum Wikipedia-Artikel European Payment Council (EPC) verriet mir, welchen Aufbau der EPC-Text haben muss, damit alle darin hinterlegten Überweisungsinformationen von BankingApps korrekt eingelesen werden können. Der Artikel ist sehr übersichtlich und klar geschrieben, sodass ich den nicht zusammenzufassen brauche. Das einzige, was ich extra erwähnen würde, ist, dass im Betrag der dezimale Punkt(nicht Komma!) als Trennzeichen zu verwenden ist. Dies hab ich nämlich beim ersten Lesen übersehen.

Der so aufbereitete EPC-Text (im Listing ist es die Variable strQrCodeMessage) wird bei der Erstellung der Rechnung an den Konstruktor zusammen mit dem Fehlerkorrekturlevel übergeben. Ist die Verarbeitung ohne Fehler durchgelaufen, kann der generierte QR-Code nun tatsächlich ausgebeben werden.

In meinen ersten QR-Library-Versionen wurden erzeugte QR-Codes physisch auf der Festplatte unter einem festen Namen gespeichert und anschließend direkt vom Access-Rechnungsbericht eingebunden und dargestellt. Doch damit war ich nicht ganz zufrieden. Es war keine Lösung wie aus einem Guss, sondern ein Umweg, bei dem ich mich mit unschönen Nebeneffekten wie verzögertes Speichern befassen musste. Dabei war die Codezeile für die QR-Codeerzeugung schon abgearbeitet, der PC war unter Umständen jedoch noch mit dem physischen Speichervorgang des QR-Codes beschäftigt, sodass die nächste Codezeile beim Einbinden des QR-Codes ins Leere lief.

Zum Glück hat sich bei meiner Recherche herausgestellt, dass Access nicht nur die Möglichkeit bietet, Bilder von der Festplatte einzubinden, sondern kann auch Bilder in Form eines ByteArrays darstellen.
Das war genau das, was ich gesucht habe. Aus diesem Grund habe ich neben SVG- und JPEG-Exportmethode auch eine weitere Methode realisiert, die das vorbereitete QR-Code-Bildobjekt in einen Bytestrom umwandelt und diesen ausgibt. So konnte ich den Output, den diese Methode liefert, direkt dem Bildcontainer (seinem Attribut pictureData) im Rechnungsbericht zuweisen.

    On Error Resume Next
    
    Set objQrGenerator = CreateObject("QRCodeGeneratorVBALibrary")
    If Err.Number = 0 Then
        Call objQrGenerator.CreateQRCodeGenerator(strQrCodeMessage, "M")
        If Err.Number = 0 Then
            bytQrCodeArray = objQrGenerator.getQRBytes()
        End If
    End If
    
    Err.Clear
    On Error GoTo 0

Diese Zuweisung bewirkt, dass auf der Rechnung der QR-Code (in diesem Zusammenhang oft als EPC QR-Code oder als GiroCode bezeichnet) dargestellt wird, ohne dass dieser zuvor als Bild abgespeichert werden muss. Der komplette Prozess läuft ausschließlich auf dem lokalen Rechner ab und benötigt keine Internetverbindung.

4 thoughts on “Rechnungsstellung mit QR-Codes

  1. Hallo Anton,
    Kompliment an den Autor Deiner Webseite und danke fürs teilen 🙂

    Ich bin auf diesen Content gestoßen, da Ich mich mit der Offlinerzeugung von QR-Codes via VBA beschäftigen möchte.

    Den Quellcode der QRCodegeneratorBatch.exe habe Ich nicht finden können, daher meine Frage, wie viel Zeit hat dieses Projekt in Anspruch genommen?

    1. Hallo Marco, vielen Dank für die Anerkennung, ich leite sie gerne an Tony aka Anton weiter 🙂
      Das Batchprogramm habe ich an 1-2 Abenden entwickelt – dort befindet sich allerdings auch keinerlei Geschäfts/Verarbeitungslogik. Es nimmt lediglich übergebene Parameter (eine Zeichenkette für einen einzelnen QR-Code oder CSV-Dateipfad für eine Sammelerzeugung) entgegen, prüft sie und leitet sie an den QR-CodeGenerator weiter und gibt sein Output in Form von QR-Bildern aus. Die Hauptarbeit war definitiv der QR-CodeGenerator – wenn man alles berücksichtigt, also Recherche der QR-Spezifikationen, Implementierung und das Testen, dann war ich mit Sicherheit 1,5-2 Monate damit beschäftigt. Natürlich nicht am Stück von morgens bis Abends, aber dennoch nahezu jeden Abend.
      Wenn du bei deinem Vorhaben Fragen hast, kannst dich gerne melden, können in einer Zoom-Session die Thematik besprechen.

      Viele Grüße
      Anton

  2. Hallo ,
    ich bin auf der Suche nach genau der oben beschriebenen Methode auf meine Rechnungen einen EPC-QR CODE zu drucken. Ich muss aber gestehen, dass ich bei weitem nicht so mit Access bewandert bin wie der Autor, deshalb stelle ich hier einfach mal die Frage ob es möglich ist diese Methode als Beispieldatenbank zu kaufen?
    Vielen Dank!

    1. Hallo Herr Reinhold, sehr gerne, lassen Sie uns hierzu telefonieren und prüfen, wie sich die QR-Generator-Bibliothek in Ihre Datenbank integrieren lässt.
      Viele Grüße
      Anton Ristau

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert