Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 14 additions & 9 deletions src/Layers/W1/BaseApp/System/Workflow/WorkflowSetup.Codeunit.al
Original file line number Diff line number Diff line change
Expand Up @@ -261,16 +261,21 @@ codeunit 1502 "Workflow Setup"
begin
Workflow.SetRange(Template, true);
Workflow.SetFilter(Code, '%1', GetWorkflowTemplateToken() + '*');
Workflow.DeleteAll();

WorkflowStep.SetFilter("Workflow Code", '%1', GetWorkflowTemplateToken() + '*');
if WorkflowStep.FindSet() then begin
if Workflow.FindSet() then
repeat
WorkflowStepArgument.SetRange(ID, WorkflowStep.Argument);
WorkflowStepArgument.DeleteAll();
until WorkflowStep.Next() = 0;
WorkflowStep.DeleteAll();
end;
// Only delete the steps that belong to the template itself. Workflows created from a
// template keep the template token prefix in their code (e.g. MS-XYZ-01) but are not
// templates, so filtering steps by the token wildcard would also delete their steps.
WorkflowStep.SetRange("Workflow Code", Workflow.Code);
if WorkflowStep.FindSet() then begin
repeat
WorkflowStepArgument.SetRange(ID, WorkflowStep.Argument);
WorkflowStepArgument.DeleteAll();
until WorkflowStep.Next() = 0;
WorkflowStep.DeleteAll();
end;
until Workflow.Next() = 0;
Workflow.DeleteAll();

InitWorkflow();
end;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -85,12 +85,14 @@ page 1505 "Workflow Templates"
Caption = 'Reset Microsoft Templates';
Visible = not IsLookupMode;
Image = ResetStatus;
ToolTip = 'Recreate all Microsoft templates';
ToolTip = 'Delete and recreate the built-in Microsoft workflow templates. This affects only the templates, not the workflows that were created from them.';

trigger OnAction()
var
WorkflowSetup: Codeunit "Workflow Setup";
begin
if not Confirm(ResetTemplatesQst) then
exit;
WorkflowSetup.ResetWorkflowTemplates();
Initialize();
end;
Expand Down Expand Up @@ -151,6 +153,7 @@ page 1505 "Workflow Templates"
var
WorkflowSetup: Codeunit "Workflow Setup";
QueryClosePageLookupErr: Label 'Select a workflow template to continue, or choose Cancel to close the page.';
ResetTemplatesQst: Label 'This will delete and recreate all Microsoft workflow templates. Do you want to continue?';
DescriptionStyle: Text;

protected var
Expand Down
106 changes: 106 additions & 0 deletions src/Layers/W1/Tests/Workflow/CopyWorkflowTests.Codeunit.al
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ codeunit 134306 "Copy Workflow Tests"
AmountCondXmlTemplateTxt: Label '<?xml version="1.0" standalone="yes"?><ReportParameters name="Purch. Inv. Event Conditions" id="1502"><DataItems><DataItem name="Purchase Header">SORTING(Document Type,No.) WHERE(Amount=FILTER(%1))</DataItem><DataItem name="Purchase Line">SORTING(Document Type,Document No.,Line No.)</DataItem></DataItems></ReportParameters>', Locked = true;
LibraryUtility: Codeunit "Library - Utility";
LibraryRandom: Codeunit "Library - Random";
LibraryVariableStorage: Codeunit "Library - Variable Storage";
ResetTemplatesConfirmQst: Label 'delete and recreate all Microsoft workflow templates', Locked = true;

[Test]
[Scope('OnPrem')]
Expand Down Expand Up @@ -350,8 +352,81 @@ codeunit 134306 "Copy Workflow Tests"
Assert.AreEqual(0, FromWorkflow.Count, 'A new workflow was created.')
end;

[Test]
[HandlerFunctions('ConfirmHandler')]
[Scope('OnPrem')]
procedure TestResetTemplatesKeepsStepsOfWorkflowCreatedFromTemplate()
var
TemplateWorkflow: Record Workflow;
WorkflowFromTemplate: Record Workflow;
WorkflowStep: Record "Workflow Step";
WorkflowSetup: Codeunit "Workflow Setup";
WorkflowTemplatesPage: TestPage "Workflow Templates";
TemplateCode: Code[20];
WorkflowFromTemplateCode: Code[20];
begin
// [SCENARIO 640937] Resetting Microsoft templates must not remove the steps of active
// workflows that were created from a template and still carry the template code prefix.

// [GIVEN] A workflow template whose code starts with the Microsoft template token, with steps.
Initialize();
TemplateCode := CopyStr(WorkflowSetup.GetWorkflowTemplateToken() + 'BUG640937', 1, MaxStrLen(TemplateWorkflow.Code));
CreateTwoStepWorkflowWithCode(TemplateWorkflow, TemplateCode);
TemplateWorkflow.Validate(Template, true);
TemplateWorkflow.Modify(true);

