Inkey Solution Logo
banner

Blogs

How to create a QR Code that is the Base64 encoded TLV (Tag, Length, Value) in Dynamics 365 Business Central

, August 30, 2024 419 Views

Microsoft Dynamics 365 Business Central is a powerful Enterprise Resource Planning (ERP) solution that offers a wide range of customization options to meet the unique needs of your business. One such customization is to create a QR Code that is the Base64 encoded TLV (Tag, Length, Value) in Dynamics 365 Business Central.

Prerequisites

  • Access to a Dynamics 365 Business Central instance.
  • Basic knowledge of AL (Application Language) code.
  • Visual Studio Code with AL Language extension installed.

Requirement

How to create a QR code that is the Base64 encoded TLV (Tag, Length, Value) in Dynamics 365 Business Central where TLV is:

  • Tag: Identifies uniquely the type of data. It’s stored in a single byte.
  • Length: Length of the data field in bytes. The length shall be stored in one byte.
  • Value: The byte array of the actual data being transmitted, which can be of any type or format.

Solution (Implementation Steps)

First, let’s understand what Tag-Length-Value (TLV) is:

Tag-Length-Value (TLV) is a binary format used to represent data in a structured way. It’s a simple and widely used encoding format in computer systems. TLV is commonly used in:

  • Communication protocols
  • Data storage formats
  • Application-specific data exchanges
  • Computer networking protocols
  • Smart card applications
  • Payment processing systems

TLV is a byte array that has three parts:

  • Tag: Identifies the type of data
  • Length: Specifies the length of the data in bytes or octets
  • Value: The data itself

TLV allows groups of variable-length data elements to be combined into one buffer. The value part may contain other TLVs.

TLV is also known as BER-TLV, which stands for Basic Encoding Rules.

Step 1: To create a QR code that is Base64 encoded TLV (Tag, Length, Value) in Dynamics 365 Business Central, first we will create a procedure that will convert the data into TLV format.

So, let’s Define a procedure that has two parameters ‘TagInt’ of integer type and ‘ValueStr’of text type, and the function also returns a text value (variable name is ‘ByteStr’).

procedure getTLVByteStr(TagInt: Integer; ValueStr: Text) ByteStr: Text
begin
end;

Step 2: Now declare three variables in the function,

procedure getTLVByteStr(TagInt: Integer; ValueStr: Text) ByteStr: Text
var
   ByteArr: array[1000000] of Byte;
   i: integer;
   j: integer;
begin
end;

Step 3: Now, let’s store ‘TagInt’ and the length of the ‘ValueStr’ parameters in byte array (ByteArr). Because as mentioned above TLV values are stored in bytes so here we are storing the tag and length of the value in one byte each.

procedure getTLVByteStr(TagInt: Integer; ValueStr: Text) ByteStr: Text
var
   ByteArr: array[1000000] of Byte;
   i: integer;
   j: integer;
begin
   ByteArr[1] := TagInt;
   ByteArr[2] := StrLen(ValueStr);		
end;

Step 4: So, we have stored Tag and Length in a byte array (ByteArr). But to store a Value string (ValueStr) in a byte array (ByteArr), we will use a for loop to store every Value string (ValueStr) character in a byte array (ByteArr).

procedure getTLVByteStr(TagInt: Integer; ValueStr: Text) ByteStr: Text
    var
        ByteArr: array[1000000] of Byte;
        i: integer;
        j: integer;
    begin
        ByteArr[1] := TagInt;
        ByteArr[2] := StrLen(ValueStr);

        j := 3;

        for i := 1 to StrLen(ValueStr) do begin
            ByteArr[j] := ValueStr[i];
            j += 1;
    end;
end

Here, we have stored Tag and Length in positions 1 and 2 of the byte array respectively. So, we will store Value from position 3 of the byte array.

Step 5: Now we will store the byte array as a text in a Bytestr text variable using a for loop.

