Skip to Content
Technical Articles
Author's profile photo S M Firoz Ashraf

QR Code in Base64 encoding for KSA E-Invoicing

As per Zakat, Tax and Customs Authority (ZATCA) of Saudi Arabia, one of the main requirements is the implementation of QR codes on tax invoices in the e-invoicing project (Fatoora), which will be mandatory starting December 4, 2021

As per the ZATCA instructions(Page No. 23), the minimum requirements that must be shown after scanning a QR code are the following fields, which should be represented in form of based64 encoding:

  1. Seller’s name.
  2. VAT registration number of the seller.
  3. Time stamp of the invoice (date and time).
  4. Invoice total (with VAT).
  5. VAT total.

In this blog,  I will show how to encode the QR data in base64 format using ABAP and then using it in SAPScript/SmartForms to print QR code on Invoice layouts.

1st Step is to prepare each of the five values in TLV (Tag-Length-Value) structure

Tag is fixed (1 for Seller’s name, 2 for VAT No……5 for VAT Total)

Length is the size of the value field in bytes (it’s not the count of characters but how many bytes the value represents)

Value is the data against each of the five fields.

Let’s take an example to clarify TLV

    1. Seller name; for example, “Firoz Ashraf
      • Tag      = 1 (1 as a type represents the seller name)
      • Length = 12 (The number of the bytes in “Firoz Ashraf” word)
      • Value   = Firoz Ashraf
    2. VAT Number; for example, 1234567891
      • Tag      = 2 (2 as a type represents the VAT number)
      • Length = 10
      • Value   = 1234567891
    3. Time Stamp; for example, 2021-11-17 08:30:00
      • Tag      = 3 (3 as a type represents invoice time stamp)
      • Length = 19
      • Value   = 2021-11-17 08:30:00
    4. Invoice Total; for example, 100.00
      • Tag      = 4 (4 as a type represents the invoice amount)
      • Length = 6
      • Value   = 100.00
    5. VAT Total; for example, 15.00
      • Tag      = 5 (5 as a type represents the tax amount)
      • Length = 5
      • Value   = 15.00

 

2nd Step is to convert ‘Tag’ and ‘Length’ to Hexadecimal and then to string. Then concatenate these two strings with ‘Value’ (stored as string)

concatenate all the five TLVs into one string

‘##Firoz Ashraf##1234567891##2021-11-17 08:30:00##115.00##15.00’

 

3rd Step is to convert the concatenated string to Base64 format

From the above example we get the following Base64 encoded value

AQxGaXJveiBBc2hyYWYCCjEyMzQ1Njc4OTEDEzIwMjEtMTEtMTcgMDg6MzA6MDAEBjExNS4wMAUFMTUuMDA=

Now let’s see how we can do this in ABAP

To get the ‘Length’ in the TLV structure, we will use the Function Module SCMS_STRING_TO_XSTRING to convert the text to xString and then we will use xstrlen to get the length.

FORM tag_length  USING    p_string
                 CHANGING p_length.
  DATA: v_xstr TYPE xstring.
*First Convert string to xString
  CALL FUNCTION 'SCMS_STRING_TO_XSTRING'
    EXPORTING
      text   = p_string
*     MIMETYPE       = ' '
*     ENCODING       =
    IMPORTING
      buffer = v_xstr
    EXCEPTIONS
      failed = 1
      OTHERS = 2.
  IF sy-subrc <> 0.
* Implement suitable error handling here
  ELSE.
    p_length = xstrlen( v_xstr ).
  ENDIF.

ENDFORM.

To convert the string to Base64 we have two ways in ABAP:

The first one is using Class CL_HTTP_UTILITY method ENCODE_BASE64

The second one is using Function Module SCMS_STRING_TO_XSTRING to Convert String to Xstring and the using another Function Module SCMS_BASE64_ENCODE_STR to Convert the Xstring to Base64.

You can choose either of the ways (either Class or FM)

I have used the Class method to convert string to Base64.

To start with, I created a custom FM which takes invoice number as input and gives QR code values in text as well as in Base64.

I use this FM in SAPScript/SmartForms to print the QR Code.

FUNCTION z_einvoice_base64_qrcode_value.
*"----------------------------------------------------------------------
*"*"Local Interface:
*"  IMPORTING
*"     REFERENCE(INVOICE_NO) TYPE  VBELN_VF
*"  EXPORTING
*"     REFERENCE(QRCODE_STRING) TYPE  STRING
*"     REFERENCE(QRCODE_BASE64) TYPE  STRING
*"  EXCEPTIONS
*"      NO_INVOICE
*"      XSTR_ERROR
*"----------------------------------------------------------------------
*-----------------------------------------------------------------------
*  The QR code fields shall be encoded in Tag-Length-Value (TLV) format
*  The TLV encoding shall be as follows:
*  Tag    : the tag value (1 to 5) stored in one byte
*  Length : the length of the byte array resulted from the UTF8 encoding of the field value.
*  Value  : the byte array resulting from the UTF8 encoding of the field value.
*----------------------------------------------------------------------
  DATA: wa_vbrk     TYPE vbrk,

        v_t1_cname  TYPE string,
        v_t2_vatno  TYPE string, v_date(10), v_time(8),
        v_t3_tstmp  TYPE string,
        v_t4_invamt TYPE vbrk-netwr, v_t4_invamx TYPE string,
        v_t5_vatamt TYPE vbrk-netwr, v_t5_vatamx TYPE string,

        v_t1_len    TYPE i,v_t2_len TYPE i,v_t3_len TYPE i,
        v_t4_len    TYPE i,v_t5_len TYPE i,

        v_t1_lenx   TYPE xstring,v_t2_lenx TYPE xstring,v_t3_lenx TYPE xstring,
        v_t4_lenx   TYPE xstring,v_t5_lenx TYPE xstring,

        v_t1_lent   TYPE string,v_t2_lent TYPE string,v_t3_lent TYPE string,
        v_t4_lent   TYPE string,v_t5_lent TYPE string,

        v_t1_tag    TYPE string, v_t2_tag TYPE string, v_t3_tag TYPE string,
        v_t4_tag    TYPE string, v_t5_tag TYPE string.

  SELECT SINGLE * FROM vbrk INTO wa_vbrk
     WHERE vbeln = invoice_no.
  IF sy-subrc = 0.
