DHL-Versandetiketten erstellen per VBA

Lies in den Artikel rein und unten bekommst Du ein unschlagbares Angebot!

Wer Kunden und Bestellungen mit einer Access-Datenbank verwaltet oder gegebenenfalls auch mit einer Excel-Tabelle, möchte vielleicht Zeit sparen und die Etiketten für den Versand von Lieferungen an seine Kunden automatisieren. Das gelingt mit den verschiedenen Webservices von DHL. Wir haben bereits einmal eine solche Lösung vorgestellt, aber DHL hat seine Schnittstellen für die Erstellung von Versandetiketten aktualisiert. In diesem Artikel schauen wir uns an, wie die neuen Schnittstellen funktionieren: Welche Daten benötige ich? Welche URL muss für den Zugriff verwendet werden? In welcher Form übergebe ich beispielsweise die Adressdaten an den Webservice?

Voraussetzung für die Verwendung der Lösung

Wenn wir die Webservices von DHL für die Erstellung von Versandetiketten nutzen wollen, sind einige Voraussetzungen zu erfüllen. Als Erstes benötigen wir ein Konto als Geschäftskunde bei DHL. Wie Du dieses anlegst, wollen wir hier nicht im Detail beschreiben. Wir wollen Dir aber zumindest den Link zum Geschäftskundenportal mit auf den Weg geben:

https://www.dhl.de/de/geschaeftskunden.html

Nach der Anmeldung benötigen wir später Deine Zugangsdaten für Dein Kundenkonto, also Benutzername und Kennwort.

Als Zweites benötigst Du ein Entwicklerkonto bei DHL. Dazu besuchst Du die folgende Adresse und erstellst einen Account:

https://developer.dhl.com/

Damit können wir bereits starten.

App erstellen

Nachdem wir einen Entwickler-Account erstellt haben, benötigen wir eine App. Wozu brauchen wir diese? Weil eine App uns einen API Key und ein API Secret liefert, mit dem wir auf die API-Schnittstelle zugreifen können. Also klicken wir, nachdem wir den Developer Account erstellt haben, auf die Schaltfläche App erstellen (siehe Bild 1).

App anlegen für weitere Daten

Bild 1: App anlegen für weitere Daten

Dies führt uns zu der Seite aus Bild 2, wo wir den Namen der App und eine Beschreibung eingeben. Außerdem wählen wir hier bereits die API aus, die wir in dieser App verwenden wollen – in diesem Fall Parcel DE Shipping (Post & Parcel Germany).

Angeben von App-Name und Beschreibung sowie Auswahl der APIs

Bild 2: Angeben von App-Name und Beschreibung sowie Auswahl der APIs

Im nächsten Schritt wählen wir weiter unten aus, ob wir die API zunächst testen oder direkt produktiv einsetzen wollen. Wir entscheiden uns zunächst für den Testbetrieb (siehe Bild 3).

Angabe, ob die App zum Testen oder produktiv genutzt werden soll

Bild 3: Angabe, ob die App zum Testen oder produktiv genutzt werden soll

Nach diesem Schritt erstellen wir schließlich mit einem Klick auf App erstellen die App (siehe Bild 4).

Erstellen der App

Bild 4: Erstellen der App

Die App wird nun in der Übersicht angezeigt, wo wir mit einem Klick auf den Namen der App die Detailseite öffnen können (siehe Bild 5). Außerdem können wir die App hier löschen oder Analysedaten anzeigen.

Ein Klick auf den App-Namen zeigt die Details an.

Bild 5: Ein Klick auf den App-Namen zeigt die Details an.

Diese liefert uns unter Credentials die gesuchten Informationen – den API Key und das API Secret (siehe Bild 6). Diese können wir mit einem Klick auf den Link Show key jeweils einblenden.

Anzeige von API Key und API Secret

Bild 6: Anzeige von API Key und API Secret

Bevor es weitergeht: Produktiv-Version

Wenn wir schon auf dieser Seite sind, können wir auch gleich die Produktiv-Version der API hinzufügen. Wenn wir die API Parcel DE Shipping erneut auswählen, wird unter Environment direkt Production angeboten. Dieses behalten wir bei und klicken auf die Schaltfläche zum Hinzufügen (siehe Bild 7).

API produktiv machen

Bild 7: API produktiv machen

Dies wird jedoch nicht direkt freigegeben, sondern wir erhalten die Meldung, dass sich die API im Status Pending befindet.

Als wir die produktive Version hinzugefügt haben, dauerte die Freigabe allerdings nur wenige Minuten. Es empfiehlt sich jedoch, die ersten Tests zunächst einmal mit der Sandbox-Version durchzuführen.

Informationen über die API suchen

