diff --git a/Apps/W1/EDocument/app/src/Integration/EDocIntegrationManagement.Codeunit.al b/Apps/W1/EDocument/app/src/Integration/EDocIntegrationManagement.Codeunit.al index 28af37ac3a..b36bc3b91e 100644 --- a/Apps/W1/EDocument/app/src/Integration/EDocIntegrationManagement.Codeunit.al +++ b/Apps/W1/EDocument/app/src/Integration/EDocIntegrationManagement.Codeunit.al @@ -198,6 +198,7 @@ codeunit 6134 "E-Doc. Integration Management" local procedure ReceiveSingleDocument(var EDocument: Record "E-Document"; var EDocumentService: Record "E-Document Service"; DocumentMetadata: Codeunit "Temp Blob"; IDocumentReceiver: Interface IDocumentReceiver): Boolean var ReceiveContext, FetchContextImpl : Codeunit ReceiveContext; + EDocumentContent: Codeunit "Temp Blob"; ErrorCount: Integer; Success, IsFetchableType : Boolean; begin @@ -209,7 +210,8 @@ codeunit 6134 "E-Doc. Integration Management" if not Success then exit(false); - if not ReceiveContext.GetTempBlob().HasValue() then + EDocumentContent := ReceiveContext.GetTempBlob(); + if not EDocumentContent.HasValue() then exit(false); IsFetchableType := IDocumentReceiver is IReceivedDocumentMarker; @@ -217,11 +219,13 @@ codeunit 6134 "E-Doc. Integration Management" ErrorCount := EDocumentErrorHelper.ErrorMessageCount(EDocument); RunMarkFetched(EDocument, EDocumentService, ReceiveContext.GetTempBlob(), IDocumentReceiver, FetchContextImpl); Success := EDocumentErrorHelper.ErrorMessageCount(EDocument) = ErrorCount; - if not Success then exit(false); end; + if HasDuplicate(EDocument, EDocumentContent, EDocumentService."Document Format") then + exit(false); + // Only after sucecssfully downloading and (optionally) marking as fetched, the document is considered imported // Insert logs for downloading document InsertLogAndEDocumentStatus(EDocument, EDocumentService, ReceiveContext.GetTempBlob(), ReceiveContext.Status().GetStatus()); @@ -234,6 +238,22 @@ codeunit 6134 "E-Doc. Integration Management" exit(true); end; + local procedure HasDuplicate(var IncomingEDocument: Record "E-Document"; var EDocumentContent: Codeunit "Temp Blob"; IEDocument: Interface "E-Document"): Boolean + var + EDocument: Record "E-Document"; + EDocGetBasicInfo: Codeunit "E-Doc. Get Basic Info"; + begin + EDocGetBasicInfo.SetValues(IEDocument, IncomingEDocument, EDocumentContent); + if not EDocGetBasicInfo.Run() then + exit(false); + EDocGetBasicInfo.GetValues(IEDocument, IncomingEDocument, EDocumentContent); + + EDocument.SetFilter("Entry No", '<>%1', IncomingEDocument."Entry No"); + EDocument.SetRange("Incoming E-Document No.", IncomingEDocument."Incoming E-Document No."); + EDocument.SetRange("Bill-to/Pay-to No.", IncomingEDocument."Bill-to/Pay-to No."); + EDocument.SetRange("Document Date", IncomingEDocument."Document Date"); + exit(not EDocument.IsEmpty()); + end; #endregion @@ -564,7 +584,6 @@ codeunit 6134 "E-Doc. Integration Management" exit(true); end; - #endregion var diff --git a/Apps/W1/EDocument/test/src/Receive/EDocReceiveTest.Codeunit.al b/Apps/W1/EDocument/test/src/Receive/EDocReceiveTest.Codeunit.al index 98a2793f6b..329bb906fc 100644 --- a/Apps/W1/EDocument/test/src/Receive/EDocReceiveTest.Codeunit.al +++ b/Apps/W1/EDocument/test/src/Receive/EDocReceiveTest.Codeunit.al @@ -1342,6 +1342,44 @@ codeunit 139628 "E-Doc. Receive Test" PurchaseHeader.Delete(true); end; + [Test] + [HandlerFunctions('ConfirmHandler')] + procedure ReceiveEDocumentDuplicate() + var + EDocService: Record "E-Document Service"; + EDocument: Record "E-Document"; + EDocument2: Record "E-Document"; + Item: Record Item; + DocumentAttachment: Record "Document Attachment"; + VATPostingSetup: Record "VAT Posting Setup"; + DocumentVendor: Record Vendor; + begin + // [FEATURE] [E-Document] [Receive] + // [SCENARIO] Receive e-document twice so the duplicate will be skipped in creation + 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 duplicated document + CreateIncomingDuplicatedPEPPOL(DocumentVendor); + + // [WHEN] Running Receive + InvokeReceive(EDocService); + + // [THEN] Only one E-Document is created + EDocument.FindLast(); + EDocument2.SetRange("Bill-to/Pay-to No.", EDocument."Bill-to/Pay-to No."); + EDocument2.SetRange("Incoming E-Document No.", EDocument."Incoming E-Document No."); + EDocument2.SetRange("Document Date", EDocument."Document Date"); + EDocument2.SetFilter("Entry No", '<>%1', EDocument."Entry No"); + Assert.IsTrue(EDocument2.IsEmpty(), 'Duplicate E-Document created.'); + end; + [ModalPageHandler] procedure SelectPOHandler(var POList: TestPage "Purchase Order List") var @@ -1443,6 +1481,98 @@ codeunit 139628 "E-Doc. Receive Test" PurchaseField.SetRange("No.", 10705); 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 Order"; + 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 CreateIncomingDuplicatedPEPPOL(var DocumentVendor: Record Vendor) + var + TempXMLBuffer: Record "XML Buffer" temporary; + TempBlob: Codeunit "Temp Blob"; + Document, Document2 : 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.SetRange(Path, '/Invoice/cbc:ID'); + TempXMLBuffer.FindFirst(); + TempXMLBuffer.Value := LibraryRandom.RandText(20); + + TempXMLBuffer.Reset(); + TempXMLBuffer.FindFirst(); + TempXMLBuffer.Save(TempBlob); + + TempBlob.CreateInStream(XMLInstream, TextEncoding::UTF8); + XMLInstream.Read(Document); + + LibraryVariableStorage.Clear(); + LibraryVariableStorage.Enqueue(Document); + LibraryVariableStorage.Enqueue(2); + EDocImplState.SetVariableStorage(LibraryVariableStorage); + end; + + local procedure CreatePurchaseOrder(var Item: Record Item; var DocumentVendor: Record Vendor) + begin + LibraryPurchase.CreatePurchHeader(PurchaseHeader, PurchaseHeader."Document Type"::Order, DocumentVendor."No."); + LibraryPurchase.CreatePurchaseLine(PurchaseLine, PurchaseHeader, PurchaseLine.Type::Item, Item."No.", 10); + PurchaseLine.Validate("Direct Unit Cost", 100); + PurchaseLine.Modify(true); + 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; + #pragma warning disable AS0018 #if not CLEAN26