Klasse für DHL-Intraship-CSV-Dateien

Die CSV-Dateien, die für die Einreichung bei DHL für die Erstellung von Versandetiketten gefordert werden, sind erstens sehr umfangreich und zweitens auch noch komplex. Diese einfach per Code zusammenzusetzen mag auf den ersten Blick schnell gehen, aber was geschieht, wenn später einmal änderungen nötig sind Um die Programmierung des Exports einer CSV-Datei für DHL-Intraship zu vereinfachen, erstellen wir in diesem Beitrag einige Klassen, mit denen das Zusammenstellen der CSV-Dateien zum Kinderspiel wird.

Im Beitrag Versandetiketten mit DHL-IntraShip (www.access-im-unternehmen.de/991) zeigen wir, wie Sie eine CSV-Datei mit den Versandinformationen an die Webseite von DHL/IntraShip übergeben und damit entsprechende Versandetiketten erhalten. Dabei setzen Sie dort einen Satz von Klassen ein, welcher die einfache Erstellung der CSV-Datei ermöglicht. Den Aufbau und die Erstellung dieser Klassen möchten wir im vorliegenden Beitrag erläutern.

Ausgangsmaterial: PDF-Dokument mit CSV-Beschreibung

Grundlage für die Erstellung der Klasse ist ein PDF-Dokument, das die verschiedenen Sätze beschreibt, die Sie benötigen, um die Informationen zu einer Versendung unterzubringen. Dieses Dokument namens Auftragsimport DD-Shipments 6.1 DE.PDF, das Sie als Geschäftskunde anfordern können (wir können es leider nicht zum Download anbieten), ist immerhin 27 Seiten lang. Wir haben davon die für eine Sendung von Deutschland aus an ein Ziel innerhalb Deutschlands oder in ein anderes EU-Land nötigen Elemente in Form entsprechender Klassen umgesetzt. Es gibt noch einige weitere Elemente, die beispielsweise zur Erstellung einer ProForma-Rechnung oder der Zollpapiere für den Versand etwa in die Schweiz benötigt werden. Deren Umsetzung beschreibt der vorliegende Beitrag nicht.

Das PDF-Dokument enthält die Beschreibung verschiedener Satzarten, von denen einige verpflichtend sind, ein paar andere können optional hinzugefügt werden. Für einen Auftrag benötigen Sie auf jeden Fall eine Zeile der Satzart Sendung, die etwa so aussieht – jede Information ist durch das Pipe-Zeichen von der nächsten Information getrennt:

1234|DPEE-SHIPMENT|EPN|20150629|1.3||||AEMA|||||||||||||||||100|EUR||||||

|01|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

Sie enthält die grundlegenden Informationen zu der Sendung wie die Sendungsart, das Datum, das Gewicht, den Warenwert oder eine Sendungsreferenz. Außerdem enthält sie als Erstes eine Zahl, die für alle weiteren Sätze für diese Sendung gleich sein muss. Dementsprechend beginnt die zweite Satzart namens Absender auch mit dieser Zahl, enthält aber die Absenderinformationen:

1234|DPEE-SENDER|6275498028|André Minhorst Verlag||André Minhorst|Borkhofer Str.|17||47137|Duisburg|DE||andre@minhorst.com|0123/4567890|||||||||||||||||||||

Das Element der Satzart Empfänger enthält logischerweise die Adresse und weitere Informationen zum Empfänger der Sendung:

1234|DPEE-RECEIVER|André Minhorst Verlag||||Herr Klaus Müller|Borkhofer Str.|17||47137|Duisburg|DE||klaus@mueller.de||||||||||||||||||

Danach folgt eine Zeile, welche die Daten für die Satzart Packstück aufnimmt (diese Zeile kann, wenn es sich um mehrere Packstücke handelt, auch mehrfach vorkommen). Sie sieht so aus:

1234|DPEE-ITEM|1.3|||||PK||

Die letzte von uns in diesem Beitrag behandelte Zeile enthält die E-Mail-Adresse des Empfängers der Versandbenachrichtigung (Satzart Benachrichtigungen).

