5

There is a new regulation from the Government asking all VAT registered companies to implement QR CODE in the new E-Invoice.

  • The QR code fields shall be encoded in Tag-Length-Value (TLV) format with the tag values specified in the “Tag” column of the adjacent table.

  • The TLV encoding shall be as follows:

    • Tag: the tag value as mentioned above stored in one byte.
    • Length: the length of the byte array resulted from the UTF8 encoding of the field value. The length shall be stored in one byte.
    • Value: the byte array resulting from the UTF8 encoding of the field value.

How do I create TLV From an Array of Information? Is there a library that I can use?

$arr = [
    1 => 'Company Name',
    2 => '1234567890',
    3 => '2021/10/11 17:20:00',
    4 => '1000',
    5 => '150'
];
Taha Khan
  • 164
  • 3
  • 16

4 Answers4

12

Yes, the QR code required is not a normal QR code with a link. It should be TLV base64 encoded. It can be done very easily. the values need to be hexed and then combined which will contain ASCII control characters.

If you still don't get it, Luckily, You can use the following package by Salla to generate a QR code from the array.

https://github.com/SallaApp/ZATCA

Make sure to follow the Tag structure provided by the ZATCA (GAZT previously). The package's example has the correct array:

$generatedString = GenerateQrCode::fromArray([
    new Seller('Salla'), // seller name
    new TaxNumber('1234567891'), // seller tax number
    new InvoiceDate('2021-07-12T14:25:09Z'), // invoice date as Zulu ISO8601 @see https://en.wikipedia.org/wiki/ISO_8601
    new InvoiceTotalAmount('100.00'), // invoice total amount
    new InvoiceTaxAmount('15.00') // invoice tax amount
    // TODO :: Support others tags
])->toTLV();
Saeed Rehman
  • 136
  • 2
  • 2
  • 1
    This library is a time saver! I've written similar class to publish on git to help others but i guess Salla beat me to it. Very well written library, this will help other devs who havnt figured it out yet. – Taha Khan Oct 13 '21 at 22:21
  • wow great, is it possible to get it without composer install, like zip format ? – Farveen Hassan Nov 07 '21 at 15:29
  • Shouldn't you use +03:00 instead of Z? – Bu Saeed Nov 19 '21 at 10:59
  • Is there any solution for PHP <= 7.3 with Unicode? – Hafizur Rahman Nov 28 '21 at 02:17
  • 1
    @HafizurRahman , The package by Salla uses "chillerlan/php-qrcode" dependency for creating the QR image. It by default installs the latest "chillerlan/php-qrcode" which requires php7.4+ , you can copy the logic from Salla package manually and then install chillerlan/php-qrcode^3.2 which supports php7.2+ .. – Saeed Rehman Dec 06 '21 at 10:22
6

For those who are still using php5 based on https://github.com/SallaApp/ZATCA

/*
 * QR Encoding Functions
 */

function __getLength($value) {
    return strlen($value);
}

function __toHex($value) {
    return pack("H*", sprintf("%02X", $value));
}

function __toString($__tag, $__value, $__length) {
    $value = (string) $__value;
    return __toHex($__tag) . __toHex($__length) . $value;
}

function __getTLV($dataToEncode) {
    $__TLVS = '';
    for ($i = 0; $i < count($dataToEncode); $i++) {
        $__tag = $dataToEncode[$i][0];
        $__value = $dataToEncode[$i][1];
        $__length = __getLength($__value);
        $__TLVS .= __toString($__tag, $__value, $__length);
    }

    return $__TLVS;
}

/*
 * QR Encoding Functions
 */


/*
 * QR Code
 */
$dataToEncode = [
    [1, 'SellerName'],
    [2, 'VATNumber'],
    [3, 'invoiceDatetime'],
    [4, 'AmtwithVAT'],
    [5, 'VATamt']
];

$__TLV = __getTLV($dataToEncode);
$__QR = base64_encode($__TLV);

echo  $__QR;


/*
 * QR Code
 */

1-- Install ZATCA SDK https://zatca.gov.sa/en/E-Invoicing/SystemsDevelopers/ComplianceEnablementToolbox/Pages/DownloadSDK.aspx

2 -- fatoorah validateqr -qr "$__QR"

3

I have been into this ZATCA TLV Base64 QR code P2C issue by my clients in SA. well, I made this function and verified its result.

function zatca_base64_tlv_encode($seller_name, $vat_registration_number, $invoice_datetimez, $invoice_amount, $invoice_tax_amount)
{
    $result = chr(1) . chr( strlen($seller_name) ) . $seller_name;
    $result.= chr(2) . chr( strlen($vat_registration_number) ) . $vat_registration_number;
    $result.= chr(3) . chr( strlen($invoice_datetimez) ) . $invoice_datetimez;
    $result.= chr(4) . chr( strlen($invoice_amount) ) . $invoice_amount;
    $result.= chr(5) . chr( strlen($invoice_tax_amount) ) . $invoice_tax_amount;
    return base64_encode($result);
}
meYnot
  • 343
  • 2
  • 6
  • 13
  • 1
    You must convert the values to hex making sure the tag and length value with fixed length of 1 byte before converting it to base64. Check the Zatca Documentation for details. QRCode requirements Document: https://zatca.gov.sa/en/E-Invoicing/SystemsDevelopers/Documents/QRCodeCreation.pdf You can Verify your qrcode base64 here: https://zatca.gov.sa/en/E-Invoicing/SystemsDevelopers/ComplianceEnablementToolbox/Pages/DownloadSDK.aspx – Taha Khan Nov 29 '21 at 19:51
  • Thanks @TahaKhan for your response, [chr — Generate a single-byte string from a number](https://www.php.net/manual/en/function.chr.php) T[chr representing index] L[chr representing length] V[string] – meYnot Nov 29 '21 at 20:16
2
function einv_generate_tlv_qr_code($array_tag=array()){
    $index=1;
    foreach($array_tag as $tag_val){
        $tlv_string.=pack("H*", sprintf("%02X",(string) "$index")).
                     pack("H*", sprintf("%02X",strlen((string) "$tag_val"))).
                     (string) "$tag_val";
        $index++;                              
    }      
    return base64_encode($tlv_string);
}

Just send you tags values in array to the function and it will return you the TLV content of QRcode

$data_tlv=einv_generate_tlv_qr_code(array($company_name,$vat_reference,$timestamp,$total,$vat);