{"id":55000429,"date":"2024-08-01T00:00:00","date_gmt":"2024-09-26T16:14:35","guid":{"rendered":"http:\/\/access-im-unternehmen.aix-dev.de\/aiu\/?p=429"},"modified":"-0001-11-30T00:00:00","modified_gmt":"-0001-11-30T00:00:00","slug":"DHLVersandetiketten_erstellen_per_VBA","status":"publish","type":"post","link":"https:\/\/vbentwickler.de\/DHLVersandetiketten_erstellen_per_VBA\/","title":{"rendered":"DHL-Versandetiketten erstellen per VBA"},"content":{"rendered":"<p><img loading=\"lazy\" decoding=\"async\" src=\"http:\/\/vg08.met.vgwort.de\/na\/10e45f071fcc4a76b63da9846c30af51\" width=\"1\" height=\"1\" alt=\"\"><b>Wer Kunden und Bestellungen mit einer Access-Datenbank verwaltet oder gegebenenfalls auch mit einer Excel-Tabelle, m&ouml;chte vielleicht Zeit sparen und die Etiketten f&uuml;r den Versand von Lieferungen an seine Kunden automatisieren. Das gelingt mit den verschiedenen Webservices von DHL. Wir haben bereits einmal eine solche L&ouml;sung vorgestellt, aber DHL hat seine Schnittstellen f&uuml;r die Erstellung von Versandetiketten aktualisiert. In diesem Artikel schauen wir uns an, wie die neuen Schnittstellen funktionieren: Welche Daten ben&ouml;tige ich? Welche URL muss f&uuml;r den Zugriff verwendet werden? In welcher Form &uuml;bergebe ich beispielsweise die Adressdaten an den Webservice?<\/b><\/p>\n<h2>Voraussetzung f&uuml;r die Verwendung der L&ouml;sung<\/h2>\n<p>Wenn wir die Webservices von DHL f&uuml;r die Erstellung von Versandetiketten nutzen wollen, sind einige Voraussetzungen zu erf&uuml;llen. Als Erstes ben&ouml;tigen wir ein Konto als Gesch&auml;ftskunde bei DHL. Wie Du dieses anlegst, wollen wir hier nicht im Detail beschreiben. Wir wollen Dir aber zumindest den Link zum Gesch&auml;ftskundenportal mit auf den Weg geben:<\/p>\n<pre>https:\/\/www.dhl.de\/de\/geschaeftskunden.html<\/pre>\n<p>Nach der Anmeldung ben&ouml;tigen wir sp&auml;ter Deine Zugangsdaten f&uuml;r Dein Kundenkonto, also Benutzername und Kennwort.<\/p>\n<p>Als Zweites ben&ouml;tigst Du ein Entwicklerkonto bei DHL. Dazu besuchst Du die folgende Adresse und erstellst einen Account:<\/p>\n<pre>https:\/\/developer.dhl.com\/<\/pre>\n<p>Damit k&ouml;nnen wir bereits starten.<\/p>\n<h2>App erstellen<\/h2>\n<p>Nachdem wir einen Entwickler-Account erstellt haben, ben&ouml;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&ouml;nnen. Also klicken wir, nachdem wir den Developer Account erstellt haben, auf die Schaltfl&auml;che <b>App erstellen <\/b>(siehe Bild 1).<\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2024_04\/pic_429_001.png\" alt=\"App anlegen f&uuml;r weitere Daten\" width=\"549,6265\" height=\"787,2445\"\/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 1: App anlegen f&uuml;r weitere Daten<\/span><\/b><\/p>\n<p>Dies f&uuml;hrt uns zu der Seite aus Bild 2, wo wir den Namen der App und eine Beschreibung eingeben. Au&szlig;erdem w&auml;hlen wir hier bereits die API aus, die wir in dieser App verwenden wollen &#8211; in diesem Fall <b>Parcel DE Shipping (Post &#038; Parcel Germany)<\/b>.<\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2024_04\/pic_429_002.png\" alt=\"Angeben von App-Name und Beschreibung sowie Auswahl der APIs\" width=\"424,6267\" height=\"703,5885\" \/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 2: Angeben von App-Name und Beschreibung sowie Auswahl der APIs<\/span><\/b><\/p>\n<p>Im n&auml;chsten Schritt w&auml;hlen wir weiter unten aus, ob wir die API zun&auml;chst testen oder direkt produktiv einsetzen wollen. Wir entscheiden uns zun&auml;chst f&uuml;r den Testbetrieb (siehe Bild 3).<\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2024_04\/pic_429_003.png\" alt=\"Angabe, ob die App zum Testen oder produktiv genutzt werden soll\" width=\"424,6267\" height=\"429,5931\" \/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 3: Angabe, ob die App zum Testen oder produktiv genutzt werden soll<\/span><\/b><\/p>\n<p>Nach diesem Schritt erstellen wir schlie&szlig;lich mit einem Klick auf <b>App erstellen<\/b> die App (siehe Bild 4).<\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2024_04\/pic_429_004.png\" alt=\"Erstellen der App\" width=\"424,6267\" height=\"261,7562\" \/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 4: Erstellen der App<\/span><\/b><\/p>\n<p>Die App wird nun in der &Uuml;bersicht angezeigt, wo wir mit einem Klick auf den Namen der App die Detailseite &ouml;ffnen k&ouml;nnen (siehe Bild 5). Au&szlig;erdem k&ouml;nnen wir die App hier l&ouml;schen oder Analysedaten anzeigen.<\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2024_04\/pic_429_005.png\" alt=\"Ein Klick auf den App-Namen zeigt die Details an.\" width=\"700\" height=\"279,8596\" \/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 5: Ein Klick auf den App-Namen zeigt die Details an.<\/span><\/b><\/p>\n<p>Diese liefert uns unter <b>Credentials<\/b> die gesuchten Informationen &#8211; den API Key und das API Secret (siehe Bild 6). Diese k&ouml;nnen wir mit einem Klick auf den Link <b>Show key <\/b>jeweils einblenden.<\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2024_04\/pic_429_006.png\" alt=\"Anzeige von API Key und API Secret\" width=\"700\" height=\"419,2856\"\/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 6: Anzeige von API Key und API Secret<\/span><\/b><\/p>\n<h2>Bevor es weitergeht: Produktiv-Version<\/h2>\n<p>Wenn wir schon auf dieser Seite sind, k&ouml;nnen wir auch gleich die Produktiv-Version der API hinzuf&uuml;gen. Wenn wir die <b>API Parcel DE Shipping <\/b>erneut ausw&auml;hlen, wird unter <b>Environment <\/b>direkt <b>Production <\/b>angeboten. Dieses behalten wir bei und klicken auf die Schaltfl&auml;che zum Hinzuf&uuml;gen (siehe Bild 7).<\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2024_04\/pic_429_008.png\" alt=\"API produktiv machen\" width=\"599,6265\" height=\"597,8315\" \/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 7: API produktiv machen<\/span><\/b><\/p>\n<p>Dies wird jedoch nicht direkt freigegeben, sondern wir erhalten die Meldung, dass sich die API im Status <b>Pending <\/b>befindet.<\/p>\n<p>Als wir die produktive Version hinzugef&uuml;gt haben, dauerte die Freigabe allerdings nur wenige Minuten. Es empfiehlt sich jedoch, die ersten Tests zun&auml;chst einmal mit der Sandbox-Version durchzuf&uuml;hren.<\/p>\n<h2>Informationen &uuml;ber die API suchen<\/h2>\n<p>Bevor wir den Zugriff auf eine REST Api programmieren k&ouml;nnen, ben&ouml;tigen wir einige Informationen &#8211; zum Beispiel die URL, an die wir die Anfrage schicken, die Art der Authentifizierung und die daf&uuml;r notwendigen Zugangsdaten, die verschiedenen API-Funktionen und deren Syntax.<\/p>\n<p>Dazu wechseln wir von der Seite <b>https:\/\/developer.dhl.com <\/b>per Klick auf den Link <b>Browse Shipping APIs <\/b>zu den gesuchten APIs.<\/p>\n<p>Hier finden wir eine Liste aller API, die wir durch Auswahl verschiedener Kriterien auf die Eintr&auml;ge aus Bild 8 begrenzen.<\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2024_04\/pic_429_007.png\" alt=\"APIs f&uuml;r den Versand\" width=\"700\" height=\"390,172\" \/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 8: APIs f&uuml;r den Versand<\/span><\/b><\/p>\n<p>All diese APIs sind entweder mit der deutschen Bezeichnung <b>Post &#038; Paket Deutschland <\/b>oder der englischen &Uuml;bersetzung <b>Post &#038; Parcel Germany <\/b>markiert, also gehen wir davon aus, dass wir diese &uuml;ber die von uns gew&auml;hlte, gleichnamige API nutzen k&ouml;nnen (siehe Bild 8).<\/p>\n<p>Mit dieser API k&ouml;nnen wir beispielsweise die folgenden Aufgaben erledigen:<\/p>\n<ul>\n<li>Erstellung von Paketmarken f&uuml;r Privatkunden f&uuml;r den Inlands- und internationalen Versand (Absenderadresse in Deutschland)<\/li>\n<li>Herunterladen erstellter Versandetiketten<\/li>\n<li>Herunterladen von mobilen Paketmarken entweder als QR-Code (PNG) oder Wallet-Datei<\/li>\n<li>Die Zahlungsfunktion wird sicher &uuml;ber die Web-Schnittstelle von DHL w&auml;hrend des Checkouts bereitgestellt<\/li>\n<li>Erstellung von Zoll- und Exportdokumenten<\/li>\n<\/ul>\n<h2>Programmierung der API<\/h2>\n<p>Wir starten mit der Programmierung der API mit einem einfachen Beispiel. Dazu wollen wir zun&auml;chst die Sandbox nutzen, also einen Testserver.<\/p>\n<h2>Einfachste Abfrage: Version ermitteln<\/h2>\n<p>Es ist immer sch&ouml;n, eine kleine Test-API zu haben, mit der man erstmal den grundlegenden Zugriff testen kann &#8211; bevor es dann ans Eingemachte geht und wir kompliziertere und umfangreichere Daten hin- und herschicken.<\/p>\n<p>Also freuen wir uns, dass es eine API gibt, die einfach Versionsinformationen zur&uuml;ckliefert.<\/p>\n<p>Diese rufen wir mit der folgenden einfachen Funktion auf:<\/p>\n<pre><span style=\"color:blue;\">Public Function <\/span>APIVersionAbfragen()<span style=\"color:blue;\"> As String<\/span>\r\n     <span style=\"color:blue;\">Dim <\/span>strMethod<span style=\"color:blue;\"> As String<\/span>\r\n     <span style=\"color:blue;\">Dim <\/span>strResponse<span style=\"color:blue;\"> As String<\/span>\r\n     <span style=\"color:blue;\">Dim <\/span>lngStatus<span style=\"color:blue;\"> As Long<\/span>\r\n     strMethod = \"GET\"\r\n     lngStatus = HTTPRequest(GetURL(<span style=\"color:blue;\">False<\/span>), _\r\n         strMethod, , , False, strResponse)\r\n     Select Case lngStatus\r\n         <span style=\"color:blue;\">Case <\/span>200\r\n             <span style=\"color:blue;\">Debug.Print<\/span> GetJSONDOM(strResponse, <span style=\"color:blue;\">True<\/span>)\r\n         <span style=\"color:blue;\">Case Else<\/span>\r\n             <span style=\"color:blue;\">Debug.Print<\/span> GetJSONDOM(strResponse, <span style=\"color:blue;\">True<\/span>)\r\n     <span style=\"color:blue;\">End Select<\/span>\r\n<span style=\"color:blue;\">End Function<\/span><\/pre>\n<p>Nat&uuml;rlich ist das nicht alles, es h&auml;ngt noch eine weitere Funktion namens <b>HTTPRequest <\/b>dahinter, die den eigentlichen API-Zugriff durchf&uuml;hrt.<\/p>\n<p>Diese sehen wir in Listing 1. Die Funktion erwartet die folgenden Parameter:<\/p>\n<pre><span style=\"color:blue;\">Public Function <\/span>HTTPRequest(strURL<span style=\"color:blue;\"> As String<\/span>, <span style=\"color:blue;\">Optional<\/span> strMethod<span style=\"color:blue;\"> As String<\/span> = \"POST\", _\r\n         <span style=\"color:blue;\">Optional<\/span> strContentType<span style=\"color:blue;\"> As String<\/span> = \"application\/json\", <span style=\"color:blue;\">Optional<\/span> strData<span style=\"color:blue;\"> As String<\/span>, _\r\n         <span style=\"color:blue;\">Optional<\/span> strResponse<span style=\"color:blue;\"> As String<\/span>, <span style=\"color:blue;\">Optional<\/span> bolProductive<span style=\"color:blue;\"> As Boolean<\/span>)<span style=\"color:blue;\"> As Integer<\/span>\r\n     <span style=\"color:blue;\">Dim <\/span>objHTTP<span style=\"color:blue;\"> As <\/span>ServerXMLHTTP60\r\n     <span style=\"color:blue;\">Set<\/span> objHTTP = <span style=\"color:blue;\">New<\/span> MSXML2.ServerXMLHTTP60\r\n     <span style=\"color:blue;\">With<\/span> objHTTP\r\n         .Open strMethod, strURL, <span style=\"color:blue;\">False<\/span>\r\n         .setRequestHeader \"Accept\", \"application\/json\"\r\n         .setRequestHeader \"Content-Type\", \"application\/json; charset=UTF-8\"\r\n         .setRequestHeader \"CharSet\", \"utf-8\"\r\n         .setRequestHeader \"dhl-api-key\", GetAPIKey\r\n         .setRequestHeader \"Authorization\", \"Basic \" & Base64Encode(GetUsername(bolProductive) & \":\" _\r\n             & GetPassword(bolProductive))\r\n         <span style=\"color:blue;\">If <\/span><span style=\"color:blue;\">Not<\/span> <span style=\"color:blue;\">Len<\/span>(strData) = 0<span style=\"color:blue;\"> Then<\/span>\r\n             .setRequestHeader \"Body\", strData\r\n         <span style=\"color:blue;\">End If<\/span>\r\n         .send strData\r\n         strResponse = .responseText\r\n         HTTPRequest = .status\r\n     End <span style=\"color:blue;\">With<\/span>\r\n<span style=\"color:blue;\">End Function<\/span><\/pre>\n<p><b><span style=\"color:darkgrey;\">Listing 1: Die Funktion HTTPRequest f&uuml;hrt den eigentlichen API-Aufruf durch.<\/span><\/b><\/p>\n<ul>\n<li><b>strURL<\/b>: Nimmt die Basis-URL der Rest-API entgegen.<\/li>\n<li><b>strMethod<\/b>: Nimmt die Methode entgegen, zum Beispiel <b>POST<\/b>, <b>GET <\/b>oder <b>PUT<\/b>.<\/li>\n<li><b>strContentType<\/b>: Nimmt die Art des Contents entgegen, hier <b>application\/json<\/b>.<\/li>\n<li><b>strData<\/b>: Nimmt eine zu &uuml;bermittelnde JSON-Datei entgegen.<\/li>\n<li><b>strResponse<\/b>: Liefert die Antwort der Rest-API.<\/li>\n<li><b>bolProductive<\/b>: Erwartet die Angabe, ob die Sandbox- oder die Produktions-API aufgerufen werden soll.<\/li>\n<\/ul>\n<p>Um nun die Version der Rest-API zu ermitteln, starten wir mit dem Aufruf der Prozedur <b>APIVersionAbfragen<\/b>. Diese legt die Methode mit <b>GET <\/b>fest und &uuml;bermittelt die mit <b>GetURL(False) <\/b>geholte URL. Die Funktion <b>GetURL <\/b>erwartet den Wert <b>True <\/b>oder <b>False<\/b>, je nachdem, ob die Produktiv- oder die Sandboxumgebung genutzt werden soll:<\/p>\n<pre><span style=\"color:blue;\">Public Function <\/span>GetURL(<span style=\"color:blue;\">Optional<\/span> bolProductive<span style=\"color:blue;\"> As Boolean<\/span>)\r\n     <span style=\"color:blue;\">If <\/span>bolProductive = <span style=\"color:blue;\">True<\/span><span style=\"color:blue;\"> Then<\/span>\r\n         GetURL = \"https:\/\/api-eu.dhl.com\/\" _\r\n             & \"parcel\/de\/shipping\/v2\/\"\r\n     <span style=\"color:blue;\">Else<\/span>\r\n         GetURL = \"https:\/\/api-sandbox.dhl.com\/\" _\r\n             & \"parcel\/de\/shipping\/v2\/\"\r\n     <span style=\"color:blue;\">End If<\/span>\r\n<span style=\"color:blue;\">End Function<\/span><\/pre>\n<p>Au&szlig;erdem &uuml;bergeben wir noch den Parameter <b>strResponse<\/b>, mit dem wir die Antwort der Rest-API entgegennehmen. Die Antwort geben wir schlie&szlig;lich sowohl f&uuml;r den Erfolgsfall als auch f&uuml;r den Fall eines Fehlers im Direktbereich des VBA-Editors aus &#8211; genau genommen das mit der Funktion <b>GetJSONDOM <\/b>bearbeitete Ergebnis. Wie diese funktioniert, haben wir bereits in den Artikeln <b>Mit JSON arbeiten <\/b>(<b>www.vbentwickler.de\/361<\/b>) und <b>JSON-Dokumente per Objektmodell zusammenstellen <\/b>(<b>www.vbentwickler.de\/412<\/b>) beschrieben.<\/p>\n<p>Das Ergebnis sieht schlie&szlig;lich wie in Bild 9 aus. Hier sehen wir die Ausdr&uuml;cke, mit denen wir direkt auf die Werte des mit der Funktion <b>ParseJSON <\/b>ermittelten Objekts zugreifen k&ouml;nnen.<\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2024_04\/pic_429_009.png\" alt=\"Ergebnis der Versionsabfrage\" width=\"649,627\" height=\"161,0452\" \/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 9: Ergebnis der Versionsabfrage<\/span><\/b><\/p>\n<h2>Erstellung von Versandmarken testen<\/h2>\n<p>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:<\/p>\n<pre><span style=\"color:blue;\">Public Sub <\/span>Test_APIOrder()\r\n     <span style=\"color:blue;\">Dim <\/span>strResponse<span style=\"color:blue;\"> As String<\/span>\r\n     <span style=\"color:blue;\">Dim <\/span>lngStatus<span style=\"color:blue;\"> As Long<\/span>\r\n     <span style=\"color:blue;\">Dim <\/span>strData<span style=\"color:blue;\"> As String<\/span>\r\n     <span style=\"color:blue;\">Dim <\/span>strPathPDF<span style=\"color:blue;\"> As String<\/span>\r\n     strPathPDF = CurrentProject.Path & \"\\test.pdf\"\r\n     strData = JSONBeispielsendung\r\n     If APIOrder(strData, strPathPDF, strResponse, _\r\n             lngStatus, True, <span style=\"color:blue;\">False<\/span>) = <span style=\"color:blue;\">True<\/span> Then\r\n         <span style=\"color:blue;\">MsgBox<\/span> \"Erfolgreich\"\r\n         OpenDocument strPathPDF\r\n     <span style=\"color:blue;\">Else<\/span>\r\n         <span style=\"color:blue;\">MsgBox<\/span> \"Nicht erfolgreich\" & <span style=\"color:blue;\">vbCrLf<\/span> & <span style=\"color:blue;\">vbCrLf<\/span> _\r\n             & strResponse\r\n     <span style=\"color:blue;\">End If<\/span>\r\n<span style=\"color:blue;\">End Sub<\/span><\/pre>\n<p>Das liegt daran, dass wir darin eine weitere Funktion namens <b>JSONBeispielsendung <\/b>aufrufen, die uns das komplette JSON-Dokument mit den Daten f&uuml;r die Sendung zusammenstellt &#8211; inklusive Absender- und Empf&auml;ngeradresse und den Details der Sendung wie die Abmessungen und das Gewicht (siehe Listing 2).<\/p>\n<pre><span style=\"color:blue;\">Public Function <\/span>JSONBeispielsendung()<span style=\"color:blue;\"> As String<\/span>\r\n     <span style=\"color:blue;\">Dim <\/span>strJSON<span style=\"color:blue;\"> As String<\/span>\r\n     strJSON = strJSON & \"{\" & <span style=\"color:blue;\">vbCrLf<\/span>\r\n     strJSON = strJSON & \"  \"\"shipments\"\": [\" & <span style=\"color:blue;\">vbCrLf<\/span>\r\n     strJSON = strJSON & \"    {\" & <span style=\"color:blue;\">vbCrLf<\/span>\r\n     strJSON = strJSON & \"      \"\"product\"\": \"\"V01PAK\"\",\" & <span style=\"color:blue;\">vbCrLf<\/span>\r\n     strJSON = strJSON & \"      \"\"billingNumber\"\": \"\"33333333330102\"\",\" & <span style=\"color:blue;\">vbCrLf<\/span>\r\n     strJSON = strJSON & \"      \"\"refNo\"\": \"\"Order No. 1234\"\",\" & <span style=\"color:blue;\">vbCrLf<\/span>\r\n     strJSON = strJSON & \"      \"\"shipper\"\": {\" & <span style=\"color:blue;\">vbCrLf<\/span>\r\n     strJSON = strJSON & \"        \"\"name1\"\": \"\"Minhorst und Minhorst GmbH\"\",\" & <span style=\"color:blue;\">vbCrLf<\/span>\r\n     strJSON = strJSON & \"        \"\"addressStreet\"\": \"\"Borkhofer Str. 17\"\",\" & <span style=\"color:blue;\">vbCrLf<\/span>\r\n     strJSON = strJSON & \"        \"\"postalCode\"\": \"\"47137\"\",\" & <span style=\"color:blue;\">vbCrLf<\/span>\r\n     strJSON = strJSON & \"        \"\"city\"\": \"\"Duisburg\"\",\" & <span style=\"color:blue;\">vbCrLf<\/span>\r\n     strJSON = strJSON & \"        \"\"country\"\": \"\"DEU\"\",\" & <span style=\"color:blue;\">vbCrLf<\/span>\r\n     strJSON = strJSON & \"        \"\"email\"\": \"\"andre@minhorst.com\"\",\" & <span style=\"color:blue;\">vbCrLf<\/span>\r\n     strJSON = strJSON & \"        \"\"phone\"\": \"\"+ 123456789\"\"\" & <span style=\"color:blue;\">vbCrLf<\/span>\r\n     strJSON = strJSON & \"      },\" & <span style=\"color:blue;\">vbCrLf<\/span>\r\n     strJSON = strJSON & \"      \"\"consignee\"\": {\" & <span style=\"color:blue;\">vbCrLf<\/span>\r\n     strJSON = strJSON & \"        \"\"name1\"\": \"\"Maria Musterfrau\"\",\" & <span style=\"color:blue;\">vbCrLf<\/span>\r\n     strJSON = strJSON & \"        \"\"addressStreet\"\": \"\"Kurt-Schumacher-Str. 20\"\",\" & <span style=\"color:blue;\">vbCrLf<\/span>\r\n     strJSON = strJSON & \"        \"\"additionalAddressInformation1\"\": \"\"Apartment 107\"\",\" & <span style=\"color:blue;\">vbCrLf<\/span>\r\n     strJSON = strJSON & \"        \"\"postalCode\"\": \"\"53113\"\",\" & <span style=\"color:blue;\">vbCrLf<\/span>\r\n     strJSON = strJSON & \"        \"\"city\"\": \"\"Bonn\"\",\" & <span style=\"color:blue;\">vbCrLf<\/span>\r\n     strJSON = strJSON & \"        \"\"country\"\": \"\"DEU\"\",\" & <span style=\"color:blue;\">vbCrLf<\/span>\r\n     strJSON = strJSON & \"        \"\"email\"\": \"\"maria@musterfrau.de\"\",\" & <span style=\"color:blue;\">vbCrLf<\/span>\r\n     strJSON = strJSON & \"        \"\"phone\"\": \"\"+ 987654321\"\"\" & <span style=\"color:blue;\">vbCrLf<\/span>\r\n     strJSON = strJSON & \"      },\" & <span style=\"color:blue;\">vbCrLf<\/span>\r\n     strJSON = strJSON & \"      \"\"details\"\": {\" & <span style=\"color:blue;\">vbCrLf<\/span>\r\n     strJSON = strJSON & \"        \"\"dim\"\": {\" & <span style=\"color:blue;\">vbCrLf<\/span>\r\n     strJSON = strJSON & \"          \"\"uom\"\": \"\"mm\"\",\" & <span style=\"color:blue;\">vbCrLf<\/span>\r\n     strJSON = strJSON & \"          \"\"height\"\": 100,\" & <span style=\"color:blue;\">vbCrLf<\/span>\r\n     strJSON = strJSON & \"          \"\"length\"\": 200,\" & <span style=\"color:blue;\">vbCrLf<\/span>\r\n     strJSON = strJSON & \"          \"\"width\"\": 150\" & <span style=\"color:blue;\">vbCrLf<\/span>\r\n     strJSON = strJSON & \"        },\" & <span style=\"color:blue;\">vbCrLf<\/span>\r\n     strJSON = strJSON & \"        \"\"weight\"\": {\" & <span style=\"color:blue;\">vbCrLf<\/span>\r\n     strJSON = strJSON & \"          \"\"uom\"\": \"\"g\"\",\" & <span style=\"color:blue;\">vbCrLf<\/span>\r\n     strJSON = strJSON & \"          \"\"value\"\": 500\" & <span style=\"color:blue;\">vbCrLf<\/span>\r\n     strJSON = strJSON & \"        }\" & <span style=\"color:blue;\">vbCrLf<\/span>\r\n     strJSON = strJSON & \"      }\" & <span style=\"color:blue;\">vbCrLf<\/span>\r\n     strJSON = strJSON & \"    }\" & <span style=\"color:blue;\">vbCrLf<\/span>\r\n     strJSON = strJSON & \"  ]\" & <span style=\"color:blue;\">vbCrLf<\/span>\r\n     strJSON = strJSON & \"}\" & <span style=\"color:blue;\">vbCrLf<\/span>\r\n     JSONBeispielsendung = strJSON\r\n<span style=\"color:blue;\">End Function<\/span><\/pre>\n<p><b><span style=\"color:darkgrey;\">Listing 2: Diese Funktion stellt das JSON-Dokument mit den Paketdaten zusammen.<\/span><\/b><\/p>\n<p>Danach ruft die die Funktion <b>APIOrder <\/b>auf, der sie alle notwendigen Variablen &uuml;bergibt &#8211; diese beschreiben wir im Anschluss mit der Funktion <b>APIOrder<\/b>.<\/p>\n<h2>Funktion zum Ausf&uuml;hren der API-Funktion Order<\/h2>\n<p>Die Funktion <b>APIOrder <\/b>erwartet die folgenden Parameter (siehe Listing 3):<\/p>\n<pre><span style=\"color:blue;\">Public Function <\/span>APIOrder(strData<span style=\"color:blue;\"> As String<\/span>, strPathPDF<span style=\"color:blue;\"> As String<\/span>, <span style=\"color:blue;\">Optional<\/span> strResponse<span style=\"color:blue;\"> As String<\/span>, _\r\n         <span style=\"color:blue;\">Optional<\/span> lngStatus<span style=\"color:blue;\"> As Long<\/span>, <span style=\"color:blue;\">Optional<\/span> bolValidate<span style=\"color:blue;\"> As Boolean<\/span>, <span style=\"color:blue;\">Optional<\/span> bolProductive<span style=\"color:blue;\"> As Boolean<\/span>)<span style=\"color:blue;\"> As String<\/span>\r\n     <span style=\"color:blue;\">Dim <\/span>strMethod<span style=\"color:blue;\"> As String<\/span>\r\n     <span style=\"color:blue;\">Dim <\/span>strURL<span style=\"color:blue;\"> As String<\/span>\r\n     <span style=\"color:blue;\">Dim <\/span>objJSON<span style=\"color:blue;\"> As Object<\/span>\r\n     <span style=\"color:blue;\">Dim <\/span>strFile<span style=\"color:blue;\"> As String<\/span>\r\n     strURL = GetURL(bolProductive) & \"orders\"\r\n     <span style=\"color:blue;\">If <\/span>bolValidate = <span style=\"color:blue;\">True<\/span><span style=\"color:blue;\"> Then<\/span>\r\n         strURL = strURL & \"?validate=true\"\r\n     <span style=\"color:blue;\">End If<\/span>\r\n     strMethod = \"POST\"\r\n     lngStatus = HTTPRequest(strURL, strMethod, , strData, strResponse, bolProductive)\r\n     Select Case lngStatus\r\n         <span style=\"color:blue;\">Case <\/span>200\r\n             <span style=\"color:blue;\">Debug.Print<\/span> GetJSONDOM(strResponse, <span style=\"color:blue;\">True<\/span>)\r\n             <span style=\"color:blue;\">Set<\/span> objJSON = ParseJson(strResponse)\r\n             <span style=\"color:blue;\">If <\/span>bolValidate = <span style=\"color:blue;\">False<\/span><span style=\"color:blue;\"> Then<\/span>\r\n                 strFile = objJSON.Item(\"items\").Item(1).Item(\"label\").Item(\"b64\")\r\n                 WriteFileFromBytes strPathPDF, DecodeBase64(strFile)\r\n             <span style=\"color:blue;\">End If<\/span>\r\n             APIOrder = <span style=\"color:blue;\">True<\/span>\r\n         <span style=\"color:blue;\">Case Else<\/span>\r\n             <span style=\"color:blue;\">Debug.Print<\/span> GetJSONDOM(strResponse, <span style=\"color:blue;\">True<\/span>)\r\n             APIOrder = <span style=\"color:blue;\">False<\/span>\r\n     <span style=\"color:blue;\">End Select<\/span>\r\n     Inzwischenablage strResponse\r\n<span style=\"color:blue;\">End Function<\/span><\/pre>\n<p><b><span style=\"color:darkgrey;\">Listing 3: Die Funktion APIOrder &uuml;bergibt den Request an die Funktion HTTPRequest und wertet die Antwort aus.<\/span><\/b><\/p>\n<ul>\n<li><b>strData<\/b>: JSON-Dokument mit den Daten f&uuml;r die DHL-Versandmarke<\/li>\n<li><b>strPathPDF<\/b>: Pfad, unter dem das erzeugte PDF-Dokument gespeichert werden soll<\/li>\n<li><b>strResponse<\/b>: Antwort des API-Aufrufs<\/li>\n<li><b>lngStatus<\/b>: Status des Aufrufs<\/li>\n<li><b>bolValidate<\/b>: Gibt an, ob der Aufruf nur der Validierung dienen soll. Der Wert <b>False <\/b>sorgt daf&uuml;r, dass der Aufruf nur getestet wird.<\/li>\n<li><b>bolProductive<\/b>: Gibt an, ob die Sandbox- oder die Produktiv-API genutzt werden soll.<\/li>\n<\/ul>\n<p>Die Funktion legt als Methode <b>POST <\/b>und als URL die URL fest, die der mit <b>bolProductive <\/b>festgelegten Plattform entspricht. Wenn der Parameter <b>bolValidate True <\/b>ist, h&auml;ngt sie noch den Ausdruck <b>?validate=true <\/b>an die URL an, damit nur ein Test der API gefahren wird. Dann ruft sie <b>HTTPRequest <\/b>auf und &uuml;bergibt die notwendigen Parameter. Liefert diese den Status <b>200 <\/b>zur&uuml;ck, gibt sie testweise das Ergebnis im Direktbereich aus. Au&szlig;erdem erstellt sie mit der Funktion <b>ParseJson <\/b>in <b>objJSON <\/b>ein Objekt auf Basis der zur&uuml;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 <b>WriteFileFromBytes <\/b>in eine Datei mit dem Dateinamen aus <b>strPathPDF<\/b>.<\/p>\n<p>Die frisch erstellte Versandmarke ruft die Funktion <b>OpenDocument <\/b>auf, um das Dokument wie in Bild 10 anzuzeigen.<\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2024_04\/pic_429_010.png\" alt=\"Beispiel f&uuml;r eine frisch erstellte Versandmarke\" width=\"424,6267\" height=\"670,4635\" \/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 10: Beispiel f&uuml;r eine frisch erstellte Versandmarke<\/span><\/b><\/p>\n<h2>Von der Sandbox zum Produktivbetrieb<\/h2>\n<p>Damit haben wir schon einmal sichergestellt, dass der Code grunds&auml;tzlich funktioniert. Bevor wir diesen so erweitern, dass wir die Empf&auml;ngeradresse und die Paketdaten aus einer Tabelle oder einem Formular entnehmen, wollen wir jedoch noch den Produktivbetrieb testen. Dazu stellen wir als Erstes den Aufruf der Funktion <b>APIOrder <\/b>in der Prozedur <b>Test_APIOrder <\/b>so um, dass der Produktivmodus verwendet wird. Gleichzeitig stellen wir den vorletzten Parameter auf den Wert <b>True <\/b>ein, damit wir den Aufruf erst einmal validieren k&ouml;nnen:<\/p>\n<pre><span style=\"color:blue;\">If <\/span>APIOrder(strData, strPathPDF, strResponse, lngStatus, True, <span style=\"color:blue;\">True<\/span>) = <span style=\"color:blue;\">True<\/span><span style=\"color:blue;\"> Then<\/span>\r\n...<\/pre>\n<p>Dabei hagelt es erst einmal Fehler, die wir zum Beispiel im Direktbereich wie in Bild 11 einsehen k&ouml;nnen. <\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2024_04\/pic_429_011.png\" alt=\"R&uuml;ckmeldung des fehlerhaften Aufrufs\" width=\"700\" height=\"182,3683\" \/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 11: R&uuml;ckmeldung des fehlerhaften Aufrufs<\/span><\/b><\/p>\n<p>In unserem Fall liegen die Fehler daran, dass wir zwar ein DHL-Gesch&auml;ftskundenkonto haben, aber keinen g&uuml;ltigen Vertrag, um Pakete zu Gesch&auml;ftskundenkonditionen zu verschicken. DHL war auch nicht bereit, uns zu Testzwecken einen entsprechenden Vertrag bereitzustellen.<\/p>\n<p>Wir haben die hier vorgestellte L&ouml;sung jedoch zusammen mit einem Kunden getestet und das Beispiel lief wie gew&uuml;nscht durch.<\/p>\n<h2>Zusammenstellung des JSON-Dokuments optimieren<\/h2>\n<p>Das JSON-Dokument hatten wir bisher zu Testzwecken einfach in vielen Anweisungen per Zeichenverkettung zeilenweise zusammengesetzt. Dies wollen wir nun optimieren, um einfacher und fehlerloser neue Elemente hinzuf&uuml;gen zu k&ouml;nnen. Dabei wollen wir dieses gleichzeitig in eine Klasse einarbeiten, der wir noch einige Eigenschaften hinzuf&uuml;gen, mit denen der Benutzer die Informationen &uuml;ber den Versender, den Empf&auml;nger und so weiter hinzuf&uuml;gen kann. Dazu verwenden wir zun&auml;chst einmal eine Prozedur, welche die in den Eigenschaften vorhandenen Informationen in einen JSON-Ausdruck umwandelt.<\/p>\n<p>Dabei greifen wir auf die bew&auml;hrte Technik zur&uuml;ck, ein aus Dictionarys und Collections bestehendes Konstrukt zu erstellen und dieses dann mit der Funktion <b>ConvertToJSON<\/b> in das JSON-Dokument umzuwandeln.<\/p>\n<h2>Klasse erstellen<\/h2>\n<p>Dazu erstellen wir eine Klasse namens <b>clsShipment<\/b>. Diese enth&auml;lt zun&auml;chst jeweils eine Variable f&uuml;r die aktuell von dieser L&ouml;sung unterst&uuml;tzten Informationen:<\/p>\n<pre><span style=\"color:blue;\">Private <\/span>m_Produkt<span style=\"color:blue;\"> As String<\/span>\r\n<span style=\"color:blue;\">Private <\/span>m_BillingNumber<span style=\"color:blue;\"> As String<\/span>\r\n<span style=\"color:blue;\">Private <\/span>m_RefNo<span style=\"color:blue;\"> As String<\/span>\r\n<span style=\"color:blue;\">Private <\/span>m_Shipper_Name1<span style=\"color:blue;\"> As String<\/span>\r\n<span style=\"color:blue;\">Private <\/span>m_Shipper_AddressStreet<span style=\"color:blue;\"> As String<\/span>\r\n<span style=\"color:blue;\">Private <\/span>m_Shipper_PostalCode<span style=\"color:blue;\"> As String<\/span>\r\n<span style=\"color:blue;\">Private <\/span>m_Shipper_City<span style=\"color:blue;\"> As String<\/span>\r\n<span style=\"color:blue;\">Private <\/span>m_Shipper_Country<span style=\"color:blue;\"> As String<\/span>\r\n<span style=\"color:blue;\">Private <\/span>m_Shipper_Email<span style=\"color:blue;\"> As String<\/span>\r\n<span style=\"color:blue;\">Private <\/span>m_Shipper_Phone<span style=\"color:blue;\"> As String<\/span>\r\n<span style=\"color:blue;\">Private <\/span>m_Consignee_Name1<span style=\"color:blue;\"> As String<\/span>\r\n<span style=\"color:blue;\">Private <\/span>m_Consignee_AddressStreet<span style=\"color:blue;\"> As String<\/span>\r\n<span style=\"color:blue;\">Private <\/span>m_Consignee_AdditionalAddressInformation1<span style=\"color:blue;\"> As String<\/span>\r\n<span style=\"color:blue;\">Private <\/span>m_Consignee_PostalCode<span style=\"color:blue;\"> As String<\/span>\r\n<span style=\"color:blue;\">Private <\/span>m_Consignee_City<span style=\"color:blue;\"> As String<\/span>\r\n<span style=\"color:blue;\">Private <\/span>m_Consignee_Country<span style=\"color:blue;\"> As String<\/span>\r\n<span style=\"color:blue;\">Private <\/span>m_Consignee_Email<span style=\"color:blue;\"> As String<\/span>\r\n<span style=\"color:blue;\">Private <\/span>m_Consignee_Phone<span style=\"color:blue;\"> As String<\/span>\r\n<span style=\"color:blue;\">Private <\/span>m_Details_Dim_Uom<span style=\"color:blue;\"> As String<\/span>\r\n<span style=\"color:blue;\">Private <\/span>m_Details_Dim_Height<span style=\"color:blue;\"> As Currency<\/span>\r\n<span style=\"color:blue;\">Private <\/span>m_Details_Dim_Length<span style=\"color:blue;\"> As Currency<\/span>\r\n<span style=\"color:blue;\">Private <\/span>m_Details_Dim_Width<span style=\"color:blue;\"> As Currency<\/span>\r\n<span style=\"color:blue;\">Private <\/span>m_Details_Weight_Uom<span style=\"color:blue;\"> As String<\/span>\r\n<span style=\"color:blue;\">Private <\/span>m_Details_Weight_Value<span style=\"color:blue;\"> As Currency<\/span><\/pre>\n<p>Um diese Variablen zu f&uuml;llen, die sp&auml;ter wiederum zum Zusammenstellen des JSON-Dokuments genutzt werden, legen wir f&uuml;r jede Variable eine &ouml;ffentliche <b>Property Let<\/b>-Prozedur an &#8211; hier nur beispielhaft f&uuml;r einige der Variablen:<\/p>\n<pre><span style=\"color:blue;\">Public Property Let <\/span>Produkt(str<span style=\"color:blue;\"> As String<\/span>)\r\n     m_Produkt = str\r\n<span style=\"color:blue;\">End Property<\/span>\r\n<span style=\"color:blue;\">Public Property Let <\/span>BillingNumber(str<span style=\"color:blue;\"> As String<\/span>)\r\n     m_BillingNumber = str\r\n<span style=\"color:blue;\">End Property<\/span>\r\n<span style=\"color:blue;\">Public Property Let <\/span>RefNo(str<span style=\"color:blue;\"> As String<\/span>)\r\n     m_RefNo = str\r\n<span style=\"color:blue;\">End Property<\/span>\r\n<span style=\"color:blue;\">Public Property Let <\/span>Shipper_Name1(str<span style=\"color:blue;\"> As String<\/span>)\r\n     m_Shipper_Name1 = str\r\n<span style=\"color:blue;\">End Property<\/span>\r\n<span style=\"color:blue;\">Public Property Let <\/span>Shipper_AddressStreet(str<span style=\"color:blue;\"> As String<\/span>)\r\n     m_Shipper_AddressStreet = str\r\n<span style=\"color:blue;\">End Property<\/span>\r\n<span style=\"color:blue;\">Public Property Let <\/span>Shipper_PostalCode(str<span style=\"color:blue;\"> As String<\/span>)\r\n     m_Shipper_PostalCode = str\r\n<span style=\"color:blue;\">End Property<\/span>\r\n<span style=\"color:blue;\">Public Property Let <\/span>Shipper_City(str<span style=\"color:blue;\"> As String<\/span>)\r\n     m_Shipper_City = str\r\n<span style=\"color:blue;\">End Property<\/span>\r\n<span style=\"color:blue;\">Public Property Let <\/span>Shipper_Country(str<span style=\"color:blue;\"> As String<\/span>)\r\n     m_Shipper_Country = str\r\n<span style=\"color:blue;\">End Property<\/span>\r\n<span style=\"color:blue;\">Public Property Let <\/span>Shipper_Email(str<span style=\"color:blue;\"> As String<\/span>)\r\n     m_Shipper_Email = str\r\n<span style=\"color:blue;\">End Property<\/span><\/pre>\n<p>Diese &ouml;ffentlichen <b>Property Let<\/b>-Prozeduren erlauben es, der Klasse nach dem Initialisieren die Werte f&uuml;r die verschiedenen Eigenschaften hinzuzuf&uuml;gen.<\/p>\n<h2>JSON-Dokument f&uuml;r Shipment zusammenstellen<\/h2>\n<p>Damit kommen wir zum Arbeitstier der Klasse &#8211; die Prozedur <b>CreateJSONRequest<\/b>. Diese soll die Werte der Eigenschaften, sofern diese &uuml;bergeben wurden, zu einem g&uuml;ltigen JSON-Dokument zusammensetzen. <\/p>\n<p>Und hier wird es spannend. W&auml;hrend wir in dem ersten Beispiel einfach nur fiktive Informationen zusammengestellt haben, die alle vollst&auml;ndig waren, wollen wir nun dem Benutzer erm&ouml;glichen, auch einmal nur die notwendigsten Informationen einzutragen. Dazu m&uuml;ssen wir allerdings erst einmal wissen, welche Informationen das sind. DHL hat dazu ein Dokument zusammengestellt, das wir hier einsehen k&ouml;nnen:<\/p>\n<pre>https:\/\/developer.dhl.com\/api-reference\/parcel-de-shipping-post-parcel-germany-v2#additional-information-section<\/pre>\n<p>Das Dokument liefert uns alle Elemente und ihre hierarchische Anordnung und gibt auch an, ob es sich um Pflichtelement handelt (erkennbar am roten Sternchen) und in welcher Anzahl diese vorkommen d&uuml;rfen (siehe Bild 12). Die Pflichtfelder sind anscheinend nicht korrekt markiert &#8211; zum Beispiel ist die <b>BillingNumber<\/b> nicht als Pflichtfeld gekennzeichnet, wird aber zwingend ben&ouml;tigt, da sonst ein Fehler auftritt.<\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2024_04\/pic_429_012.png\" alt=\"Dokumentation der Elemente des JSON-Dokuments\" width=\"700\" height=\"475,3566\" \/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 12: Dokumentation der Elemente des JSON-Dokuments<\/span><\/b><\/p>\n<p>Anhand der Informationen, die wir durch Tests ermittelt haben, wollen wir jedoch die zwingend notwendigen Elemente und diejenigen, die nicht unbedingt angegeben werden m&uuml;ssen, dadurch unterscheiden, dass wir die freiwilligen Elemente gar nicht erst in das JSON-Dokument einbinden, wenn diese nicht angegeben wurden.<\/p>\n<p>Das sehen wir in der Funktion <b>CreateJSONRequest<\/b>, deren ersten Teil wir in Listing 4 abbilden. Hier bauen wir eine Struktur aus <b>Dictionary<\/b>&#8211; und <b>Collection<\/b>-Elementen auf. Jedes JSON-Element, das mit geschweiften Klammern eingefasst ist, wird dabei durch ein <b>Dictionary<\/b>-Element abgebildet, jedes mit eckigen Klammern durch ein <b>Collection<\/b>-Objekt.<\/p>\n<pre><span style=\"color:blue;\">Public Function <\/span>CreateJSONRequest()<span style=\"color:blue;\"> As String<\/span>\r\n     <span style=\"color:blue;\">Dim <\/span>dicMain<span style=\"color:blue;\"> As <\/span>Dictionary\r\n     <span style=\"color:blue;\">Dim <\/span>colShipments<span style=\"color:blue;\"> As <\/span>Collection\r\n     <span style=\"color:blue;\">Dim <\/span>dicShipments<span style=\"color:blue;\"> As <\/span>Dictionary\r\n     <span style=\"color:blue;\">Dim <\/span>dicShipper<span style=\"color:blue;\"> As <\/span>Dictionary\r\n     <span style=\"color:blue;\">Dim <\/span>dicConsignee<span style=\"color:blue;\"> As <\/span>Dictionary\r\n     <span style=\"color:blue;\">Dim <\/span>dicDetails<span style=\"color:blue;\"> As <\/span>Dictionary\r\n     <span style=\"color:blue;\">Dim <\/span>dicDim<span style=\"color:blue;\"> As <\/span>Dictionary\r\n     <span style=\"color:blue;\">Dim <\/span>dicWeight<span style=\"color:blue;\"> As <\/span>Dictionary\r\n     <span style=\"color:blue;\">Set<\/span> dicMain = <span style=\"color:blue;\">New<\/span> Dictionary\r\n     <span style=\"color:blue;\">Set<\/span> colShipments = <span style=\"color:blue;\">New<\/span> Collection\r\n     dicMain.Add \"shipments\", colShipments\r\n     <span style=\"color:blue;\">Set<\/span> dicShipments = <span style=\"color:blue;\">New<\/span> Dictionary\r\n     colShipments.Add dicShipments\r\n     dicShipments.Add \"product\", m_Produkt\r\n     dicShipments.Add \"billingNumber\", m_BillingNumber\r\n     dicShipments.Add \"refNo\", m_RefNo\r\n     <span style=\"color:blue;\">Set<\/span> dicShipper = <span style=\"color:blue;\">New<\/span> Dictionary\r\n     dicShipments.Add \"shipper\", dicShipper\r\n     dicShipper.Add \"name1\", m_Shipper_Name1\r\n     dicShipper.Add \"addressStreet\", m_Shipper_AddressStreet\r\n     dicShipper.Add \"postalCode\", m_Shipper_PostalCode\r\n     dicShipper.Add \"city\", m_Shipper_City\r\n     dicShipper.Add \"country\", m_Shipper_Country\r\n     <span style=\"color:blue;\">If <\/span><span style=\"color:blue;\">Not<\/span> <span style=\"color:blue;\">Len<\/span>(m_Shipper_Email) = 0<span style=\"color:blue;\"> Then<\/span>\r\n         dicShipper.Add \"email\", m_Shipper_Email\r\n     <span style=\"color:blue;\">End If<\/span>\r\n     <span style=\"color:blue;\">If <\/span><span style=\"color:blue;\">Not<\/span> <span style=\"color:blue;\">Len<\/span>(m_Shipper_Phone) = 0<span style=\"color:blue;\"> Then<\/span>\r\n         dicShipper.Add \"phone\", m_Shipper_Phone\r\n     <span style=\"color:blue;\">End If<\/span>\r\n     ...<\/pre>\n<p><b><span style=\"color:darkgrey;\">Listing 4: Funktion zum Zusammenstellen einer Objekthierarchie mit dem JSON-Dokument (Teil 1)<\/span><\/b><\/p>\n<p>Hier erstellen wir zuerst ein &uuml;bergeordnetes Element namens <b>objMain<\/b>, dessen erstes Element <b>shipments<\/b> hei&szlig;t und mehrere in eckigen Klammern eingefasste Elemente enthalten kann. Diesem ordnen wir ein Element namens <b>colShipments <\/b>unter, das wiederum das Element <b>dicShipments <\/b>enth&auml;lt. F&uuml;r dieses legen wir einige Name-Wert-Paare fest, beispielsweise f&uuml;r das Produkt, die Abrechnungsnummer und die Referenznummer. Danach folgt ein weiteres Unterelement namens <b>shipper<\/b>, dem wir weitere Name-Wert-Paare mit den Adressdaten des Versenders hinzuf&uuml;gen.<\/p>\n<p>Hier pr&uuml;fen wir bei zwei Eigenschaften, ob diese &uuml;berhaupt gef&uuml;llt sind &#8211; E-Mail-Adresse und die Telefonnummer -, und legen nur dann die entsprechenden Elemente an.<\/p>\n<p>In Listing 5 geht es mit dem Element f&uuml;r den Empf&auml;nger weiter. Hier geben wir die gleichen Informationen wir f&uuml;r den Absender ein und noch eine zus&auml;tzliche Adressinformation. Danach folgt noch ein weiteres Unterelement namens <b>details<\/b>. Dieses enth&auml;lt unter anderem die Abmessungen des Pakets (<b>dim<\/b>) sowie das Gewicht samt Einheiten (<b>weight<\/b>).<\/p>\n<pre>     ...\r\n     <span style=\"color:blue;\">Set<\/span> dicConsignee = <span style=\"color:blue;\">New<\/span> Dictionary\r\n     dicShipments.Add \"consignee\", dicConsignee\r\n     dicConsignee.Add \"name1\", m_Consignee_Name1\r\n     dicConsignee.Add \"addressStreet\", m_Consignee_AddressStreet\r\n     <span style=\"color:blue;\">If <\/span><span style=\"color:blue;\">Not<\/span> <span style=\"color:blue;\">Len<\/span>(m_Consignee_AdditionalAddressInformation1) = 0<span style=\"color:blue;\"> Then<\/span>\r\n         dicConsignee.Add \"additionalAddressInformation1\", m_Consignee_AdditionalAddressInformation1\r\n     <span style=\"color:blue;\">End If<\/span>\r\n     dicConsignee.Add \"postalCode\", m_Consignee_PostalCode\r\n     dicConsignee.Add \"city\", m_Consignee_City\r\n     dicConsignee.Add \"country\", m_Consignee_Country\r\n     <span style=\"color:blue;\">If <\/span><span style=\"color:blue;\">Not<\/span> <span style=\"color:blue;\">Len<\/span>(m_Consignee_Email) = 0<span style=\"color:blue;\"> Then<\/span>\r\n         dicConsignee.Add \"email\", m_Consignee_Email\r\n     <span style=\"color:blue;\">End If<\/span>\r\n     <span style=\"color:blue;\">If <\/span><span style=\"color:blue;\">Not<\/span> <span style=\"color:blue;\">Len<\/span>(m_Consignee_Phone)<span style=\"color:blue;\"> Then<\/span>\r\n         dicConsignee.Add \"phone\", m_Consignee_Phone\r\n     <span style=\"color:blue;\">End If<\/span>\r\n     <span style=\"color:blue;\">Set<\/span> dicDetails = <span style=\"color:blue;\">New<\/span> Dictionary\r\n     <span style=\"color:blue;\">Set<\/span> dicDim = <span style=\"color:blue;\">New<\/span> Dictionary\r\n     dicShipments.Add \"details\", dicDetails\r\n     dicDetails.Add \"dim\", dicDim\r\n     dicDim.Add \"uom\", m_Details_Dim_Uom\r\n     dicDim.Add \"height\", m_Details_Dim_Height\r\n     dicDim.Add \"length\", m_Details_Dim_Length\r\n     dicDim.Add \"width\", m_Details_Dim_Width\r\n     <span style=\"color:blue;\">Set<\/span> dicWeight = <span style=\"color:blue;\">New<\/span> Dictionary\r\n     dicDetails.Add \"weight\", dicWeight\r\n     dicWeight.Add \"uom\", m_Details_Weight_Uom\r\n     dicWeight.Add \"value\", m_Details_Weight_Value\r\n     CreateJSONRequest = ConvertToJson(dicMain)\r\n<span style=\"color:blue;\">End Function<\/span><\/pre>\n<p><b><span style=\"color:darkgrey;\">Listing 5: Funktion zum Zusammenstellen einer Objekthierarchie mit dem JSON-Dokument (Teil 2)<\/span><\/b><\/p>\n<p>Schlie&szlig;lich ruft die Routine die Funktion <b>ConvertToJson <\/b>auf und gibt die ermittelte JSON-Anweisung an die aufrufende Prozedur zur&uuml;ck.<\/p>\n<h2>Steuerung der Labelerstellung<\/h2>\n<p>F&uuml;r die Steuerung der Labelerstellung ziehen wir die bereits weiter oben vorgestellte Funktion <b>APIOrder<\/b> diesmal unter dem Namen <b>GetShipmentLabel <\/b>ebenfalls in die Klasse hinein. Die Parameter, die wir <b>APIOrder<\/b> noch direkt &uuml;bergeben haben, legen wir ebenfalls als &ouml;ffentliche Eigenschaften der Klasse an. Diese deklarieren wir wie folgt im Kopf des Klassenmoduls:<\/p>\n<pre><span style=\"color:blue;\">Private <\/span>m_PathPDF<span style=\"color:blue;\"> As String<\/span>\r\n<span style=\"color:blue;\">Private <\/span>m_Productive<span style=\"color:blue;\"> As Boolean<\/span>\r\n<span style=\"color:blue;\">Private <\/span>m_Validate<span style=\"color:blue;\"> As Boolean<\/span>\r\n<span style=\"color:blue;\">Private <\/span>m_Response<span style=\"color:blue;\"> As String<\/span>\r\n<span style=\"color:blue;\">Private <\/span>m_Status<span style=\"color:blue;\"> As Long<\/span>\r\n<span style=\"color:blue;\">Private <\/span>m_PrintFormat<span style=\"color:blue;\"> As String<\/span><\/pre>\n<p>Zum Einstellen legen wir ebenfalls &ouml;ffentliche <b>Property Let<\/b>-Prozeduren wie die folgende an:<\/p>\n<pre><span style=\"color:blue;\">Public Property Let <\/span>PrintFormat(str<span style=\"color:blue;\"> As String<\/span>)\r\n     m_PrintFormat = str\r\n<span style=\"color:blue;\">End Property<\/span>\r\n<span style=\"color:blue;\">Public Property Get <\/span>PrintFormat()<span style=\"color:blue;\"> As String<\/span>\r\n     PrintFormat = m_PrintFormat\r\n<span style=\"color:blue;\">End Property<\/span><\/pre>\n<p>Alle Eigenschaften werden mit Getter und Setter angelegt. Dazu haben wir &uuml;brigens das im Artikel <b>Klassenprogrammierung mit COM-Add-In vereinfachen <\/b>(<b>www.vbentwickler.de\/433<\/b>) vorgestellte COM-Add-In genutzt. Die Funktion <b>GetShipmentLabel<\/b> selbst sieht nun wie in Listing 6 aus. Die Funktion hat, wie erw&auml;hnt, keine Parameter mehr, sondern holt sich alle notwendigen Informationen aus den Variablen wie <b>m_PathPDF <\/b>oder <b>m_Validate<\/b>. Ansonsten funktioniert sie genau wie die weiter oben bereits vorgestellte Funktion.<\/p>\n<pre><span style=\"color:blue;\">Public Function <\/span>GetShipmentLabel()<span style=\"color:blue;\"> As Boolean<\/span>\r\n     <span style=\"color:blue;\">Dim <\/span>strMethod<span style=\"color:blue;\"> As String<\/span>\r\n     <span style=\"color:blue;\">Dim <\/span>strURL<span style=\"color:blue;\"> As String<\/span>\r\n     <span style=\"color:blue;\">Dim <\/span>objJSON<span style=\"color:blue;\"> As Object<\/span>\r\n     <span style=\"color:blue;\">Dim <\/span>strFile<span style=\"color:blue;\"> As String<\/span>\r\n     <span style=\"color:blue;\">If <\/span><span style=\"color:blue;\">Len<\/span>(m_PathPDF) = 0<span style=\"color:blue;\"> Then<\/span>\r\n         <span style=\"color:blue;\">MsgBox<\/span> \"PathPDF nicht angegeben.\"\r\n         <span style=\"color:blue;\">Exit Function<\/span>\r\n     <span style=\"color:blue;\">End If<\/span>\r\n     strURL = GetURL(m_Productive) & \"orders\"\r\n     <span style=\"color:blue;\">If <\/span>m_Validate = <span style=\"color:blue;\">True<\/span><span style=\"color:blue;\"> Then<\/span>\r\n         strURL = strURL & \"?validate=true\"\r\n     <span style=\"color:blue;\">End If<\/span>\r\n     <span style=\"color:blue;\">If <\/span><span style=\"color:blue;\">Not<\/span> <span style=\"color:blue;\">Len<\/span>(m_PrintFormat) = 0<span style=\"color:blue;\"> Then<\/span>\r\n         strURL = strURL & \"?printFormat=\" & m_PrintFormat\r\n     <span style=\"color:blue;\">End If<\/span>\r\n     ...\r\n     strMethod = \"POST\"\r\n     m_Status = HTTPRequest(strURL, strMethod, , CreateJSONRequest, m_Response, m_Productive)\r\n     Select Case m_Status\r\n         <span style=\"color:blue;\">Case <\/span>200\r\n             <span style=\"color:blue;\">Set<\/span> objJSON = ParseJson(m_Response)\r\n             <span style=\"color:blue;\">If <\/span>m_Validate = <span style=\"color:blue;\">False<\/span><span style=\"color:blue;\"> Then<\/span>\r\n                 strFile = objJSON.Item(\"items\").Item(1).Item(\"label\").Item(\"b64\")\r\n                 WriteFileFromBytes m_PathPDF, DecodeBase64(strFile)\r\n             <span style=\"color:blue;\">End If<\/span>\r\n             GetShipmentLabel = <span style=\"color:blue;\">True<\/span>\r\n         <span style=\"color:blue;\">Case Else<\/span>\r\n             GetShipmentLabel = <span style=\"color:blue;\">False<\/span>\r\n     <span style=\"color:blue;\">End Select<\/span>\r\n<span style=\"color:blue;\">End Function<\/span><\/pre>\n<p><b><span style=\"color:darkgrey;\">Listing 6: Prozedur zum Holen des Versandlabels<\/span><\/b><\/p>\n<p>Die Ergebnisse kann man nach dem Aufruf aus den &ouml;ffentlichen Eigenschaften der Klasse auslesen.<\/p>\n<p>Auch die Funktion <b>HTTPRequest <\/b>haben wir in die Klasse integriert, diese brauchen wir aber nicht erneut abzubilden, da sie der oben vorgestellten Variante entspricht.<\/p>\n<h2>Erstellen eines Versandlabels &uuml;ber die Klasse clsShipment<\/h2>\n<p>Um die Klasse nun zu nutzen, verwenden wie die Prozedur, die wir in Listing 7 dargestellt haben. Diese deklariert eine Objektvariable namens <b>objShipment <\/b>auf Basis der Klasse <b>clsShipment<\/b>. Dann erstellt sie ein Objekt auf Basis dieser Klasse und referenziert es mit <b>objShipment<\/b>.<\/p>\n<pre><span style=\"color:blue;\">Public Function <\/span>CreateJSONRequest()<span style=\"color:blue;\"> As String<\/span>\r\n     <span style=\"color:blue;\">Dim <\/span>objShipment<span style=\"color:blue;\"> As <\/span>clsShipment\r\n     <span style=\"color:blue;\">Dim <\/span>bolProductive<span style=\"color:blue;\"> As Boolean<\/span>\r\n     <span style=\"color:blue;\">Set<\/span> objShipment = <span style=\"color:blue;\">New<\/span> clsShipment\r\n     bolProductive = <span style=\"color:blue;\">False<\/span>\r\n     <span style=\"color:blue;\">With<\/span> objShipment\r\n         .Produkt = \"V01PAK\"\r\n         .BillingNumber = GetBillingNumber(bolProductive)\r\n         .RefNo = \"Order No. 1234\"\r\n         .Shipper_Name1 = \"Minhorst und Minhorst GbR\"\r\n         .Shipper_AddressStreet = \"Borkhofer Str. 17\"\r\n         .Shipper_PostalCode = \"47137\"\r\n         .Shipper_City = \"Duisburg\"\r\n         .Shipper_Country = \"DEU\"\r\n         .Shipper_Email = \"andre@minhorst.com\"\r\n         .Shipper_Phone = \"0171-3145654\"\r\n         .Consignee_Name1 = \"Maria Musterfrau\"\r\n         .Consignee_AddressStreet = \"Kurt-Schumacher-Str. 20\"\r\n         .Consignee_AdditionalAddressInformation1 = \"Apartment 107\"\r\n         .Consignee_PostalCode = \"53113\"\r\n         .Consignee_City = \"Bonn\"\r\n         .Consignee_Country = \"DEU\"\r\n         .Consignee_Email = \"maria@musterfrau.de\"\r\n         .Consignee_Phone = \"+ 987654321\"\r\n         .Details_Dim_Uom = \"mm\"\r\n         .Details_Dim_Height = 100\r\n         .Details_Dim_Length = 200\r\n         .Details_Dim_Width = 150\r\n         .Details_Weight_Uom = \"g\"\r\n         .Details_Weight_Value = 500\r\n         .PathPDF = CurrentProject.Path & \"\\Test1.pdf\"\r\n         .PrintFormat = \"910-300-600\"\r\n         .Productive = <span style=\"color:blue;\">False<\/span>\r\n         .Validate = <span style=\"color:blue;\">False<\/span>\r\n         <span style=\"color:blue;\">If <\/span>.GetShipmentLabel = <span style=\"color:blue;\">True<\/span><span style=\"color:blue;\"> Then<\/span>\r\n             <span style=\"color:blue;\">MsgBox<\/span> \"Erstellung erfolgreich: \" & <span style=\"color:blue;\">vbCrLf<\/span> & <span style=\"color:blue;\">vbCrLf<\/span> & .Response\r\n             OpenDocument .PathPDF\r\n         <span style=\"color:blue;\">Else<\/span>\r\n             <span style=\"color:blue;\">MsgBox<\/span> \"Erstellung nicht erfolgreich: \" & <span style=\"color:blue;\">vbCrLf<\/span> & <span style=\"color:blue;\">vbCrLf<\/span> & .Response\r\n         <span style=\"color:blue;\">End If<\/span>\r\n     End <span style=\"color:blue;\">With<\/span>\r\n<span style=\"color:blue;\">End Function<\/span><\/pre>\n<p><b><span style=\"color:darkgrey;\">Listing 7: Verwendung der Klasse clsShipment<\/span><\/b><\/p>\n<p>Nun stellen wir die Eigenschaften der Klasse f&uuml;r das Versandlabel ein. Als Erstes geben wir die allgemeinen Informationen an, also das zu erstellende Produkt, die Abrechnungsnummer und die Referenznummer.<\/p>\n<p>Dann folgen der Name des Versenders und seine &uuml;brigen Daten &#8211; Stra&szlig;e, PLZ, Stadt und Land. Das Land geben wir als dreistelligen L&auml;ndercode an. Die verf&uuml;gbaren Codes sind im Beispielcode abgebildet. Danach f&uuml;gen wir noch eine E-Mail-Adresse sowie die Telefonnummer des Absenders hinzu.<\/p>\n<p>Anschlie&szlig;end tragen wir die Adressdaten des Empf&auml;ngers des Pakets ein, deren Aufbau weitgehend denen des Absenders entspricht. Schlie&szlig;lich folgen noch die Abmessungen des Pakets (H&ouml;he, L&auml;nge und Breite) sowie das Gewicht, beides jeweils mit der verwendeten Einheit.<\/p>\n<p>Schlie&szlig;lich folgen die f&uuml;r das Anlegen notwendigen Daten: <b>PathPDF <\/b>nimmt den Pfad f&uuml;r das zu erstellende PDF-Dokument auf und <b>PrintFormat <\/b>eines der verf&uuml;gbaren Printformate (diese sind ebenfalls im Quellcode der Klasse f&uuml;r die <b>Property Let<\/b>-Prozedur angegeben).<\/p>\n<p>Mit <b>Productive <\/b>geben wir an, ob wir den Sandbox-Modus verwenden oder die Produktivplattform. Mit <b>Validate <\/b>geben wir an, ob wir nur testen wollen, ob die Daten g&uuml;ltig sind.<\/p>\n<p>Schlie&szlig;lich rufen wir die Funktion <b>GetShipmentLabel <\/b>als Kriterium einer <b>If&#8230;Then<\/b>-Bedingung auf. Liefert diese den Wert <b>True <\/b>zur&uuml;ck, geben wir eine entsprechende Erfolgsmeldung aus und &ouml;ffnen das erstellte Dokument (siehe Bild 13). Im Falle eines Misserfolgs teilen wir dies ebenfalls per Meldungsfenster mit.<\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2024_04\/pic_429_013.png\" alt=\"Meldung im Erfolgsfall\" width=\"499,6267\" height=\"459,7049\"\/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 13: Meldung im Erfolgsfall<\/span><\/b><\/p>\n<h2>Erweitern der Versandinformationen<\/h2>\n<p>Die hier vorgestellte L&ouml;sung enth&auml;lt im Wesentlichen die mindestens erforderlichen Angaben f&uuml;r das Verwenden eines Pakets. Wenn Du weitere Elemente aus dem Data Schema der DHL hinzuf&uuml;gen m&ouml;chtest, erh&auml;ltst Du hier noch eine kurze Anleitung dazu.<\/p>\n<p>Angenommen, Du m&ouml;chtest f&uuml;r den Shipper auch noch das Feld <b>name2<\/b> verwenden. Dann sind die folgenden Schritte n&ouml;tig. <\/p>\n<p>Du f&uuml;gst dem Klassenmodul <b>clsShipment <\/b>eine private Variable f&uuml;r diesen Wert hinzu:<\/p>\n<pre><span style=\"color:blue;\">Private <\/span>m_Shipper_Name2<span style=\"color:blue;\"> As String<\/span><\/pre>\n<p>Dann legst Du eine entsprechende Getter- und Setter-Prozedur an:<\/p>\n<pre><span style=\"color:blue;\">Public Property Let <\/span>Shipper_Name2(str<span style=\"color:blue;\"> As String<\/span>)\r\n     m_Shipper_Name2 = str\r\n<span style=\"color:blue;\">End Property<\/span>\r\n<span style=\"color:blue;\">Public Property Get <\/span>Shipper_Name2()<span style=\"color:blue;\"> As String<\/span>\r\n     Shipper_Name2 = m_Shipper_Name2\r\n<span style=\"color:blue;\">End Property<\/span><\/pre>\n<p>Damit ist gew&auml;hrleistet, dass die Daten in der Klasse landen. Nun wollen wir diese verarbeiten.<\/p>\n<p>Dazu erweiterst Du die Funktion <b>CreateJSONRequest<\/b> an der entsprechenden Stelle um eine <b>If&#8230;Then<\/b>-Bedingung, die pr&uuml;ft, ob der Wert enthalten ist, und legst diesen dann als neues Element an:<\/p>\n<pre>...\r\ndicShipper.Add \"name1\", m_Shipper_Name1\r\n<span style=\"color:blue;\">If <\/span><span style=\"color:blue;\">Not<\/span> <span style=\"color:blue;\">Len<\/span>(m_Shipper_Name2) = 0<span style=\"color:blue;\"> Then<\/span>\r\n     dicShipper.Add \"name2\", m_Shipper_Name2\r\n<span style=\"color:blue;\">End If<\/span>\r\ndicShipper.Add \"addressStreet\", m_Shipper_AddressStreet\r\n...<\/pre>\n<p>Im Aufruf der Funktion f&uuml;gst Du nun den Wert f&uuml;r <b>Name2 <\/b>hinzu:<\/p>\n<pre>.Shipper_Name2 = \"Andr&eacute; Minhorst\"<\/pre>\n<p>Damit haben wir alle Schritte erledigt, die n&ouml;tig sind. Praktisch ist, dass wir beim Zusammenstellen des JSON-Dokuments nicht darauf achten m&uuml;ssen, ob wir hinten ein Komma anf&uuml;gen, ob wir einfache oder doppelte Anf&uuml;hrungszeichen setzen m&uuml;ssen und so weiter.<\/p>\n<p>Das Zusammenstellen des JSON-Dokuments &uuml;ber das Objektmodell ist wesentlich einfacher.<\/p>\n<h2>Zusammenfassung und Ausblick<\/h2>\n<p>Mit dieser L&ouml;sung kannst Du beliebigen Anwendungen die Funktion zum Erstellen von DHL-Versandetiketten hinzuf&uuml;gen.<\/p>\n<p>Dabei haben wir eine Basisversion geschaffen, die Du nach Wunsch um weitere Eigenschaften erweitern kannst &#8211; beispielsweise um weitere Absender- und Empf&auml;ngerdaten oder auch um alternative Empf&auml;ngerarten. Hier stehen verschiedene zur Verf&uuml;gung:<\/p>\n<ul>\n<li><b>Locker<\/b>: Packstation in Deutschland<\/li>\n<li><b>PostOffice<\/b>: Paketshops in Deutschland<\/li>\n<li><b>POBox<\/b>: Postf&auml;cher<\/li>\n<\/ul>\n<p>Au&szlig;erdem kann man noch zus&auml;tzliche Services integrieren wie Abgabe beim Nachbarn, Identit&auml;tscheck des Empf&auml;ngers, Alterspr&uuml;fung et cetera.<\/p>\n<h2>Downloads zu diesem Beitrag<\/h2>\n<p>Enthaltene Beispieldateien:<\/p>\n<p>DHLAPI.accdb<\/p>\n<p><a href=\"..\/fileadmin\/beispiele\/B81A059F-A998-46D8-902E-7B8DFFA7B2D3\/vbe_429.zip\">Download<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Wer Kunden und Bestellungen mit einer Access-Datenbank verwaltet oder gegebenenfalls auch mit einer Excel-Tabelle, m&ouml;chte vielleicht Zeit sparen und die Etiketten f&uuml;r den Versand von Lieferungen an seine Kunden automatisieren. Das gelingt mit den verschiedenen Webservices von DHL. Wir haben bereits einmal eine solche L&ouml;sung vorgestellt, aber DHL hat seine Schnittstellen f&uuml;r die Erstellung von Versandetiketten aktualisiert. In diesem Artikel schauen wir uns an, wie die neuen Schnittstellen funktionieren: Welche Daten ben&ouml;tige ich? Welche URL muss f&uuml;r den Zugriff verwendet werden? In welcher Form &uuml;bergebe ich beispielsweise die Adressdaten an den Webservice?<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"om_disable_all_campaigns":false,"_monsterinsights_skip_tracking":false,"_monsterinsights_sitenote_active":false,"_monsterinsights_sitenote_note":"","_monsterinsights_sitenote_category":0,"_uf_show_specific_survey":0,"_uf_disable_surveys":false,"footnotes":""},"categories":[662024,66042024,44000004],"tags":[],"yst_prominent_words":[],"class_list":["post-55000429","post","type-post","status-publish","format-standard","hentry","category-662024","category-66042024","category-Loesungen"],"aioseo_notices":[],"_links":{"self":[{"href":"https:\/\/vbentwickler.de\/data\/wp\/v2\/posts\/55000429","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/vbentwickler.de\/data\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/vbentwickler.de\/data\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/vbentwickler.de\/data\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/vbentwickler.de\/data\/wp\/v2\/comments?post=55000429"}],"version-history":[{"count":0,"href":"https:\/\/vbentwickler.de\/data\/wp\/v2\/posts\/55000429\/revisions"}],"wp:attachment":[{"href":"https:\/\/vbentwickler.de\/data\/wp\/v2\/media?parent=55000429"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/vbentwickler.de\/data\/wp\/v2\/categories?post=55000429"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/vbentwickler.de\/data\/wp\/v2\/tags?post=55000429"},{"taxonomy":"yst_prominent_words","embeddable":true,"href":"https:\/\/vbentwickler.de\/data\/wp\/v2\/yst_prominent_words?post=55000429"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}