Auch hier können Sie mehrere Sätze der gleichen Art angeben, beispielsweise um sich selbst und dem Empfänger eine Benachrichtigung zu schicken, die etwa die Nummer für die Sendungsverfolgung enthält. Sie ist beispielsweise wie folgt aufgebaut:

1234|DPEE-NOTIFICATION||andre@minhorst.com|||

Warum Klassen

Man könnte beispielsweise das erste Element mit den grundlegenden Informationen zur Sendung wie folgt in die CSV-Datei schreiben:

Print #1, lngKundeID & "|DPEE-SHIPMENT|" & strPaketart & "|" & Format(Date, "yyyymmdd") _
    & "|" & Replace(curGewicht, ",", ".") & "||||" & strKuerzel & "|||||||||||||||||" _
    & Replace(curWert, ",", ".") _
    & "|EUR|||||||01|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||"

Sobald Sie aber mal einen Parameter in der CSV-Datei benötigen, den Sie hier nicht berücksichtigt haben und der irgendwo zwischen dem 80. und 81. Pipe-Zeichen eingefügt werden muss, dürfen Sie erstmal die Dokumentation suchen, die Zeile anpassen et cetera.

Der Ansatz in der beschriebenen Codezeile ist Teil meines ersten Versuchs, die Erstellung der CSV-Datei zu automatisieren, und funktioniert natürlich gut – zumindest, bis man dann etwas an der Programmierung ändern oder, noch schlimmer, den Code anderen Entwicklern zugänglich machen möchte – also beispielsweise den Lesern dieses Beitrags.

Gerade in letzterem Fall werden doch die unterschiedlichsten Anforderungen zusammentreffen, die sich unmöglich mit einer einzigen Zeile Code je Element der CSV-Datei erledigen lassen. So ist dann nach einigem Hin und Her die Idee entstanden, ein System von Klassenmodulen aufzusetzen, von denen eines die Hauptschnittstelle zum Erstellen der CSV-Datei bildet und weitere Klassen jeweils eine Zeile der CSV-Datei repräsentieren.

CSV erstellen mit Klassen

Schauen wir uns zunächst an, wie Sie mit den nachfolgend erläuterten Klassen die CSV-Datei zusammenstellen können. Dies sieht in einem Beispiel für eine einzelne Sendung wie in Listing 1 aus. Keine Sorge: Der Code wird nicht wesentlich länger, wenn Sie beispielsweise die CSV-Datei für ein paar hundert Sendungen erstellen wollen – Sie müssen dann nur hier und da ein paar Schleifen hinzufügen und ein paar feste Zuweisungen durch Verweise auf die jeweiligen Feldinhalt ersetzen.

Public Sub BeispielDHL()
     Dim objDPEEMain As clsDPEEMain
     Set objDPEEMain = New clsDPEEMain
     With objDPEEMain
         .Ordnungsnummer = 1234
         With .DPEEShipment
             .Produktcode = eDHLPaket
             .Sendungsdatum = Date
             .Gewicht = 1.3
             .Sendungsreferenz = "AEMA"
             .Warenwert = 100
             .WarenwertWaehrung = "EUR"
             .Teilnahme = "01"
         End With
         With .DPEESender
             .Kundennummer = "6275498028"
             .Firmenname1 = "André Minhorst Verlag"
             .Kontaktperson = "André Minhorst"
             .Strasse = "Borkhofer Str."
             .Hausnummer = "17"
             .PLZ = "47137"
             .Stadt = "Duisburg"
             .Laendercode = LaendercodeAusLand("Deutschland")
             .Emailadresse = "andre@minhorst.com"
             .Telefonnummer = "0123/4567890"
         End With
         With .DPEEReceiver
             .Firmenname = "André Minhorst Verlag"
             .Firmenname2 = ""
             .Kontaktperson = "Herr Klaus Müller"
             .Strasse = "Borkhofer Str."
             .Hausnummer = "17"
             .PLZ = "47137"
             .Stadt = "Duisburg"
             .Land = LaendercodeAusLand("Deutschland")
             .Emailadresse = "klaus@mueller.de"
         End With
         With .AddDPEEItem
             .GewichtDesPackstueckesInKg = 1.3
             .PackartKollitraeger = ePaket
         End With
         With .AddDPEENotification
                .Emailadresse = "andre@minhorst.com"
         End With
         With .AddDPEENotification
             .Emailadresse = "test@test.de"
         End With
         Open CurrentProject.Path & "\dhltest.csv" For Output As #1
         Print #1, .Satz
         Close #1
     End With
