diff --git a/Apps/W1/EDocument/app/src/Document/EDocument.Page.al b/Apps/W1/EDocument/app/src/Document/EDocument.Page.al index d975f90883..a2af7dfa97 100644 --- a/Apps/W1/EDocument/app/src/Document/EDocument.Page.al +++ b/Apps/W1/EDocument/app/src/Document/EDocument.Page.al @@ -152,6 +152,13 @@ page 6121 "E-Document" ToolTip = 'Specifies the receiving company address.'; } } + part(EInvoicePreview; "E-Invoice Lines") + { + Caption = 'E-Invoice Lines'; + SubPageLink = "E-Document Entry No." = field("Entry No"); + ShowFilter = false; + Visible = IsIncomingDoc and ShowPreview; + } part(EdocoumentServiceStatus; "E-Document Service Status") { Caption = 'Service Status'; @@ -493,6 +500,7 @@ page 6121 "E-Document" begin IsProcessed := Rec.Status = Rec.Status::Processed; IsIncomingDoc := Rec.Direction = Rec.Direction::Incoming; + ShowPreview := (Rec."Document Type" = Rec."Document Type"::"Purchase Invoice") or (Rec."Document Type" = Rec."Document Type"::"Purchase Credit Memo"); RecordLinkTxt := EDocumentHelper.GetRecordLinkText(Rec); HasErrorsOrWarnings := (EDocumentErrorHelper.ErrorMessageCount(Rec) + EDocumentErrorHelper.WarningMessageCount(Rec)) > 0; @@ -597,7 +605,7 @@ page 6121 "E-Document" EDocumentHelper: Codeunit "E-Document Processing"; ErrorsAndWarningsNotification: Notification; RecordLinkTxt, StyleStatusTxt : Text; - ShowRelink, ShowMapToOrder, HasErrorsOrWarnings, HasErrors, IsIncomingDoc, IsProcessed, CopilotVisible : Boolean; + ShowRelink, ShowMapToOrder, HasErrorsOrWarnings, HasErrors, IsIncomingDoc, IsProcessed, CopilotVisible, ShowPreview : Boolean; EDocHasErrorOrWarningMsg: Label 'Errors or warnings found for E-Document. Please review below in "Error Messages" section.'; DocNotCreatedMsg: Label 'Failed to create new %1 from E-Document. Please review errors below.', Comment = '%1 - E-Document Document Type'; diff --git a/Apps/W1/EDocument/app/src/InvoicePreview/EInvoiceLine.Table.al b/Apps/W1/EDocument/app/src/InvoicePreview/EInvoiceLine.Table.al new file mode 100644 index 0000000000..23ec53c754 --- /dev/null +++ b/Apps/W1/EDocument/app/src/InvoicePreview/EInvoiceLine.Table.al @@ -0,0 +1,53 @@ +table 6100 "E-Invoice Line" +{ + DataClassification = CustomerContent; + + fields + { + field(1; "E-Document Entry No."; Integer) + { + TableRelation = "E-Document"; + Caption = 'E-Document Entry No'; + } + field(2; "Line No."; Integer) + { + Caption = 'Line No.'; + } + field(3; "No."; Code[20]) + { + Caption = 'No.'; + } + field(4; Description; Text[100]) + { + Caption = 'Description'; + } + field(5; "Unit of Measure Code"; Text[50]) + { + Caption = 'Unit of Measure Code'; + } + field(6; Quantity; Decimal) + { + Caption = 'Quantity'; + DecimalPlaces = 0 : 5; + } + field(7; "Direct Unit Cost"; Decimal) + { + Caption = 'Direct Unit Cost'; + } + field(8; "Line Discount %"; Decimal) + { + Caption = 'Line Discount %'; + DecimalPlaces = 0 : 5; + MaxValue = 100; + MinValue = 0; + } + } + + keys + { + key(Key1; "E-Document Entry No.", "Line No.") + { + Clustered = true; + } + } +} \ No newline at end of file diff --git a/Apps/W1/EDocument/app/src/InvoicePreview/EInvoiceLines.Page.al b/Apps/W1/EDocument/app/src/InvoicePreview/EInvoiceLines.Page.al new file mode 100644 index 0000000000..8735718a6e --- /dev/null +++ b/Apps/W1/EDocument/app/src/InvoicePreview/EInvoiceLines.Page.al @@ -0,0 +1,43 @@ +page 6100 "E-Invoice Lines" +{ + PageType = ListPart; + ApplicationArea = Basic, Suite; + Editable = false; + InsertAllowed = false; + DeleteAllowed = false; + SourceTable = "E-Invoice Line"; + + layout + { + area(Content) + { + repeater(EInvoiceLines) + { + field("No."; Rec."No.") + { + ToolTip = 'Specifies what is being purchased.'; + } + field(Description; Rec.Description) + { + ToolTip = 'Describes what is being purchased.'; + } + field("Unit of Measure Code"; Rec."Unit of Measure Code") + { + ToolTip = 'Specifies how each unit of the item or resource is measured, such as in pieces or hours.'; + } + field(Quantity; Rec.Quantity) + { + ToolTip = 'Specifies the quantity of what you''re buying. The number is based on the unit chosen in the Unit of Measure Code field.'; + } + field("Direct Unit Cost"; Rec."Direct Unit Cost") + { + ToolTip = 'Specifies the price of one unit of what you are buying.'; + } + field("Line Discount %"; Rec."Line Discount %") + { + ToolTip = 'Specifies the discount percentage that is granted for the item on the line.'; + } + } + } + } +} \ No newline at end of file diff --git a/Apps/W1/EDocument/app/src/Processing/EDocImport.Codeunit.al b/Apps/W1/EDocument/app/src/Processing/EDocImport.Codeunit.al index 0591dfdb3b..263cb361dc 100644 --- a/Apps/W1/EDocument/app/src/Processing/EDocImport.Codeunit.al +++ b/Apps/W1/EDocument/app/src/Processing/EDocImport.Codeunit.al @@ -536,9 +536,46 @@ codeunit 6140 "E-Doc. Import" SourceDocumentHeader.Copy(SourceDocumentHeaderMapped, true); SourceDocumentLine.Copy(SourceDocumentLineMapped, true); + CreateEInvoiceLinesPreview(EDocument, SourceDocumentLine); + OnAfterPrepareReceivedDoc(EDocument, TempBlob, SourceDocumentHeader, SourceDocumentLine, TempEDocMapping); end; + local procedure CreateEInvoiceLinesPreview(EDocument: Record "E-Document"; SourceDocumentLine: RecordRef) + var + EDocumentImportHelper: Codeunit "E-Document Import Helper"; + EInvoiceLine: Record "E-Invoice Line"; + PurchaseLine: Record "Purchase Line"; + LineAmount: Decimal; + LineDiscountAmount: Decimal; + begin + EInvoiceLine.SetRange("E-Document Entry No.", EDocument."Entry No"); + if not EInvoiceLine.IsEmpty() then + EInvoiceLine.DeleteAll(true); + + if (EDocument."Document Type" <> EDocument."Document Type"::"Purchase Invoice") and (EDocument."Document Type" <> EDocument."Document Type"::"Purchase Credit Memo") then + exit; + + if SourceDocumentLine.FindSet() then + repeat + EInvoiceLine.Init(); + EInvoiceLine."E-Document Entry No." := EDocument."Entry No"; + EInvoiceLine."Line No." := SourceDocumentLine.Field(PurchaseLine.FieldNo("Line No.")).Value(); // (line number from e-invoice file if exist, if not just ordered lines) + EInvoiceLine."No." := SourceDocumentLine.Field(PurchaseLine.FieldNo("No.")).Value(); + EInvoiceLine."Description" := SourceDocumentLine.Field(PurchaseLine.FieldNo("Description")).Value(); + EInvoiceLine."Unit of Measure Code" := SourceDocumentLine.Field(PurchaseLine.FieldNo("Unit of Measure Code")).Value(); + EInvoiceLine."Quantity" := SourceDocumentLine.Field(PurchaseLine.FieldNo("Quantity")).Value(); + EInvoiceLine."Direct Unit Cost" := SourceDocumentLine.Field(PurchaseLine.FieldNo("Direct Unit Cost")).Value(); + + LineAmount := SourceDocumentLine.Field(PurchaseLine.FieldNo(Amount)).Value(); + LineDiscountAmount := SourceDocumentLine.Field(PurchaseLine.FieldNo("Line Discount Amount")).Value(); + if LineDiscountAmount <> 0 then + EInvoiceLine."Line Discount %" := 100 * (LineDiscountAmount / (LineAmount + LineDiscountAmount)); + + EInvoiceLine.Insert(true); + until SourceDocumentLine.Next() = 0; + end; + local procedure CreateDocument(var EDocument: Record "E-Document"; var TempDocumentHeader: RecordRef; var TempDocumentLine: RecordRef; var DocumentHeader: RecordRef; PurchaseDocumentType: Enum "Purchase Document Type") var EDocumentCreatePurchase: Codeunit "E-Document Create Purch. Doc."; diff --git a/Apps/W1/EDocument/edocument_workspace.code-workspace b/Apps/W1/EDocument/edocument_workspace.code-workspace new file mode 100644 index 0000000000..35fb4f1ea3 --- /dev/null +++ b/Apps/W1/EDocument/edocument_workspace.code-workspace @@ -0,0 +1,24 @@ +{ + "settings": { + "al.enableCodeAnalysis": true, + "al.codeAnalyzers": [ + "${CodeCop}", + "${UICop}", + "${AppSourceCop}" + ] + }, + "folders": [ + { + "name": "app", + "path": "app" + }, + { + "name": "test", + "path": "test" + }, + { + "name": "demo data", + "path": "demo data" + } + ] +} \ No newline at end of file diff --git a/Apps/W1/EDocument/test/src/Receive/EDocReceiveTest.Codeunit.al b/Apps/W1/EDocument/test/src/Receive/EDocReceiveTest.Codeunit.al index 98a2793f6b..7b0efad5fb 100644 --- a/Apps/W1/EDocument/test/src/Receive/EDocReceiveTest.Codeunit.al +++ b/Apps/W1/EDocument/test/src/Receive/EDocReceiveTest.Codeunit.al @@ -2763,6 +2763,126 @@ codeunit 139628 "E-Doc. Receive Test" end; + [Test] + [HandlerFunctions('ConfirmHandler')] + procedure PreviewEDocumentPurchaseInvoiceLines() + var + EDocService: Record "E-Document Service"; + EDocument: Record "E-Document"; + Item: Record Item; + DocumentAttachment: Record "Document Attachment"; + VATPostingSetup: Record "VAT Posting Setup"; + DocumentVendor: Record Vendor; + EDocumentPage: TestPage "E-Document"; + EInvoiceLine: Record "E-Invoice Line"; + begin + // [FEATURE] [E-Document] [Receive] + // [SCENARIO] Receive single e-document with two attachments without linking to purchase order + Initialize(); + BindSubscription(EDocImplState); + + // [GIVEN] e-Document service to receive one single purchase order + CreateEDocServiceToReceivePurchaseOrder(EDocService); + // [GIVEN] Vendor with VAT Posting Setup + CreateVendorWithVatPostingSetup(DocumentVendor, VATPostingSetup); + // [GIVEN] Item with item reference + CreateItemWithReference(Item, VATPostingSetup); + // [GIVEN] Incoming PEPPOL file + CreateIncomingPEPPOL(DocumentVendor); + + // [WHEN] Running Receive + InvokeReceive(EDocService); + EDocumentPage.OpenView(); + EDocumentPage.Last(); + + // [THEN] E-Invoice preview fast tab is visible and not editable + Assert.IsFalse(EDocumentPage.EInvoicePreview.Editable(), 'E-Invoice preview fast tab should not be editable'); + + // [THEN] E-Invoice lines are created + EDocument.FindLast(); + EInvoiceLine.SetRange("E-Document Entry No.", EDocument."Entry No"); + Assert.IsFalse(EInvoiceLine.IsEmpty(), 'E-Invoice lines not created.'); + end; + + local procedure CreateEDocServiceToReceivePurchaseOrder(var EDocService: Record "E-Document Service") + begin + LibraryEDoc.CreateTestReceiveServiceForEDoc(EDocService, Enum::"Service Integration"::Mock); + SetDefaultEDocServiceValues(EDocService); + end; + + local procedure CreateVendorWithVatPostingSetup(var DocumentVendor: Record Vendor; var VATPostingSetup: Record "VAT Posting Setup") + begin + LibraryPurchase.CreateVendorWithVATRegNo(DocumentVendor); + LibraryERM.CreateVATPostingSetupWithAccounts(VATPostingSetup, Enum::"Tax Calculation Type"::"Normal VAT", 1); + DocumentVendor."VAT Bus. Posting Group" := VATPostingSetup."VAT Bus. Posting Group"; + DocumentVendor."Receive E-Document To" := Enum::"E-Document Type"::"Purchase Invoice"; + DocumentVendor.Modify(false); + end; + + local procedure CreateItemWithReference(var Item: Record Item; var VATPostingSetup: Record "VAT Posting Setup") + var + ItemReference: Record "Item Reference"; + begin + Item.FindFirst(); + Item."VAT Prod. Posting Group" := VATPostingSetup."VAT Prod. Posting Group"; + Item.Modify(false); + ItemReference.DeleteAll(false); + ItemReference."Item No." := Item."No."; + ItemReference."Reference No." := '1000'; + ItemReference.Insert(false); + end; + + local procedure CreateIncomingPEPPOL(var DocumentVendor: Record Vendor) + var + TempXMLBuffer: Record "XML Buffer" temporary; + TempBlob: Codeunit "Temp Blob"; + Document: Text; + XMLInstream: InStream; + begin + TempXMLBuffer.LoadFromText(EDocReceiveFiles.GetDocument1()); + TempXMLBuffer.Reset(); + TempXMLBuffer.SetRange(Type, TempXMLBuffer.Type::Element); + TempXMLBuffer.SetRange(Path, '/Invoice/cac:AccountingSupplierParty/cac:Party/cbc:EndpointID'); + TempXMLBuffer.FindFirst(); + TempXMLBuffer.Value := DocumentVendor."VAT Registration No."; + TempXMLBuffer.Modify(); + + TempXMLBuffer.Reset(); + TempXMLBuffer.FindFirst(); + TempXMLBuffer.Save(TempBlob); + + TempBlob.CreateInStream(XMLInstream, TextEncoding::UTF8); + XMLInstream.Read(Document); + + LibraryVariableStorage.Clear(); + LibraryVariableStorage.Enqueue(Document); + LibraryVariableStorage.Enqueue(1); + EDocImplState.SetVariableStorage(LibraryVariableStorage); + end; + + local procedure InvokeReceive(var EDocService: Record "E-Document Service") + var + EDocServicePage: TestPage "E-Document Service"; + begin + EDocServicePage.OpenView(); + EDocServicePage.Filter.SetFilter(Code, EDocService.Code); + EDocServicePage.Receive.Invoke(); + end; + + local procedure SetDefaultEDocServiceValues(var EDocService: Record "E-Document Service") + begin + EDocService."Document Format" := "E-Document Format"::"PEPPOL BIS 3.0"; + EDocService."Lookup Account Mapping" := false; + EDocService."Lookup Item GTIN" := false; + EDocService."Lookup Item Reference" := false; + EDocService."Resolve Unit Of Measure" := false; + EDocService."Validate Line Discount" := false; + EDocService."Verify Totals" := false; + EDocService."Use Batch Processing" := false; + EDocService."Validate Receiving Company" := false; + EDocService.Modify(false); + end; + #endif #pragma warning restore AS0018