procedure getTLVByteStr(TagInt: Integer; ValueStr: Text) ByteStr: Text
    var
        ByteArr: array[1000000] of Byte;
        i: integer;
        j: integer;
    begin
        ByteArr[1] := TagInt;
        ByteArr[2] := StrLen(ValueStr);

        j := 3;

        for i := 1 to StrLen(ValueStr) do begin
            ByteArr[j] := ValueStr[i];
            j += 1;
        end;

        Clear(ByteStr);

        for i := 1 to ArrayLen(ByteArr) do begin
            if ByteArr[i] <> 0 then begin
                ByteStr += Format(ByteArr[i])
            end
            else
                break
        end;
end;

Make sure to use the Clear() method for the ByteStr variable because here we are appending the values in it without assigning any default value.

 

Step 6: Now let’s put this function in a report and declare two global variables ‘QR Code’ text type and ‘Convert’ codeunit type for the report as well.

 

Here, the ‘Convert’ variable contains the codeunit from the following link:

ALCodeSamples/Base64Convert/Base64Convert.al at master · ajkauffmann/ALCodeSamples · GitHub

report 50104 ItemBarCode
{
    UsageCategory = Administration;
    ApplicationArea = All;
    DefaultLayout = RDLC;
    Caption = 'Item Barcodes';
    RDLCLayout = 'ItemBarcodes.rdl';

    dataset
    {
        dataitem(Item; Item)
        {
            DataItemTableView = sorting("No.");
            RequestFilterFields = "No.";
            RequestFilterHeading = 'Items';
            column(No_; "No.")
            {
            }
            column(Description; Description)
            {
            }
            column(QRCode; QRCode)
            {
            }
            trigger OnAfterGetRecord()
            begin
                GenerateQRCode();
            end;
        }
    }

    procedure getTLVByteStr(TagInt: Integer; ValueStr: Text) ByteStr: Text
    var
        ByteArr: array[1000000] of Byte;
        i: integer;
        j: integer;
    begin
        ByteArr[1] := TagInt;
        ByteArr[2] := StrLen(ValueStr);

        j := 3;

        for i := 1 to StrLen(ValueStr) do begin
            ByteArr[j] := ValueStr[i];
            j += 1;
        end;

        Clear(ByteStr);

        for i := 1 to ArrayLen(ByteArr) do begin
            if ByteArr[i] <> 0 then begin
                ByteStr += Format(ByteArr[i])
            end
            else
                break
        end;
    end;

    var
        QRCode: Text;
        Convert: Codeunit "Base64Convert"; 
}

Step 7: Now let’s create one more method that converts the TLV value into a Base64 string and then creates the QR code of that Base64 string.

First, let’s declare a method with the following variables,

procedure GenerateQRCode()
    var
        BarcodeString: Text;
        Base64BarcodeString: Text;
        BarcodeSymbology2D: Enum "Barcode Symbology 2D";
        BarcodeFontProvider2D: Interface "Barcode Font Provider 2D";
    begin
    

Step 8: Now, call the getTLVByteStr() functions with the parameters that contain the Tag and Value you want to convert to the proper TLV byte array and store it in a BarcodeString variable.

(Here I’ve taken an integer tag with values like item number, item description, and item unit price because I am creating a QR code for an item report)

procedure GenerateQRCode()
    var
        BarcodeString: Text;
        Base64BarcodeString: Text;
        BarcodeSymbology2D: Enum "Barcode Symbology 2D";
        BarcodeFontProvider2D: Interface "Barcode Font Provider 2D";
    begin
        BarcodeString := getTLVByteStr(1, Item."No.") + getTLVByteStr(2, Item.Description) + getTLVByteStr(3, Format(Item."Unit Price"));
    end;

Step 9: Now convert the BarcodeString values into Base64 using the Base64Covert codeunit and store it in the Base64BarcodeString variable.

procedure GenerateQRCode()
    var
        BarcodeString: Text;
        Base64BarcodeString: Text;
        BarcodeSymbology2D: Enum "Barcode Symbology 2D";
        BarcodeFontProvider2D: Interface "Barcode Font Provider 2D";
    begin
        BarcodeString := getTLVByteStr(1, Item."No.") + getTLVByteStr(2, Item.Description) + getTLVByteStr(3, Format(Item."Unit Price"));

        Base64BarcodeString := Convert.TextToBase64String(BarcodeString);
    end;