End Sub

Listing 1: Erstellen einer CSV-Datei für den Versand

Die Prozedur deklariert ein Objekt auf Basis der Klasse clsDPEEMain. Dieses erstellt sie gleich in der darauffolgenden Zeile mit der New-Anweisung. Da wir nachfolgend einige Eigenschaften dieser Klasse einstellen möchten, verwenden wir nun die With-Anweisung, damit wir den Objektbezeichner objDPEEMain nicht in jeder Zeile wiederholen müssen.

Als Erstes legen wir die Ordnungsnummer fest. Dies ist die Nummer, die wir in jedem Satz als erstes Element angeben müssen, damit wir die einzelnen Sätze als zu einer Versendung gehörend markieren können. Gleichzeitig ist das auch die einzige Information, die wir direkt an diese Klasse übergeben.

über diese Klasse greifen wir jedoch über Eigenschaften wie DPEEShipment (Satzart Sendung), DPEESender (Satzart Absender), DPEEReceiver (Satzart Empfaenger), DPEEItem (Satzart Packstück) und DPEENotification (Satzart Benachrichtigungen) auf die Objekte für die einzelnen Sätze beziehungsweise Zeilen in der CSV-Datei zu.

über DPEEShipment stellen Sie so etwa den Produktcode, das Sendungsdatum oder das Gesamtgewicht ein.

DPEESender stellt Eigenschaften bereit, mit denen Sie die Kundennummer und die Adresse des Absenders festlegen.

Dementsprechend dient das Objekt DPEEReceiver dazu, die Adresse des Empfängers zu übergeben.

Auf die Objekte DPEEItem und DPEENotification greifen Sie nicht wie auf die anderen Elemente zu. Der Grund ist, dass Sie beide mehrfach anlegen können. Daher legen Sie diese jeweils mit der entsprechenden Add…-Methode an, also etwa AddDPEEItem oder AddDPEENotification. Da die beiden Methoden aber auch jeweils ein Element des Typs clsDPEEItem beziehungsweise clsDPEENotification zurückliefern, können Sie auf die Add…-Methode jeweils mit der With-Anweisung verweisen und darüber die einzelnen Eigenschaften festlegen – bei der Satzart Packstück also etwa das Gewicht und die Packart (Paket oder Palette).

Bei der Benachrichtigung verwenden Sie die Methode AddDPEENotification, für die Sie nur die jeweilige E-Mail-Adresse des Empfängers angeben müssen. Im Beispiel legen wir gleich zwei E-Mail-Adressen für die Versandbestätigung an – eine für den Sender und eine für den Empfänger.

Schließlich erstellt die Prozedur eine neue Textdatei mit der Endung .csv und schreibt den Wert der Eigenschaft Satz des Objekts objDPEEMain hinein. Diese Eigenschaft liefert den Inhalt der CSV-Datei, den die Klasse auf Basis der übergebenen Werte zusammengestellt hat. Für unser Beispiel sieht diese Datei nun genau wie in Listing 2 aus.

1234|DPEE-SHIPMENT|EPN|20150629|1.3||||AEMA|||||||||||||||||100|EUR||||||
|01|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
1234|DPEE-SENDER|6275498028|André Minhorst Verlag||André Minhorst
|Borkhofer Str.|17||47137|Duisburg|DE|
|andre@minhorst.com|0123/4567890|||||||||||||||||||||
1234|DPEE-RECEIVER|André Minhorst Verlag||||Herr Klaus Müller
|Borkhofer Str.|17||47137|Duisburg|DE|| klaus@mueller.de||||||||||||||||||
1234|DPEE-ITEM|1.3|||||PK||
1234|DPEE-NOTIFICATION||andre@minhorst.com|||
1234|DPEE-NOTIFICATION||test@test.de|||

Listing 2: Frisch erstellte CSV-Datei mit Sendungsdaten

