Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 19 additions & 18 deletions src/Apps/W1/EDocument/App/.resources/AITools/ubl_example.json
Original file line number Diff line number Diff line change
Expand Up @@ -106,26 +106,26 @@
"allowance_charge_reason": "",
"amount": {
"currency_id": "",
"value": "0"
"value": 0
},
"tax_category": {
"id": "",
"percent": "0",
"percent": 0,
"tax_scheme": {
"id": ""
}
}
}
],
"tax_total": {
"tax_amount": "0",
"tax_amount": 0,
"tax_subtotal": [
{
"taxable_amount": "0",
"tax_amount": "0",
"taxable_amount": 0,
"tax_amount": 0,
"tax_category": {
"id": "",
"percent": "0",
"percent": 0,
"tax_scheme": {
"id": ""
}
Expand All @@ -134,32 +134,33 @@
]
},
"legal_monetary_total": {
"line_extension_amount": "0",
"tax_exclusive_amount": "0",
"tax_inclusive_amount": "0",
"allowance_total_amount": "0",
"charge_total_amount": "0",
"payable_amount": "0"
"line_extension_amount": 0,
"tax_exclusive_amount": 0,
"tax_inclusive_amount": 0,
"allowance_total_amount": 0,
"charge_total_amount": 0,
"payable_amount": 0
},
"invoice_line": [
{
"id": "",
"invoiced_quantity": {
"unit_code": "",
"value": "0"
"value": 0
},
"line_extension_amount": "0",
"line_extension_amount": 0,
"allowance_charge": {
"charge_indicator": false,
"allowance_charge_reason_code": 0,
"allowance_charge_reason": "",
"percent": 0,
"amount": {
"currency_id": "",
"value": "0"
"value": 0
},
"tax_category": {
"id": "",
"percent": "0",
"percent": 0,
"tax_scheme": {
"id": ""
}
Expand All @@ -172,14 +173,14 @@
},
"classified_tax_category": {
"id": "",
"percent": "0",
"percent": 0,
"tax_scheme": {
"id": ""
}
}
},
"price": {
"price_amount": "0"
"price_amount": 0
}
}
]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,8 @@ CRITICAL FORMAT RULES:
- Tax scheme ID: Always use "VAT"
- Tax category ID: Use standard codes: S=Standard rate, Z=Zero rate, E=Exempt, AE=Reverse charge
- Unit codes: Use UN/ECE codes
- Allowance Charge: Leave allowance_charge section empty if no discount/charge exists on the document
- Allowance Charge: Leave allowance_charge section empty if no discount/charge exists on the document. Use allowance_charge.percent (0-100) when the invoice shows a discount percentage AND price_amount is the PRE-discount unit price; use allowance_charge.amount.value when the invoice shows a monetary discount amount. If the invoice shows a post-discount unit price (e.g. "Pris efter rab.", "Net price"), use it as price_amount and leave allowance_charge empty — do NOT combine a post-discount price with a percentage
- Numbers: Use XML decimal format — period (.) as decimal separator, no thousands separators (e.g., 1083 not "1 083", 2.34 not "2,34")


Output ONLY valid JSON. No markdown, no explanation.
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
// ------------------------------------------------------------------------------------------------
namespace Microsoft.eServices.EDocument.Processing.Import;

using Microsoft.eServices.EDocument;
using Microsoft.eServices.EDocument.Processing.Import.Purchase;
using Microsoft.Finance.GeneralLedger.Setup;
using Microsoft.Foundation.Company;
Expand Down Expand Up @@ -126,16 +127,21 @@ codeunit 6232 "E-Doc. MLLM Schema Helper"
end;
end;

procedure MapLinesFromJson(LinesArray: JsonArray; EDocEntryNo: Integer; var TempLine: Record "E-Document Purchase Line" temporary)
procedure MapLinesFromJson(LinesArray: JsonArray; EDocEntryNo: Integer; var TempLine: Record "E-Document Purchase Line" temporary; CurrencyCode: Code[10])
var
EDocumentImportHelper: Codeunit "E-Document Import Helper";
LineToken: JsonToken;
LineObj: JsonObject;
NestedObj: JsonObject;
NestedObj2: JsonObject;
LineNumber: Integer;
DiscountPct: Decimal;
RoundingPrecision: Decimal;
begin
TempLine.DeleteAll();

RoundingPrecision := EDocumentImportHelper.GetCurrencyRoundingPrecision(CurrencyCode);

for LineNumber := 0 to LinesArray.Count() - 1 do
if LinesArray.Get(LineNumber, LineToken) then begin
Clear(TempLine);
Expand Down Expand Up @@ -164,9 +170,16 @@ codeunit 6232 "E-Doc. MLLM Schema Helper"

GetDecimal(LineObj, 'line_extension_amount', TempLine."Sub Total");

if GetNestedObject(LineObj, 'allowance_charge', NestedObj) then
if GetNestedObject(LineObj, 'allowance_charge', NestedObj) then begin
if GetNestedObject(NestedObj, 'amount', NestedObj2) then
GetDecimal(NestedObj2, 'value', TempLine."Total Discount");
if TempLine."Total Discount" = 0 then begin
DiscountPct := 0;
GetDecimal(NestedObj, 'percent', DiscountPct);
if DiscountPct <> 0 then
TempLine."Total Discount" := Round(TempLine."Unit Price" * TempLine.Quantity * DiscountPct / 100, RoundingPrecision);
end;
end;

TempLine.Insert();
end;
Expand Down Expand Up @@ -208,12 +221,17 @@ codeunit 6232 "E-Doc. MLLM Schema Helper"
local procedure GetDecimal(JsonObj: JsonObject; PropertyName: Text; var FieldValue: Decimal)
var
JsonToken: JsonToken;
DecimalValue: Decimal;
DecimalParseFailedLbl: Label 'Could not parse decimal value returned by the model for property %1.', Comment = '%1 = JSON property name';
begin
if not JsonObj.Get(PropertyName, JsonToken) then
exit;
if JsonToken.AsValue().IsNull() then
exit;
FieldValue := JsonToken.AsValue().AsDecimal();
if Evaluate(DecimalValue, JsonToken.AsValue().AsText(), 9) then
FieldValue := DecimalValue
else
Session.LogMessage('0000UAR', StrSubstNo(DecimalParseFailedLbl, PropertyName), Verbosity::Warning, DataClassification::SystemMetadata, TelemetryScope::All, 'Category', 'E-Document');
end;

local procedure GetNestedObject(JsonObj: JsonObject; PropertyName: Text; var NestedObj: JsonObject): Boolean
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -298,7 +298,7 @@ codeunit 6231 "E-Document MLLM Handler" implements IStructureReceivedEDocument,
if SourceJsonObject.Get('invoice_line', LinesToken) then
if LinesToken.IsArray() then begin
LinesArray := LinesToken.AsArray();
EDocMLLMSchemaHelper.MapLinesFromJson(LinesArray, EDocument."Entry No", TempEDocPurchaseLine);
EDocMLLMSchemaHelper.MapLinesFromJson(LinesArray, EDocument."Entry No", TempEDocPurchaseLine, TempEDocPurchaseHeader."Currency Code");
end;
end;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@ codeunit 135647 "EDoc MLLM Tests"

LinesArray := BuildThreeLineArray();

EDocMLLMSchemaHelper.MapLinesFromJson(LinesArray, 1, TempLine);
EDocMLLMSchemaHelper.MapLinesFromJson(LinesArray, 1, TempLine, '');

TempLine.FindSet();
Assert.AreEqual(10000, TempLine."Line No.", 'First line number');
Expand Down Expand Up @@ -180,7 +180,7 @@ codeunit 135647 "EDoc MLLM Tests"
LineObj.Add('invoiced_quantity', QuantityObj);
LinesArray.Add(LineObj);

EDocMLLMSchemaHelper.MapLinesFromJson(LinesArray, 1, TempLine);
EDocMLLMSchemaHelper.MapLinesFromJson(LinesArray, 1, TempLine, '');

TempLine.FindFirst();
Assert.AreEqual(1, TempLine.Quantity, 'Zero quantity should default to 1');
Expand All @@ -197,7 +197,7 @@ codeunit 135647 "EDoc MLLM Tests"
// [SCENARIO] Empty lines array produces no line records
LibraryLowerPermission.SetOutsideO365Scope();

EDocMLLMSchemaHelper.MapLinesFromJson(LinesArray, 1, TempLine);
EDocMLLMSchemaHelper.MapLinesFromJson(LinesArray, 1, TempLine, '');

Assert.IsTrue(TempLine.IsEmpty(), 'No lines should be inserted for empty array');
end;
Expand Down
Loading