![]() |
Chilkat HOME Android™ AutoIt C C# C++ Chilkat2-Python CkPython Classic ASP DataFlex Delphi DLL Go Java Node.js Objective-C PHP Extension Perl PowerBuilder PowerShell PureBasic Ruby SQL Server Swift Tcl Unicode C Unicode C++ VB.NET VBScript Visual Basic 6.0 Visual FoxPro Xojo Plugin
(PureBasic) Send ZATCA Invoice for ClearanceSee more ZATCA ExamplesDemonstrates how to send a ZATCA invoice for clearance, which is to send the HTTP POST with invoice hash and the signed invoice in base64 format.Note: This example requires Chilkat v11.0.0 or greater.
IncludeFile "CkBinData.pb" IncludeFile "CkXml.pb" IncludeFile "CkHttpResponse.pb" IncludeFile "CkJsonObject.pb" IncludeFile "CkHttp.pb" Procedure ChilkatExample() success.i = 0 ; This example requires the Chilkat API to have been previously unlocked. ; See Global Unlock Sample for sample code. ; This example will send a POST with HTTP Basic Authentication to ; https://gw-fatoora.zatca.sa/e-invoicing/simulation/invoices/clearance/single ; NOTE: At the time of this writing, I don't know for sure if the above URL is correct. ; ; The body of the POST will contain JSON formatted as such: ; { ; "summary": "Standard Invoice", ; "value": { ; "invoiceHash": "PEx8bNFcEMEpHzUVvQntQI6ot8eFqTT/l59b+H1HqX4=", ; "uuid": "16e78469-64af-406d-9cfd-895e724198f0", ; "invoice": "PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz4KPEl....." ; } ; } ; The above JSON is created from the signed XML invoice, such as the following: ; *** Look at the above base64 data for the invoiceHash and uuid. These values are found in the invoice as shown below. ; *** We'll write code to load the signed invoice into a Chilkat XML object, grab the invoice hash and the uuid, ; *** and then construct the above JSON, which will then be sent in a POST. (See below...) ; <?xml version="1.0" encoding="UTF-8"?> ; <Invoice xmlns="urn:oasis:names:specification:ubl:schema:xsd:Invoice-2" xmlns:cac="urn:oasis:names:specification:ubl:schema:xsd:CommonAggregateComponents-2" xmlns:cbc="urn:oasis:names:specification:ubl:schema:xsd:CommonBasicComponents-2" xmlns:ext="urn:oasis:names:specification:ubl:schema:xsd:CommonExtensionComponents-2"><ext:UBLExtensions> ; <ext:UBLExtension> ; <ext:ExtensionURI>urn:oasis:names:specification:ubl:dsig:enveloped:xades</ext:ExtensionURI> ; <ext:ExtensionContent> ; <!-- Please note that the signature values are sample values only --> ; <sig:UBLDocumentSignatures xmlns:sig="urn:oasis:names:specification:ubl:schema:xsd:CommonSignatureComponents-2" xmlns:sac="urn:oasis:names:specification:ubl:schema:xsd:SignatureAggregateComponents-2" xmlns:sbc="urn:oasis:names:specification:ubl:schema:xsd:SignatureBasicComponents-2"> ; <sac:SignatureInformation> ; <cbc:ID>urn:oasis:names:specification:ubl:signature:1</cbc:ID> ; <sbc:ReferencedSignatureID>urn:oasis:names:specification:ubl:signature:Invoice</sbc:ReferencedSignatureID> ; <ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#" Id="signature"> ; <ds:SignedInfo> ; <ds:CanonicalizationMethod Algorithm="http://www.w3.org/2006/12/xml-c14n11"/> ; <ds:SignatureMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#ecdsa-sha256"/> ; <ds:Reference Id="invoiceSignedData" URI=""> ; <ds:Transforms> ; <ds:Transform Algorithm="http://www.w3.org/TR/1999/REC-xpath-19991116"> ; <ds:XPath>not(//ancestor-or-self::ext:UBLExtensions)</ds:XPath> ; </ds:Transform> ; <ds:Transform Algorithm="http://www.w3.org/TR/1999/REC-xpath-19991116"> ; <ds:XPath>not(//ancestor-or-self::cac:Signature)</ds:XPath> ; </ds:Transform> ; <ds:Transform Algorithm="http://www.w3.org/TR/1999/REC-xpath-19991116"> ; <ds:XPath>not(//ancestor-or-self::cac:AdditionalDocumentReference[cbc:ID='QR'])</ds:XPath> ; </ds:Transform> ; <ds:Transform Algorithm="http://www.w3.org/2006/12/xml-c14n11"/> ; </ds:Transforms> ; <ds:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"/> ; <ds:DigestValue>PEx8bNFcEMEpHzUVvQntQI6ot8eFqTT/l59b+H1HqX4=</ds:DigestValue> ; </ds:Reference> ; <ds:Reference Type="http://www.w3.org/2000/09/xmldsig#SignatureProperties" URI="#xadesSignedProperties"> ; <ds:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"/> ; <ds:DigestValue>ZDEyMDUyODJjYzk4MGViNTJhNmYzMGIyZTgxODhkY2JlOWEzNmRiMTFlZTVhMDAxNjk5OTRkYTg3ODhlY2ZiMw==</ds:DigestValue> ; </ds:Reference> ; </ds:SignedInfo> ; ... ; ... ; ... ; </ext:ExtensionContent> ; </ext:UBLExtension> ; </ext:UBLExtensions> ; ; <cbc:ProfileID>reporting:1.0</cbc:ProfileID> ; <cbc:ID>SME00062</cbc:ID> ; <cbc:UUID>16e78469-64af-406d-9cfd-895e724198f0</cbc:UUID> ; <cbc:IssueDate>2022-03-13</cbc:IssueDate> ; <cbc:IssueTime>14:40:40</cbc:IssueTime> ; <cbc:InvoiceTypeCode name="0111010">388</cbc:InvoiceTypeCode> ; ... ; ... ; ... ; </cac:InvoiceLine> ; </Invoice> ; ------------------------------------------------------------------- ; First, let's load our signed XML into a Chilkat XML object so we can get the uuid and invoice hash. signedXmlFilePath.s = "qa_data/zatca/http_post_clearance/sample_signed_invoice.xml" signedXml.i = CkXml::ckCreate() If signedXml.i = 0 Debug "Failed to create object." ProcedureReturn EndIf success = CkXml::ckLoadXmlFile(signedXml,signedXmlFilePath) If success = 0 Debug CkXml::ckLastErrorText(signedXml) CkXml::ckDispose(signedXml) ProcedureReturn EndIf invoiceHash.s = CkXml::ckGetChildContent(signedXml,"ext:UBLExtensions|ext:UBLExtension|ext:ExtensionContent|sig:UBLDocumentSignatures|sac:SignatureInformation|ds:Signature|ds:SignedInfo|ds:Reference[0]|ds:DigestValue") Debug "invoiceHash: " + invoiceHash cbc_UUID.s = CkXml::ckGetChildContent(signedXml,"cbc:UUID") Debug "UUID: " + cbc_UUID ; The Chilkat XML object was used purely for getting the above 2 values. ; We must send the EXACT signed XML in base64 format. Therefore, we should load the signed XML into a Chilkat BinData and get it in base64 single-line format. bd.i = CkBinData::ckCreate() If bd.i = 0 Debug "Failed to create object." ProcedureReturn EndIf success = CkBinData::ckLoadFile(bd,signedXmlFilePath) base64Invoice.s = CkBinData::ckGetEncoded(bd,"base64") ; OK, let's build the JSON that will be in the HTTP POST body. json.i = CkJsonObject::ckCreate() If json.i = 0 Debug "Failed to create object." ProcedureReturn EndIf CkJsonObject::ckUpdateString(json,"summary","Standard Invoice") CkJsonObject::ckUpdateString(json,"value.invoiceHash",invoiceHash) CkJsonObject::ckUpdateString(json,"value.uuid",cbc_UUID) CkJsonObject::ckUpdateString(json,"value.invoice",base64Invoice) ; Now create the HTTP object and send the POST. http.i = CkHttp::ckCreate() If http.i = 0 Debug "Failed to create object." ProcedureReturn EndIf ; We'll want HTTP basic authentication. CkHttp::setCkBasicAuth(http, 1) CkHttp::setCkLogin(http, "your login") CkHttp::setCkPassword(http, "your password") resp.i = CkHttpResponse::ckCreate() If resp.i = 0 Debug "Failed to create object." ProcedureReturn EndIf success = CkHttp::ckHttpJson(http,"POST","https://gw-fatoora.zatca.sa/e-invoicing/simulation/invoices/clearance/single",json,"application/json",resp) If success = 0 Debug CkHttp::ckLastErrorText(http) CkXml::ckDispose(signedXml) CkBinData::ckDispose(bd) CkJsonObject::ckDispose(json) CkHttp::ckDispose(http) CkHttpResponse::ckDispose(resp) ProcedureReturn EndIf ; Check the response status code. A 200 or 202 indicates success.. statusCode.i = CkHttpResponse::ckStatusCode(resp) Debug "Response status code = " + Str(statusCode) ; Examine the response, which is JSON. jsonResp.i = CkJsonObject::ckCreate() If jsonResp.i = 0 Debug "Failed to create object." ProcedureReturn EndIf CkHttpResponse::ckGetBodyJson(resp,jsonResp) CkJsonObject::setCkEmitCompact(jsonResp, 0) Debug "JSON Response:" Debug CkJsonObject::ckEmit(jsonResp) ; Use this online tool to generate parsing code from sample JSON: ; Generate Parsing Code from JSON CkXml::ckDispose(signedXml) CkBinData::ckDispose(bd) CkJsonObject::ckDispose(json) CkHttp::ckDispose(http) CkHttpResponse::ckDispose(resp) CkJsonObject::ckDispose(jsonResp) ProcedureReturn EndProcedure |
© 2000-2025 Chilkat Software, Inc. All Rights Reserved.