*   Company Name & VAT No.
    SELECT SINGLE butxt stceg FROM t001 INTO ( v_t1_cname, v_t2_vatno )
      WHERE bukrs = wa_vbrk-bukrs.
*   Invoice Time Stamp
    CONCATENATE wa_vbrk-fkdat(4) '-' wa_vbrk-fkdat+4(2) '-' wa_vbrk-fkdat+6(2)
    INTO v_date.
    CONCATENATE wa_vbrk-erzet(2) ':' wa_vbrk-erzet+2(2) ':' wa_vbrk-erzet+4(2)
    INTO v_time.
    CONCATENATE v_date v_time INTO v_t3_tstmp SEPARATED BY space.
*  Invoice Total (with VAT)
    v_t4_invamt = wa_vbrk-netwr + wa_vbrk-mwsbk.
    v_t4_invamx = v_t4_invamt. CONDENSE v_t4_invamx.
*  VAT Total
    v_t5_vatamt = wa_vbrk-mwsbk.
    v_t5_vatamx = v_t5_vatamt. CONDENSE v_t5_vatamx.

**********Tag & Length (T&L from TLV) should be first converted to 
*         Hexadecimal format then it should be converted to string.
*         Finally these two strings should be concatenated with 'Value' (of TLV).
*         Since tags are 1 to 5. We take the hexa values as 01 to 05

    PERFORM convert_hex_to_str USING '01' CHANGING v_t1_tag.
    PERFORM convert_hex_to_str USING '02' CHANGING v_t2_tag.
    PERFORM convert_hex_to_str USING '03' CHANGING v_t3_tag.
    PERFORM convert_hex_to_str USING '04' CHANGING v_t4_tag.
    PERFORM convert_hex_to_str USING '05' CHANGING v_t5_tag.

    PERFORM tag_length USING v_t1_cname  CHANGING v_t1_len.
    v_t1_lenx = v_t1_len. " Convert to hexadecial value
    PERFORM convert_hex_to_str USING v_t1_lenx CHANGING v_t1_lent.

    PERFORM tag_length USING v_t2_vatno  CHANGING v_t2_len.
    v_t2_lenx = v_t2_len.
    PERFORM convert_hex_to_str USING v_t2_lenx CHANGING v_t2_lent.

    PERFORM tag_length USING v_t3_tstmp  CHANGING v_t3_len.
    v_t3_lenx = v_t3_len.
    PERFORM convert_hex_to_str USING v_t3_lenx CHANGING v_t3_lent.

    PERFORM tag_length USING v_t4_invamx CHANGING v_t4_len.
    v_t4_lenx = v_t4_len.
    PERFORM convert_hex_to_str USING v_t4_lenx CHANGING v_t4_lent.

    PERFORM tag_length USING v_t5_vatamx CHANGING v_t5_len.
    v_t5_lenx = v_t5_len.
    PERFORM convert_hex_to_str USING v_t5_lenx CHANGING v_t5_lent.

***************Concatenate all TLV data********************
    CONCATENATE v_t1_tag v_t1_lent v_t1_cname
                v_t2_tag v_t2_lent v_t2_vatno
                v_t3_tag v_t3_lent v_t3_tstmp
                v_t4_tag v_t4_lent v_t4_invamx
                v_t5_tag v_t5_lent v_t5_vatamx
    INTO qrcode_string.

***************Encode String to Base64*********************
    CALL METHOD cl_http_utility=>if_http_utility~encode_base64
      EXPORTING
        unencoded = qrcode_string
      RECEIVING
        encoded   = qrcode_base64.
  ELSE.
    RAISE no_invoice.
  ENDIF.

ENDFUNCTION.

 

PERFORM convert_hex_to_str

*&---------------------------------------------------------------------*
*&      Form  CONVERT_HEX_TO_STR
*&---------------------------------------------------------------------*
*       text
*----------------------------------------------------------------------*
*      -->P_HEX  text
*      <--P_STR  text
*----------------------------------------------------------------------*
FORM convert_hex_to_str  USING    p_hex
                         CHANGING p_str.
*  CALL FUNCTION 'HR_RU_CONVERT_HEX_TO_STRING'
*    EXPORTING
*      xstring = p_hex
*    IMPORTING
*      cstring = p_str.