Bevor wir den Zugriff auf eine REST Api programmieren können, benötigen wir einige Informationen – zum Beispiel die URL, an die wir die Anfrage schicken, die Art der Authentifizierung und die dafür notwendigen Zugangsdaten, die verschiedenen API-Funktionen und deren Syntax.

Dazu wechseln wir von der Seite https://developer.dhl.com per Klick auf den Link Browse Shipping APIs zu den gesuchten APIs.

Hier finden wir eine Liste aller API, die wir durch Auswahl verschiedener Kriterien auf die Einträge aus Bild 8 begrenzen.

APIs für den Versand

Bild 8: APIs für den Versand

All diese APIs sind entweder mit der deutschen Bezeichnung Post & Paket Deutschland oder der englischen Übersetzung Post & Parcel Germany markiert, also gehen wir davon aus, dass wir diese über die von uns gewählte, gleichnamige API nutzen können (siehe Bild 8).

Mit dieser API können wir beispielsweise die folgenden Aufgaben erledigen:

  • Erstellung von Paketmarken für Privatkunden für den Inlands- und internationalen Versand (Absenderadresse in Deutschland)
  • Herunterladen erstellter Versandetiketten
  • Herunterladen von mobilen Paketmarken entweder als QR-Code (PNG) oder Wallet-Datei
  • Die Zahlungsfunktion wird sicher über die Web-Schnittstelle von DHL während des Checkouts bereitgestellt
  • Erstellung von Zoll- und Exportdokumenten

Programmierung der API

Wir starten mit der Programmierung der API mit einem einfachen Beispiel. Dazu wollen wir zunächst die Sandbox nutzen, also einen Testserver.

Einfachste Abfrage: Version ermitteln

Es ist immer schön, eine kleine Test-API zu haben, mit der man erstmal den grundlegenden Zugriff testen kann – bevor es dann ans Eingemachte geht und wir kompliziertere und umfangreichere Daten hin- und herschicken.

Also freuen wir uns, dass es eine API gibt, die einfach Versionsinformationen zurückliefert.

Diese rufen wir mit der folgenden einfachen Funktion auf:

Public Function APIVersionAbfragen() As String
     Dim strMethod As String
     Dim strResponse As String
     Dim lngStatus As Long
     strMethod = "GET"
     lngStatus = HTTPRequest(GetURL(False), _
         strMethod, , , False, strResponse)
     Select Case lngStatus
         Case 200
             Debug.Print GetJSONDOM(strResponse, True)
         Case Else
             Debug.Print GetJSONDOM(strResponse, True)
     End Select
End Function

Natürlich ist das nicht alles, es hängt noch eine weitere Funktion namens HTTPRequest dahinter, die den eigentlichen API-Zugriff durchführt.

Diese sehen wir in Listing 1. Die Funktion erwartet die folgenden Parameter:

Public Function HTTPRequest(strURL As String, Optional strMethod As String = "POST", _
         Optional strContentType As String = "application/json", Optional strData As String, _
         Optional strResponse As String, Optional bolProductive As Boolean) As Integer
     Dim objHTTP As ServerXMLHTTP60
     Set objHTTP = New MSXML2.ServerXMLHTTP60
     With objHTTP
         .Open strMethod, strURL, False
         .setRequestHeader "Accept", "application/json"
         .setRequestHeader "Content-Type", "application/json; charset=UTF-8"
         .setRequestHeader "CharSet", "utf-8"
         .setRequestHeader "dhl-api-key", GetAPIKey
         .setRequestHeader "Authorization", "Basic " & Base64Encode(GetUsername(bolProductive) & ":" _
             & GetPassword(bolProductive))
         If Not Len(strData) = 0 Then
             .setRequestHeader "Body", strData
         End If
         .send strData
         strResponse = .responseText
         HTTPRequest = .status
     End With
End Function

Listing 1: Die Funktion HTTPRequest führt den eigentlichen API-Aufruf durch.

  • strURL: Nimmt die Basis-URL der Rest-API entgegen.
  • strMethod: Nimmt die Methode entgegen, zum Beispiel POST, GET oder PUT.
  • strContentType: Nimmt die Art des Contents entgegen, hier application/json.
  • strData: Nimmt eine zu übermittelnde JSON-Datei entgegen.
  • strResponse: Liefert die Antwort der Rest-API.
  • bolProductive: Erwartet die Angabe, ob die Sandbox- oder die Produktions-API aufgerufen werden soll.

Um nun die Version der Rest-API zu ermitteln, starten wir mit dem Aufruf der Prozedur APIVersionAbfragen. Diese legt die Methode mit GET fest und übermittelt die mit GetURL(False) geholte URL. Die Funktion GetURL erwartet den Wert True oder False, je nachdem, ob die Produktiv- oder die Sandboxumgebung genutzt werden soll:

