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(JsonText) then
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', Jtoken) then
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, Jtoken) then
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, Jtoken) then
if Jtoken.AsObject.Get('QtyToShip', Jtoken) then 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, Jtoken) then
if Jtoken.AsObject.Get('Status', Jtoken) then 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