diff --git a/Apps/DE/EDocumentDE/app/src/XRechnung/EDocumentXRechnungHandler.Codeunit.al b/Apps/DE/EDocumentDE/app/src/XRechnung/EDocumentXRechnungHandler.Codeunit.al
new file mode 100644
index 0000000000..2f40d9687e
--- /dev/null
+++ b/Apps/DE/EDocumentDE/app/src/XRechnung/EDocumentXRechnungHandler.Codeunit.al
@@ -0,0 +1,323 @@
+// ------------------------------------------------------------------------------------------------
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License. See License.txt in the project root for license information.
+// ------------------------------------------------------------------------------------------------
+namespace Microsoft.eServices.EDocument.Formats;
+
+using Microsoft.eServices.EDocument;
+using Microsoft.eServices.EDocument.Helpers;
+using Microsoft.eServices.EDocument.Processing.Import;
+using Microsoft.eServices.EDocument.Processing.Import.Purchase;
+using Microsoft.eServices.EDocument.Processing.Interfaces;
+using Microsoft.eServices.EDocument.Service.Participant;
+using Microsoft.Purchases.Vendor;
+using System.Telemetry;
+using System.Utilities;
+
+codeunit 13921 "E-Document XRechnung Handler" implements IStructuredFormatReader
+{
+ Access = Internal;
+ InherentEntitlements = X;
+ InherentPermissions = X;
+
+ var
+ SchemeIDGLNTok: Label '0088', Locked = true;
+ InvoiceLineTok: Label 'cac:InvoiceLine', Locked = true;
+ CreditNoteLineTok: Label 'cac:CreditNoteLine', Locked = true;
+
+ ///
+ /// Reads an XRechnung format XML document and converts it into a draft purchase document.
+ /// This procedure processes both Invoice and CreditNote document types and populates the E-Document Purchase Header with the extracted data.
+ ///
+ /// The E-Document record that contains the document metadata and information.
+ /// A temporary blob containing the XML document stream to be processed.
+ /// Returns an enum indicating that the process resulted in a purchase document draft.
+ internal procedure ReadIntoDraft(EDocument: Record "E-Document"; TempBlob: Codeunit "Temp Blob"): Enum "E-Doc. Process Draft"
+ var
+ EDocumentPurchaseHeader: Record "E-Document Purchase Header";
+ FeatureTelemetry: Codeunit "Feature Telemetry";
+ XRechnungXml: XmlDocument;
+ XmlNamespaces: XmlNamespaceManager;
+ XmlElement: XmlElement;
+ CommonAggregateComponentsTok: Label 'urn:oasis:names:specification:ubl:schema:xsd:CommonAggregateComponents-2', Locked = true;
+ CommonBasicComponentsTok: Label 'urn:oasis:names:specification:ubl:schema:xsd:CommonBasicComponents-2', Locked = true;
+ DefaultInvoiceTok: Label 'urn:oasis:names:specification:ubl:schema:xsd:Invoice-2', Locked = true;
+ DefaultCreditNoteTok: Label 'urn:oasis:names:specification:ubl:schema:xsd:CreditNote-2', Locked = true;
+ FeatureNameTok: Label 'E-document XRechnung Format', Locked = true;
+ StartEventNameTok: Label 'E-document XRechnung import started. Parsing basic information.', Locked = true;
+ begin
+ FeatureTelemetry.LogUsage('0000EXH', FeatureNameTok, StartEventNameTok);
+ EDocumentPurchaseHeader.InsertForEDocument(EDocument);
+
+ XmlDocument.ReadFrom(TempBlob.CreateInStream(TextEncoding::UTF8), XRechnungXml);
+ XmlNamespaces.AddNamespace('cac', CommonAggregateComponentsTok);
+ XmlNamespaces.AddNamespace('cbc', CommonBasicComponentsTok);
+ XmlNamespaces.AddNamespace('inv', DefaultInvoiceTok);
+ XmlNamespaces.AddNamespace('cn', DefaultCreditNoteTok);
+
+ XRechnungXml.GetRoot(XmlElement);
+ case UpperCase(XmlElement.LocalName()) of
+ 'INVOICE':
+ PopulateEDocumentForInvoice(XRechnungXml, XmlNamespaces, EDocumentPurchaseHeader, EDocument);
+ 'CREDITNOTE':
+ PopulateEDocumentForCreditNote(XRechnungXml, XmlNamespaces, EDocumentPurchaseHeader, EDocument);
+ end;
+
+ EDocumentPurchaseHeader.Modify(false);
+ EDocument.Direction := EDocument.Direction::Incoming;
+ exit(Enum::"E-Doc. Process Draft"::"Purchase Document");
+ end;
+
+ ///
+ /// Displays a readable view of the processed E-Document purchase information.
+ /// This procedure opens a page showing the purchase header and lines in a user-friendly format for review.
+ ///
+ /// The E-Document record that contains the document to be displayed.
+ /// A temporary blob containing the document data (not used in current implementation).
+ internal procedure View(EDocument: Record "E-Document"; TempBlob: Codeunit "Temp Blob")
+ var
+ EDocPurchaseHeader: Record "E-Document Purchase Header";
+ EDocPurchaseLine: Record "E-Document Purchase Line";
+ EDocReadablePurchaseDoc: Page "E-Doc. Readable Purchase Doc.";
+ begin
+ EDocPurchaseHeader.GetFromEDocument(EDocument);
+ EDocPurchaseLine.SetRange("E-Document Entry No.", EDocPurchaseHeader."E-Document Entry No.");
+ EDocReadablePurchaseDoc.SetBuffer(EDocPurchaseHeader, EDocPurchaseLine);
+ EDocReadablePurchaseDoc.Run();
+ end;
+
+ local procedure PopulateEDocumentForInvoice(XRechnungXml: XmlDocument; XmlNamespaces: XmlNamespaceManager; var EDocumentPurchaseHeader: Record "E-Document Purchase Header"; var EDocument: Record "E-Document")
+ var
+ EDocumentXMLHelper: Codeunit "EDocument XML Helper";
+ VendorNo: Code[20];
+ begin
+ EDocumentPurchaseHeader."E-Document Type" := "E-Document Type"::"Purchase Invoice";
+#pragma warning disable AA0139 // false positive: overflow handled by SetStringValueInField
+ EDocumentXMLHelper.SetStringValueInField(XRechnungXml, XmlNamespaces, '/inv:Invoice/cbc:ID', MaxStrLen(EDocumentPurchaseHeader."Sales Invoice No."), EDocumentPurchaseHeader."Sales Invoice No.");
+ EDocumentXMLHelper.SetDateValueInField(XRechnungXml, XmlNamespaces, '/inv:Invoice/cbc:IssueDate', EDocumentPurchaseHeader."Document Date");
+ EDocumentXMLHelper.SetDateValueInField(XRechnungXml, XmlNamespaces, '/inv:Invoice/cbc:DueDate', EDocumentPurchaseHeader."Due Date");
+ EDocumentXMLHelper.SetCurrencyValueInField(XRechnungXml, XmlNamespaces, '/inv:Invoice/cbc:DocumentCurrencyCode', MaxStrLen(EDocumentPurchaseHeader."Currency Code"), EDocumentPurchaseHeader."Currency Code");
+ EDocumentXMLHelper.SetStringValueInField(XRechnungXml, XmlNamespaces, '/inv:Invoice/cac:OrderReference/cbc:ID', MaxStrLen(EDocumentPurchaseHeader."Purchase Order No."), EDocumentPurchaseHeader."Purchase Order No.");
+#pragma warning restore AA0139
+ EDocumentXMLHelper.SetNumberValueInField(XRechnungXml, XmlNamespaces, '/inv:Invoice/cac:LegalMonetaryTotal/cbc:TaxExclusiveAmount', EDocumentPurchaseHeader."Sub Total");
+ EDocumentXMLHelper.SetNumberValueInField(XRechnungXml, XmlNamespaces, '/inv:Invoice/cac:LegalMonetaryTotal/cbc:TaxInclusiveAmount', EDocumentPurchaseHeader.Total);
+ EDocumentXMLHelper.SetNumberValueInField(XRechnungXml, XmlNamespaces, '/inv:Invoice/cac:LegalMonetaryTotal/cbc:PayableAmount', EDocumentPurchaseHeader."Amount Due");
+ EDocumentPurchaseHeader."Total VAT" := EDocumentPurchaseHeader.Total - EDocumentPurchaseHeader."Sub Total" - EDocumentPurchaseHeader."Total Discount";
+ VendorNo := ParseAccountingSupplierParty(XRechnungXml, XmlNamespaces, EDocumentPurchaseHeader, EDocument, 'inv:Invoice');
+ ParseAccountingCustomerParty(XRechnungXml, XmlNamespaces, EDocumentPurchaseHeader, 'inv:Invoice');
+ if VendorNo <> '' then
+ EDocumentPurchaseHeader."[BC] Vendor No." := VendorNo;
+ InsertXRechnungPurchaseLines(XRechnungXml, XmlNamespaces, EDocumentPurchaseHeader."E-Document Entry No.", EDocumentPurchaseHeader."E-Document Type");
+ end;
+
+ local procedure PopulateEDocumentForCreditNote(XRechnungXml: XmlDocument; XmlNamespaces: XmlNamespaceManager; var EDocumentPurchaseHeader: Record "E-Document Purchase Header"; var EDocument: Record "E-Document")
+ var
+ EDocumentXMLHelper: Codeunit "EDocument XML Helper";
+ VendorNo: Code[20];
+ begin
+ EDocumentPurchaseHeader."E-Document Type" := "E-Document Type"::"Purchase Credit Memo";
+#pragma warning disable AA0139 // false positive: overflow handled by SetStringValueInField
+ EDocumentXMLHelper.SetStringValueInField(XRechnungXml, XmlNamespaces, '/cn:CreditNote/cbc:ID', MaxStrLen(EDocumentPurchaseHeader."Sales Invoice No."), EDocumentPurchaseHeader."Sales Invoice No.");
+ EDocumentXMLHelper.SetDateValueInField(XRechnungXml, XmlNamespaces, '/cn:CreditNote/cbc:IssueDate', EDocumentPurchaseHeader."Document Date");
+ EDocumentXMLHelper.SetDateValueInField(XRechnungXml, XmlNamespaces, '/cn:CreditNote/cbc:DueDate', EDocumentPurchaseHeader."Due Date");
+ EDocumentXMLHelper.SetCurrencyValueInField(XRechnungXml, XmlNamespaces, '/cn:CreditNote/cbc:DocumentCurrencyCode', MaxStrLen(EDocumentPurchaseHeader."Currency Code"), EDocumentPurchaseHeader."Currency Code");
+ EDocumentXMLHelper.SetStringValueInField(XRechnungXml, XmlNamespaces, '/cn:CreditNote/cac:OrderReference/cbc:ID', MaxStrLen(EDocumentPurchaseHeader."Purchase Order No."), EDocumentPurchaseHeader."Purchase Order No.");
+#pragma warning restore AA0139
+ EDocumentXMLHelper.SetNumberValueInField(XRechnungXml, XmlNamespaces, '/cn:CreditNote/cac:LegalMonetaryTotal/cbc:TaxExclusiveAmount', EDocumentPurchaseHeader."Sub Total");
+ EDocumentXMLHelper.SetNumberValueInField(XRechnungXml, XmlNamespaces, '/cn:CreditNote/cac:LegalMonetaryTotal/cbc:TaxInclusiveAmount', EDocumentPurchaseHeader.Total);
+ EDocumentXMLHelper.SetNumberValueInField(XRechnungXml, XmlNamespaces, '/cn:CreditNote/cac:LegalMonetaryTotal/cbc:PayableAmount', EDocumentPurchaseHeader."Amount Due");
+ EDocumentPurchaseHeader."Total VAT" := EDocumentPurchaseHeader.Total - EDocumentPurchaseHeader."Sub Total" - EDocumentPurchaseHeader."Total Discount";
+ VendorNo := ParseAccountingSupplierParty(XRechnungXml, XmlNamespaces, EDocumentPurchaseHeader, EDocument, 'cn:CreditNote');
+ ParseAccountingCustomerParty(XRechnungXml, XmlNamespaces, EDocumentPurchaseHeader, 'cn:CreditNote');
+ if VendorNo <> '' then
+ EDocumentPurchaseHeader."[BC] Vendor No." := VendorNo;
+ InsertXRechnungPurchaseLines(XRechnungXml, XmlNamespaces, EDocumentPurchaseHeader."E-Document Entry No.", EDocumentPurchaseHeader."E-Document Type");
+ end;
+
+ local procedure ParseAccountingSupplierParty(XRechnungXml: XmlDocument; XmlNamespaces: XmlNamespaceManager; var EDocumentPurchaseHeader: Record "E-Document Purchase Header"; var EDocument: Record "E-Document"; DocumentType: Text) VendorNo: Code[20]
+ var
+ EDocumentImportHelper: Codeunit "E-Document Import Helper";
+ EDocumentXMLHelper: Codeunit "EDocument XML Helper";
+ EMTok: Label 'EM', Locked = true;
+ RoutingIdTok: Label '0198', Locked = true;
+ VATRegNoTok: Label '9930', Locked = true;
+ VendorName, VendorAddress, VendorParticipantId : Text;
+ VATRegistrationNo: Text[20];
+ EndpointID, SchemeID : Text;
+ GLN: Code[13];
+ BasePathTxt: Text;
+ XMLNode: XmlNode;
+ begin
+#pragma warning disable AA0139 // false positive: overflow handled by SetStringValueInField
+ BasePathTxt := '/' + DocumentType + '/cac:AccountingSupplierParty/cac:Party';
+ EDocumentXMLHelper.SetStringValueInField(XRechnungXml, XmlNamespaces, BasePathTxt + '/cac:PartyName/cbc:Name', MaxStrLen(EDocumentPurchaseHeader."Vendor Company Name"), EDocumentPurchaseHeader."Vendor Company Name");
+ EDocumentXMLHelper.SetStringValueInField(XRechnungXml, XmlNamespaces, BasePathTxt + '/cac:PostalAddress/cbc:StreetName', MaxStrLen(EDocumentPurchaseHeader."Vendor Address"), EDocumentPurchaseHeader."Vendor Address");
+ EDocumentXMLHelper.SetStringValueInField(XRechnungXml, XmlNamespaces, BasePathTxt + '/cac:PostalAddress/cbc:AdditionalStreetName', MaxStrLen(EDocumentPurchaseHeader."Vendor Address Recipient"), EDocumentPurchaseHeader."Vendor Address Recipient");
+ EDocumentXMLHelper.SetStringValueInField(XRechnungXml, XmlNamespaces, BasePathTxt + '/cac:PartyTaxScheme/cbc:CompanyID', MaxStrLen(EDocumentPurchaseHeader."Vendor VAT Id"), EDocumentPurchaseHeader."Vendor VAT Id");
+ EDocumentXMLHelper.SetStringValueInField(XRechnungXml, XmlNamespaces, BasePathTxt + '/cac:Contact/cbc:Name', MaxStrLen(EDocumentPurchaseHeader."Vendor Contact Name"), EDocumentPurchaseHeader."Vendor Contact Name");
+#pragma warning restore AA0139
+ if XRechnungXml.SelectSingleNode(BasePathTxt + '/cbc:EndpointID/@schemeID', XmlNamespaces, XMLNode) then begin
+ SchemeID := XMLNode.AsXmlAttribute().Value();
+ EndpointID := EDocumentXMLHelper.GetNodeValue(XRechnungXml, XmlNamespaces, BasePathTxt + '/cbc:EndpointID');
+ case SchemeID of
+ EMTok, RoutingIdTok, VATRegNoTok:
+ VATRegistrationNo := CopyStr(EndpointID, 1, MaxStrLen(VATRegistrationNo));
+ SchemeIDGLNTok:
+ begin
+ GLN := CopyStr(EndpointID, 1, MaxStrLen(GLN));
+ EDocumentPurchaseHeader."Vendor GLN" := GLN;
+ end;
+ end;
+ VendorParticipantId := SchemeID + ':' + EndpointID;
+ end;
+ VATRegistrationNo := CopyStr(EDocumentPurchaseHeader."Vendor VAT Id", 1, MaxStrLen(VATRegistrationNo));
+ VendorName := EDocumentPurchaseHeader."Vendor Company Name";
+ VendorAddress := EDocumentPurchaseHeader."Vendor Address";
+ if not FindVendorByVATRegNoOrGLN(VendorNo, VATRegistrationNo, GLN) then
+ if not FindVendorByParticipantId(VendorNo, EDocument, VendorParticipantId) then
+ VendorNo := EDocumentImportHelper.FindVendorByNameAndAddress(VendorName, VendorAddress);
+ end;
+
+ local procedure ParseAccountingCustomerParty(XRechnungXml: XmlDocument; XmlNamespaces: XmlNamespaceManager; var EDocumentPurchaseHeader: Record "E-Document Purchase Header"; DocumentType: Text)
+ var
+ EDocumentXMLHelper: Codeunit "EDocument XML Helper";
+ BasePathTxt: Text;
+ XMLNode: XmlNode;
+ SchemeID, EndpointID : Text;
+ begin
+#pragma warning disable AA0139 // false positive: overflow handled by SetStringValueInField
+ BasePathTxt := '/' + DocumentType + '/cac:AccountingCustomerParty/cac:Party';
+ EDocumentXMLHelper.SetStringValueInField(XRechnungXml, XmlNamespaces, BasePathTxt + '/cac:PartyName/cbc:Name', MaxStrLen(EDocumentPurchaseHeader."Customer Company Name"), EDocumentPurchaseHeader."Customer Company Name");
+ EDocumentXMLHelper.SetStringValueInField(XRechnungXml, XmlNamespaces, BasePathTxt + '/cac:PartyLegalEntity/cbc:RegistrationName', MaxStrLen(EDocumentPurchaseHeader."Customer Company Name"), EDocumentPurchaseHeader."Customer Company Name");
+ EDocumentXMLHelper.SetStringValueInField(XRechnungXml, XmlNamespaces, BasePathTxt + '/cac:PostalAddress/cbc:StreetName', MaxStrLen(EDocumentPurchaseHeader."Customer Address"), EDocumentPurchaseHeader."Customer Address");
+ EDocumentXMLHelper.SetStringValueInField(XRechnungXml, XmlNamespaces, BasePathTxt + '/cac:PostalAddress/cbc:AdditionalStreetName', MaxStrLen(EDocumentPurchaseHeader."Customer Address Recipient"), EDocumentPurchaseHeader."Customer Address Recipient");
+ EDocumentXMLHelper.SetStringValueInField(XRechnungXml, XmlNamespaces, BasePathTxt + '/cac:PartyTaxScheme/cbc:CompanyID', MaxStrLen(EDocumentPurchaseHeader."Customer VAT Id"), EDocumentPurchaseHeader."Customer VAT Id");
+#pragma warning restore AA0139
+ if XRechnungXml.SelectSingleNode(BasePathTxt + '/cbc:EndpointID/@schemeID', XmlNamespaces, XMLNode) then begin
+ SchemeID := XMLNode.AsXmlAttribute().Value();
+ EndpointID := EDocumentXMLHelper.GetNodeValue(XRechnungXml, XmlNamespaces, BasePathTxt + '/cbc:EndpointID');
+ if SchemeID = SchemeIDGLNTok then
+ EDocumentPurchaseHeader."Customer GLN" := CopyStr(EndpointID, 1, MaxStrLen(EDocumentPurchaseHeader."Customer GLN"));
+ end;
+ end;
+
+ local procedure InsertXRechnungPurchaseLines(XRechnungXml: XmlDocument; XmlNamespaces: XmlNamespaceManager; EDocumentEntryNo: Integer; DocumentType: Enum "E-Document Type")
+ var
+ EDocumentPurchaseLine: Record "E-Document Purchase Line";
+ NewLineXML: XmlDocument;
+ LineXMLList: XmlNodeList;
+ LineXMLNode: XmlNode;
+ LineXPath: Text;
+ LineElementName: Text;
+ begin
+ case DocumentType of
+ "E-Document Type"::"Purchase Invoice":
+ begin
+ LineElementName := InvoiceLineTok;
+ LineXPath := '//inv:Invoice/cac:InvoiceLine';
+ end;
+ "E-Document Type"::"Purchase Credit Memo":
+ begin
+ LineElementName := CreditNoteLineTok;
+ LineXPath := '//cn:CreditNote/cac:CreditNoteLine';
+ end;
+ end;
+
+ if not XRechnungXml.SelectNodes(LineXPath, XmlNamespaces, LineXMLList) then
+ exit;
+
+ foreach LineXMLNode in LineXMLList do begin
+ Clear(EDocumentPurchaseLine);
+ EDocumentPurchaseLine.Validate("E-Document Entry No.", EDocumentEntryNo);
+ EDocumentPurchaseLine."Line No." := EDocumentPurchaseLine.GetNextLineNo(EDocumentEntryNo);
+ NewLineXML.ReplaceNodes(LineXMLNode);
+ PopulateXRechnungPurchaseLine(NewLineXML, XmlNamespaces, EDocumentPurchaseLine, LineElementName);
+ EDocumentPurchaseLine.Insert(false);
+ end;
+ end;
+
+ local procedure PopulateXRechnungPurchaseLine(LineXML: XmlDocument; XmlNamespaces: XmlNamespaceManager; var EDocumentPurchaseLine: Record "E-Document Purchase Line"; LineElementName: Text)
+ var
+ EDocumentXMLHelper: Codeunit "EDocument XML Helper";
+ QuantityFieldName: Text;
+ begin
+#pragma warning disable AA0139 // false positive: overflow handled by SetStringValueInField
+ case LineElementName of
+ InvoiceLineTok:
+ QuantityFieldName := 'cac:InvoiceLine/cbc:InvoicedQuantity';
+ CreditNoteLineTok:
+ QuantityFieldName := 'cac:CreditNoteLine/cbc:CreditedQuantity';
+ end;
+ EDocumentXMLHelper.SetStringValueInField(LineXML, XmlNamespaces, LineElementName + '/cbc:ID', MaxStrLen(EDocumentPurchaseLine."Product Code"), EDocumentPurchaseLine."Product Code");
+ EDocumentXMLHelper.SetStringValueInField(LineXML, XmlNamespaces, LineElementName + '/cac:Item/cbc:Name', MaxStrLen(EDocumentPurchaseLine.Description), EDocumentPurchaseLine.Description);
+ EDocumentXMLHelper.SetStringValueInField(LineXML, XmlNamespaces, LineElementName + '/cac:Item/cac:SellersItemIdentification/cbc:ID', MaxStrLen(EDocumentPurchaseLine."Product Code"), EDocumentPurchaseLine."Product Code");
+ EDocumentXMLHelper.SetStringValueInField(LineXML, XmlNamespaces, LineElementName + '/cac:Item/cac:StandardItemIdentification/cbc:ID', MaxStrLen(EDocumentPurchaseLine."Product Code"), EDocumentPurchaseLine."Product Code");
+ EDocumentXMLHelper.SetNumberValueInField(LineXML, XmlNamespaces, QuantityFieldName, EDocumentPurchaseLine.Quantity);
+ EDocumentXMLHelper.SetStringValueInField(LineXML, XmlNamespaces, QuantityFieldName + '/@unitCode', MaxStrLen(EDocumentPurchaseLine."Unit of Measure"), EDocumentPurchaseLine."Unit of Measure");
+ EDocumentXMLHelper.SetNumberValueInField(LineXML, XmlNamespaces, LineElementName + '/cac:Price/cbc:PriceAmount', EDocumentPurchaseLine."Unit Price");
+ EDocumentXMLHelper.SetNumberValueInField(LineXML, XmlNamespaces, LineElementName + '/cbc:LineExtensionAmount', EDocumentPurchaseLine."Sub Total");
+ EDocumentXMLHelper.SetCurrencyValueInField(LineXML, XmlNamespaces, LineElementName + '/cbc:LineExtensionAmount/@currencyID', MaxStrLen(EDocumentPurchaseLine."Currency Code"), EDocumentPurchaseLine."Currency Code");
+ EDocumentXMLHelper.SetNumberValueInField(LineXML, XmlNamespaces, LineElementName + '/cac:Item/cac:ClassifiedTaxCategory/cbc:Percent', EDocumentPurchaseLine."VAT Rate");
+#pragma warning restore AA0139
+ end;
+
+ local procedure FindVendorByVATRegNoOrGLN(var VendorNo: Code[20]; VATRegistrationNo: Text[20]; GLN: Code[13]): Boolean
+ var
+ Vendor: Record Vendor;
+ begin
+ // Try to find vendor by VAT Registration Number
+ if VATRegistrationNo <> '' then begin
+ Vendor.Reset();
+ Vendor.SetLoadFields("VAT Registration No.");
+ Vendor.SetRange("VAT Registration No.", VATRegistrationNo);
+ if Vendor.FindFirst() then begin
+ VendorNo := Vendor."No.";
+ exit(true);
+ end;
+ end;
+
+ // Try to find vendor by GLN
+ if GLN <> '' then begin
+ Vendor.Reset();
+ Vendor.SetLoadFields("GLN");
+ Vendor.SetRange("GLN", GLN);
+ if Vendor.FindFirst() then begin
+ VendorNo := Vendor."No.";
+ exit(true);
+ end;
+ end;
+
+ exit(false);
+ end;
+
+ local procedure FindVendorByParticipantId(var VendorNo: Code[20]; EDocument: Record "E-Document"; ParticipantId: Text): Boolean
+ var
+ EDocServiceParticipant: Record "Service Participant";
+ EDocumentService: Record "E-Document Service";
+ EDocumentHelper: Codeunit "E-Document Helper";
+ begin
+ if ParticipantId = '' then
+ exit(false);
+
+ EDocumentHelper.GetEdocumentService(EDocument, EDocumentService);
+ EDocServiceParticipant.SetRange("Participant Type", EDocServiceParticipant."Participant Type"::Vendor);
+ EDocServiceParticipant.SetRange("Participant Identifier", ParticipantId);
+ EDocServiceParticipant.SetRange(Service, EDocumentService.Code);
+ if not EDocServiceParticipant.FindFirst() then begin
+ EDocServiceParticipant.SetRange(Service);
+ if not EDocServiceParticipant.FindFirst() then
+ exit(false);
+ end;
+
+ VendorNo := EDocServiceParticipant.Participant;
+ exit(true);
+ end;
+
+ procedure ResetDraft(EDocument: Record "E-Document")
+ var
+ EDocPurchaseHeader: Record "E-Document Purchase Header";
+ begin
+ EDocPurchaseHeader.GetFromEDocument(EDocument);
+ EDocPurchaseHeader.Delete(true);
+ end;
+}
diff --git a/Apps/DE/EDocumentDE/app/src/XRechnung/XRechnungEDocReadIntoDraft.EnumExt.al b/Apps/DE/EDocumentDE/app/src/XRechnung/XRechnungEDocReadIntoDraft.EnumExt.al
new file mode 100644
index 0000000000..812c14ecfc
--- /dev/null
+++ b/Apps/DE/EDocumentDE/app/src/XRechnung/XRechnungEDocReadIntoDraft.EnumExt.al
@@ -0,0 +1,18 @@
+// ------------------------------------------------------------------------------------------------
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License. See License.txt in the project root for license information.
+// ------------------------------------------------------------------------------------------------
+namespace Microsoft.eServices.EDocument;
+
+using Microsoft.eServices.EDocument.Processing.Import;
+using Microsoft.eServices.EDocument.Formats;
+using Microsoft.eServices.EDocument.Processing.Interfaces;
+
+enumextension 13917 "XRechnung EDoc Read into Draft" extends "E-Doc. Read into Draft"
+{
+ value(13914; "XRechnung")
+ {
+ Caption = 'XRechnung';
+ Implementation = IStructuredFormatReader = "E-Document XRechnung Handler";
+ }
+}
diff --git a/Apps/DE/EDocumentDE/test/.resources/xrechnung/xrechnung-invoice-0.xml b/Apps/DE/EDocumentDE/test/.resources/xrechnung/xrechnung-invoice-0.xml
new file mode 100644
index 0000000000..ef430f47a5
--- /dev/null
+++ b/Apps/DE/EDocumentDE/test/.resources/xrechnung/xrechnung-invoice-0.xml
@@ -0,0 +1,166 @@
+
+
+ urn:cen.eu:en16931:2017#compliant#urn:xeinkauf.de:kosit:xrechnung_3.0
+ urn:fdc:peppol.eu:2017:poacc:billing:01:1.0
+ 103033
+ 2026-01-22
+ 2026-02-22
+ 380
+ XYZ
+ 1
+
+ 2
+
+
+ 103033
+
+
+ 103033
+
+
+
+
+
+ 103033
+
+
+
+
+
+
+ seller@email.de
+
+ CRONUS International
+
+
+ Main Street, 14
+ Birmingham
+ B27 4KT
+
+ GB
+
+
+
+ GB123456789
+
+ VAT
+
+
+
+ CRONUS International
+ 123456789
+ 123/456/7890, HRA-Eintrag in […]
+
+
+ Jim Olive
+ JO@contoso.com
+
+
+
+
+
+ buyer@info.de
+
+ 8712345000004
+
+
+ The Cannon Group PLC
+
+
+ 192 Market Square
+ Birmingham
+ B27 4KT
+
+ GB
+
+
+
+ GB789456278
+
+ VAT
+
+
+
+ The Cannon Group PLC
+ 789456278
+
+
+
+
+ 2026-01-22
+
+
+
+
+ 58
+
+ DE75512108001245126199
+
+
+
+ Zahlbar sofort ohne Abzug.
+
+
+ 980
+
+ 14000
+ 980
+
+ S
+ 7
+
+ VAT
+
+
+
+
+
+ 14000
+ 14000
+ 14980
+ 0
+ 0.00
+ 0
+ 14980
+
+
+ 1000
+ Item
+ 1
+ 4000
+
+ Bicycle
+
+ S
+ 25
+
+ VAT
+
+
+
+
+ 4000
+
+
+
+ 2000
+ Item
+ 2
+ 10000
+
+ Bicycle v2
+
+ S
+ 25
+
+ VAT
+
+
+
+
+ 5000
+
+
+
\ No newline at end of file
diff --git a/Apps/DE/EDocumentDE/test/app.json b/Apps/DE/EDocumentDE/test/app.json
index d00c6971aa..a8c143604d 100644
--- a/Apps/DE/EDocumentDE/test/app.json
+++ b/Apps/DE/EDocumentDE/test/app.json
@@ -58,7 +58,7 @@
},
{
"from": 13922,
- "to": 13923
+ "to": 13926
}
],
"features": [
@@ -70,5 +70,8 @@
"allowDownloadingSource": true,
"includeSourceInSymbolFile": true
},
- "application": "27.0.0.0"
-}
+ "application": "27.0.0.0",
+ "resourceFolders": [
+ ".resources"
+ ]
+}
\ No newline at end of file
diff --git a/Apps/DE/EDocumentDE/test/src/EDocFormatMock.Codeunit.al b/Apps/DE/EDocumentDE/test/src/EDocFormatMock.Codeunit.al
new file mode 100644
index 0000000000..206fda4303
--- /dev/null
+++ b/Apps/DE/EDocumentDE/test/src/EDocFormatMock.Codeunit.al
@@ -0,0 +1,56 @@
+codeunit 13926 "E-Doc. Format Mock" implements "E-Document"
+{
+ SingleInstance = true;
+
+ procedure Check(var SourceDocumentHeader: RecordRef; EDocService: Record "E-Document Service"; EDocumentProcessingPhase: enum "E-Document Processing Phase");
+ begin
+ OnCheck(SourceDocumentHeader, EDocService, EDocumentProcessingPhase);
+ end;
+
+ procedure Create(EDocService: Record "E-Document Service"; var EDocument: Record "E-Document"; var SourceDocumentHeader: RecordRef; var SourceDocumentLines: RecordRef; var TempBlob: codeunit "Temp Blob");
+ begin
+ OnCreate(EDocService, EDocument, SourceDocumentHeader, SourceDocumentLines, TempBlob);
+ end;
+
+ procedure CreateBatch(EDocService: Record "E-Document Service"; var EDocuments: Record "E-Document"; var SourceDocumentHeaders: RecordRef; var SourceDocumentsLines: RecordRef; var TempBlob: codeunit "Temp Blob");
+ begin
+ OnCreateBatch(EDocService, EDocuments, SourceDocumentHeaders, SourceDocumentsLines, TempBlob);
+ end;
+
+ procedure GetBasicInfoFromReceivedDocument(var EDocument: Record "E-Document"; var TempBlob: codeunit "Temp Blob");
+ begin
+ OnGetBasicInfoFromReceivedDocument(EDocument, TempBlob);
+ end;
+
+ procedure GetCompleteInfoFromReceivedDocument(var EDocument: Record "E-Document"; var CreatedDocumentHeader: RecordRef; var CreatedDocumentLines: RecordRef; var TempBlob: codeunit "Temp Blob");
+ begin
+ OnGetCompleteInfoFromReceivedDocument(EDocument, CreatedDocumentHeader, CreatedDocumentLines, TempBlob);
+ end;
+
+ [IntegrationEvent(false, false)]
+ local procedure OnCheck(var SourceDocumentHeader: RecordRef; EDocService: Record "E-Document Service"; EDocumentProcessingPhase: enum "E-Document Processing Phase")
+ begin
+ end;
+
+ [IntegrationEvent(false, false)]
+ local procedure OnCreate(EDocService: Record "E-Document Service"; var EDocument: Record "E-Document"; var SourceDocumentHeader: RecordRef; var SourceDocumentLines: RecordRef; var TempBlob: codeunit "Temp Blob");
+ begin
+ end;
+
+ [IntegrationEvent(false, false)]
+ local procedure OnCreateBatch(EDocService: Record "E-Document Service"; var EDocuments: Record "E-Document"; var SourceDocumentHeaders: RecordRef; var SourceDocumentsLines: RecordRef; var TempBlob: codeunit "Temp Blob");
+ begin
+ end;
+
+ [IntegrationEvent(false, false)]
+ local procedure OnGetBasicInfoFromReceivedDocument(var EDocument: Record "E-Document"; var TempBlob: codeunit "Temp Blob");
+ begin
+ end;
+
+ [IntegrationEvent(false, false)]
+ local procedure OnGetCompleteInfoFromReceivedDocument(var EDocument: Record "E-Document"; var CreatedDocumentHeader: RecordRef; var CreatedDocumentLines: RecordRef; var TempBlob: codeunit "Temp Blob");
+ begin
+ end;
+
+
+}
\ No newline at end of file
diff --git a/Apps/DE/EDocumentDE/test/src/EDocFormatMock.EnumExt.al b/Apps/DE/EDocumentDE/test/src/EDocFormatMock.EnumExt.al
new file mode 100644
index 0000000000..017e1f0d4b
--- /dev/null
+++ b/Apps/DE/EDocumentDE/test/src/EDocFormatMock.EnumExt.al
@@ -0,0 +1,7 @@
+enumextension 13918 "E-Doc. Format Mock" extends "E-Document Format"
+{
+ value(6160; "Mock")
+ {
+ Implementation = "E-Document" = "E-Doc. Format Mock";
+ }
+}
\ No newline at end of file
diff --git a/Apps/DE/EDocumentDE/test/src/EDocumentStructuredTests.Codeunit.al b/Apps/DE/EDocumentDE/test/src/EDocumentStructuredTests.Codeunit.al
new file mode 100644
index 0000000000..31713dbe12
--- /dev/null
+++ b/Apps/DE/EDocumentDE/test/src/EDocumentStructuredTests.Codeunit.al
@@ -0,0 +1,272 @@
+codeunit 13924 "E-Document Structured Tests"
+{
+ Subtype = Test;
+ TestType = IntegrationTest;
+
+ var
+ Customer: Record Customer;
+ Vendor: Record Vendor;
+ EDocumentService: Record "E-Document Service";
+ Assert: Codeunit Assert;
+ LibraryVariableStorage: Codeunit "Library - Variable Storage";
+ LibraryEDoc: Codeunit "Library - E-Document";
+ LibraryLowerPermission: Codeunit "Library - Lower Permissions";
+ XRechnungStructuredValidations: Codeunit "XRechnung Struct. Validations";
+ IsInitialized: Boolean;
+ EDocumentStatusNotUpdatedErr: Label 'The status of the EDocument was not updated to the expected status after the step was executed.';
+ TestFileTok: Label 'xrechnung/xrechnung-invoice-0.xml', Locked = true;
+ MockCurrencyCode: Code[10];
+ MockDate: Date;
+
+ #region XRechnung XML
+ [Test]
+ procedure TestXRechnungInvoice_ValidDocument()
+ var
+ EDocument: Record "E-Document";
+ begin
+ // [FEATURE] [E-Document] [XRechnung] [Content Extraction]
+ // [SCENARIO] Process a valid XRechnung invoice document and validate full content extraction
+
+ // [GIVEN] A valid XRechnung XML invoice document is imported
+ Initialize(Enum::"Service Integration"::"No Integration");
+ SetupXRechnungEDocumentService();
+ CreateInboundEDocumentFromXML(EDocument, TestFileTok);
+
+ // [WHEN] The document is processed to read into draft step
+ if ProcessEDocumentToStep(EDocument, "Import E-Document Steps"::"Read into Draft") then begin
+ XRechnungStructuredValidations.SetMockCurrencyCode(MockCurrencyCode);
+ XRechnungStructuredValidations.SetMockDate(MockDate);
+
+ // [THEN] All content from the XRechnung document is correctly extracted and validated
+ XRechnungStructuredValidations.AssertFullEDocumentContentExtracted(EDocument."Entry No");
+ end else
+ Assert.Fail(EDocumentStatusNotUpdatedErr);
+ end;
+
+ [Test]
+ [HandlerFunctions('EDocumentPurchaseHeaderPageHandler')]
+ procedure TestXRechnungInvoice_ValidDocument_ViewExtractedData()
+ var
+ EDocument: Record "E-Document";
+ EDocImport: Codeunit "E-Doc. Import";
+ begin
+ // [FEATURE] [E-Document] [XRechnung] [View Data]
+ // [SCENARIO] View extracted data from a valid XRechnung invoice document
+
+ // [GIVEN] A valid XRechnung XML invoice document is imported
+ Initialize(Enum::"Service Integration"::"No Integration");
+ SetupXRechnungEDocumentService();
+ CreateInboundEDocumentFromXML(EDocument, TestFileTok);
+
+ // [WHEN] The document is processed to draft status
+ ProcessEDocumentToStep(EDocument, "Import E-Document Steps"::"Read into Draft");
+ EDocument.Get(EDocument."Entry No");
+
+ // [WHEN] View extracted data is called
+ EDocImport.ViewExtractedData(EDocument);
+
+ // [THEN] The extracted data page opens and can be handled properly (verified by page handler)
+ // EDocumentPurchaseHeaderPageHandler
+ end;
+
+ [Test]
+ procedure TestXRechnungInvoice_ValidDocument_PurchaseInvoiceCreated()
+ var
+ EDocument: Record "E-Document";
+ PurchaseHeader: Record "Purchase Header";
+ DummyItem: Record Item;
+ EDocumentProcessing: Codeunit "E-Document Processing";
+ DataTypeManagement: Codeunit "Data Type Management";
+ RecRef: RecordRef;
+ VariantRecord: Variant;
+ begin
+ // [FEATURE] [E-Document] [XRechnung] [Purchase Invoice Creation]
+ // [SCENARIO] Create a purchase invoice from a valid XRechnung invoice document
+
+ // [GIVEN] A valid XRechnung XML invoice document is imported
+ Initialize(Enum::"Service Integration"::"No Integration");
+ Vendor."VAT Registration No." := 'GB123456789';
+ Vendor.Modify(true);
+ SetupXRechnungEDocumentService();
+ CreateInboundEDocumentFromXML(EDocument, TestFileTok);
+
+ // [WHEN] The document is processed through finish draft step
+ ProcessEDocumentToStep(EDocument, "Import E-Document Steps"::"Finish draft");
+ EDocument.Get(EDocument."Entry No");
+
+ // [WHEN] The created purchase record is retrieved
+ EDocumentProcessing.GetRecord(EDocument, VariantRecord);
+ DataTypeManagement.GetRecordRef(VariantRecord, RecRef);
+ RecRef.SetTable(PurchaseHeader);
+
+ // [THEN] The purchase header is correctly created with XRechnung data
+ XRechnungStructuredValidations.SetMockCurrencyCode(MockCurrencyCode);
+ XRechnungStructuredValidations.SetMockDate(MockDate);
+ XRechnungStructuredValidations.AssertPurchaseDocument(Vendor."No.", PurchaseHeader, DummyItem);
+ end;
+
+ [Test]
+ procedure TestXRechnungInvoice_ValidDocument_UpdateDraftAndFinalize()
+ var
+ EDocument: Record "E-Document";
+ PurchaseHeader: Record "Purchase Header";
+ Item: Record Item;
+ EDocImportParameters: Record "E-Doc. Import Parameters";
+ EDocImport: Codeunit "E-Doc. Import";
+ EDocumentProcessing: Codeunit "E-Document Processing";
+ DataTypeManagement: Codeunit "Data Type Management";
+ RecRef: RecordRef;
+ EDocPurchaseDraft: TestPage "E-Document Purchase Draft";
+ VariantRecord: Variant;
+ begin
+ // [FEATURE] [E-Document] [XRechnung] [Draft Update]
+ // [SCENARIO] Update draft purchase document data and finalize processing
+
+ // [GIVEN] A valid XRechnung XML invoice document is imported and processed to draft preparation
+ Initialize(Enum::"Service Integration"::"No Integration");
+ Vendor."VAT Registration No." := 'GB123456789';
+ Vendor.Modify(true);
+ SetupXRechnungEDocumentService();
+ CreateInboundEDocumentFromXML(EDocument, TestFileTok);
+ ProcessEDocumentToStep(EDocument, "Import E-Document Steps"::"Prepare draft");
+
+ // [GIVEN] A generic item is created for manual assignment
+ LibraryEDoc.CreateGenericItem(Item, '');
+
+ // [WHEN] The draft document is opened and modified through UI
+ EDocPurchaseDraft.OpenEdit();
+ EDocPurchaseDraft.GoToRecord(EDocument);
+ EDocPurchaseDraft.Lines.First();
+ EDocPurchaseDraft.Lines."No.".SetValue(Item."No.");
+ EDocPurchaseDraft.Lines.Next();
+
+ // [WHEN] The processing is completed to finish draft step
+ EDocImportParameters."Step to Run" := "Import E-Document Steps"::"Finish draft";
+ EDocImport.ProcessIncomingEDocument(EDocument, EDocImportParameters);
+ EDocument.Get(EDocument."Entry No");
+
+ // [WHEN] The final purchase record is retrieved
+ EDocumentProcessing.GetRecord(EDocument, VariantRecord);
+ DataTypeManagement.GetRecordRef(VariantRecord, RecRef);
+ RecRef.SetTable(PurchaseHeader);
+
+ // [THEN] The purchase header contains both imported XRechnung data and manual updates
+ XRechnungStructuredValidations.SetMockCurrencyCode(MockCurrencyCode);
+ XRechnungStructuredValidations.SetMockDate(MockDate);
+ XRechnungStructuredValidations.AssertPurchaseDocument(Vendor."No.", PurchaseHeader, Item);
+ end;
+
+ [PageHandler]
+ procedure EDocumentPurchaseHeaderPageHandler(var EDocReadablePurchaseDoc: TestPage "E-Doc. Readable Purchase Doc.")
+ begin
+ EDocReadablePurchaseDoc.Close();
+ end;
+ #endregion
+
+ local procedure Initialize(Integration: Enum "Service Integration")
+ var
+ TransformationRule: Record "Transformation Rule";
+ EDocument: Record "E-Document";
+ EDocDataStorage: Record "E-Doc. Data Storage";
+ EDocumentsSetup: Record "E-Documents Setup";
+ EDocumentServiceStatus: Record "E-Document Service Status";
+ EDocumentPurchaseHeader: Record "E-Document Purchase Header";
+ EDocumentPurchaseLine: Record "E-Document Purchase Line";
+ DocumentAttachment: Record "Document Attachment";
+ Currency: Record Currency;
+ begin
+ LibraryLowerPermission.SetOutsideO365Scope();
+ LibraryVariableStorage.Clear();
+ Clear(LibraryVariableStorage);
+
+ if IsInitialized then
+ exit;
+
+ EDocument.DeleteAll(false);
+ EDocumentServiceStatus.DeleteAll(false);
+ EDocumentService.DeleteAll(false);
+ EDocDataStorage.DeleteAll(false);
+ EDocumentPurchaseHeader.DeleteAll(false);
+ EDocumentPurchaseLine.DeleteAll(false);
+ DocumentAttachment.DeleteAll(false);
+
+ LibraryEDoc.SetupStandardVAT();
+ LibraryEDoc.SetupStandardSalesScenario(Customer, EDocumentService, Enum::"E-Document Format"::Mock, Integration);
+ LibraryEDoc.SetupStandardPurchaseScenario(Vendor, EDocumentService, Enum::"E-Document Format"::Mock, Integration);
+ EDocumentService."Import Process" := "E-Document Import Process"::"Version 2.0";
+ EDocumentService."Read into Draft Impl." := "E-Doc. Read into Draft"::XRechnung;
+ EDocumentService.Modify();
+ EDocumentsSetup.InsertNewExperienceSetup();
+
+ // Set a currency that can be used across all localizations
+ MockCurrencyCode := 'XYZ';
+ Currency.Init();
+ Currency.Validate(Code, MockCurrencyCode);
+ if Currency.Insert(true) then;
+ CreateCurrencyExchangeRate();
+
+ MockDate := DMY2Date(22, 01, 2026);
+
+ TransformationRule.DeleteAll(false);
+ TransformationRule.CreateDefaultTransformations();
+
+ IsInitialized := true;
+ end;
+
+ local procedure SetupXRechnungEDocumentService()
+ begin
+ EDocumentService."Read into Draft Impl." := "E-Doc. Read into Draft"::XRechnung;
+ EDocumentService.Modify(false);
+ end;
+
+ local procedure CreateInboundEDocumentFromXML(var EDocument: Record "E-Document"; FilePath: Text)
+ var
+ EDocLogRecord: Record "E-Document Log";
+ EDocumentLog: Codeunit "E-Document Log";
+ begin
+ LibraryEDoc.CreateInboundEDocument(EDocument, EDocumentService);
+
+ EDocumentLog.SetBlob('Test', Enum::"E-Doc. File Format"::XML, NavApp.GetResourceAsText(FilePath));
+ EDocumentLog.SetFields(EDocument, EDocumentService);
+ EDocLogRecord := EDocumentLog.InsertLog(Enum::"E-Document Service Status"::Imported, Enum::"Import E-Doc. Proc. Status"::Readable);
+
+ EDocument."Structured Data Entry No." := EDocLogRecord."E-Doc. Data Storage Entry No.";
+ EDocument.Modify(false);
+ end;
+
+ local procedure ProcessEDocumentToStep(var EDocument: Record "E-Document"; ProcessingStep: Enum "Import E-Document Steps"): Boolean
+ var
+ EDocImportParameters: Record "E-Doc. Import Parameters";
+ EDocImport: Codeunit "E-Doc. Import";
+ EDocumentProcessing: Codeunit "E-Document Processing";
+ begin
+ EDocumentProcessing.ModifyEDocumentProcessingStatus(EDocument, "Import E-Doc. Proc. Status"::Readable);
+ EDocImportParameters."Step to Run" := ProcessingStep;
+ EDocImport.ProcessIncomingEDocument(EDocument, EDocImportParameters);
+ EDocument.CalcFields("Import Processing Status");
+
+ // Update the exit condition to handle different processing steps
+ case ProcessingStep of
+ "Import E-Document Steps"::"Read into Draft":
+ exit(EDocument."Import Processing Status" = Enum::"Import E-Doc. Proc. Status"::"Ready for draft");
+ "Import E-Document Steps"::"Finish draft":
+ exit(EDocument."Import Processing Status" = Enum::"Import E-Doc. Proc. Status"::Processed);
+ "Import E-Document Steps"::"Prepare draft":
+ exit(EDocument."Import Processing Status" = Enum::"Import E-Doc. Proc. Status"::"Draft Ready");
+ else
+ exit(EDocument."Import Processing Status" = Enum::"Import E-Doc. Proc. Status"::"Ready for draft");
+ end;
+ end;
+
+ local procedure CreateCurrencyExchangeRate()
+ var
+ CurrencyExchangeRate: Record "Currency Exchange Rate";
+ begin
+ CurrencyExchangeRate.Init();
+ CurrencyExchangeRate."Currency Code" := MockCurrencyCode;
+ CurrencyExchangeRate."Starting Date" := WorkDate();
+ CurrencyExchangeRate."Exchange Rate Amount" := 10;
+ CurrencyExchangeRate."Relational Exch. Rate Amount" := 1.23;
+ CurrencyExchangeRate.Insert(true);
+ end;
+}
\ No newline at end of file
diff --git a/Apps/DE/EDocumentDE/test/src/LibraryEDocument.Codeunit.al b/Apps/DE/EDocumentDE/test/src/LibraryEDocument.Codeunit.al
new file mode 100644
index 0000000000..88596086a7
--- /dev/null
+++ b/Apps/DE/EDocumentDE/test/src/LibraryEDocument.Codeunit.al
@@ -0,0 +1,1080 @@
+codeunit 13923 "Library - E-Document"
+{
+ EventSubscriberInstance = Manual;
+ Permissions = tabledata "E-Document Service" = rimd,
+ tabledata "E-Doc. Service Supported Type" = rimd,
+ tabledata "E-Doc. Mapping" = rimd;
+
+ var
+ StandardItem: Record Item;
+ VATPostingSetup: Record "VAT Posting Setup";
+ Assert: Codeunit Assert;
+ LibraryUtility: Codeunit "Library - Utility";
+ LibraryWorkflow: Codeunit "Library - Workflow";
+ LibrarySales: Codeunit "Library - Sales";
+ LibraryPurchase: Codeunit "Library - Purchase";
+ LibraryERM: Codeunit "Library - ERM";
+ LibraryRandom: Codeunit "Library - Random";
+ LibraryInvt: Codeunit "Library - Inventory";
+ LibraryVariableStorage: Codeunit "Library - Variable Storage";
+ LibraryFinChargeMemo: Codeunit "Library - Finance Charge Memo";
+ LibraryInventory: Codeunit "Library - Inventory";
+
+ procedure SetupStandardVAT()
+ begin
+ if (VATPostingSetup."VAT Bus. Posting Group" = '') and (VATPostingSetup."VAT Prod. Posting Group" = '') then
+ LibraryERM.CreateVATPostingSetupWithAccounts(VATPostingSetup, Enum::"Tax Calculation Type"::"Normal VAT", 1);
+ end;
+
+#if not CLEAN26
+#pragma warning disable AL0432
+ [Obsolete('Use SetupStandardSalesScenario(var Customer: Record Customer; var EDocService: Record "E-Document Service"; EDocDocumentFormat: Enum "E-Document Format"; EDocIntegration: Enum "Service Integration") instead', '26.0')]
+ procedure SetupStandardSalesScenario(var Customer: Record Customer; var EDocService: Record "E-Document Service"; EDocDocumentFormat: Enum "E-Document Format"; EDocIntegration: Enum "E-Document Integration")
+ var
+ ServiceCode: Code[20];
+ begin
+ // Create standard service and simple workflow
+ ServiceCode := CreateService(EDocDocumentFormat, EDocIntegration);
+ EDocService.Get(ServiceCode);
+ SetupStandardSalesScenario(Customer, EDocService);
+ end;
+#pragma warning restore AL0432
+#endif
+
+ procedure SetupStandardSalesScenario(var Customer: Record Customer; var EDocService: Record "E-Document Service"; EDocDocumentFormat: Enum "E-Document Format"; EDocIntegration: Enum "Service Integration")
+ var
+ ServiceCode: Code[20];
+ begin
+ // Create standard service and simple workflow
+ ServiceCode := CreateService(EDocDocumentFormat, EDocIntegration);
+ EDocService.Get(ServiceCode);
+ SetupStandardSalesScenario(Customer, EDocService);
+ end;
+
+ procedure SetupStandardSalesScenario(var Customer: Record Customer; var EDocService: Record "E-Document Service")
+ var
+ CountryRegion: Record "Country/Region";
+ DocumentSendingProfile: Record "Document Sending Profile";
+ SalesSetup: Record "Sales & Receivables Setup";
+ WorkflowSetup: Codeunit "Workflow Setup";
+ WorkflowCode: Code[20];
+ begin
+ LibraryWorkflow.DeleteAllExistingWorkflows();
+ WorkflowSetup.InitWorkflow();
+ SetupCompanyInfo();
+
+ CreateDocSendingProfile(DocumentSendingProfile);
+ WorkflowCode := CreateSimpleFlow(DocumentSendingProfile.Code, EDocService.Code);
+ DocumentSendingProfile."Electronic Document" := DocumentSendingProfile."Electronic Document"::"Extended E-Document Service Flow";
+ DocumentSendingProfile."Electronic Service Flow" := WorkflowCode;
+ DocumentSendingProfile.Modify();
+
+ // Create Customer for sales scenario
+ LibrarySales.CreateCustomer(Customer);
+ LibraryERM.FindCountryRegion(CountryRegion);
+ Customer.Validate(Address, LibraryUtility.GenerateRandomCode(Customer.FieldNo(Address), DATABASE::Customer));
+ Customer.Validate("Country/Region Code", CountryRegion.Code);
+ Customer.Validate(City, LibraryUtility.GenerateRandomCode(Customer.FieldNo(City), DATABASE::Customer));
+ Customer.Validate("Post Code", LibraryUtility.GenerateRandomCode(Customer.FieldNo("Post Code"), DATABASE::Customer));
+ Customer.Validate("VAT Bus. Posting Group", VATPostingSetup."VAT Bus. Posting Group");
+ Customer."VAT Registration No." := LibraryERM.GenerateVATRegistrationNo(CountryRegion.Code);
+ Customer.Validate(GLN, '1234567890128');
+ Customer."Document Sending Profile" := DocumentSendingProfile.Code;
+ Customer.Modify(true);
+
+ // Create Item
+ if StandardItem."No." = '' then begin
+ VATPostingSetup.TestField("VAT Prod. Posting Group");
+ CreateGenericItem(StandardItem);
+ StandardItem."VAT Prod. Posting Group" := VATPostingSetup."VAT Prod. Posting Group";
+ StandardItem.Modify();
+ end;
+
+ SalesSetup.Get();
+ SalesSetup."Invoice Rounding" := false;
+ SalesSetup.Modify();
+ end;
+
+ procedure GetGenericItem(var Item: Record Item)
+ begin
+ if StandardItem."No." = '' then
+ CreateGenericItem(StandardItem);
+ Item.Get(StandardItem."No.");
+ end;
+
+#if not CLEAN26
+#pragma warning disable AL0432
+ [Obsolete('Use SetupStandardPurchaseScenario(var Vendor: Record Vendor; var EDocService: Record "E-Document Service"; EDocDocumentFormat: Enum "E-Document Format"; EDocIntegration: Enum "Service Integration") instead', '26.0')]
+ procedure SetupStandardPurchaseScenario(var Vendor: Record Vendor; var EDocService: Record "E-Document Service"; EDocDocumentFormat: Enum "E-Document Format"; EDocIntegration: Enum "E-Document Integration")
+ var
+ ServiceCode: Code[20];
+ begin
+ // Create standard service and simple workflow
+ if EDocService.Code = '' then begin
+ ServiceCode := CreateService(EDocDocumentFormat, EDocIntegration);
+ EDocService.Get(ServiceCode);
+ end;
+ SetupStandardPurchaseScenario(Vendor, EDocService);
+ end;
+#pragma warning restore AL0432
+#endif
+
+ procedure SetupStandardPurchaseScenario(var Vendor: Record Vendor; var EDocService: Record "E-Document Service"; EDocDocumentFormat: Enum "E-Document Format"; EDocIntegration: Enum "Service Integration")
+ var
+ ServiceCode: Code[20];
+ begin
+ // Create standard service and simple workflow
+ if EDocService.Code = '' then begin
+ ServiceCode := CreateService(EDocDocumentFormat, EDocIntegration);
+ EDocService.Get(ServiceCode);
+ end;
+ SetupStandardPurchaseScenario(Vendor, EDocService);
+ end;
+
+
+ procedure SetupStandardPurchaseScenario(var Vendor: Record Vendor; var EDocService: Record "E-Document Service")
+ var
+ CountryRegion: Record "Country/Region";
+ ItemReference: Record "Item Reference";
+ UnitOfMeasure: Record "Unit of Measure";
+ ExtraItem: Record "Item";
+ WorkflowSetup: Codeunit "Workflow Setup";
+ LibraryItemReference: Codeunit "Library - Item Reference";
+ begin
+ WorkflowSetup.InitWorkflow();
+ SetupCompanyInfo();
+
+ // Create Customer for sales scenario
+ LibraryPurchase.CreateVendor(Vendor);
+ LibraryERM.FindCountryRegion(CountryRegion);
+ Vendor.Validate(Address, LibraryUtility.GenerateRandomCode(Vendor.FieldNo(Address), DATABASE::Vendor));
+ Vendor.Validate("Country/Region Code", CountryRegion.Code);
+ Vendor.Validate(City, LibraryUtility.GenerateRandomCode(Vendor.FieldNo(City), DATABASE::Vendor));
+ Vendor.Validate("Post Code", LibraryUtility.GenerateRandomCode(Vendor.FieldNo("Post Code"), DATABASE::Vendor));
+ Vendor.Validate("VAT Bus. Posting Group", VATPostingSetup."VAT Bus. Posting Group");
+ Vendor."VAT Registration No." := LibraryERM.GenerateVATRegistrationNo(CountryRegion.Code);
+ Vendor."Receive E-Document To" := Enum::"E-Document Type"::"Purchase Invoice";
+ Vendor.Validate(GLN, '1234567890128');
+ Vendor.Modify(true);
+
+ // Create Item
+ if StandardItem."No." = '' then begin
+ VATPostingSetup.TestField("VAT Prod. Posting Group");
+ CreateGenericItem(StandardItem, VATPostingSetup."VAT Prod. Posting Group");
+ end;
+
+ UnitOfMeasure.Init();
+ UnitOfMeasure."International Standard Code" := 'PCS';
+ UnitOfMeasure.Code := 'PCS';
+ if UnitOfMeasure.Insert() then;
+
+ CreateItemUnitOfMeasure(StandardItem."No.", UnitOfMeasure.Code);
+ LibraryItemReference.CreateItemReference(ItemReference, StandardItem."No.", '', 'PCS', Enum::"Item Reference Type"::Vendor, Vendor."No.", '1000');
+
+ CreateGenericItem(ExtraItem, VATPostingSetup."VAT Prod. Posting Group");
+ CreateItemUnitOfMeasure(ExtraItem."No.", UnitOfMeasure.Code);
+ LibraryItemReference.CreateItemReference(ItemReference, ExtraItem."No.", '', 'PCS', Enum::"Item Reference Type"::Vendor, Vendor."No.", '2000');
+ end;
+
+ procedure PostSalesShipment(var Customer: Record Customer) SalesShipmentHeader: Record "Sales Shipment Header";
+ var
+ SalesHeader: Record "Sales Header";
+ begin
+ this.CreateSalesHeaderWithItem(Customer, SalesHeader, Enum::"Sales Document Type"::Order);
+ SalesShipmentHeader.Get(this.LibrarySales.PostSalesDocument(SalesHeader, true, false));
+ end;
+
+ procedure CreateInboundEDocument(var EDocument: Record "E-Document"; EDocService: Record "E-Document Service")
+ var
+ EDocumentServiceStatus: Record "E-Document Service Status";
+ begin
+ EDocument.Insert();
+ EDocumentServiceStatus."E-Document Entry No" := EDocument."Entry No";
+ EDocumentServiceStatus."E-Document Service Code" := EDocService.Code;
+ EDocumentServiceStatus.Insert();
+ end;
+
+ procedure MockPurchaseDraftPrepared(EDocument: Record "E-Document")
+ var
+ EDocumentPurchaseHeader: Record "E-Document Purchase Header";
+ EDocumentProcessing: Codeunit "E-Document Processing";
+ begin
+ EDocumentPurchaseHeader.InsertForEDocument(EDocument);
+ EDocumentPurchaseHeader."Sub Total" := 1000;
+ EDocumentPurchaseHeader."Total VAT" := 100;
+ EDocumentPurchaseHeader.Total := 1100;
+ EDocumentPurchaseHeader.Modify();
+ EDocumentProcessing.ModifyEDocumentProcessingStatus(EDocument, "Import E-Doc. Proc. Status"::"Draft Ready");
+ EDocument."Document Type" := "E-Document Type"::"Purchase Invoice";
+ EDocument.Modify();
+ end;
+
+ procedure CreateInboundPEPPOLDocumentToState(var EDocument: Record "E-Document"; EDocumentService: Record "E-Document Service"; FileName: Text; EDocImportParams: Record "E-Doc. Import Parameters"): Boolean
+ var
+ EDocImport: Codeunit "E-Doc. Import";
+ InStream: InStream;
+ begin
+ NavApp.GetResource(FileName, InStream, TextEncoding::UTF8);
+ EDocImport.CreateFromType(EDocument, EDocumentService, Enum::"E-Doc. File Format"::XML, 'TestFile', InStream);
+ exit(EDocImport.ProcessIncomingEDocument(EDocument, EDocImportParams));
+ end;
+
+ ///
+ /// Given a purchase header with purchase lines created from an e-document, it modifies the required fields to make it ready for posting.
+ ///
+ procedure EditPurchaseDocumentFromEDocumentForPosting(var PurchaseHeader: Record "Purchase Header"; var EDocument: Record "E-Document")
+ var
+ PurchaseLine: Record "Purchase Line";
+ GLAccount: Record "G/L Account";
+ GeneralPostingSetup: Record "General Posting Setup";
+ GenBusinessPostingGroup: Record "Gen. Business Posting Group";
+ GenProductPostingGroup: Record "Gen. Product Posting Group";
+ VATBusinessPostingGroup: Record "VAT Business Posting Group";
+ VATProductPostingGroup: Record "VAT Product Posting Group";
+ LocalVATPostingSetup: Record "VAT Posting Setup";
+ begin
+ Assert.AreEqual(EDocument.SystemId, PurchaseHeader."E-Document Link", 'The purchase header has no link to the e-document.');
+ LibraryERM.CreateGenBusPostingGroup(GenBusinessPostingGroup);
+ LibraryERM.CreateGenProdPostingGroup(GenProductPostingGroup);
+ LibraryERM.CreateGeneralPostingSetup(GeneralPostingSetup, GenBusinessPostingGroup.Code, GenProductPostingGroup.Code);
+ LibraryERM.CreateVATBusinessPostingGroup(VATBusinessPostingGroup);
+ LibraryERM.CreateVATProductPostingGroup(VATProductPostingGroup);
+ LibraryERM.CreateVATPostingSetup(LocalVATPostingSetup, VATBusinessPostingGroup.Code, VATProductPostingGroup.Code);
+ LibraryERM.CreateGLAccount(GLAccount);
+ LocalVATPostingSetup."Purchase VAT Account" := GLAccount."No.";
+ LocalVATPostingSetup.Modify();
+ LibraryERM.CreateGLAccount(GLAccount);
+ PurchaseLine.SetRange("Document Type", PurchaseHeader."Document Type");
+ PurchaseLine.SetRange("Document No.", PurchaseHeader."No.");
+ PurchaseLine.FindSet();
+ repeat
+ PurchaseLine.Type := PurchaseLine.Type::"G/L Account";
+ PurchaseLine."No." := GLAccount."No.";
+ PurchaseLine."Gen. Bus. Posting Group" := GenBusinessPostingGroup.Code;
+ PurchaseLine."Gen. Prod. Posting Group" := GenProductPostingGroup.Code;
+ PurchaseLine."VAT Bus. Posting Group" := VATBusinessPostingGroup.Code;
+ PurchaseLine."VAT Prod. Posting Group" := VATProductPostingGroup.Code;
+ PurchaseLine.UpdateAmounts();
+ PurchaseLine.Modify();
+ until PurchaseLine.Next() = 0;
+ PurchaseHeader.CalcFields("Amount Including VAT");
+ EDocument."Amount Incl. VAT" := PurchaseHeader."Amount Including VAT";
+ EDocument.Modify();
+ end;
+
+ procedure CreateDocSendingProfile(var DocumentSendingProfile: Record "Document Sending Profile")
+ begin
+ DocumentSendingProfile.Init();
+ DocumentSendingProfile.Code := LibraryUtility.GenerateRandomCode(DocumentSendingProfile.FieldNo(Code), DATABASE::"Document Sending Profile");
+ DocumentSendingProfile.Insert();
+ end;
+
+
+ procedure CreateSimpleFlow(DocSendingProfileCode: Code[20]; ServiceCode: Code[20]): Code[20]
+ var
+ Workflow: Record Workflow;
+ WorkflowStepResponse: Record "Workflow Step";
+ WorkflowStepArgument: Record "Workflow Step Argument";
+ WorkflowStep: Record "Workflow Step";
+ EDocWorkflowSetup: Codeunit "E-Document Workflow Setup";
+ EDocCreatedEventID, SendEDocResponseEventID : Integer;
+ begin
+ // Create a simple workflow
+ // Send to Service 'ServiceCode' when using Document Sending Profile 'DocSendingProfile'
+ WorkflowStep.SetRange("Function Name", EDocWorkflowSetup.EDocCreated());
+ WorkflowStep.SetRange("Entry Point", true);
+ if WorkflowStep.FindSet() then
+ repeat
+ Workflow.Get(WorkflowStep."Workflow Code");
+ if not Workflow.Template then
+ exit;
+ until WorkflowStep.Next() = 0;
+
+ LibraryWorkflow.CreateWorkflow(Workflow);
+ EDocCreatedEventID := LibraryWorkflow.InsertEntryPointEventStep(Workflow, EDocWorkflowSetup.EDocCreated());
+ SendEDocResponseEventID := LibraryWorkflow.InsertResponseStep(Workflow, EDocWorkflowSetup.EDocSendEDocResponseCode(), EDocCreatedEventID);
+
+ WorkflowStepResponse.Get(Workflow.Code, SendEDocResponseEventID);
+ WorkflowStepArgument.Get(WorkflowStepResponse.Argument);
+
+ WorkflowStepArgument."E-Document Service" := ServiceCode;
+ WorkflowStepArgument.Modify();
+
+ LibraryWorkflow.EnableWorkflow(Workflow);
+ exit(Workflow.Code);
+ end;
+
+ procedure CreateCustomerNoWithEDocSendingProfile(var DocumentSendingProfile: Code[20]): Code[20]
+ var
+ CustomerNo: Code[20];
+ begin
+ CustomerNo := LibrarySales.CreateCustomerNo();
+ DocumentSendingProfile := CreateDocumentSendingProfileForWorkflow(CustomerNo, '');
+ exit(CustomerNo);
+ end;
+
+ procedure CreateEDocumentFromSales(var EDocument: Record "E-Document")
+ begin
+ CreateEDocumentFromSales(EDocument, LibrarySales.CreateCustomerNo());
+ end;
+
+ procedure CreateEDocumentFromSales(var EDocument: Record "E-Document"; CustomerNo: Code[20])
+ var
+ SalesInvHeader: Record "Sales Invoice Header";
+ SalesHeader: Record "Sales Header";
+ begin
+ LibrarySales.CreateSalesInvoiceForCustomerNo(SalesHeader, CustomerNo);
+ SalesInvHeader.Get(LibrarySales.PostSalesDocument(SalesHeader, true, true));
+ EDocument.FindLast();
+ end;
+
+ local procedure CreateGenericSalesHeader(var Cust: Record Customer; var SalesHeader: Record "Sales Header"; DocumentType: Enum "Sales Document Type")
+ begin
+ LibrarySales.CreateSalesHeader(SalesHeader, DocumentType, Cust."No.");
+ SalesHeader.Validate("Your Reference", LibraryUtility.GenerateRandomCode(SalesHeader.FieldNo("Your Reference"), DATABASE::"Sales Header"));
+
+ if DocumentType = SalesHeader."Document Type"::"Credit Memo" then
+ SalesHeader.Validate("Shipment Date", WorkDate());
+
+ SalesHeader.Modify(true);
+ end;
+
+ procedure CreateGenericItem(var Item: Record Item; VATProdPostingGroupCode: Code[20])
+ begin
+ CreateGenericItem(Item);
+ Item."VAT Prod. Posting Group" := VATPostingSetup."VAT Prod. Posting Group";
+ Item.Modify();
+ end;
+
+ procedure CreateGenericItem(var Item: Record Item)
+ var
+ UOM: Record "Unit of Measure";
+ ItemUOM: Record "Item Unit of Measure";
+ QtyPerUnit: Integer;
+ begin
+ QtyPerUnit := LibraryRandom.RandInt(10);
+
+ LibraryInvt.CreateUnitOfMeasureCode(UOM);
+ UOM.Validate("International Standard Code",
+ LibraryUtility.GenerateRandomCode(UOM.FieldNo("International Standard Code"), DATABASE::"Unit of Measure"));
+ UOM.Modify(true);
+
+ CreateItemWithPrice(Item, LibraryRandom.RandInt(10));
+
+ LibraryInvt.CreateItemUnitOfMeasure(ItemUOM, Item."No.", UOM.Code, QtyPerUnit);
+
+ Item.Validate("Sales Unit of Measure", UOM.Code);
+ Item.Modify(true);
+ end;
+
+ local procedure CreateItemWithPrice(var Item: Record Item; UnitPrice: Decimal)
+ begin
+ LibraryInvt.CreateItem(Item);
+ Item."Unit Price" := UnitPrice;
+ Item.Modify();
+ end;
+
+ procedure SetupCompanyInfo()
+ var
+ CompanyInfo: Record "Company Information";
+ CountryRegion: Record "Country/Region";
+ begin
+ LibraryERM.FindCountryRegion(CountryRegion);
+
+ CompanyInfo.Get();
+ CompanyInfo.Validate(IBAN, 'GB33BUKB20201555555555');
+ CompanyInfo.Validate("SWIFT Code", 'MIDLGB22Z0K');
+ CompanyInfo.Validate("Bank Branch No.", '1234');
+ CompanyInfo.Validate(Address, CopyStr(LibraryUtility.GenerateRandomXMLText(MaxStrLen(CompanyInfo.Address)), 1, MaxStrLen(CompanyInfo.Address)));
+ CompanyInfo.Validate("Post Code", CopyStr(LibraryUtility.GenerateRandomXMLText(MaxStrLen(CompanyInfo."Post Code")), 1, MaxStrLen(CompanyInfo."Post Code")));
+ CompanyInfo.Validate("City", CopyStr(LibraryUtility.GenerateRandomXMLText(MaxStrLen(CompanyInfo."City")), 1, MaxStrLen(CompanyInfo."Post Code")));
+ CompanyInfo."Country/Region Code" := CountryRegion.Code;
+
+ if CompanyInfo."VAT Registration No." = '' then
+ CompanyInfo."VAT Registration No." := LibraryERM.GenerateVATRegistrationNo(CompanyInfo."Country/Region Code");
+
+ CompanyInfo.Modify(true);
+ end;
+
+ procedure CreateSalesHeaderWithItem(Customer: Record Customer; var SalesHeader: Record "Sales Header"; DocumentType: Enum "Sales Document Type")
+ var
+ SalesLine: Record "Sales Line";
+ begin
+ CreateGenericSalesHeader(Customer, SalesHeader, DocumentType);
+
+ if StandardItem."No." = '' then
+ CreateGenericItem(StandardItem);
+
+ LibrarySales.CreateSalesLine(SalesLine, SalesHeader, SalesLine.Type::Item, StandardItem."No.", 1);
+ end;
+
+ procedure CreatePurchaseOrderWithLine(var Vendor: Record Vendor; var PurchaseHeader: Record "Purchase Header"; var PurchaseLine: Record "Purchase Line"; Quantity: Decimal)
+ begin
+ LibraryPurchase.CreatePurchHeader(PurchaseHeader, Enum::"Purchase Document Type"::Order, Vendor."No.");
+ if StandardItem."No." = '' then
+ CreateGenericItem(StandardItem);
+ LibraryPurchase.CreatePurchaseLine(PurchaseLine, PurchaseHeader, PurchaseLine.Type::Item, StandardItem."No.", Quantity);
+ end;
+
+ procedure PostSalesDocument(var SalesHeader: Record "Sales Header"; var SalesInvHeader: Record "Sales Invoice Header")
+ begin
+ SalesInvHeader.Get(LibrarySales.PostSalesDocument(SalesHeader, true, true));
+ end;
+
+ procedure PostSalesDocument(var SalesHeader: Record "Sales Header"; var SalesInvHeader: Record "Sales Invoice Header"; Ship: Boolean)
+ begin
+ SalesInvHeader.Get(LibrarySales.PostSalesDocument(SalesHeader, Ship, true));
+ end;
+
+ procedure CreateReminderWithLine(Customer: Record Customer; var ReminderHeader: Record "Reminder Header")
+ var
+ ReminderLine: Record "Reminder Line";
+ begin
+ LibraryERM.CreateReminderHeader(ReminderHeader);
+ ReminderHeader.Validate("Customer No.", Customer."No.");
+ ReminderHeader."Your Reference" := LibraryRandom.RandText(35);
+ ReminderHeader.Modify(false);
+
+ LibraryERM.CreateReminderLine(ReminderLine, ReminderHeader."No.", Enum::"Reminder Source Type"::"G/L Account");
+ ReminderLine.Validate("Remaining Amount", this.LibraryRandom.RandInt(100));
+ ReminderLine.Description := LibraryRandom.RandText(100);
+ ReminderLine.Modify(false);
+ end;
+
+ procedure CreateFinChargeMemoWithLine(Customer: Record Customer; var FinChargeMemoHeader: Record "Finance Charge Memo Header")
+ var
+ FinChargeMemoLine: Record "Finance Charge Memo Line";
+ FinanceChargeTerms: Record "Finance Charge Terms";
+ begin
+ LibraryERM.CreateFinanceChargeMemoHeader(FinChargeMemoHeader, Customer."No.");
+ LibraryFinChargeMemo.CreateFinanceChargeTermAndText(FinanceChargeTerms);
+ FinChargeMemoHeader.Validate("Fin. Charge Terms Code", FinanceChargeTerms.Code);
+ FinChargeMemoHeader."Your Reference" := LibraryRandom.RandText(35);
+ FinChargeMemoHeader.Modify(false);
+
+ LibraryERM.CreateFinanceChargeMemoLine(FinChargeMemoLine, FinChargeMemoHeader."No.", FinChargeMemoLine.Type::"G/L Account");
+ FinChargeMemoLine.Validate("Remaining Amount", this.LibraryRandom.RandInt(100));
+ FinChargeMemoLine.Description := LibraryRandom.RandText(100);
+ FinChargeMemoLine.Modify(false);
+ end;
+
+ procedure IssueReminder(Customer: Record Customer) IssuedReminderHeader: Record "Issued Reminder Header"
+ var
+ ReminderHeader: Record "Reminder Header";
+ ReminderIssue: Codeunit "Reminder-Issue";
+ begin
+ CreateReminderWithLine(Customer, ReminderHeader);
+
+ ReminderHeader.SetRange("No.", ReminderHeader."No.");
+ ReminderIssue.Set(ReminderHeader, false, 0D);
+ ReminderIssue.Run();
+
+ ReminderIssue.GetIssuedReminder(IssuedReminderHeader);
+ end;
+
+ procedure IssueFinChargeMemo(Customer: Record Customer) IssuedFinChargeMemoHeader: Record "Issued Fin. Charge Memo Header"
+ var
+ FinChargeMemoHeader: Record "Finance Charge Memo Header";
+ FinChargeMemoIssue: Codeunit "FinChrgMemo-Issue";
+ begin
+ CreateFinChargeMemoWithLine(Customer, FinChargeMemoHeader);
+
+ FinChargeMemoHeader.SetRange("No.", FinChargeMemoHeader."No.");
+ FinChargeMemoIssue.Set(FinChargeMemoHeader, false, 0D);
+ FinChargeMemoIssue.Run();
+
+ FinChargeMemoIssue.GetIssuedFinChrgMemo(IssuedFinChargeMemoHeader);
+ end;
+
+ procedure SetupReminderNoSeries()
+ var
+ SalesSetup: Record "Sales & Receivables Setup";
+ begin
+ SalesSetup.Get();
+ SalesSetup.Validate("Reminder Nos.", this.LibraryERM.CreateNoSeriesCode());
+ SalesSetup.Validate("Issued Reminder Nos.", this.LibraryERM.CreateNoSeriesCode());
+ SalesSetup.Modify(false);
+ end;
+
+ procedure SetupFinChargeMemoNoSeries()
+ var
+ SalesSetup: Record "Sales & Receivables Setup";
+ begin
+ SalesSetup.Get();
+ SalesSetup.Validate("Fin. Chrg. Memo Nos.", this.LibraryERM.CreateNoSeriesCode());
+ SalesSetup.Validate("Issued Fin. Chrg. M. Nos.", this.LibraryERM.CreateNoSeriesCode());
+ SalesSetup.Modify(false);
+ end;
+
+ procedure Initialize()
+ var
+ DocumentSendingProfile: Record "Document Sending Profile";
+ EDocService: Record "E-Document Service";
+ EDocServiceStatus: Record "E-Document Service Status";
+ EDocServiceSupportedType: Record "E-Doc. Service Supported Type";
+ EDocMapping: Record "E-Doc. Mapping";
+ EDocLogs: Record "E-Document Log";
+ EDocMappingLogs: Record "E-Doc. Mapping Log";
+ EDocDataStorage: Record "E-Doc. Data Storage";
+ EDocument: Record "E-Document";
+ WorkflowSetup: Codeunit "Workflow Setup";
+ begin
+ LibraryWorkflow.DeleteAllExistingWorkflows();
+ WorkflowSetup.InitWorkflow();
+ DocumentSendingProfile.DeleteAll();
+ EDocService.DeleteAll();
+ EDocServiceSupportedType.DeleteAll();
+ EDocument.DeleteAll();
+ EDocServiceStatus.DeleteAll();
+ EDocDataStorage.DeleteAll();
+ EDocMapping.DeleteAll();
+ EDocLogs.DeleteAll();
+ EDocMappingLogs.DeleteAll();
+ Commit();
+ end;
+
+ procedure PostSalesDocument(CustomerNo: Code[20]): Code[20]
+ var
+ SalesInvHeader: Record "Sales Invoice Header";
+ SalesHeader: Record "Sales Header";
+ begin
+ LibrarySales.CreateSalesInvoiceForCustomerNo(SalesHeader, CustomerNo);
+ SalesInvHeader.Get(LibrarySales.PostSalesDocument(SalesHeader, true, true));
+ exit(SalesInvHeader."No.");
+ end;
+
+ procedure PostSalesDocument(): Code[20]
+ begin
+ PostSalesDocument('');
+ end;
+
+ procedure CreateDocumentSendingProfileForWorkflow(CustomerNo: Code[20]; WorkflowCode: Code[20]): Code[20]
+ var
+ Customer: Record Customer;
+ DocumentSendingProfile: Record "Document Sending Profile";
+ begin
+ DocumentSendingProfile.Init();
+ DocumentSendingProfile.Code := LibraryUtility.GenerateRandomCode20(DocumentSendingProfile.FieldNo(Code), Database::"Document Sending Profile");
+ DocumentSendingProfile."Electronic Document" := Enum::"Doc. Sending Profile Elec.Doc."::"Extended E-Document Service Flow";
+ DocumentSendingProfile."Electronic Service Flow" := WorkflowCode;
+ DocumentSendingProfile.Insert();
+
+ Customer.Get(CustomerNo);
+ Customer.Validate("Document Sending Profile", DocumentSendingProfile.Code);
+ Customer.Modify();
+ exit(DocumentSendingProfile.Code);
+ end;
+
+ procedure UpdateWorkflowOnDocumentSendingProfile(DocSendingProfile: Code[20]; WorkflowCode: Code[20])
+ var
+ DocumentSendingProfile: Record "Document Sending Profile";
+ begin
+ DocumentSendingProfile.Get(DocSendingProfile);
+ DocumentSendingProfile.Validate("Electronic Service Flow", WorkflowCode);
+ DocumentSendingProfile.Modify();
+ end;
+
+ procedure CreateFlowWithService(DocSendingProfile: Code[20]; ServiceCode: Code[20]): Code[20]
+ var
+ Workflow: Record Workflow;
+ WorkflowStepResponse: Record "Workflow Step";
+ WorkflowStepArgument: Record "Workflow Step Argument";
+ EDocWorkflowSetup: Codeunit "E-Document Workflow Setup";
+ EDocCreatedEventID, SendEDocResponseEventID : Integer;
+ EventConditions: Text;
+ begin
+ LibraryWorkflow.CreateWorkflow(Workflow);
+ EventConditions := CreateWorkflowEventConditionDocSendingProfileFilter(DocSendingProfile);
+
+ EDocCreatedEventID := LibraryWorkflow.InsertEntryPointEventStep(Workflow, EDocWorkflowSetup.EDocCreated());
+ LibraryWorkflow.InsertEventArgument(EDocCreatedEventID, EventConditions);
+ SendEDocResponseEventID := LibraryWorkflow.InsertResponseStep(Workflow, EDocWorkflowSetup.EDocSendEDocResponseCode(), EDocCreatedEventID);
+
+ WorkflowStepResponse.Get(Workflow.Code, SendEDocResponseEventID);
+ WorkflowStepArgument.Get(WorkflowStepResponse.Argument);
+
+ WorkflowStepArgument.Validate("E-Document Service", ServiceCode);
+ WorkflowStepArgument.Modify();
+
+ LibraryWorkflow.EnableWorkflow(Workflow);
+ exit(Workflow.Code);
+ end;
+
+ procedure CreateEmptyFlow(): Code[20]
+ var
+ Workflow: Record Workflow;
+ EDocWorkflowSetup: Codeunit "E-Document Workflow Setup";
+ EDocCreatedEventID: Integer;
+ begin
+ LibraryWorkflow.CreateWorkflow(Workflow);
+ EDocCreatedEventID := LibraryWorkflow.InsertEntryPointEventStep(Workflow, EDocWorkflowSetup.EDocCreated());
+ LibraryWorkflow.InsertResponseStep(Workflow, EDocWorkflowSetup.EDocSendEDocResponseCode(), EDocCreatedEventID);
+
+ LibraryWorkflow.EnableWorkflow(Workflow);
+ exit(Workflow.Code);
+ end;
+
+ procedure CreateFlowWithServices(DocSendingProfile: Code[20]; ServiceCodeA: Code[20]; ServiceCodeB: Code[20]): Code[20]
+ var
+ Workflow: Record Workflow;
+ WorkflowStepResponse: Record "Workflow Step";
+ WorkflowStepArgument: Record "Workflow Step Argument";
+ EDocWorkflowSetup: Codeunit "E-Document Workflow Setup";
+ EDocCreatedEventID, SendEDocResponseEventIDA, SendEDocResponseEventIDB : Integer;
+ EventConditionsDocProfile, EventConditionsService : Text;
+ begin
+ LibraryWorkflow.CreateWorkflow(Workflow);
+ EventConditionsDocProfile := CreateWorkflowEventConditionDocSendingProfileFilter(DocSendingProfile);
+ EventConditionsService := CreateWorkflowEventConditionServiceFilter(ServiceCodeA);
+
+ EDocCreatedEventID := LibraryWorkflow.InsertEntryPointEventStep(Workflow, EDocWorkflowSetup.EDocCreated());
+ LibraryWorkflow.InsertEventArgument(EDocCreatedEventID, EventConditionsDocProfile);
+ SendEDocResponseEventIDA := LibraryWorkflow.InsertResponseStep(Workflow, EDocWorkflowSetup.EDocSendEDocResponseCode(), EDocCreatedEventID);
+ SendEDocResponseEventIDB := LibraryWorkflow.InsertResponseStep(Workflow, EDocWorkflowSetup.EDocSendEDocResponseCode(), SendEDocResponseEventIDA);
+
+ WorkflowStepResponse.Get(Workflow.Code, SendEDocResponseEventIDA);
+ WorkflowStepArgument.Get(WorkflowStepResponse.Argument);
+ WorkflowStepArgument."E-Document Service" := ServiceCodeA;
+ WorkflowStepArgument.Modify();
+
+ WorkflowStepResponse.Get(Workflow.Code, SendEDocResponseEventIDB);
+ WorkflowStepArgument.Get(WorkflowStepResponse.Argument);
+ WorkflowStepArgument."E-Document Service" := ServiceCodeB;
+ WorkflowStepArgument.Modify();
+
+ LibraryWorkflow.EnableWorkflow(Workflow);
+ exit(Workflow.Code);
+ end;
+
+ local procedure DeleteEDocumentRelatedEntities()
+ var
+ DynamicRequestPageEntity: Record "Dynamic Request Page Entity";
+ begin
+ DynamicRequestPageEntity.SetRange("Table ID", DATABASE::"E-Document");
+ DynamicRequestPageEntity.DeleteAll(true);
+ end;
+
+ local procedure CreateWorkflowEventConditionDocSendingProfileFilter(DocSendingProfile: Code[20]): Text
+ var
+ RequestPageParametersHelper: Codeunit "Request Page Parameters Helper";
+ FilterPageBuilder: FilterPageBuilder;
+ EntityName: Code[20];
+ begin
+ EntityName := CreateDynamicRequestPageEntity(DATABASE::"E-Document", Database::"Document Sending Profile");
+ CreateEDocumentDocSendingProfileDataItem(FilterPageBuilder, DocSendingProfile);
+ exit(RequestPageParametersHelper.GetViewFromDynamicRequestPage(FilterPageBuilder, EntityName, Database::"E-Document"));
+ end;
+
+ local procedure CreateWorkflowEventConditionServiceFilter(ServiceCode: Code[20]): Text
+ var
+ RequestPageParametersHelper: Codeunit "Request Page Parameters Helper";
+ FilterPageBuilder: FilterPageBuilder;
+ EntityName: Code[20];
+ begin
+ EntityName := CreateDynamicRequestPageEntity(DATABASE::"E-Document", Database::"E-Document Service");
+ CreateEDocServiceDataItem(FilterPageBuilder, ServiceCode);
+ exit(RequestPageParametersHelper.GetViewFromDynamicRequestPage(FilterPageBuilder, EntityName, Database::"E-Document Service"));
+ end;
+
+ local procedure CreateEDocumentDocSendingProfileDataItem(var FilterPageBuilder: FilterPageBuilder; DocumentSendingProfile: Code[20])
+ var
+ EDocument: Record "E-Document";
+ EDocumentDataItem: Text;
+ begin
+ EDocumentDataItem := FilterPageBuilder.AddTable(EDocument.TableCaption, DATABASE::"E-Document");
+ FilterPageBuilder.AddField(EDocumentDataItem, EDocument."Document Sending Profile", DocumentSendingProfile);
+ end;
+
+ local procedure CreateEDocServiceDataItem(var FilterPageBuilder: FilterPageBuilder; ServiceCode: Code[20])
+ var
+ EDocService: Record "E-Document Service";
+ EDocumentDataItem: Text;
+ begin
+ EDocumentDataItem := FilterPageBuilder.AddTable(EDocService.TableCaption, DATABASE::"E-Document Service");
+ FilterPageBuilder.AddField(EDocumentDataItem, EDocService.Code, ServiceCode);
+ end;
+
+ local procedure CreateDynamicRequestPageEntity(TableID: Integer; RelatedTable: Integer): Code[20]
+ var
+ EntityName: Code[20];
+ begin
+ DeleteEDocumentRelatedEntities();
+ EntityName := LibraryUtility.GenerateGUID();
+ LibraryWorkflow.CreateDynamicRequestPageEntity(EntityName, TableID, RelatedTable);
+ exit(EntityName);
+ end;
+
+#if not CLEAN26
+#pragma warning disable AL0432
+ [Obsolete('Use CreateService(EDocDocumentFormat: Enum "E-Document Format"; EDocIntegration: Enum "Service Integration") instead', '26.0')]
+ procedure CreateService(Integration: Enum "E-Document Integration"): Code[20]
+ var
+ EDocService: Record "E-Document Service";
+ begin
+ EDocService.Init();
+ EDocService.Code := LibraryUtility.GenerateRandomCode20(EDocService.FieldNo(Code), Database::"E-Document Service");
+ EDocService."Document Format" := "E-Document Format"::Mock;
+ EDocService."Service Integration" := Integration;
+ EDocService.Insert();
+
+ CreateSupportedDocTypes(EDocService);
+
+ exit(EDocService.Code);
+ end;
+#pragma warning restore AL0432
+#endif
+
+ procedure CreateService(Integration: Enum "Service Integration"): Code[20]
+ var
+ EDocService: Record "E-Document Service";
+ begin
+ EDocService.Init();
+ EDocService.Code := LibraryUtility.GenerateRandomCode20(EDocService.FieldNo(Code), Database::"E-Document Service");
+ EDocService."Document Format" := "E-Document Format"::Mock;
+ EDocService."Service Integration V2" := Integration;
+ EDocService.Insert();
+
+ CreateSupportedDocTypes(EDocService);
+
+ exit(EDocService.Code);
+ end;
+
+#if not CLEAN26
+#pragma warning disable AL0432
+ [Obsolete('Use CreateService(EDocDocumentFormat: Enum "E-Document Format"; EDocIntegration: Enum "Service Integration") instead', '26.0')]
+ procedure CreateService(EDocDocumentFormat: Enum "E-Document Format"; EDocIntegration: Enum "E-Document Integration"): Code[20]
+ var
+ EDocService: Record "E-Document Service";
+ begin
+ EDocService.Init();
+ EDocService.Code := LibraryUtility.GenerateRandomCode20(EDocService.FieldNo(Code), Database::"E-Document Service");
+ EDocService."Document Format" := EDocDocumentFormat;
+ EDocService."Service Integration" := EDocIntegration;
+ EDocService.Insert();
+
+ CreateSupportedDocTypes(EDocService);
+
+ exit(EDocService.Code);
+ end;
+#pragma warning restore AL0432
+#endif
+
+ procedure CreateService(EDocDocumentFormat: Enum "E-Document Format"; EDocIntegration: Enum "Service Integration"): Code[20]
+ var
+ EDocService: Record "E-Document Service";
+ begin
+ EDocService.Init();
+ EDocService.Code := LibraryUtility.GenerateRandomCode20(EDocService.FieldNo(Code), Database::"E-Document Service");
+ EDocService."Document Format" := EDocDocumentFormat;
+ EDocService."Service Integration V2" := EDocIntegration;
+ EDocService.Insert();
+
+ CreateSupportedDocTypes(EDocService);
+
+ exit(EDocService.Code);
+ end;
+
+
+ procedure CreateServiceMapping(EDocService: Record "E-Document Service")
+ var
+ TransformationRule: Record "Transformation Rule";
+ EDocMapping: Record "E-Doc. Mapping";
+ SalesInvHeader: Record "Sales Invoice Header";
+ begin
+ TransformationRule.Get(TransformationRule.GetLowercaseCode());
+ // Lower case mapping
+ CreateTransformationMapping(EDocMapping, TransformationRule, EDocService.Code);
+ EDocMapping."Table ID" := Database::"Sales Invoice Header";
+ EDocMapping."Field ID" := SalesInvHeader.FieldNo("Bill-to Name");
+ EDocMapping.Modify();
+ CreateTransformationMapping(EDocMapping, TransformationRule, EDocService.Code);
+ EDocMapping."Table ID" := Database::"Sales Invoice Header";
+ EDocMapping."Field ID" := SalesInvHeader.FieldNo("Bill-to Address");
+ EDocMapping.Modify();
+ end;
+
+ procedure DeleteServiceMapping(EDocService: Record "E-Document Service")
+ var
+ EDocMapping: Record "E-Doc. Mapping";
+ begin
+ EDocMapping.SetRange(Code, EDocService.Code);
+ EDocMapping.DeleteAll();
+ end;
+
+
+ // procedure CreateServiceWithMapping(var EDocMapping: Record "E-Doc. Mapping"; TransformationRule: Record "Transformation Rule"; Integration: Enum "E-Document Integration"): Code[20]
+ // begin
+ // exit(CreateServiceWithMapping(EDocMapping, TransformationRule, false, Integration));
+ // end;
+
+ // procedure CreateServiceWithMapping(var EDocMapping: Record "E-Doc. Mapping"; TransformationRule: Record "Transformation Rule"; UseBatching: Boolean; Integration: Enum "E-Document Integration"): Code[20]
+ // var
+ // SalesInvHeader: Record "Sales Invoice Header";
+ // EDocService: Record "E-Document Service";
+ // begin
+ // EDocService.Init();
+ // EDocService.Code := LibraryUtility.GenerateRandomCode20(EDocService.FieldNo(Code), Database::"E-Document Service");
+ // EDocService."Document Format" := "E-Document Format"::Mock;
+ // EDocService."Service Integration" := Integration;
+ // EDocService."Use Batch Processing" := UseBatching;
+ // EDocService.Insert();
+
+ // CreateSupportedDocTypes(EDocService);
+
+ // // Lower case mapping
+ // CreateTransformationMapping(EDocMapping, TransformationRule, EDocService.Code);
+ // EDocMapping."Table ID" := Database::"Sales Invoice Header";
+ // EDocMapping."Field ID" := SalesInvHeader.FieldNo("Bill-to Name");
+ // EDocMapping.Modify();
+ // CreateTransformationMapping(EDocMapping, TransformationRule, EDocService.Code);
+ // EDocMapping."Table ID" := Database::"Sales Invoice Header";
+ // EDocMapping."Field ID" := SalesInvHeader.FieldNo("Bill-to Address");
+ // EDocMapping.Modify();
+
+ // exit(EDocService.Code);
+ // end;
+
+ procedure CreateSupportedDocTypes(EDocService: Record "E-Document Service")
+ var
+ EDocServiceSupportedType: Record "E-Doc. Service Supported Type";
+ begin
+ EDocServiceSupportedType.Init();
+ EDocServiceSupportedType."E-Document Service Code" := EDocService.Code;
+ EDocServiceSupportedType."Source Document Type" := EDocServiceSupportedType."Source Document Type"::"Sales Invoice";
+ EDocServiceSupportedType.Insert();
+
+ EDocServiceSupportedType."Source Document Type" := EDocServiceSupportedType."Source Document Type"::"Sales Credit Memo";
+ EDocServiceSupportedType.Insert();
+
+ EDocServiceSupportedType."Source Document Type" := EDocServiceSupportedType."Source Document Type"::"Service Invoice";
+ EDocServiceSupportedType.Insert();
+
+ EDocServiceSupportedType."Source Document Type" := EDocServiceSupportedType."Source Document Type"::"Service Credit Memo";
+ EDocServiceSupportedType.Insert();
+
+ EDocServiceSupportedType."Source Document Type" := EDocServiceSupportedType."Source Document Type"::"Issued Finance Charge Memo";
+ EDocServiceSupportedType.Insert();
+
+ EDocServiceSupportedType."Source Document Type" := EDocServiceSupportedType."Source Document Type"::"Issued Reminder";
+ EDocServiceSupportedType.Insert();
+ end;
+
+ procedure AddEDocServiceSupportedType(EDocService: Record "E-Document Service"; EDocumentType: Enum "E-Document Type")
+ var
+ EDocServiceSupportedType: Record "E-Doc. Service Supported Type";
+ begin
+ if not EDocService.Get(EDocService.Code) then
+ exit;
+
+ EDocServiceSupportedType.Init();
+ EDocServiceSupportedType."E-Document Service Code" := EDocService.Code;
+ EDocServiceSupportedType."Source Document Type" := EDocumentType;
+ if EDocServiceSupportedType.Insert() then;
+ end;
+
+ procedure CreateTestReceiveServiceForEDoc(var EDocService: Record "E-Document Service"; Integration: Enum "Service Integration")
+ begin
+ if not EDocService.Get('TESTRECEIVE') then begin
+ EDocService.Init();
+ EDocService.Code := 'TESTRECEIVE';
+ EDocService."Document Format" := "E-Document Format"::Mock;
+ EDocService."Service Integration V2" := Integration;
+ EDocService.Insert();
+ end;
+ end;
+
+#if not CLEAN26
+#pragma warning disable AL0432
+ [Obsolete('Use CreateTestReceiveServiceForEDoc(var EDocService: Record "E-Document Service"; Integration: Enum "Service Integration") instead', '26.0')]
+ procedure CreateTestReceiveServiceForEDoc(var EDocService: Record "E-Document Service"; Integration: Enum "E-Document Integration")
+ begin
+ if not EDocService.Get('TESTRECEIVE') then begin
+ EDocService.Init();
+ EDocService.Code := 'TESTRECEIVE';
+ EDocService."Document Format" := "E-Document Format"::Mock;
+ EDocService."Service Integration" := Integration;
+ EDocService.Insert();
+ end;
+ end;
+#pragma warning restore AL0432
+#endif
+
+ procedure CreateGetBasicInfoErrorReceiveServiceForEDoc(var EDocService: Record "E-Document Service"; Integration: Enum "Service Integration")
+ begin
+ if not EDocService.Get('BIERRRECEIVE') then begin
+ EDocService.Init();
+ EDocService.Code := 'BIERRRECEIVE';
+ EDocService."Document Format" := "E-Document Format"::Mock;
+ EDocService."Service Integration V2" := Integration;
+ EDocService.Insert();
+ end;
+ end;
+
+#if not CLEAN26
+#pragma warning disable AL0432
+ [Obsolete('Use CreateGetBasicInfoErrorReceiveServiceForEDoc(var EDocService: Record "E-Document Service"; Integration: Enum "Service Integration") instead', '26.0')]
+ procedure CreateGetBasicInfoErrorReceiveServiceForEDoc(var EDocService: Record "E-Document Service"; Integration: Enum "E-Document Integration")
+ begin
+ if not EDocService.Get('BIERRRECEIVE') then begin
+ EDocService.Init();
+ EDocService.Code := 'BIERRRECEIVE';
+ EDocService."Document Format" := "E-Document Format"::Mock;
+ EDocService."Service Integration" := Integration;
+ EDocService.Insert();
+ end;
+ end;
+#pragma warning restore AL0432
+#endif
+
+ procedure CreateGetCompleteInfoErrorReceiveServiceForEDoc(var EDocService: Record "E-Document Service"; Integration: Enum "Service Integration")
+ begin
+ if not EDocService.Get('CIERRRECEIVE') then begin
+ EDocService.Init();
+ EDocService.Code := 'CIERRRECEIVE';
+ EDocService."Document Format" := "E-Document Format"::Mock;
+ EDocService."Service Integration V2" := Integration;
+ EDocService.Insert();
+ end;
+ end;
+
+#if not CLEAN26
+#pragma warning disable AL0432
+ [Obsolete('Use CreateGetCompleteInfoErrorReceiveServiceForEDoc(var EDocService: Record "E-Document Service"; Integration: Enum "Service Integration") instead', '26.0')]
+ procedure CreateGetCompleteInfoErrorReceiveServiceForEDoc(var EDocService: Record "E-Document Service"; Integration: Enum "E-Document Integration")
+ begin
+ if not EDocService.Get('CIERRRECEIVE') then begin
+ EDocService.Init();
+ EDocService.Code := 'CIERRRECEIVE';
+ EDocService."Document Format" := "E-Document Format"::Mock;
+ EDocService."Service Integration" := Integration;
+ EDocService.Insert();
+ end;
+ end;
+#pragma warning restore AL0432
+#endif
+
+ procedure CreateDirectMapping(var EDocMapping: Record "E-Doc. Mapping"; EDocService: Record "E-Document Service"; FindValue: Text; ReplaceValue: Text)
+ begin
+ CreateDirectMapping(EDocMapping, EDocService, FindValue, ReplaceValue, 0, 0);
+ end;
+
+ procedure CreateTransformationMapping(var EDocMapping: Record "E-Doc. Mapping"; TransformationRule: Record "Transformation Rule")
+ begin
+ CreateTransformationMapping(EDocMapping, TransformationRule, '');
+ end;
+
+ procedure CreateTransformationMapping(var EDocMapping: Record "E-Doc. Mapping"; TransformationRule: Record "Transformation Rule"; ServiceCode: Code[20])
+ begin
+ EDocMapping.Init();
+ EDocMapping.Code := ServiceCode;
+ EDocMapping."Entry No." := 0;
+ EDocMapping."Transformation Rule" := TransformationRule.Code;
+ EDocMapping.Insert();
+ end;
+
+ procedure CreateDirectMapping(var EDocMapping: Record "E-Doc. Mapping"; EDocService: Record "E-Document Service"; FindValue: Text; ReplaceValue: Text; TableId: Integer; FieldId: Integer)
+ begin
+ EDocMapping.Init();
+ EDocMapping."Entry No." := 0;
+ EDocMapping.Code := EDocService.Code;
+ EDocMapping."Table ID" := TableId;
+ EDocMapping."Field ID" := FieldId;
+ EDocMapping."Find Value" := CopyStr(FindValue, 1, LibraryUtility.GetFieldLength(DATABASE::"E-Doc. Mapping", EDocMapping.FieldNo("Find Value")));
+ EDocMapping."Replace Value" := CopyStr(ReplaceValue, 1, LibraryUtility.GetFieldLength(DATABASE::"E-Doc. Mapping", EDocMapping.FieldNo("Replace Value")));
+ EDocMapping.Insert();
+ end;
+
+ local procedure CreateItemUnitOfMeasure(ItemNo: Code[20]; UnitOfMeasureCode: Code[10])
+ var
+ ItemUnitOfMeasure: Record "Item Unit of Measure";
+ begin
+ ItemUnitOfMeasure.Init();
+ ItemUnitOfMeasure.Validate("Item No.", ItemNo);
+ ItemUnitOfMeasure.Validate(Code, UnitOfMeasureCode);
+ ItemUnitOfMeasure."Qty. per Unit of Measure" := 1;
+ if ItemUnitOfMeasure.Insert() then;
+ end;
+
+ procedure TempBlobToTxt(var TempBlob: Codeunit "Temp Blob"): Text
+ var
+ InStr: InStream;
+ Content: Text;
+ begin
+ TempBlob.CreateInStream(InStr);
+ InStr.Read(Content);
+ exit(Content);
+ end;
+
+ internal procedure CreateLocationsWithPostingSetups(
+ var FromLocation: Record Location;
+ var ToLocation: Record Location;
+ var InTransitLocation: Record Location;
+ var InventoryPostingGroup: Record "Inventory Posting Group")
+ var
+ InventoryPostingSetupFromLocation: Record "Inventory Posting Setup";
+ InventoryPostingSetupToLocation: Record "Inventory Posting Setup";
+ InventoryPostingSetupInTransitLocation: Record "Inventory Posting Setup";
+ LibraryWarehouse: Codeunit "Library - Warehouse";
+ begin
+ LibraryWarehouse.CreateLocation(FromLocation);
+ LibraryWarehouse.CreateLocation(ToLocation);
+ LibraryWarehouse.CreateInTransitLocation(InTransitLocation);
+
+ LibraryInventory.CreateInventoryPostingGroup(InventoryPostingGroup);
+ LibraryInventory.CreateInventoryPostingSetup(InventoryPostingSetupFromLocation, FromLocation.Code, InventoryPostingGroup.Code);
+ LibraryInventory.UpdateInventoryPostingSetup(FromLocation, InventoryPostingGroup.Code);
+
+ InventoryPostingSetupFromLocation.Get(FromLocation.Code, InventoryPostingGroup.Code);
+ InventoryPostingSetupToLocation := InventoryPostingSetupFromLocation;
+ InventoryPostingSetupToLocation."Location Code" := ToLocation.Code;
+ InventoryPostingSetupToLocation.Insert(false);
+
+ InventoryPostingSetupInTransitLocation := InventoryPostingSetupFromLocation;
+ InventoryPostingSetupInTransitLocation."Location Code" := InTransitLocation.Code;
+ InventoryPostingSetupInTransitLocation.Insert(false);
+ end;
+
+ internal procedure CreateItemWithInventoryPostingGroup(var Item: Record Item; InventoryPostingGroupCode: Code[20])
+ begin
+ LibraryInventory.CreateItem(Item);
+ Item."Inventory Posting Group" := InventoryPostingGroupCode;
+ Item.Modify(false);
+ end;
+
+ internal procedure CreateItemWIthInventoryStock(var Item: Record Item; var FromLocation: Record Location; var InventoryPostingGroup: Record "Inventory Posting Group")
+ var
+ ItemJournalLine: Record "Item Journal Line";
+ begin
+ CreateItemWithInventoryPostingGroup(Item, InventoryPostingGroup.Code);
+ LibraryInventory.CreateItemJournalLineInItemTemplate(
+ ItemJournalLine, Item."No.", FromLocation.Code, '', LibraryRandom.RandIntInRange(10, 20));
+ LibraryInventory.PostItemJournalLine(
+ ItemJournalLine."Journal Template Name", ItemJournalLine."Journal Batch Name");
+ end;
+
+ // Verify procedures
+
+ procedure AssertEDocumentLogs(EDocument: Record "E-Document"; EDocumentService: Record "E-Document Service"; EDocLogList: List of [Enum "E-Document Service Status"])
+ var
+ EDocLog: Record "E-Document Log";
+ Count: Integer;
+ begin
+ EDocLog.SetRange("E-Doc. Entry No", EDocument."Entry No");
+ EDocLog.SetRange("Service Code", EDocumentService.Code);
+ Assert.AreEqual(EDocLogList.Count(), EDocLog.Count(), 'Wrong number of logs');
+ Count := 1;
+ EDocLog.SetCurrentKey("Entry No.");
+ EDocLog.SetAscending("Entry No.", true);
+ if EDocLog.FindSet() then
+ repeat
+ Assert.AreEqual(EDocLogList.Get(Count), EDocLog.Status, 'Wrong status');
+ Count := Count + 1;
+ until EDocLog.Next() = 0;
+ end;
+
+ [EventSubscriber(ObjectType::Codeunit, Codeunit::"E-Doc. Export", 'OnAfterCreateEDocument', '', false, false)]
+ local procedure OnAfterCreateEDocument(var EDocument: Record "E-Document")
+ begin
+ LibraryVariableStorage.Enqueue(EDocument);
+ end;
+}
\ No newline at end of file
diff --git a/Apps/DE/EDocumentDE/test/src/XRechnungStructValidations.Codeunit.al b/Apps/DE/EDocumentDE/test/src/XRechnungStructValidations.Codeunit.al
new file mode 100644
index 0000000000..844b19651c
--- /dev/null
+++ b/Apps/DE/EDocumentDE/test/src/XRechnungStructValidations.Codeunit.al
@@ -0,0 +1,107 @@
+codeunit 13925 "XRechnung Struct. Validations"
+{
+ var
+ Assert: Codeunit Assert;
+ UnitOfMeasureCodeTok: Label 'PCS', Locked = true;
+ SalesInvoiceNoTok: Label '103033', Locked = true;
+ PurchaseorderNoTok: Label '2', Locked = true;
+ MockDate: Date;
+ MockCurrencyCode: Code[10];
+ MockDataMismatchErr: Label 'The %1 in %2 does not align with the mock data. Expected: %3, Actual: %4', Locked = true, Comment = '%1 = Field caption, %2 = Table caption, %3 = Expected value, %4 = Actual value';
+
+
+ internal procedure AssertFullEDocumentContentExtracted(EDocumentEntryNo: Integer)
+ var
+ EDocumentPurchaseHeader: Record "E-Document Purchase Header";
+ EDocumentPurchaseLine: Record "E-Document Purchase Line";
+ begin
+ EDocumentPurchaseHeader.Get(EDocumentEntryNo);
+ Assert.AreEqual(SalesInvoiceNoTok, EDocumentPurchaseHeader."Sales Invoice No.", StrSubstNo(MockDataMismatchErr, EDocumentPurchaseHeader.FieldCaption("Sales Invoice No."), EDocumentPurchaseHeader.TableCaption(), SalesInvoiceNoTok, EDocumentPurchaseHeader."Sales Invoice No."));
+ Assert.AreEqual(MockDate, EDocumentPurchaseHeader."Document Date", StrSubstNo(MockDataMismatchErr, EDocumentPurchaseHeader.FieldCaption("Document Date"), EDocumentPurchaseHeader.TableCaption(), MockDate, EDocumentPurchaseHeader."Document Date"));
+ Assert.AreEqual(CalcDate('<+1M>', MockDate), EDocumentPurchaseHeader."Due Date", StrSubstNo(MockDataMismatchErr, EDocumentPurchaseHeader.FieldCaption("Due Date"), EDocumentPurchaseHeader.TableCaption(), CalcDate('<+1M>', MockDate), EDocumentPurchaseHeader."Due Date"));
+ Assert.AreEqual(MockCurrencyCode, EDocumentPurchaseHeader."Currency Code", StrSubstNo(MockDataMismatchErr, EDocumentPurchaseHeader.FieldCaption("Currency Code"), EDocumentPurchaseHeader.TableCaption(), MockCurrencyCode, EDocumentPurchaseHeader."Currency Code"));
+ Assert.AreEqual(PurchaseorderNoTok, EDocumentPurchaseHeader."Purchase Order No.", StrSubstNo(MockDataMismatchErr, EDocumentPurchaseHeader.FieldCaption("Purchase Order No."), EDocumentPurchaseHeader.TableCaption(), PurchaseorderNoTok, EDocumentPurchaseHeader."Purchase Order No."));
+ Assert.AreEqual('CRONUS International', EDocumentPurchaseHeader."Vendor Company Name", StrSubstNo(MockDataMismatchErr, EDocumentPurchaseHeader.FieldCaption("Vendor Company Name"), EDocumentPurchaseHeader.TableCaption(), 'CRONUS International', EDocumentPurchaseHeader."Vendor Company Name"));
+ Assert.AreEqual('Main Street, 14', EDocumentPurchaseHeader."Vendor Address", StrSubstNo(MockDataMismatchErr, EDocumentPurchaseHeader.FieldCaption("Vendor Address"), EDocumentPurchaseHeader.TableCaption(), 'Main Street, 14', EDocumentPurchaseHeader."Vendor Address"));
+ Assert.AreEqual('GB123456789', EDocumentPurchaseHeader."Vendor VAT Id", StrSubstNo(MockDataMismatchErr, EDocumentPurchaseHeader.FieldCaption("Vendor VAT Id"), EDocumentPurchaseHeader.TableCaption(), 'GB123456789', EDocumentPurchaseHeader."Vendor VAT Id"));
+ Assert.AreEqual('Jim Olive', EDocumentPurchaseHeader."Vendor Contact Name", StrSubstNo(MockDataMismatchErr, EDocumentPurchaseHeader.FieldCaption("Vendor Contact Name"), EDocumentPurchaseHeader.TableCaption(), 'Jim Olive', EDocumentPurchaseHeader."Vendor Contact Name"));
+ Assert.AreEqual('The Cannon Group PLC', EDocumentPurchaseHeader."Customer Company Name", StrSubstNo(MockDataMismatchErr, EDocumentPurchaseHeader.FieldCaption("Customer Company Name"), EDocumentPurchaseHeader.TableCaption(), 'The Cannon Group PLC', EDocumentPurchaseHeader."Customer Company Name"));
+ Assert.AreEqual('GB789456278', EDocumentPurchaseHeader."Customer VAT Id", StrSubstNo(MockDataMismatchErr, EDocumentPurchaseHeader.FieldCaption("Customer VAT Id"), EDocumentPurchaseHeader.TableCaption(), 'GB789456278', EDocumentPurchaseHeader."Customer VAT Id"));
+ Assert.AreEqual('192 Market Square', EDocumentPurchaseHeader."Customer Address", StrSubstNo(MockDataMismatchErr, EDocumentPurchaseHeader.FieldCaption("Customer Address"), EDocumentPurchaseHeader.TableCaption(), '192 Market Square', EDocumentPurchaseHeader."Customer Address"));
+
+ EDocumentPurchaseLine.SetRange("E-Document Entry No.", EDocumentEntryNo);
+ EDocumentPurchaseLine.FindSet();
+ Assert.AreEqual(1, EDocumentPurchaseLine."Quantity", StrSubstNo(MockDataMismatchErr, EDocumentPurchaseLine.FieldCaption("Quantity"), EDocumentPurchaseLine.TableCaption(), 1, EDocumentPurchaseLine."Quantity"));
+ Assert.AreEqual(UnitOfMeasureCodeTok, EDocumentPurchaseLine."Unit of Measure", StrSubstNo(MockDataMismatchErr, EDocumentPurchaseLine.FieldCaption("Unit of Measure"), EDocumentPurchaseLine.TableCaption(), UnitOfMeasureCodeTok, EDocumentPurchaseLine."Unit of Measure"));
+ Assert.AreEqual(4000, EDocumentPurchaseLine."Sub Total", StrSubstNo(MockDataMismatchErr, EDocumentPurchaseLine.FieldCaption("Sub Total"), EDocumentPurchaseLine.TableCaption(), 4000, EDocumentPurchaseLine."Sub Total"));
+ Assert.AreEqual(MockCurrencyCode, EDocumentPurchaseLine."Currency Code", StrSubstNo(MockDataMismatchErr, EDocumentPurchaseLine.FieldCaption("Currency Code"), EDocumentPurchaseLine.TableCaption(), MockCurrencyCode, EDocumentPurchaseLine."Currency Code"));
+ Assert.AreEqual(0, EDocumentPurchaseLine."Total Discount", StrSubstNo(MockDataMismatchErr, EDocumentPurchaseLine.FieldCaption("Total Discount"), EDocumentPurchaseLine.TableCaption(), 0, EDocumentPurchaseLine."Total Discount"));
+ Assert.AreEqual('Bicycle', EDocumentPurchaseLine.Description, StrSubstNo(MockDataMismatchErr, EDocumentPurchaseLine.FieldCaption(Description), EDocumentPurchaseLine.TableCaption(), 'Bicycle', EDocumentPurchaseLine.Description));
+ Assert.AreEqual('1000', EDocumentPurchaseLine."Product Code", StrSubstNo(MockDataMismatchErr, EDocumentPurchaseLine.FieldCaption("Product Code"), EDocumentPurchaseLine.TableCaption(), '1000', EDocumentPurchaseLine."Product Code"));
+ Assert.AreEqual(25, EDocumentPurchaseLine."VAT Rate", StrSubstNo(MockDataMismatchErr, EDocumentPurchaseLine.FieldCaption("VAT Rate"), EDocumentPurchaseLine.TableCaption(), 25, EDocumentPurchaseLine."VAT Rate"));
+ Assert.AreEqual(4000, EDocumentPurchaseLine."Unit Price", StrSubstNo(MockDataMismatchErr, EDocumentPurchaseLine.FieldCaption("Unit Price"), EDocumentPurchaseLine.TableCaption(), 4000, EDocumentPurchaseLine."Unit Price"));
+
+ EDocumentPurchaseLine.Next();
+ Assert.AreEqual(2, EDocumentPurchaseLine."Quantity", StrSubstNo(MockDataMismatchErr, EDocumentPurchaseLine.FieldCaption("Quantity"), EDocumentPurchaseLine.TableCaption(), 2, EDocumentPurchaseLine."Quantity"));
+ Assert.AreEqual(UnitOfMeasureCodeTok, EDocumentPurchaseLine."Unit of Measure", StrSubstNo(MockDataMismatchErr, EDocumentPurchaseLine.FieldCaption("Unit of Measure"), EDocumentPurchaseLine.TableCaption(), UnitOfMeasureCodeTok, EDocumentPurchaseLine."Unit of Measure"));
+ Assert.AreEqual(10000, EDocumentPurchaseLine."Sub Total", StrSubstNo(MockDataMismatchErr, EDocumentPurchaseLine.FieldCaption("Sub Total"), EDocumentPurchaseLine.TableCaption(), 10000, EDocumentPurchaseLine."Sub Total"));
+ Assert.AreEqual(MockCurrencyCode, EDocumentPurchaseLine."Currency Code", StrSubstNo(MockDataMismatchErr, EDocumentPurchaseLine.FieldCaption("Currency Code"), EDocumentPurchaseLine.TableCaption(), MockCurrencyCode, EDocumentPurchaseLine."Currency Code"));
+ Assert.AreEqual(0, EDocumentPurchaseLine."Total Discount", StrSubstNo(MockDataMismatchErr, EDocumentPurchaseLine.FieldCaption("Total Discount"), EDocumentPurchaseLine.TableCaption(), 0, EDocumentPurchaseLine."Total Discount"));
+ Assert.AreEqual('Bicycle v2', EDocumentPurchaseLine.Description, StrSubstNo(MockDataMismatchErr, EDocumentPurchaseLine.FieldCaption(Description), EDocumentPurchaseLine.TableCaption(), 'Bicycle v2', EDocumentPurchaseLine.Description));
+ Assert.AreEqual('2000', EDocumentPurchaseLine."Product Code", StrSubstNo(MockDataMismatchErr, EDocumentPurchaseLine.FieldCaption("Product Code"), EDocumentPurchaseLine.TableCaption(), '2000', EDocumentPurchaseLine."Product Code"));
+ Assert.AreEqual(25, EDocumentPurchaseLine."VAT Rate", StrSubstNo(MockDataMismatchErr, EDocumentPurchaseLine.FieldCaption("VAT Rate"), EDocumentPurchaseLine.TableCaption(), 25, EDocumentPurchaseLine."VAT Rate"));
+ Assert.AreEqual(5000, EDocumentPurchaseLine."Unit Price", StrSubstNo(MockDataMismatchErr, EDocumentPurchaseLine.FieldCaption("Unit Price"), EDocumentPurchaseLine.TableCaption(), 5000, EDocumentPurchaseLine."Unit Price"));
+ end;
+
+ internal procedure AssertPurchaseDocument(VendorNo: Code[20]; PurchaseHeader: Record "Purchase Header"; Item: Record Item)
+ var
+ PurchaseLine: Record "Purchase Line";
+ Item1NoTok: Label 'GL00000001', Locked = true;
+ Item2NoTok: Label 'GL00000003', Locked = true;
+ begin
+ Assert.AreEqual(SalesInvoiceNoTok, PurchaseHeader."Vendor Invoice No.", StrSubstNo(MockDataMismatchErr, PurchaseHeader.FieldCaption("Vendor Invoice No."), PurchaseHeader.TableCaption(), SalesInvoiceNoTok, PurchaseHeader."Vendor Invoice No."));
+ Assert.AreEqual(MockDate, PurchaseHeader."Document Date", StrSubstNo(MockDataMismatchErr, PurchaseHeader.FieldCaption("Document Date"), PurchaseHeader.TableCaption(), MockDate, PurchaseHeader."Document Date"));
+ Assert.AreEqual(CalcDate('<+1M>', MockDate), PurchaseHeader."Due Date", StrSubstNo(MockDataMismatchErr, PurchaseHeader.FieldCaption("Due Date"), PurchaseHeader.TableCaption(), CalcDate('<+1M>', MockDate), PurchaseHeader."Due Date"));
+ Assert.AreEqual(MockCurrencyCode, PurchaseHeader."Currency Code", StrSubstNo(MockDataMismatchErr, PurchaseHeader.FieldCaption("Currency Code"), PurchaseHeader.TableCaption(), MockCurrencyCode, PurchaseHeader."Currency Code"));
+ Assert.AreEqual(PurchaseorderNoTok, PurchaseHeader."Vendor Order No.", StrSubstNo(MockDataMismatchErr, PurchaseHeader.FieldCaption("Vendor Order No."), PurchaseHeader.TableCaption(), PurchaseorderNoTok, PurchaseHeader."Vendor Order No."));
+ Assert.AreEqual(VendorNo, PurchaseHeader."Buy-from Vendor No.", StrSubstNo(MockDataMismatchErr, PurchaseHeader.FieldCaption("Buy-from Vendor No."), PurchaseHeader.TableCaption(), VendorNo, PurchaseHeader."Buy-from Vendor No."));
+
+ PurchaseLine.SetRange("Document Type", PurchaseHeader."Document Type");
+ PurchaseLine.SetRange("Document No.", PurchaseHeader."No.");
+ PurchaseLine.FindSet();
+ Assert.AreEqual(1, PurchaseLine.Quantity, StrSubstNo(MockDataMismatchErr, PurchaseLine.FieldCaption(Quantity), PurchaseLine.TableCaption(), 1, PurchaseLine.Quantity));
+ Assert.AreEqual(4000, PurchaseLine."Direct Unit Cost", StrSubstNo(MockDataMismatchErr, PurchaseLine.FieldCaption("Direct Unit Cost"), PurchaseLine.TableCaption(), 4000, PurchaseLine."Direct Unit Cost"));
+ Assert.AreEqual(MockCurrencyCode, PurchaseLine."Currency Code", StrSubstNo(MockDataMismatchErr, PurchaseLine.FieldCaption("Currency Code"), PurchaseLine.TableCaption(), MockCurrencyCode, PurchaseLine."Currency Code"));
+ Assert.AreEqual(0, PurchaseLine."Line Discount Amount", StrSubstNo(MockDataMismatchErr, PurchaseLine.FieldCaption("Line Discount Amount"), PurchaseLine.TableCaption(), 0, PurchaseLine."Line Discount Amount"));
+ // In the import file we have a name 'Bicycle' but because of Item Cross Reference validation Item description is being used
+ if Item."No." <> '' then begin
+ Assert.AreEqual('Bicycle', PurchaseLine.Description, StrSubstNo(MockDataMismatchErr, PurchaseLine.FieldCaption(Description), PurchaseLine.TableCaption(), Item."No.", PurchaseLine.Description));
+ Assert.AreEqual(Item."No.", PurchaseLine."No.", StrSubstNo(MockDataMismatchErr, PurchaseLine.FieldCaption("No."), PurchaseLine.TableCaption(), Item."No.", PurchaseLine."No."));
+ Assert.AreEqual(Item."Purch. Unit of Measure", PurchaseLine."Unit of Measure Code", StrSubstNo(MockDataMismatchErr, PurchaseLine.FieldCaption("Unit of Measure Code"), PurchaseLine.TableCaption(), UnitOfMeasureCodeTok, PurchaseLine."Unit of Measure Code"));
+ end else begin
+ Assert.AreEqual(Item1NoTok, PurchaseLine.Description, StrSubstNo(MockDataMismatchErr, PurchaseLine.FieldCaption(Description), PurchaseLine.TableCaption(), Item1NoTok, PurchaseLine.Description));
+ Assert.AreEqual(Item1NoTok, PurchaseLine."No.", StrSubstNo(MockDataMismatchErr, PurchaseLine.FieldCaption("No."), PurchaseLine.TableCaption(), Item1NoTok, PurchaseLine."No."));
+ Assert.AreEqual(UnitOfMeasureCodeTok, PurchaseLine."Unit of Measure Code", StrSubstNo(MockDataMismatchErr, PurchaseLine.FieldCaption("Unit of Measure Code"), PurchaseLine.TableCaption(), UnitOfMeasureCodeTok, PurchaseLine."Unit of Measure Code"));
+ end;
+
+ PurchaseLine.Next();
+ Assert.AreEqual(2, PurchaseLine.Quantity, StrSubstNo(MockDataMismatchErr, PurchaseLine.FieldCaption(Quantity), PurchaseLine.TableCaption(), 2, PurchaseLine.Quantity));
+ Assert.AreEqual(UnitOfMeasureCodeTok, PurchaseLine."Unit of Measure Code", StrSubstNo(MockDataMismatchErr, PurchaseLine.FieldCaption("Unit of Measure Code"), PurchaseLine.TableCaption(), UnitOfMeasureCodeTok, PurchaseLine."Unit of Measure Code"));
+ Assert.AreEqual(5000, PurchaseLine."Direct Unit Cost", StrSubstNo(MockDataMismatchErr, PurchaseLine.FieldCaption("Direct Unit Cost"), PurchaseLine.TableCaption(), 5000, PurchaseLine."Direct Unit Cost"));
+ Assert.AreEqual(MockCurrencyCode, PurchaseLine."Currency Code", StrSubstNo(MockDataMismatchErr, PurchaseLine.FieldCaption("Currency Code"), PurchaseLine.TableCaption(), MockCurrencyCode, PurchaseLine."Currency Code"));
+ Assert.AreEqual(0, PurchaseLine."Line Discount Amount", StrSubstNo(MockDataMismatchErr, PurchaseLine.FieldCaption("Line Discount Amount"), PurchaseLine.TableCaption(), 0, PurchaseLine."Line Discount Amount"));
+ // In the import file we have a name 'Bicycle v2' but because of Item Cross Reference validation Item description is being used
+ Assert.AreEqual(Item2NoTok, PurchaseLine.Description, StrSubstNo(MockDataMismatchErr, PurchaseLine.FieldCaption(Description), PurchaseLine.TableCaption(), Item2NoTok, PurchaseLine.Description));
+ Assert.AreEqual(Item2NoTok, PurchaseLine."No.", StrSubstNo(MockDataMismatchErr, PurchaseLine.FieldCaption("No."), PurchaseLine.TableCaption(), Item2NoTok, PurchaseLine."No."));
+ end;
+
+ procedure SetMockDate(MockDate: Date)
+ begin
+ this.MockDate := MockDate;
+ end;
+
+ procedure SetMockCurrencyCode(MockCurrencyCode: Code[10])
+ begin
+ this.MockCurrencyCode := MockCurrencyCode;
+ end;
+}
\ No newline at end of file
diff --git a/Apps/W1/EDocument/app/app.json b/Apps/W1/EDocument/app/app.json
index 98dceb38a3..f193c1dead 100644
--- a/Apps/W1/EDocument/app/app.json
+++ b/Apps/W1/EDocument/app/app.json
@@ -37,6 +37,16 @@
"id": "967eceac-106e-4102-b76a-fe5dc3d799e5",
"name": "Payables Agent Tests",
"publisher": "Microsoft"
+ },
+ {
+ "id": "fdeb586e-beff-49d8-947d-1e73ce980b34",
+ "name": "E-Document for Germany",
+ "publisher": "Microsoft"
+ },
+ {
+ "id": "4022897d-41ca-4ae2-a766-a429d0b19273",
+ "name": "E-Document for Germany Tests",
+ "publisher": "Microsoft"
}
],
"screenshots": [],