Public Function GetURL(Optional bolProductive As Boolean)
     If bolProductive = True Then
         GetURL = "https://api-eu.dhl.com/" _
             & "parcel/de/shipping/v2/"
     Else
         GetURL = "https://api-sandbox.dhl.com/" _
             & "parcel/de/shipping/v2/"
     End If
End Function

Außerdem übergeben wir noch den Parameter strResponse, mit dem wir die Antwort der Rest-API entgegennehmen. Die Antwort geben wir schließlich sowohl für den Erfolgsfall als auch für den Fall eines Fehlers im Direktbereich des VBA-Editors aus – genau genommen das mit der Funktion GetJSONDOM bearbeitete Ergebnis. Wie diese funktioniert, haben wir bereits in den Artikeln Mit JSON arbeiten (www.vbentwickler.de/361) und JSON-Dokumente per Objektmodell zusammenstellen (www.vbentwickler.de/412) beschrieben.

Das Ergebnis sieht schließlich wie in Bild 9 aus. Hier sehen wir die Ausdrücke, mit denen wir direkt auf die Werte des mit der Funktion ParseJSON ermittelten Objekts zugreifen können.

Ergebnis der Versionsabfrage

Bild 9: Ergebnis der Versionsabfrage

Erstellung von Versandmarken testen

Nachdem der Zugriff auf die Version funktioniert hat, gehen wir einen Schritt weiter und schauen uns direkt die Hauptfunktion an. Diese wiederum testen wir mit der folgenden Prozedur, die wie folgt aussieht und gar nicht so kompliziert aussieht:

Public Sub Test_APIOrder()
     Dim strResponse As String
     Dim lngStatus As Long
     Dim strData As String
     Dim strPathPDF As String
     strPathPDF = CurrentProject.Path & "\test.pdf"
     strData = JSONBeispielsendung
     If APIOrder(strData, strPathPDF, strResponse, _
             lngStatus, True, False) = True Then
         MsgBox "Erfolgreich"
         OpenDocument strPathPDF
     Else
         MsgBox "Nicht erfolgreich" & vbCrLf & vbCrLf _
             & strResponse
     End If
End Sub

Das liegt daran, dass wir darin eine weitere Funktion namens JSONBeispielsendung aufrufen, die uns das komplette JSON-Dokument mit den Daten für die Sendung zusammenstellt – inklusive Absender- und Empfängeradresse und den Details der Sendung wie die Abmessungen und das Gewicht (siehe Listing 2).

Public Function JSONBeispielsendung() As String
     Dim strJSON As String
     strJSON = strJSON & "{" & vbCrLf
     strJSON = strJSON & "  ""shipments"": [" & vbCrLf
     strJSON = strJSON & "    {" & vbCrLf
     strJSON = strJSON & "      ""product"": ""V01PAK""," & vbCrLf
     strJSON = strJSON & "      ""billingNumber"": ""33333333330102""," & vbCrLf
     strJSON = strJSON & "      ""refNo"": ""Order No. 1234""," & vbCrLf
     strJSON = strJSON & "      ""shipper"": {" & vbCrLf
     strJSON = strJSON & "        ""name1"": ""Minhorst und Minhorst GmbH""," & vbCrLf
     strJSON = strJSON & "        ""addressStreet"": ""Borkhofer Str. 17""," & vbCrLf
     strJSON = strJSON & "        ""postalCode"": ""47137""," & vbCrLf
     strJSON = strJSON & "        ""city"": ""Duisburg""," & vbCrLf
     strJSON = strJSON & "        ""country"": ""DEU""," & vbCrLf
     strJSON = strJSON & "        ""email"": ""andre@minhorst.com""," & vbCrLf
     strJSON = strJSON & "        ""phone"": ""+ 123456789""" & vbCrLf
     strJSON = strJSON & "      }," & vbCrLf
     strJSON = strJSON & "      ""consignee"": {" & vbCrLf
     strJSON = strJSON & "        ""name1"": ""Maria Musterfrau""," & vbCrLf
     strJSON = strJSON & "        ""addressStreet"": ""Kurt-Schumacher-Str. 20""," & vbCrLf
     strJSON = strJSON & "        ""additionalAddressInformation1"": ""Apartment 107""," & vbCrLf
     strJSON = strJSON & "        ""postalCode"": ""53113""," & vbCrLf
     strJSON = strJSON & "        ""city"": ""Bonn""," & vbCrLf
     strJSON = strJSON & "        ""country"": ""DEU""," & vbCrLf
     strJSON = strJSON & "        ""email"": ""maria@musterfrau.de""," & vbCrLf
     strJSON = strJSON & "        ""phone"": ""+ 987654321""" & vbCrLf
     strJSON = strJSON & "      }," & vbCrLf
     strJSON = strJSON & "      ""details"": {" & vbCrLf
     strJSON = strJSON & "        ""dim"": {" & vbCrLf
     strJSON = strJSON & "          ""uom"": ""mm""," & vbCrLf
     strJSON = strJSON & "          ""height"": 100," & vbCrLf
     strJSON = strJSON & "          ""length"": 200," & vbCrLf
     strJSON = strJSON & "          ""width"": 150" & vbCrLf
     strJSON = strJSON & "        }," & vbCrLf
     strJSON = strJSON & "        ""weight"": {" & vbCrLf
     strJSON = strJSON & "          ""uom"": ""g""," & vbCrLf
     strJSON = strJSON & "          ""value"": 500" & vbCrLf
     strJSON = strJSON & "        }" & vbCrLf
     strJSON = strJSON & "      }" & vbCrLf
     strJSON = strJSON & "    }" & vbCrLf
     strJSON = strJSON & "  ]" & vbCrLf
     strJSON = strJSON & "}" & vbCrLf
     JSONBeispielsendung = strJSON