// [GIVEN] An active (non-template) workflow created from that template: its code keeps the
// template token prefix (e.g. MS-...-01) and it has its own steps.
WorkflowFromTemplateCode := CopyStr(TemplateCode + '-01', 1, MaxStrLen(WorkflowFromTemplate.Code));
CreateTwoStepWorkflowWithCode(WorkflowFromTemplate, WorkflowFromTemplateCode);

// [WHEN] The user runs Reset Microsoft Templates and confirms.
LibraryVariableStorage.Enqueue(ResetTemplatesConfirmQst);
LibraryVariableStorage.Enqueue(true);
WorkflowTemplatesPage.OpenView();
WorkflowTemplatesPage."Reset Templates".Invoke();

// [THEN] The active workflow still exists and keeps all of its steps.
Assert.IsTrue(WorkflowFromTemplate.Get(WorkflowFromTemplateCode), 'The workflow created from the template must not be deleted.');
WorkflowStep.SetRange("Workflow Code", WorkflowFromTemplateCode);
Assert.IsFalse(WorkflowStep.IsEmpty(), 'The steps of the workflow created from the template must not be deleted.');
LibraryVariableStorage.AssertEmpty();
end;

[Test]
[HandlerFunctions('ConfirmHandler')]
[Scope('OnPrem')]
procedure TestResetTemplatesIsSkippedWhenConfirmationDeclined()
var
TemplateWorkflow: Record Workflow;
WorkflowSetup: Codeunit "Workflow Setup";
WorkflowTemplatesPage: TestPage "Workflow Templates";
TemplateCode: Code[20];
begin
// [SCENARIO 640937] The Reset Microsoft Templates action asks for confirmation and does
// nothing when the user declines.

// [GIVEN] A Microsoft workflow template with steps.
Initialize();
TemplateCode := CopyStr(WorkflowSetup.GetWorkflowTemplateToken() + 'BUG640937', 1, MaxStrLen(TemplateWorkflow.Code));
CreateTwoStepWorkflowWithCode(TemplateWorkflow, TemplateCode);
TemplateWorkflow.Validate(Template, true);
TemplateWorkflow.Modify(true);

// [WHEN] The user runs Reset Microsoft Templates but declines the confirmation.
LibraryVariableStorage.Enqueue(ResetTemplatesConfirmQst);
LibraryVariableStorage.Enqueue(false);
WorkflowTemplatesPage.OpenView();
WorkflowTemplatesPage."Reset Templates".Invoke();

// [THEN] Nothing is reset: the template still exists.
Assert.IsTrue(TemplateWorkflow.Get(TemplateCode), 'The templates must not be reset when the confirmation is declined.');
LibraryVariableStorage.AssertEmpty();
end;

local procedure Initialize()
begin
LibraryVariableStorage.Clear();
LibraryWorkflow.DeleteAllExistingWorkflows();
end;

Expand Down Expand Up @@ -439,5 +514,36 @@ codeunit 134306 "Copy Workflow Tests"
until FromWorkflowRule.Next() = 0;
until ToWorkflowStep.Next() = 0;
end;

local procedure CreateTwoStepWorkflowWithCode(var Workflow: Record Workflow; NewWorkflowCode: Code[20])
var
WorkflowEvent: Record "Workflow Event";
WorkflowRule: Record "Workflow Rule";
WorkflowResponseHandling: Codeunit "Workflow Response Handling";
EntryPointEventID: Integer;
ResponseID: Integer;
begin
Workflow.Init();
Workflow.Code := NewWorkflowCode;
Workflow.Description := CopyStr(LibraryUtility.GenerateRandomXMLText(MaxStrLen(Workflow.Description)), 1, MaxStrLen(Workflow.Description));
Workflow.Category := LibraryWorkflow.CreateWorkflowCategory();
Workflow.Template := false;
Workflow.Insert(true);

CreateAnyPurchaseHeaderEvent(WorkflowEvent);
EntryPointEventID := LibraryWorkflow.InsertEntryPointEventStep(Workflow, WorkflowEvent."Function Name");
ResponseID := LibraryWorkflow.InsertResponseStep(Workflow, WorkflowResponseHandling.CreateNotificationEntryCode(), EntryPointEventID);

LibraryWorkflow.InsertEventArgument(EntryPointEventID, StrSubstNo(AmountCondXmlTemplateTxt, Format(LibraryRandom.RandDec(1000, 2))));
LibraryWorkflow.InsertEventRule(EntryPointEventID, 0, WorkflowRule.Operator::Changed);
LibraryWorkflow.InsertNotificationArgument(ResponseID, UserId, 0, '');
end;

[ConfirmHandler]
procedure ConfirmHandler(Question: Text[1024]; var Reply: Boolean)
begin
Assert.ExpectedConfirm(LibraryVariableStorage.DequeueText(), Question);
Reply := LibraryVariableStorage.DequeueBoolean();
end;
}

Loading