Das Tolle bei der Verwendung dieser Klassen ist, dass Sie nicht erst die Dokumentation nach den Namen der einzelnen Eigenschaften einer Zeile der CSV-Datei suchen oder die Position innerhalb der Zeile ermitteln müssen, sondern einfach einen Punkt hinter dem Objektbezeichner einfügen und dann alle möglichen Eigenschaften per IntelliSense präsentiert bekommen (s. Bild 1).

IntelliSense beim Programmieren der Erstellung der CSV-Datei

Bild 1: IntelliSense beim Programmieren der Erstellung der CSV-Datei

Versierte Access-Entwickler haben nach der Durchsicht dieses Beispielcodes schon eine Vorstellung, wie sie auf dieser Basis den Code erstellen, um die benötigten Informationen aus einigen Tabellen zusammenzusuchen und so in die CSV-Datei zu schreiben.

Klassen programmieren

Nun fehlt noch die Antwort auf die Frage: Wie kommt man von der Definition des Aufbaus der verschiedenen Satzarten aus einem 27 Seiten langen PDF-Dokument, das beispielsweise wie in Bild 2 aussieht, zu einer Reihe von Klassenmodulen, welche die Eingabe dann wie hier beschrieben erleichtern Dazu gehört in der Tat entweder eine Menge Handarbeit oder, was wir Access-Entwickler eindeutig bevorzugen, ein paar Zeilen VBA-Code, die uns einen Großteil der Arbeit abnehmen.

Umzusetzende Beschreibung aus dem PDF

Bild 2: Umzusetzende Beschreibung aus dem PDF

Wir haben es im Detail mit fünf Tabellen zu tun, die von weniger als zehn bis zu knapp 100 Zeilen enthalten.

Jede Tabelle beschreibt eine Satzart, also benötigen wir für jede Tabelle eine eigene Klasse. Jede Zeile der Tabelle beschreibt eine Eigenschaft, also benötigen wir für jede Zeile eine private Variable in der Klasse, um den zugewiesenen Wert speichern zu können, sowie eine Property Let-Prozedur, um diese Eigenschaften von außerhalb der Klasse füllen zu können.

Schließlich soll jede Klasse noch eine Eigenschaft namens Satz bereitstellen, die nach dem Zuweisen der Eigenschaften alle Eigenschaften auswertet und die Zeile der CSV-Datei für diese Satzart zusammenstellt und zurückgibt. Das wären für die fünf hier behandelten Sätze insgesamt 289 Zeilen, für die entsprechenden Eigenschaften, Property Let-Prozeduren und Einträge in die Satz-Eigenschaft vorgenommen werden müssten. Nein: Von Hand wollen wir das nicht erledigen.

Dummerweise können wir die Inhalte der Tabellen noch nicht einmal direkt in eine Excel- oder Access-Tabelle einfügen – zwar landet jede Zeile in einer eigenen Zeile der Zieltabelle, aber die Spalten werden alle in das erste Feld geschrieben. Also sind wir so vorgegangen: Wir haben die Tabellen zunächst in eine Text-Datei geschrieben, Tab-Zeichen zwischen die erste und zweite Spalte gebracht, in die dritte Spalte den Datentyp unter VBA eingetragen und die maximale Zeichenanzahl in die vierte Spalte geschrieben – alles jeweils durch Tabulatorzeichen voneinander getrennt. Das Zwischenergebnis sah dann wie in Bild 3 aus. Die Anzahl der manuellen Eingriffe hält sich hier noch in Grenzen.

Felder im Textformat

Bild 3: Felder im Textformat

Danach haben wir den kompletten Inhalt in die Zwischen-ablage kopiert und dann in eine neue Tabelle namens tblFelderDPEEItem kopiert, die wir zuvor mit den vier benötigten Feldern ausgestattet haben. Der neue Zwischenstand ist in Bild 4 abgebildet.

Felder in der Zieltabelle

Ende des frei verfügbaren Teil. Wenn Du mehr lesen möchtest, hole Dir ...

den kompletten Artikel im PDF-Format mit Beispieldatenbank

diesen und alle anderen Artikel mit dem Jahresabo

Schreibe einen Kommentar