End Function

Listing 2: Diese Funktion stellt das JSON-Dokument mit den Paketdaten zusammen.

Danach ruft die die Funktion APIOrder auf, der sie alle notwendigen Variablen übergibt – diese beschreiben wir im Anschluss mit der Funktion APIOrder.

Funktion zum Ausführen der API-Funktion Order

Die Funktion APIOrder erwartet die folgenden Parameter (siehe Listing 3):

Public Function APIOrder(strData As String, strPathPDF As String, Optional strResponse As String, _
         Optional lngStatus As Long, Optional bolValidate As Boolean, Optional bolProductive As Boolean) As String
     Dim strMethod As String
     Dim strURL As String
     Dim objJSON As Object
     Dim strFile As String
     strURL = GetURL(bolProductive) & "orders"
     If bolValidate = True Then
         strURL = strURL & "?validate=true"
     End If
     strMethod = "POST"
     lngStatus = HTTPRequest(strURL, strMethod, , strData, strResponse, bolProductive)
     Select Case lngStatus
         Case 200
             Debug.Print GetJSONDOM(strResponse, True)
             Set objJSON = ParseJson(strResponse)
             If bolValidate = False Then
                 strFile = objJSON.Item("items").Item(1).Item("label").Item("b64")
                 WriteFileFromBytes strPathPDF, DecodeBase64(strFile)
             End If
             APIOrder = True
         Case Else
             Debug.Print GetJSONDOM(strResponse, True)
             APIOrder = False
     End Select
     Inzwischenablage strResponse
End Function

Listing 3: Die Funktion APIOrder übergibt den Request an die Funktion HTTPRequest und wertet die Antwort aus.

  • strData: JSON-Dokument mit den Daten für die DHL-Versandmarke
  • strPathPDF: Pfad, unter dem das erzeugte PDF-Dokument gespeichert werden soll
  • strResponse: Antwort des API-Aufrufs
  • lngStatus: Status des Aufrufs
  • bolValidate: Gibt an, ob der Aufruf nur der Validierung dienen soll. Der Wert False sorgt dafür, dass der Aufruf nur getestet wird.
  • bolProductive: Gibt an, ob die Sandbox- oder die Produktiv-API genutzt werden soll.

Die Funktion legt als Methode POST und als URL die URL fest, die der mit bolProductive festgelegten Plattform entspricht. Wenn der Parameter bolValidate True ist, hängt sie noch den Ausdruck ?validate=true an die URL an, damit nur ein Test der API gefahren wird. Dann ruft sie HTTPRequest auf und übergibt die notwendigen Parameter. Liefert diese den Status 200 zurück, gibt sie testweise das Ergebnis im Direktbereich aus. Außerdem erstellt sie mit der Funktion ParseJson in objJSON ein Objekt auf Basis der zurückgelieferten Antwort. Erfolgt der Aufruf nicht zum Validieren, sondern direkt zum Abfragen der Versandmarke, greifen wir nachfolgend auf das als Zeichenkette kodierte PDF-Dokument zu. Dieses schreibt die Funktion dann mit der Funktion WriteFileFromBytes in eine Datei mit dem Dateinamen aus strPathPDF.

Die frisch erstellte Versandmarke ruft die Funktion OpenDocument auf, um das Dokument wie in Bild 10 anzuzeigen.

Beispiel für eine frisch erstellte Versandmarke

Bild 10: Beispiel für eine frisch erstellte Versandmarke

 

Schreibe einen Kommentar