DHL-Paketlabel per VBA erstellen

Beim Versand von Paketen kommt recht oft DHL zum Einsatz. Die einfachste Form der computergestützten Erstellung von Paketlabeln ist dabei das Anmelden bei DHL und das Erstellen eines Labels durch Eingabe der Adressdaten und Bezahlung auf der Webseite. Etwas mehr Möglichkeiten bietet ein Geschäftskundenkonto beim Anbieter DHL. Hier können wir einen Schritt weitergehen und die Adressdaten beispielsweise per CSV übermitteln. Noch schöner wäre es, wenn wir von der jeweiligen Anwendung aus – ob es sich nun um eine Access-Datenbank, eine Excel-Tabelle oder sogar Outlook handelt – direkt per Mausklick ein Paketlabel zur Sendung eines Pakets an den jeweiligen Kontakt erstellen könnten, dass dann beispielsweise als PDF auf unserem Rechner landet. Wie das gelingt, zeigen wir im vorliegenden Artikel.

Voraussetzung: Geschäftskundenkonto bei DHL

Bevor Du weiter in diesen Artikel einsteigst, hier ein wichtiger Hinweis: Um die Beispiele in der Praxis einzusetzen, benötigst Du ein Geschäftskundenkonto bei DHL – beziehungsweise der Kunde, für den Du diese Anwendung erstellst. Zum Ausprobieren der Beispiele reicht ein einfaches Entwicklerkonto bei DHL aus. Wie Du ein Geschäftskundenkonto erstellst, wollen wir hier nicht demonstrieren – aber zumindest den Weg dorthin. Dazu folgst Du diesem Link und klickst dann auf Geschäftskunden (siehe Bild 1):

Hier gelangst Du zum Geschäftskundenbereich von DHL.

Bild 1: Hier gelangst Du zum Geschäftskundenbereich von DHL.

https://www.dhl.de

Entwickler-Konto bei DHL erstellen

Wenn Du das für die Umsetzung benötigte Entwicklerkonto bei DHl erstellen möchtest, folgst Du diesem Link:

https://entwickler.dhl.de/

Hier findest Du im unteren Bereich einen Link mit dem Text Registrieren Sie sich jetzt. Dieser führt bereits zur Registrierungsseite, wo zunächst nur eine Entwickler-ID, die E-Mail sowie ein Kennwort einzugeben sind – nebst Bestätigung von AGB und Datenschutzerklärung.

Übersicht der Dienste

Nach der Registrierung des Entwicklerkontos und der ersten Anmeldung sehen wir die zur Verfügung stehenden Dienste (siehe Bild 2). Uns interessiert als Erstes der Geschäftskundenversand. Nach einem Klick auf den entsprechenden Link landen wir direkt auf der Seite Geschäftskundenversand API, die erste Informationen für uns bereithält. Hier finden wir zum Zeitpunkt der Erstellung des Artikels die Information, dass es eine neue Version mit der Nummer 3.3 mit neuer Fehlerbehandlung gibt. Und da dies beim Zugriff auf APIs über das Internet immer besonders wichtig ist, wollen wir direkt mit dieser Version einsteigen. Dazu erhalten wir den wichtigen Tipp, die gewünschte Version im XML-Block namens Version zu übergeben.

Bereiche im Entwicklerportal

Bild 2: Bereiche im Entwicklerportal

Anlegen einer Applikation

Bevor wir richtig einsteigen können, legen wir eine Applikation an. Das erledigen wir im Bereich Freigabe & Betrieb der Webseite (siehe Bild 3). Hier tragen wir den technischen Namen, den Namen und eine Beschreibung ein.

Anlegen einer neuen Anwendung

Bild 3: Anlegen einer neuen Anwendung

Außerdem fügen wir alle Operationen hinzu, die wir verwenden wollen. In diesem Fall klappen wir den Bereich Geschäftskundenversand/Business customer shipment auf und selektieren dort alle Einträge. Anschließend schließen wir das Anlegen der Applikation mit einem Klick auf Applikation speichern ab.

Authentifizierung

Nach dem Anlegen der Applikation können wir zum nächsten Menüpunkt springen und uns die Informationen rund um die Authentifizierung ansehen. Wichtig ist hier für uns die Kenntnis der sogenannten Endpunkte für Test und Entwicklung sowie später für die produktive Nutzung. Vor dieser steht allerdings noch die Freigabe. Wir wollen den Zugriff per SOAP nutzen, also können wir uns den folgenden Endpunkt für die Tests mit der Sandbox merken:

https://cig.dhl.de/services/sandbox/soap

Außerdem erhalten wir hier noch wichtige Informationen über die zu verwendenden Zugangsdaten. Für den Testzugriff auf die Sandbox verwenden wir dabei als Benutzername die zuvor festgelegte Entwickler-ID und als Kennwort das für das Entwicklerkonto festgelegte Kennwort.

Später, wenn wir die Freigabe der Anwendung erhalten haben, können wir als Benutzernamen den Namen der Anwendung angeben und ein dafür festgelegtes Token. Beides erhalten wir im Bereich Freigabe & Betrieb der Webseite, also an der gleichen Stelle, an der wir auch die Applikation erstellt haben.

Neben den Informationen über die Authentifizierung erhalten wir auch noch den wichtigen Hinweis, dass wir für den produktiven Betrieb im Header noch die jeweilige Aktion angeben müssen – dazu kommen wir später noch.

Die Geschäftskundenversand-API

Danach folgen im Menü die einzelnen Bereiche, die wir programmieren können. Wie weiter oben festgelegt, wollen wir den Geschäftskundenversand automatisieren und wechseln daher zum Menü Geschäftskundenversand.

Fingerübung: Version abfragen

Bevor wir uns an die Programmierung der Erstellung von Versandlabeln begeben, wollen wir zum Warmmachen die aktuell verfügbar maximale Version abfragen. Dazu erstellen wir als Erstes eine Funktion, die ein entsprechendes SOAP-Dokument zusammenstellt und dieses dann an eine Funktion zum Senden der Anfrage an die API schickt.

Die Funktion heißt VersionErmitteln und erwartet die beiden Parameter intMajor und intMinor, welche beides Rückgabeparameter sind, also die als leere Variablen übergeben und von der Funktion gefüllt werden (siehe Listing 1).

Public Function VersionErmitteln(intMajor As Integer, intMinor As Integer)
     Dim objXMLRequest As MSXML2.DOMDocument60
     Dim objXMLResponse As MSXML2.DOMDocument60
     Dim objMinor As MSXML2.IXMLDOMNode
     Dim objMajor As MSXML2.IXMLDOMNode
     Dim strRequest As String
     strRequest = "<soapenv:Envelope xmlns:soapenv=""http://schemas.xmlsoap.org/soap/envelope/"" " _
         & "xmlns:ns=""http://dhl.de/webservices/businesscustomershipping/3.0"">" & vbCrLf
     strRequest = strRequest & "   <soapenv:Body>" & vbCrLf
     strRequest = strRequest & "      <ns:Version>" & vbCrLf
     strRequest = strRequest & "         <majorRelease>?</majorRelease>" & vbCrLf
     strRequest = strRequest & "         <minorRelease>?</minorRelease>" & vbCrLf
     strRequest = strRequest & "         <build>?</build>" & vbCrLf
     strRequest = strRequest & "      </ns:Version>" & vbCrLf
     strRequest = strRequest & "   </soapenv:Body>" & vbCrLf
     strRequest = strRequest & "</soapenv:Envelope>" & vbCrLf
     Set objXMLRequest = New MSXML2.DOMDocument60
     If Not objXMLRequest.loadXML(strRequest) Then
         Debug.Print objXMLRequest.parseError.Line, objXMLRequest.parseError.linepos, objXMLRequest.parseError.reason, _
             objXMLRequest.parseError.errorCode
     Else
         If RequestSandbox(strRequest, objXMLResponse) Then
             Set objMinor = objXMLResponse.selectSingleNode("//minorRelease")
             If Not objMinor Is Nothing Then
                 intMinor = objMinor.nodeTypedValue
             End If
             Set objMajor = objXMLResponse.selectSingleNode("//majorRelease")
             If Not objMajor Is Nothing Then
                 intMajor = objMajor.nodeTypedValue
             End If
         End If
     End If
End Function

Listing 1: Prozedur zum Zusammenstellen einer Abfrage der aktuellen Version

