diff --git a/src/Apps/W1/EDocument/App/src/Processing/EDocExport.Codeunit.al b/src/Apps/W1/EDocument/App/src/Processing/EDocExport.Codeunit.al index 4a94fe2123..e5200de14b 100644 --- a/src/Apps/W1/EDocument/App/src/Processing/EDocExport.Codeunit.al +++ b/src/Apps/W1/EDocument/App/src/Processing/EDocExport.Codeunit.al @@ -65,6 +65,7 @@ codeunit 6102 "E-Doc. Export" EDocumentServiceStatus: Record "E-Document Service Status"; EDocWorkFlowProcessing: Codeunit "E-Document WorkFlow Processing"; EDocumentBackgroundJobs: Codeunit "E-Document Background Jobs"; + HasServiceResponses: Boolean; begin if not WorkFlow.Get(DocumentSendingProfile."Electronic Service Flow") then Error(DocumentSendingProfileWithWorkflowErr, DocumentSendingProfile."Electronic Service Flow", Format(DocumentSendingProfile."Electronic Document"::"Extended E-Document Service Flow"), DocumentSendingProfile.Code); @@ -73,14 +74,30 @@ codeunit 6102 "E-Doc. Export" if DocumentSendingProfile."Electronic Document" <> DocumentSendingProfile."Electronic Document"::"Extended E-Document Service Flow" then exit; - if not EDocWorkFlowProcessing.GetServicesFromEntryPointResponseInWorkflow(WorkFlow, EDocumentService) then + HasServiceResponses := EDocWorkFlowProcessing.GetServicesFromEntryPointResponseInWorkflow(WorkFlow, EDocumentService); + + if not HasServiceResponses then begin + if not EDocWorkFlowProcessing.WorkflowHasNonServiceResponses(WorkFlow) then + exit; + // Create E-Document for non-service workflow processing (e.g., email-only) + CreateEDocumentForNonServiceWorkflow(EDocument, DocumentHeader, EDocumentType, WorkFlow.Code, DocumentSendingProfile.Code); + if EDocument."Entry No" <> 0 then + EDocumentBackgroundJobs.StartEDocumentCreatedFlow(EDocument); exit; + end; EDocument."Workflow Code" := WorkFlow.Code; EDocument."Document Sending Profile" := DocumentSendingProfile.Code; - if not CreateEDocument(EDocument, DocumentHeader, EDocumentService, EDocumentType) then + if not CreateEDocument(EDocument, DocumentHeader, EDocumentService, EDocumentType) then begin + // No services support the document type. Check for non-service responses (e.g., email). + if not EDocWorkFlowProcessing.WorkflowHasNonServiceResponses(WorkFlow) then + exit; + CreateEDocumentForNonServiceWorkflow(EDocument, DocumentHeader, EDocumentType, WorkFlow.Code, DocumentSendingProfile.Code); + if EDocument."Entry No" <> 0 then + EDocumentBackgroundJobs.StartEDocumentCreatedFlow(EDocument); exit; + end; // For each service supporting the document type, export it before creating E-Document Created Flow EDocumentServiceStatus.SetRange("E-Document Entry No", EDocument."Entry No"); @@ -500,6 +517,34 @@ codeunit 6102 "E-Doc. Export" exit(IExportEligibilityEvaluator.ShouldExport(EDocumentService, SourceDocumentHeader, DocumentType)); end; + local procedure CreateEDocumentForNonServiceWorkflow(var EDocument: Record "E-Document"; var DocumentHeader: RecordRef; EDocumentType: Enum "E-Document Type"; WorkflowCode: Code[20]; DocSendingProfile: Code[20]) + var + EDocumentLog: Codeunit "E-Document Log"; + begin + EDocument.SetRange("Document Record ID", DocumentHeader.RecordId); + if not EDocument.IsEmpty() then + exit; + + EDocument.Init(); + EDocument."Workflow Code" := WorkflowCode; + EDocument."Document Sending Profile" := DocSendingProfile; + + OnBeforeCreateEDocument(EDocument, DocumentHeader); + + EDocument.Validate("Document Record ID", DocumentHeader.RecordId); + EDocument.Validate("Document Type", EDocumentType); + EDocument.Validate(Status, EDocument.Status::"In Progress"); + EDocument.Validate(Direction, EDocument.Direction::Outgoing); + EDocument.Insert(); + + PopulateEDocument(EDocument, DocumentHeader); + EDocument.Modify(); + + OnAfterCreateEDocument(EDocument, DocumentHeader); + + EDocumentLog.InsertLog(EDocument, Enum::"E-Document Service Status"::Created); + end; + var EDocumentProcessing: Codeunit "E-Document Processing"; EDocumentErrorHelper: Codeunit "E-Document Error Helper"; diff --git a/src/Apps/W1/EDocument/App/src/Workflow/EDocumentWorkFlowProcessing.Codeunit.al b/src/Apps/W1/EDocument/App/src/Workflow/EDocumentWorkFlowProcessing.Codeunit.al index c3121f6fa3..c0377e63c6 100644 --- a/src/Apps/W1/EDocument/App/src/Workflow/EDocumentWorkFlowProcessing.Codeunit.al +++ b/src/Apps/W1/EDocument/App/src/Workflow/EDocumentWorkFlowProcessing.Codeunit.al @@ -285,12 +285,20 @@ codeunit 6135 "E-Document WorkFlow Processing" WorkflowStepArgument: Record "Workflow Step Argument"; EDocumentService: Record "E-Document Service"; EDocument: Record "E-Document"; + EDocExport: Codeunit "E-Doc. Export"; begin if not GetEDocumentFromRecordRef(RecordRef, EDocument) then exit; if not ValidateFlowStep(EDocument, WorkflowStepArgument, WorkflowStepInstance, true) then exit; EDocumentService.Get(WorkflowStepArgument."E-Document Service"); + + // Skip if service does not support the document type, but continue workflow + if not EDocExport.IsDocumentTypeSupported(EDocumentService, EDocument."Document Type") then begin + SkipSendAndContinueWorkflow(EDocument, EDocumentService); + exit; + end; + SendEDocument(EDocument, EDocumentService); end; @@ -481,6 +489,12 @@ codeunit 6135 "E-Document WorkFlow Processing" EDocumentService.Get(WorkflowStepArgument."E-Document Service"); + // Skip if service does not support the document type, but continue workflow + if not EDocExport.IsDocumentTypeSupported(EDocumentService, EDocument."Document Type") then begin + WorkflowManagement.HandleEventOnKnownWorkflowInstance(EDocWorkflowSetup.EventEDocExported(), EDocument, EDocument."Workflow Step Instance ID"); + exit; + end; + if EDocExport.ExportEDocument(EDocument, EDocumentService) then WorkflowManagement.HandleEventOnKnownWorkflowInstance(EDocWorkflowSetup.EventEDocExported(), EDocument, EDocument."Workflow Step Instance ID"); end; @@ -554,6 +568,29 @@ codeunit 6135 "E-Document WorkFlow Processing" CannotFindEDocErr: Label 'Cannot find the E-Document with type %1, document number %2.', Comment = '%1 - E-Document type, %2 - Document number'; NotSupportedEDocTypeErr: Label 'The document type %1 is not supported for sending from email.', Comment = '%1 - E-Document type'; + internal procedure WorkflowHasNonServiceResponses(Workflow: Record Workflow): Boolean + var + WorkflowStep: Record "Workflow Step"; + EDocWorkflowSetup: Codeunit "E-Document Workflow Setup"; + begin + WorkflowStep.SetRange("Workflow Code", Workflow.Code); + WorkflowStep.SetRange(Type, WorkflowStep.Type::Response); + WorkflowStep.SetFilter("Function Name", '%1|%2', EDocWorkflowSetup.ResponseSendEDocByEmail(), EDocWorkflowSetup.ResponseSendEDocAndPDFByEmail()); + exit(not WorkflowStep.IsEmpty()); + end; + + local procedure SkipSendAndContinueWorkflow(var EDocument: Record "E-Document"; EDocumentService: Record "E-Document Service") + var + EDocumentServiceStatus: Record "E-Document Service Status"; + begin + // Insert a service status to enable workflow continuation through HandleNextEvent + if not EDocumentServiceStatus.Get(EDocument."Entry No", EDocumentService.Code) then + EDocumentProcessing.InsertServiceStatus(EDocument, EDocumentService, Enum::"E-Document Service Status"::Sent); + + EDocument.SetRecFilter(); + HandleNextEvent(EDocument, EDocumentService); + end; + [IntegrationEvent(false, false)] local procedure OnBatchSendWithCustomBatchMode(var EDocument: Record "E-Document"; var EDocumentService: Record "E-Document Service"; var IsHandled: Boolean) begin diff --git a/src/Apps/W1/EDocument/App/src/Workflow/EDocumentWorkFlowSetup.Codeunit.al b/src/Apps/W1/EDocument/App/src/Workflow/EDocumentWorkFlowSetup.Codeunit.al index 1a47924eed..5edf66b3f8 100644 --- a/src/Apps/W1/EDocument/App/src/Workflow/EDocumentWorkFlowSetup.Codeunit.al +++ b/src/Apps/W1/EDocument/App/src/Workflow/EDocumentWorkFlowSetup.Codeunit.al @@ -149,11 +149,13 @@ codeunit 6139 "E-Document Workflow Setup" end; ResponseSendEDocByEmail(): begin + WorkflowResponseHandling.AddResponsePredecessor(ResponseSendEDocByEmail(), EDocCreated()); WorkflowResponseHandling.AddResponsePredecessor(ResponseSendEDocByEmail(), EventEDocStatusChanged()); WorkflowResponseHandling.AddResponsePredecessor(ResponseSendEDocByEmail(), EventEDocExported()); end; ResponseSendEDocAndPDFByEmail(): begin + WorkflowResponseHandling.AddResponsePredecessor(ResponseSendEDocAndPDFByEmail(), EDocCreated()); WorkflowResponseHandling.AddResponsePredecessor(ResponseSendEDocAndPDFByEmail(), EventEDocStatusChanged()); WorkflowResponseHandling.AddResponsePredecessor(ResponseSendEDocAndPDFByEmail(), EventEDocExported()); end; diff --git a/src/Apps/W1/EDocument/Test/src/Flow/EDocFlowTest.Codeunit.al b/src/Apps/W1/EDocument/Test/src/Flow/EDocFlowTest.Codeunit.al index ff5a499d4a..7d1300f936 100644 --- a/src/Apps/W1/EDocument/Test/src/Flow/EDocFlowTest.Codeunit.al +++ b/src/Apps/W1/EDocument/Test/src/Flow/EDocFlowTest.Codeunit.al @@ -6,6 +6,8 @@ namespace Microsoft.eServices.EDocument.Test; using Microsoft.eServices.EDocument; using Microsoft.eServices.EDocument.Integration; +using Microsoft.Foundation.Reporting; +using Microsoft.Sales.Customer; using System.Automation; using System.IO; using System.TestLibraries.Utilities; @@ -23,6 +25,7 @@ codeunit 139631 "E-Doc. Flow Test" LibrarySales: Codeunit "Library - Sales"; LibraryVariableStorage: Codeunit "Library - Variable Storage"; LibraryEDoc: Codeunit "Library - E-Document"; + LibraryJobQueue: Codeunit "Library - Job Queue"; LibraryLowerPermission: Codeunit "Library - Lower Permissions"; WrongValueErr: Label 'Wrong value'; WorkflowEmptyErr: Label 'Must return false for an empty workflow'; @@ -203,6 +206,121 @@ codeunit 139631 "E-Doc. Flow Test" #pragma warning restore AL0432 #endif + [Test] + procedure EDocFlowShipmentCreatedWhenServiceDoesNotSupportTypeButEmailExists() + var + EDocument: Record "E-Document"; + EDocumentServiceStatus: Record "E-Document Service Status"; + Customer: Record Customer; + EDocService: Record "E-Document Service"; + DocumentSendingProfile: Record "Document Sending Profile"; + CustomerNo, DocSendProfileNo, WorkflowCode, ServiceCode : Code[20]; + begin + // [FEATURE] [E-Document] [Flow] + // [SCENARIO] E-Document is created for Sales Shipment when service does not support + // the type, but workflow contains email responses + + // [GIVEN] Service that supports Sales Invoice but NOT Sales Shipment, workflow with Send + Email + Initialize(); + LibraryEDoc.SetupStandardVAT(); + + CustomerNo := LibrarySales.CreateCustomerNo(); + DocSendProfileNo := LibraryEDoc.CreateDocumentSendingProfileForWorkflow(CustomerNo, ''); + ServiceCode := LibraryEDoc.CreateService(Enum::"Service Integration"::"Mock"); + // Standard service supports Sales Invoice, not Sales Shipment + WorkflowCode := LibraryEDoc.CreateFlowWithServiceAndEmail(DocSendProfileNo, ServiceCode); + LibraryEDoc.UpdateWorkflowOnDocumentSendingProfile(DocSendProfileNo, WorkflowCode); + + // [WHEN] Posting a Sales Shipment (type not supported by service) + EDocService.Get(ServiceCode); + Customer.Get(CustomerNo); + LibraryLowerPermission.SetTeamMember(); + LibraryJobQueue.SetDoNotHandleCodeunitJobQueueEnqueueEvent(true); + + LibraryEDoc.PostSalesShipment(Customer); + + // [THEN] E-Document should be created for Sales Shipment + EDocument.FindLast(); + Assert.AreEqual(Enum::"E-Document Type"::"Sales Shipment", EDocument."Document Type", WrongValueErr); + Assert.AreEqual(WorkflowCode, EDocument."Workflow Code", WrongValueErr); + + // [THEN] No service status should exist (service does not support type) + EDocumentServiceStatus.SetRange("E-Document Entry No", EDocument."Entry No"); + Assert.IsTrue(EDocumentServiceStatus.IsEmpty(), 'No service status should exist for unsupported document type'); + end; + + [Test] + procedure EDocFlowSendSkippedForUnsupportedDocType() + var + EDocument: Record "E-Document"; + EDocumentServiceStatus: Record "E-Document Service Status"; + WorkflowStepArgument: Record "Workflow Step Argument"; + WorkflowStepInstance: Record "Workflow Step Instance"; + EDocWorkflowProcessing: Codeunit "E-Document WorkFlow Processing"; + RecordRef: RecordRef; + CustomerNo, DocSendProfileNo, ServiceCode : Code[20]; + begin + // [FEATURE] [E-Document] [Flow] + // [SCENARIO] SendEDocument skips when service does not support the document type and sets Sent status + + // [GIVEN] E-Document with type Sales Shipment, service that only supports Sales Invoice + Initialize(); + + CustomerNo := LibrarySales.CreateCustomerNo(); + DocSendProfileNo := LibraryEDoc.CreateDocumentSendingProfileForWorkflow(CustomerNo, ''); + ServiceCode := LibraryEDoc.CreateService(Enum::"Service Integration"::"Mock"); + LibraryEDoc.CreateFlowWithService(DocSendProfileNo, ServiceCode); + + EDocument."Entry No" := 0; + EDocument."Document Type" := Enum::"E-Document Type"::"Sales Shipment"; + EDocument.Insert(); + + // [WHEN] Calling SendEDocument with a service that does not support the type + WorkflowStepArgument.FindLast(); + WorkflowStepInstance.Argument := WorkflowStepArgument.ID; + + LibraryLowerPermission.SetTeamMember(); + RecordRef.GetTable(EDocument); + EDocWorkflowProcessing.SendEDocument(RecordRef, WorkflowStepInstance); + + // [THEN] Service status is Sent (skipped sending, but workflow can continue) + EDocumentServiceStatus.SetRange("E-Document Entry No", EDocument."Entry No"); + EDocumentServiceStatus.SetRange("E-Document Service Code", ServiceCode); + Assert.IsTrue(EDocumentServiceStatus.FindFirst(), 'Service status should exist after skip'); + Assert.AreEqual(Enum::"E-Document Service Status"::Sent, EDocumentServiceStatus.Status, 'Service status should be Sent when type is not supported'); + end; + + [Test] + procedure EDocFlowEmailOnlyWorkflowCreatesEDocument() + var + EDocument: Record "E-Document"; + Customer: Record Customer; + CustomerNo, DocSendProfileNo, WorkflowCode : Code[20]; + begin + // [FEATURE] [E-Document] [Flow] + // [SCENARIO] E-Document created when workflow has only email response and no service responses + + // [GIVEN] Workflow with only email response (no service/send response) + Initialize(); + LibraryEDoc.SetupStandardVAT(); + + CustomerNo := LibrarySales.CreateCustomerNo(); + DocSendProfileNo := LibraryEDoc.CreateDocumentSendingProfileForWorkflow(CustomerNo, ''); + WorkflowCode := LibraryEDoc.CreateFlowWithEmailOnly(DocSendProfileNo); + LibraryEDoc.UpdateWorkflowOnDocumentSendingProfile(DocSendProfileNo, WorkflowCode); + + // [WHEN] Posting a Sales Invoice + Customer.Get(CustomerNo); + LibraryLowerPermission.SetTeamMember(); + LibraryJobQueue.SetDoNotHandleCodeunitJobQueueEnqueueEvent(true); + LibraryEDoc.PostInvoice(Customer); + + // [THEN] E-Document should be created even without any service + EDocument.FindLast(); + Assert.AreEqual(Enum::"E-Document Type"::"Sales Invoice", EDocument."Document Type", WrongValueErr); + Assert.AreEqual(WorkflowCode, EDocument."Workflow Code", WrongValueErr); + end; + local procedure Initialize() var TransformationRule: Record "Transformation Rule"; diff --git a/src/Apps/W1/EDocument/Test/src/LibraryEDocument.Codeunit.al b/src/Apps/W1/EDocument/Test/src/LibraryEDocument.Codeunit.al index 047fc89157..4ab625a80b 100644 --- a/src/Apps/W1/EDocument/Test/src/LibraryEDocument.Codeunit.al +++ b/src/Apps/W1/EDocument/Test/src/LibraryEDocument.Codeunit.al @@ -715,6 +715,50 @@ codeunit 139629 "Library - E-Document" exit(Workflow.Code); end; + procedure CreateFlowWithServiceAndEmail(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, EmailResponseEventID : 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); + EmailResponseEventID := LibraryWorkflow.InsertResponseStep(Workflow, EDocWorkflowSetup.ResponseSendEDocByEmail(), SendEDocResponseEventID); + + 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 CreateFlowWithEmailOnly(DocSendingProfile: Code[20]): Code[20] + var + Workflow: Record Workflow; + EDocWorkflowSetup: Codeunit "E-Document Workflow Setup"; + EDocCreatedEventID: Integer; + EventConditions: Text; + begin + LibraryWorkflow.CreateWorkflow(Workflow); + EventConditions := CreateWorkflowEventConditionDocSendingProfileFilter(DocSendingProfile); + + EDocCreatedEventID := LibraryWorkflow.InsertEntryPointEventStep(Workflow, EDocWorkflowSetup.EDocCreated()); + LibraryWorkflow.InsertEventArgument(EDocCreatedEventID, EventConditions); + LibraryWorkflow.InsertResponseStep(Workflow, EDocWorkflowSetup.ResponseSendEDocByEmail(), EDocCreatedEventID); + + LibraryWorkflow.EnableWorkflow(Workflow); + exit(Workflow.Code); + end; + local procedure DeleteEDocumentRelatedEntities() var DynamicRequestPageEntity: Record "Dynamic Request Page Entity";