Step 10: Now create a QR code for the Base64BarcodeString value by using ‘Enum “Barcode Symbology 2D”’ and ‘Interface “Barcode Font Provider 2D”;’ and put the function on the report as well.

report 50104 ItemBarCode
{
    UsageCategory = Administration;
    ApplicationArea = All;
    DefaultLayout = RDLC;
    Caption = 'Item Barcodes';
    RDLCLayout = 'ItemBarcodes.rdl';
    dataset
    {
        dataitem(Item; Item)
        {
            DataItemTableView = sorting("No.");
            RequestFilterFields = "No.";
            RequestFilterHeading = 'Items';
            column(No_; "No.")
            {
            }
            column(Description; Description)
            {
            }
            column(QRCode; QRCode)
            {
            }
            trigger OnAfterGetRecord()
            begin
                GenerateQRCode();
            end;
        }
    }

    procedure GenerateQRCode()
    var
        BarcodeString: Text;
        Base64BarcodeString: Text;
        BarcodeSymbology2D: Enum "Barcode Symbology 2D";
        BarcodeFontProvider2D: Interface "Barcode Font Provider 2D";
    begin
        BarcodeString := getTLVByteStr(1, Item."No.") + getTLVByteStr(2, Item.Description) + getTLVByteStr(3, Format(Item."Unit Price"));

        Base64BarcodeString := Convert.TextToBase64String(BarcodeString);

        BarcodeFontProvider2D := Enum::"Barcode Font Provider 2D"::IDAutomation2D;
        BarcodeSymbology2D := Enum::"Barcode Symbology 2D"::"QR-Code";
        QRCode := BarcodeFontProvider2D.EncodeFont(Base64BarcodeString, BarcodeSymbology2D);
    end;

    procedure getTLVByteStr(TagInt: Integer; ValueStr: Text) ByteStr: Text
    var
        ByteArr: array[1000000] of Byte;
        i: integer;
        j: integer;
    begin
        ByteArr[1] := TagInt;
        ByteArr[2] := StrLen(ValueStr);

        j := 3;

        for i := 1 to StrLen(ValueStr) do begin
            ByteArr[j] := ValueStr[i];
            j += 1;
        end;

        Clear(ByteStr);

        for i := 1 to ArrayLen(ByteArr) do begin
            if ByteArr[i] <> 0 then begin
                ByteStr += Format(ByteArr[i])
            end
            else
                break
        end;
    end;

    var
        QRCode: Text;
        Convert: Codeunit "Base64Convert";
}

Step 11: Now press Ctrl + Shift + B and ItemBarcodes.rdl will be created now right click on the ItemBarcodes.rdl and select ‘Open Externally’ option.

Now it will open on a Report Builder.

Step 12: Now drag the QR code field on the report body and set its font style to IDAutomation2D.

 

Step 13: Now save the report, publish the extension, and open and run the report in Business Central.

You will see the QR Code. Now, scan it with the “Barcode Data Decoder Verifier” application you can download it from the Play Store.

In the above picture at the top is the Base64 string and after that is the TLV value.

mm

Inkey

INKEY is your solution partner.
Our focus is to deliver you in-time intelligent innovative solutions ("key") for the problems in hand. Maintaining a quality standard right from the inception of a project is our top most priority.

Our team of talented professionals will execute your projects with dedication and excellence. We take ownership and accountability for the effort that goes into meeting our client’s needs.

Years of experience and proven success of delivering innovative custom solutions.

More posts by

Leave a Reply

Your email address will not be published. Required fields are marked *

The maximum upload file size: 2 MB. You can upload: image, audio, video, document, spreadsheet, interactive, text, archive, code, other. Drop file here

Would you like to digitize your business and put it on the cloud?
Do you need clear, concise reports for your organization?