Friday, September 10, 2021

Read Multiple Level Response in Business Cental AL Extension by Json Token, Json Object & Json Array

Dear Firends,

Use below sample code to read multiple array document respone in AL Extension

Sample AL Input File 



{
   "orders":[
      {
         "DocumentNo":"SO004349",
         "Status":"Partially Shipped",
         "lines":[
            {
               "LineNo":20000,
               "QtyToShip":1,
               "Status":"Finalised"
            }
         ]
      },
      {
         "DocumentNo":"SO004424",
         "Status":"Partially Shipped",
         "lines":[
            {
               "LineNo":10000,
               "QtyToShip":5,
               "Status":"Finalised"
            },
            {
               "LineNo":20000,
               "QtyToShip":5,
               "Status":"Finalised"
            }
         ]
      },
      {
         "DocumentNo":"SO004423",
         "Status":"Partially Shipped",
         "lines":[
            {
               "LineNo":10000,
               "QtyToShip":4,
               "Status":"Finalised"
            }
         ]
      }
   ]
}

AL Extensoin Code to Read Above File:

procedure UpdateSOShipmentStatus_gFnc(JsonText: Text)Boolean
    var
        SalesHeader_lRec: Record "Sales Header";
        SalesLine_lRec: Record "Sales Line";
        WarehouseShipLine_lRec: Record "Warehouse Shipment Line";
        Jtoken: JsonToken;
        JObject: JsonObject;
        jsonval: JsonValue;
        Jarray: JsonArray;
        i: Integer;
        j: Integer;
        TotalCount: Integer;
        OrderCount: Integer;
        Location_lRec: Record Location;
        ReqWareShip_lBln: Boolean;
        AnylineFound_lBln: Boolean;
    begin
        if not JObject.ReadFrom(JsonTextthen
            Error('Invalid response, expected a JSON object');

        JObject.Get('orders', Jtoken);

        if not Jarray.ReadFrom(Format(Jtoken)) then
            Error('Array not Reading Properly');

        TotalCount := 0;
        OrderCount := 0;
        TotalCount := Jarray.Count();
        for i := 0 to Jarray.Count() 1 do begin
            Jarray.Get(i, Jtoken);
            JObject := Jtoken.AsObject();

            Jtoken.AsObject.Get('DocumentNo', Jtoken);
            IF SalesHeader_lRec.GET(SalesHeader_lRec."Document Type"::Order, Jtoken.AsValue().AsCode()) then begin
                OrderCount += 1;

                Jarray.Get(i, Jtoken);
                if Jtoken.AsObject.Get('Status', Jtokenthen
                    SalesHeader_lRec."Shipment Status" := Jtoken.AsValue().AsText();

                JObject.Get('lines', Jtoken);
                for j := 0 to Jtoken.AsArray().Count() 1 do begin
                    JObject.Get('lines', Jtoken);
                    if Jtoken.AsArray().Get(j, Jtokenthen
                        Jtoken.AsObject.Get('LineNo', Jtoken);

                    if SalesLine_lRec.Get(SalesLine_lRec."Document Type"::Order, SalesHeader_lRec."No.", Jtoken.AsValue().AsInteger()) then begin
                        JObject.Get('lines', Jtoken);
                        if Jtoken.AsArray().Get(j, Jtokenthen
                            if Jtoken.AsObject.Get('QtyToShip', Jtokenthen begin
                                ReqWareShip_lBln := false;
                                IF Location_lRec.GET(SalesLine_lRec."Location Code"Then begin
                                    IF Location_lRec."Require Receive" Then begin
                                        ReqWareShip_lBln := true;
                                        WarehouseShipLine_lRec.RESET;
                                        WarehouseShipLine_lRec.Setrange("Source Type", 37);
                                        WarehouseShipLine_lRec.Setrange("Source Subtype", SalesLine_lRec."Document Type");
                                        WarehouseShipLine_lRec.Setrange("Source No.", SalesLine_lRec."Document No.");
                                        WarehouseShipLine_lRec.Setrange("Source Line No.", SalesLine_lRec."Line No.");
                                        IF WarehouseShipLine_lRec.FindFirst() Then begin
                                            IF WarehouseShipLine_lRec."Qty. Outstanding" <= Jtoken.AsValue().AsDecimal() THen
                                                WarehouseShipLine_lRec.Validate("Qty. to Ship", Jtoken.AsValue().AsDecimal())
                                            Else
                                                WarehouseShipLine_lRec.Validate("Qty. to Ship", WarehouseShipLine_lRec."Qty. Outstanding");

                                            WarehouseShipLine_lRec.Modify();
                                            AnylineFound_lBln := true;
                                        end;

                                    end;
                                end;
                                IF NOT ReqWareShip_lBln Then
                                    SalesLine_lRec.Validate("Qty. to Ship", Jtoken.AsValue().AsDecimal());
                            End;

                        JObject.Get('lines', Jtoken);
                        if Jtoken.AsArray().Get(j, Jtokenthen
                            if Jtoken.AsObject.Get('Status', Jtokenthen begin
                                SalesLine_lRec."Shipment Status" := Jtoken.AsValue().AsText();
                                SalesLine_lRec.Modify(true);
                                AnylineFound_lBln := true;

                                WarehouseShipLine_lRec.RESET;
                                WarehouseShipLine_lRec.Setrange("Source Type", 37);
                                WarehouseShipLine_lRec.Setrange("Source Subtype", SalesLine_lRec."Document Type");
                                WarehouseShipLine_lRec.Setrange("Source No.", SalesLine_lRec."Document No.");
                                WarehouseShipLine_lRec.Setrange("Source Line No.", SalesLine_lRec."Line No.");
                                IF WarehouseShipLine_lRec.FindFirst() Then begin
                                    WarehouseShipLine_lRec."Shipment Status" := SalesLine_lRec."Shipment Status";
                                    WarehouseShipLine_lRec.Modify();
                                    AnylineFound_lBln := true;
                                End;


                            end;
                    end;
                    SalesHeader_lRec.Modify(true);
                    AnylineFound_lBln := true;
                end;
            end;
        end;
        exit(AnylineFound_lBln);
    End;

========================================================================

New Example:

Simple single level Json Response:

{
    "access_token": "088e04b1-8efd-4491-a579-1cc4f07a7e68",
    "token_type": "bearer",
    "refresh_token": "cf822cb1-0b1e-48a4-aeda-db648b96d62a",
    "expires_in": 1479,
    "scope": "gstapi"
}
Reading AL code:

procedure ReadJson(JSONInput_iTxt: Text): TEXT
    var
        Jtoken: JsonToken;
        JObject: JsonObject;
        Customer_lRec: Record Customer;
        i: Integer;
        j: Integer;
        access_token: Text[100];
        token_type: Text[100];
        refresh_token: Text[100];
        expires_in: Text[80];
        scope: Guid;
        TotalCount: Integer;
        CustomerCount: Integer;
    begin
        If Not JObject.ReadFrom(JSONInput_iTxt) then
            Error('Invalid response, expected a JSON object');

        JObject.Get('access_token', Jtoken);
        access_token := Jtoken.AsValue().AsText();

        JObject.Get('token_type', Jtoken);
        token_type := Jtoken.AsValue().AsText();

        JObject.Get('refresh_token', Jtoken);
        refresh_token := Jtoken.AsValue().AsText();

        JObject.Get('expires_in', Jtoken);
        expires_in := Jtoken.AsValue().AsText();

        //JObject.Get('scope', Jtoken);
        //scope := Jtoken.AsValue().as();

        Exit(access_token);
    end;

=====================================================================

Second example where there are object inside Json Response

{
    "status": "1",
    "message": "Record Added Successfully",
    "data": {
        "docNum": "INVOICE00126",
        "ctin": "27GSPMH2101G1Z2",
        "docId": "612f4e83218788617684a121"
    }
}

Reading AL code:

 procedure ReadJosn(JsonText: Text): Boolean
    var
        Jtoken: JsonToken;
        JtokenInner: JsonToken;
        JObject: JsonObject;
        jsonval: JsonValue;
        Jarray: JsonArray;
        i: Integer;
        j: Integer;

        Status_lTxt: Text[30];
        Message_lTxt: Text[30];
        DocNum_lTxt: Text[30];
        CTIN_lTxt: Text[30];
        DocId_lTxt: Text[30];
    begin
        If Not JObject.ReadFrom(JsonText) then
            Error('Invalid response, expected a JSON object');

        if JObject.Get('status', Jtoken) then
            Status_lTxt := Jtoken.AsValue().AsText();

        if JObject.Get('message', Jtoken) then
            Message_lTxt := Jtoken.AsValue().AsText();

        JObject.Get('data', Jtoken);

        If Jtoken.AsObject().Get('docNum', JtokenInner) then
            DocNum_lTxt := JtokenInner.AsValue().AsText();

        If Jtoken.AsObject().Get('ctin', JtokenInner) then
            CTIN_lTxt := JtokenInner.AsValue().AsText();

        If Jtoken.AsObject().Get('docId', JtokenInner) then
            DocId_lTxt := JtokenInner.AsValue().AsText();

        Message(Status_lTxt, Message_lTxt, DocNum_lTxt, CTIN_lTxt, DocId_lTxt);
    end;

===========================

E-Invoice Response Read

{

    "invoices": [

        {

            "AckNo": 122610111383517,

            "AckDate": "2026-02-06 16:20:10",

            "Record": 1,

            "Success": false,

            "Fy": "202526",

            "Messages": "Duplicate IRN",

            "Status": "ERROR",

            "Irn": "8d150bd11436a6ee166e31680e1678ea38d4093932a50ed57e6a3790889f8084",

            "DocDtls": {

                "No": "DOC-NO/45253",

                "Dt": "31/01/2026",

                "Typ": "INV"

            },

            "SellerDtls": {

                "Gstin": "27AAKCM2754L1Z0"

            },

            "TranDtls": {

                "SupTyp": "B2B"

            },

            "CustDocNo": "DOC-NO/45253",

            "SignedQRCode": "eyJhbGciOiJSUzI1NiIsImtpZCI6IjNCRTE3RTUxNDE5MjUyMjY0N0YwMUZEQkZGNTI3MUFENTI2OEQ3MzUiLCJ4NXQiOiJPLUYtVVVHU1VpWkg4Ql9iXzFKeHJWSm8xelUiLCJ0eXAiOiJKV1QifQ.eyJpc3MiOiJOSUMgU2FuZGJveCIsImRhdGEiOiJ7XCJTZWxsZXJHc3RpblwiOlwiMjdBQUtDTTI3NTRMMVowXCIsXCJCdXllckdzdGluXCI6XCIwM0FBS0NNMjc1NEwxWkFcIixcIkRvY05vXCI6XCJET0MtTk8vNDUyNTNcIixcIkRvY1R5cFwiOlwiSU5WXCIsXCJEb2NEdFwiOlwiMzEvMDEvMjAyNlwiLFwiVG90SW52VmFsXCI6MTE4LFwiSXRlbUNudFwiOjEsXCJNYWluSHNuQ29kZVwiOlwiODQ3MTMwXCIsXCJJcm5cIjpcIjhkMTUwYmQxMTQzNmE2ZWUxNjZlMzE2ODBlMTY3OGVhMzhkNDA5MzkzMmE1MGVkNTdlNmEzNzkwODg5ZjgwODRcIixcIklybkR0XCI6XCIyMDI2LTAyLTA2IDE2OjIwOjEwXCJ9In0.RgKN_7aYdzyyzAFIOM4zsemZ33Aihx6iVzQNI_PdXZzW76NhkHA3rQgKevfJO-tF7soG6aTbXmK9hLMLJf06sfj3jmUXeSMVWVXjuLP1hcGmNEY3g2mpb9z_UbunsrjSOyijlSFJNukKn_UCtewCkfqeYI8-byYKql2EBZlWqiI_8XG-IlKqJDzw32yRNg3-Emz2koG1fie0fHbs0qKeehSLpOpNae8lHalcKY1JF0oR5KyZjF5fdmm6IVGwNC7iSqB-TVEP3BpBfSUbc-Ije-Im5b7-_hws5EOUyuhrrvWK8tNPFpnNwHmHIaA3POM6p3NmAO1o9KRcWx1hVT7o9w",

            "QrCode": "{\"SellerGstin\":\"27AAKCM2754L1Z0\",\"BuyerGstin\":\"03AAKCM2754L1ZA\",\"DocNo\":\"DOC-NO/45253\",\"DocTyp\":\"INV\",\"DocDt\":\"31/01/2026\",\"TotInvVal\":118,\"ItemCnt\":1,\"MainHsnCode\":\"847130\",\"Irn\":\"8d150bd11436a6ee166e31680e1678ea38d4093932a50ed57e6a3790889f8084\",\"IrnDt\":\"2026-02-06 16:20:10\"}",

            "EncodedId": "NDI0MTA4"

        }

    ]

}

FullAndFinalBody.WriteTo(ltext);

        IF EInvoiceSetup_gRec."Enable Sandbox Mode" THEN
            lurl := EInvoiceSetup_gRec."Sandbox E-Inv Generation API"
        ELSE
            lurl := EInvoiceSetup_gRec."E-Inv Generation API-URL";

        //NG-NS 040521
        IF EInvoiceSetup_gRec."Create Json File (OffLine)" THEN BEGIN
            Data_lTxt := FORMAT(ltext);
            FileName_ltxt := 'Sales Invoice_' + EInvoiceHeader_vRec.No;
            ExportAsJson(FileName_ltxt, ltext);
            EXIT;
        END;
        //NG-NE 040521

        // Message(ltext);
        IF EInvoiceSetup_gRec."Show Json Message for Debug" THEN
            MESSAGE(FORMAT(ltext));

        gcontent.WriteFrom(ltext);
        greqMsg.SetRequestUri(lurl);
        lheaders.Clear();
        gcontent.GetHeaders(lheaders);
        IF EInvoiceSetup_gRec."Enable Sandbox Mode" THEN BEGIN
            lheaders.Add('key', EInvoiceSetup_gRec."Sandbox Api Key");
        END ELSE BEGIN
            lheaders.Add('key', EInvoiceSetup_gRec."Production Api Key");
        END;
        lheaders.Remove('Content-Type');
        lheaders.Add('Content-Type', 'application/json');
        gcontent.GetHeaders(lheaders);
        greqMsg.Content(gcontent);
        greqMsg.GetHeaders(lheaders);

        greqMsg.Method := 'POST';
        if not gHttpClient.Send(greqMsg, gResponseMsg) then
            Error('API Authorization token request failed...');

        JSONResponse := '';
        gResponseMsg.Content().ReadAs(JSONResponse);

        if not JObject.ReadFrom(JSONResponse) then
            Error('Invalid response, expected a JSON object');

        if EInvoiceSetup_gRec."Show Json Message for Debug" then
            Message(JSONResponse);

        IF NOT JObject.Get('invoices', Jtoken) then
            Error(JSONResponse);

        if not Jarray.ReadFrom(Format(Jtoken)) then
            Error('Array not Reading Properly');

        Jarray.Get(0, Jtoken);  //Read First Value Only
        JObject := Jtoken.AsObject();

        ResponseStatus_lBln := false;
        if JObject.Get('Success', Jtoken) then begin
            if not Jtoken.AsValue().IsNull() then
                ResponseStatus_lBln := Jtoken.AsValue().AsBoolean();
        End;

        IF NOT ResponseStatus_lBln Then
            Error(JSONResponse);


        Jarray.Get(0, Jtoken);
        if JObject.Get('AckNo', Jtoken) then begin
            if not Jtoken.AsValue().IsNull() then
                AckNo_lTxt := Jtoken.AsValue().AsText();
        End;

        Jarray.Get(0, Jtoken);
        if JObject.Get('AckDate', Jtoken) then begin   //"2020-03-11 15:11:00"
            if not Jtoken.AsValue().IsNull() then
                AckDate_lTxt := Jtoken.AsValue().AsText();
        End;

        Jarray.Get(0, Jtoken);
        if JObject.Get('Irn', Jtoken) then begin
            if not Jtoken.AsValue().IsNull() then
                IRN_lTxt := Jtoken.AsValue().AsText();
        End;

        Jarray.Get(0, Jtoken);
        if JObject.Get('SignedQRCode', Jtoken) then begin
            if not Jtoken.AsValue().IsNull() then
                QRBase64String := Jtoken.AsValue().AsText();
        End;


        EInvoiceHeader_vRec.IRN := IRN_lTxt;
        EInvoiceHeader_vRec.AckNo := AckNo_lTxt;
        EInvoiceHeader_vRec.AckDate := AckDate_lTxt;  //"2020-03-11 15:11:00"
        //EInvoiceHeader_vRec.QrCodeImage := TempBlob.Blob;
        //GenrateQRCode(QRBase64String, EInvoiceHeader_vRec);
        if QRBase64String <> '' then begin
            Clear(TempBlob);
            Clear(RecordRef);
            Clear(FieldRef);
            EInvoiceHeader_vRec.Modify(True);
            RecordRef.Get(EInvoiceHeader_vRec.RecordId);
            QRGenerator.GenerateQRCodeImage(QRBase64String, TempBlob);
            FieldRef := RecordRef.Field(EInvoiceHeader_vRec.FieldNo(QrCodeImage));
            TempBlob.ToRecordRef(RecordRef, EInvoiceHeader_vRec.FieldNo(QrCodeImage));
            FieldRef := RecordRef.Field(EInvoiceHeader_vRec.FieldNo(QrCodeImage));
            EInvoiceHeader_vRec.QrCodeImage := FieldRef.Value;
        end;

        EInvoiceHeader_vRec.Status := EInvoiceHeader_vRec.Status::Generated;
        EInvoiceHeader_vRec.MODIFY(TRUE);

        CASE EInvoiceHeader_vRec."Document Type" OF
            EInvoiceHeader_vRec."Document Type"::"Sales Invoice":
                BEGIN
                    SIH_lRec.GET(EInvoiceHeader_vRec.No);
                    SIH_lRec."IRN Hash" := EInvoiceHeader_vRec.IRN;
                    SIH_lRec."Acknowledgement No." := EInvoiceHeader_vRec.AckNo;
                    SIH_lRec."Acknowledgement Date" := ConvertTextToDateTime_gFnc(EInvoiceHeader_vRec.AckDate, 2);
                    SIH_lRec."QR Code" := EInvoiceHeader_vRec.QrCodeImage;
                    SIH_lRec."E-Invoice Status" := EInvoiceHeader_vRec.Status;
                    SIH_lRec."E-Invoice Error" := FALSE;
                    SIH_lRec.MODIFY;
                END;
            EInvoiceHeader_vRec."Document Type"::"Sales Credit Memo":
                BEGIN
                    SCMH_lRec.GET(EInvoiceHeader_vRec.No);
                    SCMH_lRec."IRN Hash" := EInvoiceHeader_vRec.IRN;
                    SCMH_lRec."Acknowledgement No." := EInvoiceHeader_vRec.AckNo;
                    SCMH_lRec."Acknowledgement Date" := ConvertTextToDateTime_gFnc(EInvoiceHeader_vRec.AckDate, 2);
                    SCMH_lRec."QR Code" := EInvoiceHeader_vRec.QrCodeImage;
                    SCMH_lRec."E-Invoice Status" := EInvoiceHeader_vRec.Status;
                    SCMH_lRec."E-Invoice Error" := FALSE;
                    SCMH_lRec.MODIFY;
                END;
            EInvoiceHeader_vRec."Document Type"::"Purchase Credit Memo":
                BEGIN
                    PurchCrMemoHdr_lRec.GET(EInvoiceHeader_vRec.No);
                    PurchCrMemoHdr_lRec."IRN Hash" := EInvoiceHeader_vRec.IRN;
                    PurchCrMemoHdr_lRec."Acknowledgement No." := EInvoiceHeader_vRec.AckNo;
                    PurchCrMemoHdr_lRec."Acknowledgement Date" := ConvertTextToDateTime_gFnc(EInvoiceHeader_vRec.AckDate, 2);
                    PurchCrMemoHdr_lRec."QR Code" := EInvoiceHeader_vRec.QrCodeImage;
                    PurchCrMemoHdr_lRec."E-Invoice Status" := EInvoiceHeader_vRec.Status;
                    PurchCrMemoHdr_lRec."E-Invoice Error" := FALSE;
                    PurchCrMemoHdr_lRec.MODIFY;
                END;
            EInvoiceHeader_vRec."Document Type"::"Transfer Shipment":
                BEGIN

                END;
            EInvoiceHeader_vRec."Document Type"::"Service Invoice":
                BEGIN
                    SerIH_lRec.GET(EInvoiceHeader_vRec.No);
                    SerIH_lRec."IRN Hash" := EInvoiceHeader_vRec.IRN;
                    SerIH_lRec."Acknowledgement No." := EInvoiceHeader_vRec.AckNo;
                    SerIH_lRec."Acknowledgement Date" := ConvertTextToDateTime_gFnc(EInvoiceHeader_vRec.AckDate, 2);
                    SerIH_lRec."QR Code" := EInvoiceHeader_vRec.QrCodeImage;
                    SerIH_lRec."E-Invoice Status" := EInvoiceHeader_vRec.Status;
                    SerIH_lRec.MODIFY;
                END;
            EInvoiceHeader_vRec."Document Type"::"Service Credit Memo":
                BEGIN
                    SerCMHdr_lRec.GET(EInvoiceHeader_vRec.No);
                    SerCMHdr_lRec."IRN Hash" := EInvoiceHeader_vRec.IRN;
                    SerCMHdr_lRec."Acknowledgement No." := EInvoiceHeader_vRec.AckNo;
                    SerCMHdr_lRec."Acknowledgement Date" := ConvertTextToDateTime_gFnc(EInvoiceHeader_vRec.AckDate, 2);
                    SerCMHdr_lRec."QR Code" := EInvoiceHeader_vRec.QrCodeImage;
                    SerCMHdr_lRec."E-Invoice Status" := EInvoiceHeader_vRec.Status;
                    SerCMHdr_lRec."E-Invoice Error" := FALSE;
                    SerCMHdr_lRec.MODIFY;
                END;
            ELSE
                ERROR('Case not define for Document Type %1', EInvoiceHeader_vRec."Document Type");
        END;

=========================================

Reading below Response


























==============================



No comments:

Post a Comment