diff --git a/Apps/W1/EDocument/app/src/Document/EDocument.Page.al b/Apps/W1/EDocument/app/src/Document/EDocument.Page.al index 801a23f7df..388c63c964 100644 --- a/Apps/W1/EDocument/app/src/Document/EDocument.Page.al +++ b/Apps/W1/EDocument/app/src/Document/EDocument.Page.al @@ -395,6 +395,19 @@ page 6121 "E-Document" EDocOrderMatch.RunMatching(Rec); end; } + action(DeleteRelatedDocument) + { + Caption = 'Delete Related Document'; + ToolTip = 'Delete the related purchase document.'; + Image = Delete; + Visible = IsIncomingDoc and IsProcessed; + + trigger OnAction() + begin + if Confirm(StrSubstNo(this.ConfirmDeleteRelatedDocQst, this.RecordLinkTxt)) then + this.EDocumentHelper.DeleteRelatedRecord(Rec); + end; + } } group(Troubleshoot) { @@ -462,7 +475,6 @@ page 6121 "E-Document" actionref(Cancel_promoteed; Cancel) { } actionref(Approval_promoteed; GetApproval) { } actionref(Preview_promoteed; ViewFile) { } - } group(Category_Troubleshoot) { @@ -651,5 +663,6 @@ page 6121 "E-Document" ShowRelink, ShowMapToOrder, HasErrorsOrWarnings, HasErrors, IsIncomingDoc, IsProcessed, CopilotVisible : 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'; + ConfirmDeleteRelatedDocQst: Label 'Do you want to delete the related document %1?', Comment = '%1 - related record ID'; } diff --git a/Apps/W1/EDocument/app/src/Document/EDocumentServiceStatus.Enum.al b/Apps/W1/EDocument/app/src/Document/EDocumentServiceStatus.Enum.al index ad49ffec3c..38a1c0f2cd 100644 --- a/Apps/W1/EDocument/app/src/Document/EDocumentServiceStatus.Enum.al +++ b/Apps/W1/EDocument/app/src/Document/EDocumentServiceStatus.Enum.al @@ -28,4 +28,5 @@ enum 6106 "E-Document Service Status" value(17; "Order Linked") { Caption = 'Order linked'; } value(18; "Pending") { Caption = 'Pending Document Link'; } value(19; "Approval Error") { Caption = 'Approval error'; } + value(21; "Imported Document Deleted") { Caption = 'Imported document deleted'; } } diff --git a/Apps/W1/EDocument/app/src/Processing/EDocumentProcessing.Codeunit.al b/Apps/W1/EDocument/app/src/Processing/EDocumentProcessing.Codeunit.al index f871f39042..1749cf9094 100644 --- a/Apps/W1/EDocument/app/src/Processing/EDocumentProcessing.Codeunit.al +++ b/Apps/W1/EDocument/app/src/Processing/EDocumentProcessing.Codeunit.al @@ -275,6 +275,21 @@ codeunit 6108 "E-Document Processing" exit(GetPostedRecord(EDocument, RelatedRecord)); end; + /// + /// Deletes related record if it is not posted. + /// + /// E-Document record + procedure DeleteRelatedRecord(EDocument: Record "E-Document") + var + RecRef: RecordRef; + begin + if this.GetRelatedRecord(EDocument, RecRef) then + if RecRef.Number = Database::"Purchase Header" then + RecRef.Delete(true) + else + Error(this.CannotDeletePostedRecordErr); + end; + procedure GetTelemetryDimensions(EDocService: Record "E-Document Service"; var EDocument: Record "E-Document"; var Dimensions: Dictionary of [Text, Text]) var EDocument2: Record "E-Document"; @@ -454,4 +469,5 @@ codeunit 6108 "E-Document Processing" EDocTelemetryCategoryLbl: Label 'E-Document', Locked = true; EDocTelemetryIdLbl: Label 'E-Doc %1', Locked = true; EDocTok: Label 'W1 E-Document', Locked = true; + CannotDeletePostedRecordErr: Label 'Cannot delete related record because it is already posted.'; } diff --git a/Apps/W1/EDocument/app/src/Processing/EDocumentSubscription.Codeunit.al b/Apps/W1/EDocument/app/src/Processing/EDocumentSubscription.Codeunit.al index 99292f1b1a..e96a2bef90 100644 --- a/Apps/W1/EDocument/app/src/Processing/EDocumentSubscription.Codeunit.al +++ b/Apps/W1/EDocument/app/src/Processing/EDocumentSubscription.Codeunit.al @@ -198,7 +198,37 @@ codeunit 6103 "E-Document Subscription" local procedure OnBeforeOnDeletePurchaseHeader(var PurchaseHeader: Record "Purchase Header"; var IsHandled: Boolean) begin if not IsNullGuid(PurchaseHeader."E-Document Link") then - Error(DeleteNotAllowedErr); + if GuiAllowed() then + if not Confirm(this.ConfirmDeleteQst) then + Error(''); + end; + + [EventSubscriber(ObjectType::Table, Database::"Purchase Header", 'OnAfterDeleteEvent', '', false, false)] + local procedure OnAfterDeletePurchaseHeader(var Rec: Record "Purchase Header"; RunTrigger: Boolean) + var + EDocument: Record "E-Document"; + EDocumentService: Record "E-Document Service"; + EDocumentLog: Codeunit "E-Document Log"; + EDocumentProcessing: Codeunit "E-Document Processing"; + EDocServiceStatusDeleted: Enum "E-Document Service Status"; + begin + if IsNullGuid(Rec."E-Document Link") then + exit; + + if not EDocument.GetBySystemId(Rec."E-Document Link") then + exit; + + EDocServiceStatusDeleted := Enum::"E-Document Service Status"::"Imported Document Deleted"; + EDocumentService := EDocumentLog.GetLastServiceFromLog(EDocument); + + Clear(EDocument."Document No."); + Clear(EDocument."Document Record ID"); + if Rec."Document Type" = Rec."Document Type"::Order then + Clear(EDocument."Order No."); + + EDocumentLog.InsertLog(EDocument, EDocumentService, EDocServiceStatusDeleted); + EDocumentProcessing.ModifyServiceStatus(EDocument, EDocumentService, EDocServiceStatusDeleted); + EDocumentProcessing.ModifyEDocumentStatus(EDocument, EDocServiceStatusDeleted); end; local procedure RunEDocumentCheck(Record: Variant; EDocumentProcPhase: Enum "E-Document Processing Phase") @@ -270,6 +300,7 @@ codeunit 6103 "E-Document Subscription" EDocService: Record "E-Document Service"; EDocumentLog: Codeunit "E-Document Log"; EDocLogHelper: Codeunit "E-Document Log Helper"; + EDocumentProcessing: Codeunit "E-Document Processing"; PostedSourceDocumentHeader: RecordRef; begin PostedSourceDocumentHeader.GetTable(PostedRecord); @@ -281,6 +312,7 @@ codeunit 6103 "E-Document Subscription" EDocService := EDocumentLog.GetLastServiceFromLog(EDocument); EDocLogHelper.InsertLog(EDocument, EDocService, Enum::"E-Document Service Status"::"Imported Document Created"); + EDocumentProcessing.ModifyServiceStatus(EDocument, EDocService, Enum::"E-Document Service Status"::"Imported Document Created"); end; local procedure CreateEDocumentFromPosedDocument(PostedRecord: Variant) @@ -308,5 +340,5 @@ codeunit 6103 "E-Document Subscription" EDocumentHelper: Codeunit "E-Document Helper"; EDocumentProcessingPhase: Enum "E-Document Processing Phase"; WrongAmountErr: Label 'Purchase Document cannot be released as Amount Incl. VAT: %1, is different from E-Document Amount Incl. VAT: %2', Comment = '%1 - Purchase document amount, %2 - E-document amount'; - DeleteNotAllowedErr: Label 'Deletion of Purchase Header linked to E-Document is not allowed.'; + ConfirmDeleteQst: Label 'This purchase document is created from an E-Document. Do you want to proceed with deletion?'; } 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/Processing/EDocE2ETest.Codeunit.al b/Apps/W1/EDocument/test/src/Processing/EDocE2ETest.Codeunit.al index da634b7b85..e1fdd0df77 100644 --- a/Apps/W1/EDocument/test/src/Processing/EDocE2ETest.Codeunit.al +++ b/Apps/W1/EDocument/test/src/Processing/EDocE2ETest.Codeunit.al @@ -1430,6 +1430,7 @@ codeunit 139624 "E-Doc E2E Test" end; [Test] + [HandlerFunctions('DeleteConfirmationHandler')] procedure DeleteLinkedPurchaseHeaderNoAllowedSuccess() var PurchaseHeader: Record "Purchase Header"; @@ -1445,9 +1446,8 @@ codeunit 139624 "E-Doc E2E Test" PurchaseHeader.Modify(); Commit(); - // [THEN] Fails to delete + // [THEN] Show confirmation message and throw error if cancelled asserterror PurchaseHeader.Delete(true); - Assert.ExpectedError(DeleteNotAllowedErr); // [GIVEN] Reset link PurchaseHeader."E-Document Link" := NullGuid; @@ -2233,6 +2233,7 @@ codeunit 139624 "E-Doc E2E Test" end; [Test] + [HandlerFunctions('DeleteConfirmationHandler')] internal procedure DeleteLinkedPurchaseHeaderNoAllowedSuccess26() var PurchaseHeader: Record "Purchase Header"; @@ -2248,9 +2249,8 @@ codeunit 139624 "E-Doc E2E Test" PurchaseHeader.Modify(); Commit(); - // [THEN] Fails to delete + // [THEN] Show confirmation message and throw error if cancelled asserterror PurchaseHeader.Delete(true); - Assert.ExpectedError(DeleteNotAllowedErr); // [GIVEN] Reset link PurchaseHeader."E-Document Link" := NullGuid; @@ -2261,4 +2261,12 @@ codeunit 139624 "E-Doc E2E Test" end; #endif + [ConfirmHandler] + procedure DeleteConfirmationHandler(Message: Text[1024]; var Reply: Boolean) + var + ExpectedConfirmLbl: Label 'This purchase document is created from E-Document. Do you want to proceed with deletion?'; + begin + Assert.ExpectedConfirm(ExpectedConfirmLbl, Message); + Reply := false; + end; } diff --git a/Apps/W1/EDocument/test/src/Receive/EDocReceiveTest.Codeunit.al b/Apps/W1/EDocument/test/src/Receive/EDocReceiveTest.Codeunit.al index 61041d9c2d..1431c62293 100644 --- a/Apps/W1/EDocument/test/src/Receive/EDocReceiveTest.Codeunit.al +++ b/Apps/W1/EDocument/test/src/Receive/EDocReceiveTest.Codeunit.al @@ -1340,6 +1340,59 @@ codeunit 139628 "E-Doc. Receive Test" PurchaseHeader.Delete(true); end; + [Test] + [HandlerFunctions('ConfirmHandlerYes')] + procedure RecreateReceivedPurchaseInvoice() + var + EDocService: Record "E-Document Service"; + EDocServicePage: TestPage "E-Document Service"; + EDocumentPage: TestPage "E-Document"; + CreatedInvoiceNo: Text[20]; + begin + // [FEATURE] [E-Document] [Receive] + // [SCENARIO] Delete and recreate purchase invoice from E-Document page + Initialize(); + + // [GIVEN] e-Document service to receive one single purchase invoice + LibraryEDoc.CreateTestReceiveServiceForEDoc(EDocService, Enum::"Service Integration"::"Mock"); + BindSubscription(this.EDocImplState); + + SetDefaultEDocServiceValues(EDocService); + + // [GIVEN] Purchase invoice + CreatePurchaseInvoiceWithLines(this.PurchaseHeader, this.PurchaseLine, this.Vendor); + + PurchOrderTestBuffer.ClearTempVariables(); + PurchOrderTestBuffer.AddPurchaseDocToTemp(this.PurchaseHeader); + + // [WHEN] Running Receive + EDocServicePage.OpenView(); + EDocServicePage.Filter.SetFilter(Code, EDocService.Code); + EDocServicePage.Receive.Invoke(); + + // [THEN] Purchase invoice is created with corresponding values + EDocumentPage.OpenView(); + EDocumentPage.Last(); + CreatedInvoiceNo := EDocumentPage."Document No.".Value; + + CheckPurchaseInvoiceCreatedWithCorrectValues(this.PurchaseHeader, this.CreatedPurchaseHeader, this.PurchaseLine, this.CreatedPurchaseLine, CreatedInvoiceNo); + + // [WHEN] Delete created purchase invoice from E-Document page + EDocumentPage.DeleteRelatedDocument.Invoke(); + + // [THEN] Check that purchase invoice is deleted + this.Assert.AreEqual('', EDocumentPage."Document No.".Value, ''); + CheckPurchaseInvoiceDeleted(this.CreatedPurchaseHeader, CreatedInvoiceNo); + + // [WHEN] Recreate purchase invoice + EDocumentPage.CreateDocument.Invoke(); + + // [THEN] Check that purchase invoice is created again with corresponding values + CheckPurchaseInvoiceCreatedWithCorrectValues(this.PurchaseHeader, this.CreatedPurchaseHeader, this.PurchaseLine, this.CreatedPurchaseLine, EDocumentPage."Document No.".Value); + + DeletePurchaseHeaders(this.PurchaseHeader, this.CreatedPurchaseHeader); + end; + [ModalPageHandler] procedure SelectPOHandler(var POList: TestPage "Purchase Order List") var @@ -1397,6 +1450,36 @@ codeunit 139628 "E-Doc. Receive Test" EDocument.DeleteAll(); end; + local procedure SetDefaultEDocServiceValues(var EDocService: Record "E-Document Service") + begin + 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."Create Journal Lines" := false; + EDocService.Modify(false); + end; + + local procedure CreatePurchaseInvoiceWithLines(var PurchHeader: Record "Purchase Header"; var PurchLine: Record "Purchase Line"; var Vendor: Record Vendor) + var + i: Integer; + begin + this.LibraryPurchase.CreateVendorWithAddress(this.Vendor); + this.Vendor."Receive E-Document To" := this.Vendor."Receive E-Document To"::"Purchase Invoice"; + this.Vendor.Modify(false); + this.LibraryPurchase.CreatePurchHeader(PurchHeader, PurchHeader."Document Type"::Invoice, this.Vendor."No."); + + for i := 1 to 3 do begin + this.LibraryPurchase.CreatePurchaseLine(PurchLine, PurchHeader, PurchLine.Type::Item, this.LibraryInventory.CreateItemNo(), this.LibraryRandom.RandInt(100)); + PurchLine.Validate("Direct Unit Cost", this.LibraryRandom.RandDecInRange(1, 100, 2)); + PurchLine.Modify(true); + end; + end; + local procedure CheckPurchaseHeadersAreEqual(var PurchHeader1: Record "Purchase Header"; var PurchHeader2: Record "Purchase Header") begin Assert.AreEqual(PurchHeader1."Pay-to Vendor No.", PurchHeader2."Pay-to Vendor No.", ''); @@ -1435,6 +1518,46 @@ codeunit 139628 "E-Doc. Receive Test" Assert.AreEqual(PurchHeader."Amount Including VAT", Abs(GenJnlLine.Amount), ''); end; + local procedure CheckPurchaseInvoiceCreatedWithCorrectValues(PurchHeader: Record "Purchase Header"; var CreatedPurchHeader: Record "Purchase Header"; PurchLine: Record "Purchase Line"; CreatedPurchLine: Record "Purchase Line"; DocumentNo: Code[20]) + begin + CreatedPurchHeader.Reset(); + CreatedPurchHeader.SetRange("Document Type", CreatedPurchHeader."Document Type"::Invoice); + CreatedPurchHeader.SetRange("No.", DocumentNo); + CreatedPurchHeader.FindFirst(); + + CheckPurchaseHeadersAreEqual(PurchHeader, CreatedPurchHeader); + + CreatedPurchLine.SetRange("Document Type", CreatedPurchHeader."Document Type"); + CreatedPurchLine.SetRange("Document No.", CreatedPurchHeader."No."); + if CreatedPurchLine.FindSet() then + repeat + PurchLine.SetRange("Document Type", PurchHeader."Document Type"); + PurchLine.SetRange("Document No.", PurchHeader."No."); + PurchLine.SetRange("Line No.", CreatedPurchLine."Line No."); + PurchLine.FindFirst(); + CheckPurchaseLinesAreEqual(PurchLine, CreatedPurchLine); + until CreatedPurchLine.Next() = 0; + end; + + local procedure CheckPurchaseInvoiceDeleted(var CreatedPurchHeader: Record "Purchase Header"; DocumentNo: Code[20]) + begin + CreatedPurchHeader.Reset(); + CreatedPurchHeader.SetRange("Document Type", CreatedPurchHeader."Document Type"::Invoice); + CreatedPurchHeader.SetRange("No.", DocumentNo); + Assert.RecordIsEmpty(CreatedPurchHeader); + end; + + local procedure DeletePurchaseHeaders(var PurchHeader: Record "Purchase Header"; var CreatedPurchHeader: Record "Purchase Header") + begin + PurchHeader.SetHideValidationDialog(true); + PurchHeader."E-Document Link" := NullGuid; + PurchHeader.Delete(true); + + CreatedPurchHeader.SetHideValidationDialog(true); + CreatedPurchHeader."E-Document Link" := NullGuid; + CreatedPurchHeader.Delete(true); + end; + [EventSubscriber(ObjectType::Codeunit, Codeunit::"E-Document Create Purch. Doc.", 'OnBeforeProcessHeaderFieldsAssignment', '', false, false)] local procedure OnBeforeProcessHeaderFieldsAssignment(var DocumentHeader: RecordRef; var PurchaseField: Record Field); begin @@ -2761,5 +2884,4 @@ codeunit 139628 "E-Doc. Receive Test" #endif - } \ No newline at end of file