**Note: Above FM was sometimes not giving correct   **
**      conversion. Hence we have changed it to     **
**      class based explicitly using UTF-8          **

  DATA: loc_conv TYPE REF TO cl_abap_conv_in_ce.

  CALL METHOD cl_abap_conv_in_ce=>create
    EXPORTING
      input       = p_hex
      encoding    = 'UTF-8'
      replacement = '?'
      ignore_cerr = abap_true
    RECEIVING
      conv        = loc_conv.

  TRY.
      CALL METHOD loc_conv->read
        IMPORTING
          data = p_str.
    CATCH cx_sy_conversion_codepage.
*-- Should ignore errors in code conversions
    CATCH cx_sy_codepage_converter_init.
*-- Should ignore errors in code conversions
    CATCH cx_parameter_invalid_type.
    CATCH cx_parameter_invalid_range.
  ENDTRY.ENDFORM.

Setting up the QR Code font 

Using SE73, create a new ‘System Bar Code’

SE73%20QR%20Code%20Font%20Creation

Once this is done, create a Character format say QR in your SAPScript using the Bar Code (QR Code) created above.

SE71%20Character%20Format%20QR

You can then use this in your Window

Here I am calling the subroutine ZEDOC_KSA_QRBASE64 in ABAP program ZSDLINCLUDE which actually has our custom FM Z_EINVOICE_BASE64_QRCODE_VALUE

Note that a single text variable in SAPScript has a capacity to hold 80 characters and our QR code value is more than 80 hence I had to spilt the values in two variables V_QRCODE1 & V_QRCODE2.

FORM zedoc_ksa_qrbase64 TABLES in_tab STRUCTURE itcsy
                               out_tab STRUCTURE itcsy.
  DATA: v_vbeln TYPE vbeln,
        v_qrb64 TYPE string,
        v_len   TYPE i,
        v_rem   TYPE i.

  READ TABLE in_tab INDEX 1.
  IF sy-subrc = 0.
    v_vbeln = in_tab-value.
    CALL FUNCTION 'Z_EINVOICE_BASE64_QRCODE_VALUE'
      EXPORTING
        invoice_no    = v_vbeln
      IMPORTING
*       QRCODE_STRING =
        qrcode_base64 = v_qrb64
      EXCEPTIONS
        no_invoice    = 1
        xstr_error    = 2
        OTHERS        = 3.
    IF sy-subrc <> 0.
* Implement suitable error handling here
    ELSE.
      v_len = strlen( v_qrb64 ).

      READ TABLE out_tab INDEX 1.
      IF sy-subrc = 0.
        IF v_len GT 80. "Split into two variables
          out_tab-value = v_qrb64(80).
          v_rem = v_len - 80.
          MODIFY out_tab INDEX 1.CLEAR out_tab.
          READ TABLE out_tab INDEX 2.
          IF sy-subrc = 0.
            out_tab-value = v_qrb64+80(v_rem).
            MODIFY out_tab INDEX 2.CLEAR out_tab.
          ENDIF.
        ELSE.
          out_tab-value = v_qrb64.
          MODIFY out_tab INDEX 1.CLEAR out_tab.
        ENDIF.
      ENDIF.
    ENDIF.
  ENDIF.
ENDFORM.

After doing this when you call the layout you will get the QR Code

If you scan this QR code then you will get the the following Base64 coded text

AQxGaXJveiBBc2hyYWYCCjEyMzQ1Njc4OTEDEzIwMjEtMTEtMTcgMDg6MzA6MDAEBjExNS4wMAUFMTUuMDA=

When decoded this will give the following text value (as shown below )

You may go through the following blogs and links which were quite helpful in getting the pieces together.

  1. https://blogs.sap.com/2019/03/29/base64-function-modules-in-sap-abap/
  2. https://sapintegrationhub.com/abap/base64/base64-encoding-and-decoding-in-sap-abap/
  3. https://blogs.sap.com/2020/10/12/display-qr-code-for-gst-india-e-invoicing-on-script-and-smartform/
  4. https://salla.dev/blog/qr-code-fatoora-e-invoicing-zatca/
  5. https://www.textencode.com/decoder/decodeBase64

Note: if you have set up EDOC_COCKPIT then you can directly get the QR code data in base64 encoding without bothering about TLV conversion. You may follow my another blog where I have explained how you can use the data stored in field QR_CODE from table EDOSAINV.

Enjoy coding !!

Firoz Ashraf.

 