Sie deklariert zwei Variablen des Typs MSXML2.DOMDocument60, womit wir gleich bei einer Voraussetzung landen – dem Hinzufügen eines Verweises auf die Bibliothek Microsoft XML, v6.0. Dies erledigen wir im Dialog Verweise, den wir vom VBA-Editor der verwendeten Anwendung aus mit dem Menübefehl Extras|Verweise öffnen. Die benötigte Bibliothek fügen wir wie in Bild 4 hinzu. Anschließend können wir die enthaltenen Klassen, Methoden und Eigenschaften im VBA-Editor unter Verwendung von IntelliSense eingeben.

Hinzufügen eines Verweises auf die XML-Bibliothek

Bild 4: Hinzufügen eines Verweises auf die XML-Bibliothek

Neben diesen beiden Objektvariablen nutzen wir zwei weitere namens objMinor und objMajor, jeweils mit dem Typ MSXML2.IXMLDOMNode, um Elemente mit Versionsangabe zu referenzieren. Die Funktion stellt nun den Code der Anfrage zusammen, die wir an die API von DHL schicken wollen. Zusammengefasst sieht diese in der Variablen strRequest erfasste Zeichenkette wie folgt aus:

<soapenv:Envelope         xmlns:soapenv="http://schemas.xmlsoap.org/soap/        envelope/" xmlns:ns="http://dhl.de/webservices/        businesscustomershipping/3.0">
     <soapenv:Body>
         <ns:Version>
             <majorRelease>?</majorRelease>
             <minorRelease>?</minorRelease>
             <build>?</build>
         </ns:Version>
     </soapenv:Body>
</soapenv:Envelope>

Nach dem Zusammenstellen dieser Zeichenkette erstellt die Funktion ein neues Objekt des Typs DOMDocument60 und ruft dessen Funktion loadXML auf. Dieser übergibt sie den Inhalt von strRequest und füllt das Objekt aus objXMLRequest damit mit der XML-Anfrage. Die loadXML-Funktion prüft gleichzeitig die Gültigkeit des übergebenen XML-Dokuments und gibt eine Meldung im Direktbereich aus, sollte dieses nicht gültig sein.

Anderenfalls ruft sie die Funktion Request auf und übergibt dieser das gefüllte Objekt objXMLRequest sowie das noch leere Objekt objXMLResponse. Diese Funktion beschreiben wir gleich im Anschluss. Wenn die Funktion den Wert True zurückgibt, die Abfrage also erfolgreich war, dann ist objXMLResponse anschließend mit einem XML-Dokument wie dem folgenden gefüllt:

<soapenv:Envelope 
         xmlns:bus="http://dhl.de/webservices/
         businesscustomershipping/3.0" 
         xmlns:soapenv="http://schemas.xmlsoap.org/soap/
         envelope/">
     <soapenv:Header/>
     <soapenv:Body>
         <bus:GetVersionResponse>
             <bus:Version>
                 <majorRelease>3</majorRelease>
                 <minorRelease>0</minorRelease>
                 <build>0</build>
             </bus:Version>
         </bus:GetVersionResponse>
     </soapenv:Body>
</soapenv:Envelope>

Die Aufgabe lautet nun noch, den Inhalt der beiden Elemente majorRelease und minorRelease auszulesen und in die Rückgabeparameter zu schreiben. Das erledigen wir, indem wir mit der Funktion selectSingleNode nach den entsprechenden Elementen suchen. Finden wir diese, lesen wir daraus über die Eigenschaft nodeTypedValue die enthaltenen Werte aus. Diese füllen wir in die Rückgabeparameter intMinor und intMajor.

Diese Funktion rufen wir beispielsweise mit der folgenden Prozedur auf:

Public Sub Test_VersionErmitteln()
     Dim intMajor As Integer
     Dim intMinor As Integer
     VersionErmitteln intMajor, intMinor
     Debug.Print "Version " & intMajor & "." & intMinor
End Sub

Die Request-Funktion

Die eigentliche Arbeit beim Aufruf der DHL-API übernimmt die Funktion RequestSandbox (siehe Listing 2). Diese nimmt über den Parameter strRequest den Aufruf entgegen und soll den Rückgabeparameter objXMLResponse mit dem DOMDocument60-Objekt mit der Antwort füllen. Dieses erstellt die Funktion mit dem New-Schlüsselwort zunächst neu. Außerdem erstellt sie ein Objekt des Typs XMLHTTP60 und referenziert es mit der Objektvariablen objXMLHTTP. Hier kommt nun eine Konstante ins Spiel, die wir im Kopf des Moduls deklarieren und mit der weiter oben angegebenen URL für den Zugriff auf die API in der Sandbox-Version füllen – also mit der URL für unsere Tests der API:

Public Function RequestSandbox(strRequest As String, objXMLResponse As MSXML2.DOMDocument60) As Boolean
     Dim strURL As String
     Dim objXMLHTTP As MSXML2.XMLHTTP60
     Set objXMLHTTP = New MSXML2.XMLHTTP60
     Set objXMLResponse = New MSXML2.DOMDocument60
     With objXMLHTTP
         .Open "post", cStrURLBase, False
         .setRequestHeader "Content-Type", "text/xml; charset=utf-8"
         .setRequestHeader "Content-Length", Len(strRequest)
         .setRequestHeader "Authorization", "Basic " + Base64Encode(strUserSandbox + ":" + strPasswordSandbox)
         .send strRequest
         Select Case .status
             Case 200
                 Request = True
                 objXMLResponse.loadXML .responseText
             Case Else
                 MsgBox "Fehler beim Request:" & vbCrLf & .statusText
         End Select
     End With
End Function

Listing 2: Die Request-Funktion zum Durchführen eines API-Aufrufs

Public Const cStrURLBase As String = _
     "https://cig.dhl.de/services/sandbox/soap"

Diese übergeben wir als zweiten Parameter der Open-Methode von objXMLHTTP. Der erste Parameter lautet post und bedeutet, dass wir später mit der send-Methode noch Informationen senden statt diese an die URL anzuhängen.

Danach stellen wir drei Header ein, zunächst Content-Type und Content-Length. Der erste gibt an, dass wir mit Daten im Format text/xml mit dem Zeichensatz utf-8 arbeiten. Der zweite legt die Länge des übermittelten XML-Dokuments fest. Der dritte Header nimmt die Zugangsdaten auf. Diese speichern wir in Form entsprechender Konstanten wieder im Kopf des Moduls mdlDHL. Die Konstanten sehen wie folgt aus:

Public Const strUserSandbox As String = "[EntwicklerID]"
Public Const strPasswordSandbox As String = "[Kennwort]"

Für strUserSandbox geben wir die Entwickler-ID aus dem Entwicklerportal an, die wir unter folgendem Link finden:

https://entwickler.dhl.de/group/ep/mein-konto

Für strPasswordSandbox hinterlegen wir das Kennwort für die Anmeldung am Entwicklerportal. Die Anmeldedaten werden in einer durch einen Doppelpunkt getrennten Zeichenkette zusammengefasst und Base64-kodiert.

Dann stellen wir diesem Ausdruck den Text Basic und ein Leerzeichen voran und übergeben dies für den Header Authorization. Schließlich ruft die Funktion die send-Methode auf und übergibt dieser als Parameter die in strRequest gespeicherte XML-Anfrage.

Nachdem diese ausgeführt wurde, können wir das Ergebnis in Form der Eigenschaft status auswerten. Der Wert 200 entspricht dem Ergebnis OK. In diesem Fall stellen wir das Ergebnis der Funktion auf True ein und lesen den Inhalt der Eigenschaft responseText, die von der API gefüllt wurde, mit der loadXML-Methode in das DOMDocument60-Objekt objXMLResponse ein. Anderenfalls gibt die Funktion den Statustext mit der Fehlermeldung in einem Meldungsfenster aus.

Benutzerdaten manuell eingeben

Wenn Du die Benutzerdaten nicht im Code speichern möchtest, kannst Du die Übergabe der dritten Header-Zeile auch weglassen. Dann erscheint eine Meldung wie in Bild 5, um die Zugangsdaten abzufragen.

Manuelle Eingabe der Zugangsdaten

Möchten Sie weiterlesen? Dann lösen Sie Ihr Ticket!
Hier geht es zur Bestellung des Jahresabonnements des Magazins Visual Basic Entwickler:
Zur Bestellung ...
Danach greifen Sie sofort auf alle rund 200 Artikel unseres Angebots zu - auch auf diesen hier!
Oder haben Sie bereits Zugangsdaten? Dann loggen Sie sich gleich hier ein:

Schreibe einen Kommentar