Assigned Tags

      48 Comments
      You must be Logged on to comment or reply to a post.
      Author's profile photo MUHZIN MUHAMMED
      MUHZIN MUHAMMED

      Hi brother,

      Can you check following encoded data.

      "AQVTYWxsYQIKMTIzNDU2Nzg5MQMUMjAyMS0wNy0xMlQxNDoyNTowOVoEBjEwMC4wMAUFMTUuMDA="
      
      Encryption method is little bit different than you mentioned.
      
      Tags are not visible while decoding base64.
      
      Ref. https://github.com/SallaApp/ZATCA
      https://topnotepad.com/sa/qr-code-in-e-invoice
       

       

      Author's profile photo S M Firoz Ashraf
      S M Firoz Ashraf
      Blog Post Author

      Yes, one conversion was missing due to which encryption was not proper. The correct base64 encoded value is

      AQxGaXJveiBBc2hyYWYCCjEyMzQ1Njc4OTEDEzIwMjEtMTEtMTcgMDg6MzA6MDAEBjExNS4wMAUFMTUuMDA=

      Missing Part - Conversion of 'Tag' and 'Length' to Hexadecimal and then to string.

      So, the correct order is ..

      Convert 'Tag' to Hexadecimal, then convert it to strings of characters with the corresponding ASCII code. Similarly convert 'Length' to Hexadecimal, and to string. Then concatenate these two strings with 'Value' (stored as string). Do this for all the TLVs and concatenate into one string. Finally this single string is to be converted to Base64 using METHOD cl_http_utility=>if_http_utility~encode_base64

      I have updated my codes of the custom FM.

      Thanks.

       

       

       

       

      Author's profile photo Mohammad Nawazuddin
      Mohammad Nawazuddin

      Brother Asharf,

       

      I am able to generate Base64 QRCODE perfectly  and scannable on screen also no issue, but when print the  invoice from VF03 using

      device type ( PDFUC :pdf unicode 1:3)   printer :EPSON LQ-690 printer print(Adobe Form)   the generated QR code unable to  read

      in zatca app or any QRSCANer.

       

      do you have any idea  what is the issue why its not scanning , please give any input to solve this issue.

       

      Thanks,

      Nawazuddin.

       

       

      Author's profile photo Abdul Mateen
      Abdul Mateen

      Dear Firoz Ashraf, I am really impress your work. I want to ask one question. When I convert TAG 1 to Hexa it is giving 1 and after that i convert it to ascci string it is giving 31. in case of len "Firoz Ashraf" len is 12 When i convert it  it is giving 3128. then concatenate the string is '313128Firoz ashraf. is it correct? if not pls guide me about this. or pls tel us the comp concatenated string

      Author's profile photo S M Firoz Ashraf
      S M Firoz Ashraf
      Blog Post Author

      Dear Abdul Mateen,

      Hexa of 1 will be '01' and then converting it to text using METHOD cl_abap_conv_in_ce=>create and METHOD loc_conv->read will give you '#'

      Author's profile photo ahmed aledrisi
      ahmed aledrisi

      Hi S M Firoz

      I am facing a problem if the name of the resource is Arabic in the base64 site is working, but through the scanner it does not work

       

      ASDZhdi12YbYuSDYsdmI2LYg2KfZhNij2LXZitmEINmE2YTYqti52KjYptipINmI2KfZhNiq2LrZhNmK2YECDzMwMDc4NjMxMjcwMDAwMwMKMjAyMS8xMS8yNgQGOTIwLjAwBQYxMjAuMDA=

       

      Base64

      مصنع روض الأصيل للتعبئة والتغليف3007863127000032021/11/26920.00120.00

       

      can you help me

      Author's profile photo S M Firoz Ashraf
      S M Firoz Ashraf
      Blog Post Author

      Dear Ahmed,

      Try to convert the single concatenated string value into hex with UTF-8 encoding and then use this hex to finally convert to base64.

      ***************Concatenate all TLV data********************
          CONCATENATE v_t1_tag v_t1_lent v_t1_cname
                      v_t2_tag v_t2_lent v_t2_vatno
                      v_t3_tag v_t3_lent v_t3_tstmp
                      v_t4_tag v_t4_lent v_t4_invamx
                      v_t5_tag v_t5_lent v_t5_vatamx
          INTO qrcode_string.
      ****************************************************************
      *   Convert this one string to hex and then convert hex to base64
      *   because if there is arabic text then QR code is not readable.
      
          loc_out_conv = cl_abap_conv_out_ce=>create( encoding = '4110' ). "UTF-8 is 4110
          loc_out_conv->convert( EXPORTING data = qrcode_string IMPORTING buffer = qrcode_xstring ).
      ***************Encode xString to Base64*********************
          CALL METHOD cl_http_utility=>if_http_utility~encode_x_base64
            EXPORTING
              unencoded = qrcode_xstring
            RECEIVING
              encoded   = qrcode_base64.

      Additionally, please make sure the 'Mode' of the QR Code created in SE73 is 'A' 

      Regards,

      Firoz.

      Author's profile photo Solanki Vishal Himmatlal
      Solanki Vishal Himmatlal

      Hi Firoz,

      I am following the same steps but still arabic text is not getting scanned. 

      After concatenating into final string, called below code before base64 conversion.

      ****************************************************************
      *   Convert this one string to hex and then convert hex to base64
      *   because if there is arabic text then QR code is not readable.
      
          loc_out_conv = cl_abap_conv_out_ce=>create( encoding = '4110' ). "UTF-8 is 4110
          loc_out_conv->convert( EXPORTING data = qrcode_string IMPORTING buffer = qrcode_xstring ).

      Also, Bar code Mode is to 'A' only.

      S M Firoz Ashraf

      Kindly help on this problem as it is very important for us to go live with this Arabic QR code.

       

      Regards,

      Vishal Solanki

      Author's profile photo S M Firoz Ashraf
      S M Firoz Ashraf
      Blog Post Author

      Try with Mode  'U'

      Author's profile photo Solanki Vishal Himmatlal
      Solanki Vishal Himmatlal

      Hi Firoz,

      Done the same setting but still error remains same.

       

      Barcode

      Barcode

      Author's profile photo S M Firoz Ashraf
      S M Firoz Ashraf
      Blog Post Author

      Please try to check the print preview & actual print of the QR code that you are using from SE73. See if you are getting the Arabic letters in the preview/print.

      Author's profile photo Mohammad Aamir Khan
      Mohammad Aamir Khan

      Hi Firoz,

      I am facing issue if Seller name value is having '.' ( 'Test Co. Main Branch.') . FM HR_RU_CONVERT_HEX_TO_STRING is giving strange character when I pass value '15'.

      Are you facing issue if Seller name value is having '.'  ?

      Author's profile photo S M Firoz Ashraf
      S M Firoz Ashraf
      Blog Post Author

      Hi Aamir,

      It is perfectly fine to get 'Strange Character' in ABAP, for example '§' when you pass the hexadecimal value 15 in the FM HR_RU_CONVERT_HEX_TO_STRING.

      Please go ahead and concatenate it to the final string.

      Once you convert it to base64 you will get the value as AadUZXN0IENvLiBNYWluIEJyYW5jaC4CCjEyMzQ1Njc4OTEDEzIwMjEtMTEtMjMgMTM6MDE6MDEEBjExNS4wMAUFMTUuMDA=

      which can be decoded as

      Test Co. Main Branch.
      12345678912021-11-23 13:01:01115.0015.00

      You can see that that the Seller name is 'Test Co. Main Branch.' with two dots.

       

      Regards,

      Firoz.

      Author's profile photo Mohammad Aamir Khan
      Mohammad Aamir Khan

      Dear Firoz,

      Below are final strings

      When using Test Co. Main Branch.

      ASNUZXN0IENvLiBNYWluIEJyYW5jaC4CDjMwMDI0MDg4NTgxMTExAxMyMDIxLTA3LTE1IDE2OjEwOjA4BAgxMjI2Mi40NQUHMTU5OS40NQ==

       

      When using Test Co Main Branch ( removing .)

      ASNUZXN0IENvIE1haW4gQnJhbmNoAg4zMDAyNDA4ODU4MTExMQMTMjAyMS0wNy0xNSAxNjoxMDowOAQIMTIyNjIuNDUFBzE1OTkuNDU=

       

      QR code generated by first one is showing not compliance on E-invoice QR Reader tool, where as for second QR, it is showing as complaint.

       

      Author's profile photo S M Firoz Ashraf
      S M Firoz Ashraf
      Blog Post Author

      Hello Aamir,

      Which E-invoice QR Reader tool are you using?

      I can see that both your code results in the same output on https://www.base64decode.org/

      Author's profile photo Mohammad Aamir Khan
      Mohammad Aamir Khan

      Hi Firoz,

      You can scan QR Code and check compliance by below ZATCA app

      for Android https://play.google.com/store/apps/details?id=com.posbankbh.einvoiceqrreader

      For Iphone https://apps.apple.com/us/app/e-invoice-qr-reader-ksa/id1580793042

      Last time I put some wrong value ( testing with so many data). Below is where i am facing issue.

      Test Co. Main Branch. ( With dots)

      AadUZXN0IENvLiBNYWluIEJyYW5jaC4CDjMwMDI0MDg4NTgxMTExAxMyMDIxLTA3LTE1IDE2OjEwOjA4BAgxMjI2Mi40NQUHMTU5OS40NQ==

      Test Co Main Branch

      ARNUZXN0IENvIE1haW4gQnJhbmNoAg4zMDAyNDA4ODU4MTExMQMTMjAyMS0wNy0xNSAxNjoxMDowOAQIMTIyNjIuNDUFBzE1OTkuNDU=

      As you see below value is slight different in case of first data. I am attaching QR code .

      issue

      issue

      Original

      Original

      dots_removed

      dots_removed

      Author's profile photo S M Firoz Ashraf
      S M Firoz Ashraf
      Blog Post Author

      Hi Aamir,

      I have changed the hexadecimal conversion in my subroutine convert_hex_to_str  from FM HR_RU_CONVERT_HEX_TO_STRING to Class CL_ABAP_CONV_IN_CE explicitly utilizing UTF-8 encoding. Now the results seems to be fine.

      Kindly use my updated code and create the QR code. Hopefully the ZATCA app will give you the correct result.

      ARVUZXN0IENvLiBNYWluIEJyYW5jaC4CDjMwMDI0MDg4NTgxMTExAxMyMDIxLTA3LTE1IDE2OjEwOjA4BAgxMjI2Mi40NQUHMTU5OS40NQ==

      Regards,

      Firoz.

      Author's profile photo Mohammad Aamir Khan
      Mohammad Aamir Khan

      Dear Firoz,

      If you have string of length 32, then corresponding hex value is '20'. when you pass this value to your method, again this QR code will fail as method will return blank value for hex = '20'. You can verify by changing Seller name of length 32 in debug mode and scanning the generated barcode.

      I done it in slight different way. We have 3 parts. TAG LENGTH and VALUE.

      TAG you already giving hex value as '01' '02'....

      LENGTH you are getting in hex by passing xtrlen output to variable of type xstring.

      VALUE you are converting in hex by calling FM 'SCMS_STRING_TO_XSTRING'.

      Now you have all 3 parts in hex. No need to convert to string, Just concatenate all in variable of type xstring using CONCATENATE INTO lv_xstring IN BYTE MODE.

      Now you have hex string. Use cl_http_utility=>if_http_utility~encode_x_base64 to convert to base 64.

      This is working with all length of values as we are not converting hex to str and then back to hex.

      Thanks

      Author's profile photo tarek taha
      tarek taha

      hi mr/ashraf

      we do every this as yoy say

      but still tag and length

      can you give me exampe for first tag,first length whicj will add it in the begining of string?

      Author's profile photo S M Firoz Ashraf
      S M Firoz Ashraf
      Blog Post Author

      Hi Taha,

      I have updated my code for hexadecimal conversion. Kindly follow it as explained.

      Regards,

      Firoz.

      Author's profile photo Murty Maganti
      Murty Maganti

      Hi,

      It is not matching with what they specified in the document  https://zatca.gov.sa/ar/E-Invoicing/SystemsDevelopers/Documents/20210528_ZATCA_Electronic_Invoice_Security_Features_Implementation_Standards_vShared.pdf

      As per the document (section 4.1), Tag should be stored in first byte, Length is the length of the byte array of UTF8 encoded value string stored as single byte. You are converting tag and length into hex values and then to string. Which one is correct?

       

      Author's profile photo S M Firoz Ashraf
      S M Firoz Ashraf
      Blog Post Author

      Hi Murty,

      I believe, ABAP is taking care of  what has been specified.

      Since we have to concatenate the TLV strings therefore we are doing this hexa and then string conversion.

      At the end... conversion to base64 should be correct and readable by any ZATCA approved QR reader app. like this Android App or Apple App

      You can build your QR code and check the result.

      Author's profile photo Murty Maganti
      Murty Maganti

      Hi Firoz,

      Thanks for your quick response. It didn't work for me because I was including the '$' sign to the total amount. It is working now and nothing to do with hex or byte. Thanks again.

       

      Murty

      Author's profile photo Javed Parvez
      Javed Parvez

      Thanks, It is working fine and also, validated it using ZATCA QR scanner

      Author's profile photo Raza Hassan
      Raza Hassan

      Can you please share the tag length raw value for any column against the variable "

      v_t1_lent

      I am doing this method in Oracle but want to know what value you are returning against tag length in string. Thanks in advance.

       

      Raza

      Author's profile photo S M Firoz Ashraf
      S M Firoz Ashraf
      Blog Post Author

      It's   #

      Author's profile photo Raza Hassan
      Raza Hassan

      can you explain this function as example value. for example your first tag is company. and you passed the value to function "Firoz Ashraf" so first you are converting it to hex value and then to calculate the length of hex or actual string?

       

      FORM tag_length  USING    p_string
                       CHANGING p_length.
        DATA: v_xstr TYPE xstring.
      *First Convert string to xString
        CALL FUNCTION 'SCMS_STRING_TO_XSTRING'
          EXPORTING
            text   = p_string
      *     MIMETYPE       = ' '
      *     ENCODING       =
          IMPORTING
            buffer = v_xstr
          EXCEPTIONS
            failed = 1
            OTHERS = 2.
        IF sy-subrc <> 0.
      * Implement suitable error handling here
        ELSE.
          p_length = xstrlen( v_xstr ).
        ENDIF.
      
      ENDFORM.
      Author's profile photo S M Firoz Ashraf
      S M Firoz Ashraf
      Blog Post Author

      We are passing the string 'Firoz Ashraf' to the FM which basically converts it to hexadecimal value in the variable v_xstr. Next we are calculating the length (as a number of bytes) of v_xstr using the predefined ABAP function xstrlen.

      Author's profile photo Mohammad Nawazuddin
      Mohammad Nawazuddin

      Brother Asharf,

       

      I am able to generate Base64 QRCODE perfectly  and scannable on screen also no issue, but when print the  invoice from VF03 using

      device type ( PDFUC :pdf unicode 1:3)   printer :EPSON LQ-690 printer print(Adobe Form)   the generated QR code unable to  read

      in zatca app or any QRSCANer.

       

      do you have any idea  what is the issue why its not scanning , please give any input to solve this issue.

       

      Thanks,

      Nawazuddin.

      Author's profile photo S M Firoz Ashraf
      S M Firoz Ashraf
      Blog Post Author

      Dear Nawazuddin,

      For printing QR Code on DotMatrix printer EPSON LQ-690 you may try device type SWIN instead of PDFUC.

      Take help of BASIS guy if needed.

      Regards,

      Author's profile photo Sandra Rossi
      Sandra Rossi

      If needed, you may simplify the code a little bit, here is a test code with test data as above in the comments, which gives the exact same result, with full standard ABAP API (cl_abap_codepage for UTF-8 encoding and call transformation for transforming bytes into base64) :

      REPORT.
      
      TYPES: ty_byte TYPE x LENGTH 1.
      
      DATA: qrcode_base64 TYPE string.
      PERFORM z_einvoice_base64_qrcode_value USING
          'Test Co. Main Branch.' '30024088581111' '2021-07-15 16:10:08' 
          '12262.45' '1599.45'
        CHANGING qrcode_base64.
      
      FORM z_einvoice_base64_qrcode_value USING
          v_t1_cname       TYPE string
          v_t2_vatno       TYPE string
          v_t3_tstmp       TYPE string " Invoice Time Stamp
          v_t4_invamx      TYPE string " Invoice Total (with VAT)
          v_t5_vatamx      TYPE string " VAT Total
        CHANGING qrcode_base64 TYPE string.
      
      *-----------------------------------------------------------------------
      *  The QR code fields shall be encoded in Tag-Length-Value (TLV) format
      *  The TLV encoding shall be as follows:
      *  Tag    : the tag value (1 to 5) stored in one byte
      *  Length : the length of the byte array resulted from the UTF8 encoding of the field value, in one byte
      *  Value  : the byte array resulting from the UTF8 encoding of the field value.
      *----------------------------------------------------------------------
        DATA:
          qrcode_xstring TYPE xstring,
          tlv_1          TYPE xstring,
          tlv_2          TYPE xstring,
          tlv_3          TYPE xstring,
          tlv_4          TYPE xstring,
          tlv_5          TYPE xstring.
      
        PERFORM tlv USING 1 v_t1_cname  CHANGING tlv_1.
        PERFORM tlv USING 2 v_t2_vatno  CHANGING tlv_2.
        PERFORM tlv USING 3 v_t3_tstmp  CHANGING tlv_3.
        PERFORM tlv USING 4 v_t4_invamx CHANGING tlv_4.
        PERFORM tlv USING 5 v_t5_vatamx CHANGING tlv_5.
      
      ***************Concatenate all TLV data********************
        CONCATENATE tlv_1 tlv_2 tlv_3 tlv_4 tlv_5
          INTO qrcode_xstring IN BYTE MODE.
      
      ***************Encode xString to Base64*********************
        CALL TRANSFORMATION id SOURCE whatever = qrcode_xstring 
                               RESULT whatever = qrcode_base64.
      
      ENDFORM.
      
      FORM tlv USING tag TYPE i value TYPE string
               CHANGING tlv TYPE xstring.
      
        DATA: tag_byte TYPE ty_byte,
              utf8     TYPE xstring,
              length   TYPE ty_byte.
      
        tag_byte = tag.
        utf8 = cl_abap_codepage=>convert_to( value ).
        length = xstrlen( utf8 ).
        CONCATENATE tag_byte length utf8 INTO tlv IN BYTE MODE.
      
      ENDFORM.
      Author's profile photo S M Firoz Ashraf
      S M Firoz Ashraf
      Blog Post Author

      Thanks for your suggestion Sandra.

      Definitely it's simpler and cleaner code.

      However, the base64 code resulted from CALL TRANSFORMATION is not readable from tax authority compliant app.

      But when method IF_HTTP_UTILITY~ENCODE_X_BASE64 is used as shown below, the result is readable.

      ***************Encode xString to Base64*********************
          CALL METHOD cl_http_utility=>if_http_utility~encode_x_base64
            EXPORTING
              unencoded = qrcode_xstring
            RECEIVING
              encoded   = qrcode_base64.

       

      Regards,

      Firoz.

      Author's profile photo Eman Elgammal
      Eman Elgammal

      Hi

      Please I write this code it is working right and tested on

      https://www.base64decode.org/

      My issue when I put it on Adobe form it is empty when I scanned it

      Can you help me

      Author's profile photo S M Firoz Ashraf
      S M Firoz Ashraf
      Blog Post Author

      Hi Eman,

      If you are getting the base64 value and it's showing the result on any decoder then please check the QR Code created from SE73 which you are using on your forms.

      Author's profile photo Eman Elgammal
      Eman Elgammal

      It is Adobe form not smart form

      Author's profile photo S M Firoz Ashraf
      S M Firoz Ashraf
      Blog Post Author

      you may check your data binding or the inserted QR Code type in Adobe Forms.

      I tried on Adobe Forms and it is working for me.

      Author's profile photo Mohammad Nawazuddin
      Mohammad Nawazuddin

      Dear AShar ,

       

      Did you tried  arabic with this code , when i am passing the arabic value to this code to convert in Base64  not working.

       

       

      Thanks,

      Nawazuddin.

      Author's profile photo Mohammad Nawazuddin
      Mohammad Nawazuddin

      Dear Eman,

       

      Increase the size of QR code it will work not only layout you need to increase  size of QRCODE in XML.

       

      XML

      XML

       

      Thanks,

      Nawazuddin

      Author's profile photo Eman Elgammal
      Eman Elgammal

      Thanks for your replay

      It is solved

      Author's profile photo KHALID SHOKRY
      KHALID SHOKRY

      Hello  every body

      Dear Firoz Ashraf  thank you very much for helping us in e invoice problem

       

      I have the same problem in arabic name in seller name 

      I use vb.net

      Author's profile photo S M Firoz Ashraf
      S M Firoz Ashraf
      Blog Post Author

      For Arabic name make sure your text is converted to UTF-8 encoding

      Author's profile photo Mohammad Nawazuddin
      Mohammad Nawazuddin

      Dear Ashraf,

       

      I tried like this .

       

      CALL METHOD cl_http_utility=>if_http_utility~encode_utf8
        EXPORTING
          unencoded v_t1_cname    " string arabic
        receiving
          encoded   v_t1_cnamex.    " xstring 

      clear :v_t1_cnames.

      CALL METHOD cl_http_utility=>if_http_utility~decode_utf8
      EXPORTING
        encoded   v_t1_cnamex " xstring 
        RECEIVING
        unencoded v_t1_cnames. "string arabic

       

      its generating string like this.

       

      الجواهري العربي##310122393500003##2022-04-25T15:30:00Z##1000.00##150.00

       

      arabic text comming in between.

       

      Thanks,

      Nawazuddin

       

       

      Author's profile photo S M Firoz Ashraf
      S M Firoz Ashraf
      Blog Post Author

      Just try to generate the QR code from the base64 data that you get even if the display of arabic is at the end or in the middle.

      if that does not works then use the below code

      ***************Concatenate all TLV data********************
          CONCATENATE v_t1_tag v_t1_lent v_t1_cname
                      v_t2_tag v_t2_lent v_t2_vatno
                      v_t3_tag v_t3_lent v_t3_tstmp
                      v_t4_tag v_t4_lent v_t4_invamx
                      v_t5_tag v_t5_lent v_t5_vatamx
          INTO qrcode_string.
      ****************************************************************
      *   Convert this one string to hex and then convert hex to base64
      *   because if there is arabic text then QR code is not readable.
      
          loc_out_conv = cl_abap_conv_out_ce=>create( encoding = '4110' ). "UTF-8 is 4110
          loc_out_conv->convert( EXPORTING data = qrcode_string IMPORTING buffer = qrcode_xstring ).
      ***************Encode xString to Base64*********************
          CALL METHOD cl_http_utility=>if_http_utility~encode_x_base64
            EXPORTING
              unencoded = qrcode_xstring
            RECEIVING
              encoded   = qrcode_base64.

      I tried with your data and following is the result

      QRCODE_STRING

      ##الجواهري العربي##310122393500003##2021-12-01 14:40:20##1150.00##150.00

      QRCODE_XSTRING

      011DD8A7D984D8ACD988D8A7D987D8B1D98A20D8A7D984D8B9D8B1D8A8D98A020F3331303132323339333530303030330313323032312D31322D30312031343A34303A3230040731313530

      QRCODE_BASE64 AR3Yp9mE2KzZiNin2YfYsdmKINin2YTYudix2KjZigIPMzEwMTIyMzkzNTAwMDAzAxMyMDIxLTEyLTAxIDE0OjQwOjIwBAcxMTUwLjAwBQYxNTAuMDA=

      Author's profile photo Mohammad Nawazuddin
      Mohammad Nawazuddin

      Brother Asharaf,,

      Thanks for your reply but  that generated QRCODE is not compataible with E-invoice QR Reader application   actully i am looking same like what they given QRCODE in example zatca site.

       

       

       

       

       

      Thanks,

      Nawazuddin.

      Author's profile photo S M Firoz Ashraf
      S M Firoz Ashraf
      Blog Post Author

      Try the code suggested in

      https://blogs.sap.com/2021/11/18/qr-code-in-base64-encoding-for-ksa-e-invoicing/comment-page-1/#comment-601245

      The generated base64 value is

      AR3Yp9mE2KzZiNin2YfYsdmKINin2YTYudix2KjZigIPMzEwMTIyMzkzNTAwMDAzAxMyMDIxLTEyLTAxIDEwOjIwOjMwBAcxMTUwLjAwBQYxNTAuMDA=

      Author's profile photo KHALID SHOKRY
      KHALID SHOKRY

      same problem

      this is my code

       

      Dim qrCode As New QRCodeEncoder
      qrCode.QRCodeEncodeMode = QRCodeEncoder.ENCODE_MODE.BYTE
      qrCode.QRCodeErrorCorrect = QRCodeEncoder.ERROR_CORRECTION.L

      Me.PictureBox1.Image = qrCode.Encode(Me.lblQR_CODE.Text, System.Text.Encoding.UTF8)

      Author's profile photo Ishaan Tabish
      Ishaan Tabish

      Hi Firoz Ashraf,

      Can you please explain more about 2nd step?

      after step one I am getting this result

      112Firoz Ashraf21012345678913192021-11-17 08:30:0046115.005515.00

      how to convert this to

      ‘##Firoz Ashraf##1234567891##2021-11-17 08:30:00##115.00##15.00’

      As you mentioned to convert tag and length to hexadecimal. I tried but got a different result. Please guide for the 2nd and 3rd steps. Thank You.

      Author's profile photo S M Firoz Ashraf
      S M Firoz Ashraf
      Blog Post Author

      Use the following code:

      **********Tag, Length & Value (TLV) all are converted to hexadecimal
      *         format and then concatenated into one hexa string. This
      *         hexa string is then transformed to base64.
      DATA:   v_tlv_1     TYPE xstring,
              v_tlv_2     TYPE xstring,
              v_tlv_3     TYPE xstring,
              v_tlv_4     TYPE xstring,
              v_tlv_5     TYPE xstring.
      
          PERFORM tlv USING 1 v_t1_cname  CHANGING v_tlv_1.
          PERFORM tlv USING 2 v_t2_vatno  CHANGING v_tlv_2.
          PERFORM tlv USING 3 v_t3_tstmp  CHANGING v_tlv_3.
          PERFORM tlv USING 4 v_t4_invamx CHANGING v_tlv_4.
          PERFORM tlv USING 5 v_t5_vatamx CHANGING v_tlv_5.
      
      ***************Concatenate all TLV data********************
          CONCATENATE v_tlv_1 v_tlv_2 v_tlv_3 v_tlv_4 v_tlv_5
            INTO qrcode_xstring IN BYTE MODE.
      
      ***************Encode xString to Base64*********************
          CALL METHOD cl_http_utility=>if_http_utility~encode_x_base64
            EXPORTING
              unencoded = qrcode_xstring
            RECEIVING
              encoded   = qrcode_base64.

      Subroutine TLV is

      FORM tlv  USING    p_tag TYPE i
                         p_value TYPE string
                CHANGING p_tlv TYPE xstring.
      
        DATA: v_tag_byte TYPE x LENGTH 1,
              v_utf8     TYPE xstring,
              v_length   TYPE x LENGTH 1.
      
        v_tag_byte = p_tag.
        v_utf8 = cl_abap_codepage=>convert_to( p_value ).
        v_length = xstrlen( v_utf8 ).
        CONCATENATE v_tag_byte v_length v_utf8 INTO p_tlv IN BYTE MODE.
      
      ENDFORM.