diff --git a/src/System Application/App/Retention Policy/src/Apply Retention Policy/ApplyRetentionPolicyImpl.Codeunit.al b/src/System Application/App/Retention Policy/src/Apply Retention Policy/ApplyRetentionPolicyImpl.Codeunit.al index b191b1baf6b..d275e3c0c8f 100644 --- a/src/System Application/App/Retention Policy/src/Apply Retention Policy/ApplyRetentionPolicyImpl.Codeunit.al +++ b/src/System Application/App/Retention Policy/src/Apply Retention Policy/ApplyRetentionPolicyImpl.Codeunit.al @@ -79,6 +79,7 @@ codeunit 3904 "Apply Retention Policy Impl." TotalNumberOfRecordsDeleted := Rec."Number Of Records Deleted"; ApplyRetentionPolicy(RetentionPolicySetup, false, false); Rec."Number Of Records Deleted" := TotalNumberOfRecordsDeleted; + Rec."End Current Run" := EndCurrentRun; end; end; @@ -192,6 +193,7 @@ codeunit 3904 "Apply Retention Policy Impl." exit end; TotalNumberOfRecordsDeleted := TempRetentionPolicySetup."Number Of Records Deleted"; + EndCurrentRun := TempRetentionPolicySetup."End Current Run"; end; local procedure CanApplyRetentionPolicy(var RetentionPolicySetup: Record "Retention Policy Setup"; Manual: Boolean): Boolean diff --git a/src/System Application/App/Retention Policy/src/Retention Policy Setup/RetentionPolicySetup.Table.al b/src/System Application/App/Retention Policy/src/Retention Policy Setup/RetentionPolicySetup.Table.al index 7015a2f4d7d..3d3e3f3fa62 100644 --- a/src/System Application/App/Retention Policy/src/Retention Policy Setup/RetentionPolicySetup.Table.al +++ b/src/System Application/App/Retention Policy/src/Retention Policy Setup/RetentionPolicySetup.Table.al @@ -154,6 +154,12 @@ table 3901 "Retention Policy Setup" Access = Internal; Editable = false; } + field(101; "End Current Run"; Boolean) + { + DataClassification = SystemMetadata; + Access = Internal; + Editable = false; + } } keys diff --git a/src/System Application/Test/Retention Policy/src/RetentionPolicyTest.Codeunit.al b/src/System Application/Test/Retention Policy/src/RetentionPolicyTest.Codeunit.al index 906e4d96aa7..60dee4dafd5 100644 --- a/src/System Application/Test/Retention Policy/src/RetentionPolicyTest.Codeunit.al +++ b/src/System Application/Test/Retention Policy/src/RetentionPolicyTest.Codeunit.al @@ -1455,6 +1455,56 @@ codeunit 138702 "Retention Policy Test" Assert.RecordIsEmpty(RetentionPolicyTestData3); end; + [Test] + procedure TestApplyRetentionPolicyStopsAtLimitAcrossTables() + begin + VerifyApplyRetentionPolicyRecordLimit(RetentionPolicyTestLibrary.MaxNumberOfRecordsToDelete(), 0, true); + end; + + [Test] + procedure TestApplyRetentionPolicyStopsWithRecordsRemainingAcrossTables() + var + RemainingRecords: Integer; + begin + RemainingRecords := RetentionPolicyTestLibrary.MaxNumberOfRecordsToDeleteBuffer() + 1; + VerifyApplyRetentionPolicyRecordLimit(RetentionPolicyTestLibrary.MaxNumberOfRecordsToDelete() + RemainingRecords, RemainingRecords, true); + end; + + [Test] + procedure TestApplyRetentionPolicyContinuesBelowLimitAcrossTables() + begin + VerifyApplyRetentionPolicyRecordLimit(RetentionPolicyTestLibrary.MaxNumberOfRecordsToDelete() - 2, 0, false); + end; + + [Test] + procedure TestApplyRetentionPolicyContinuesAfterPolicyError() + var + RetentionPeriod: Record "Retention Period"; + RetentionPolicySetup: Record "Retention Policy Setup"; + RetentionPolicyTestData: Record "Retention Policy Test Data"; + RetentionPolicyTestData3: Record "Retention Policy Test Data 3"; + ApplyRetentionPolicy: Codeunit "Apply Retention Policy"; + begin + // Setup + // Enabled policy setup can schedule Base Application job queue entries. + PermissionsMock.Set('SUPER'); + RetentionPolicyTestLibrary.RaiseOnRefreshAllowedTables(); + ClearTestData(); + InsertOneMonthRetentionPeriod(RetentionPeriod); + InsertEnabledRetentionPolicySetupForAllRecords(RetentionPolicySetup, RetentionPeriod, 0); + InsertRetentionPolicySetupTable3(RetentionPolicySetup, RetentionPeriod, RetentionPolicyTestData3.FieldNo("Datetime Field")); + PermissionsMock.Set('Retention Pol. Admin'); + InsertRetentionPolicyTestData('<-2M>'); + InsertRetentionPolicyTestData3('<-2M>'); + + // Exercise + ApplyRetentionPolicy.ApplyRetentionPolicy(false); + + // Verify + Assert.AreEqual(1, RetentionPolicyTestData.Count(), 'Records for the invalid policy must not be deleted.'); + Assert.RecordIsEmpty(RetentionPolicyTestData3); + end; + [Test] procedure TestApplyRetentionPolicyTooManyLinesToDeleteOneTableAndReschedule() var @@ -1624,6 +1674,53 @@ codeunit 138702 "Retention Policy Test" RetentionPeriod.DeleteAll(true); end; + local procedure VerifyApplyRetentionPolicyRecordLimit(RecordsTableOne: Integer; RemainingRecordsTableOne: Integer; LimitReached: Boolean) + var + RetentionPeriod: Record "Retention Period"; + RetentionPolicySetup: Record "Retention Policy Setup"; + RetentionPolicyTestData: Record "Retention Policy Test Data"; + RetentionPolicyTestData3: Record "Retention Policy Test Data 3"; + ApplyRetentionPolicy: Codeunit "Apply Retention Policy"; + RetentionPolicyTestLibrarySubs: Codeunit "Retention Policy Test Library"; + i: Integer; + begin + // Setup + // Enabled policy setup can schedule Base Application job queue entries. + PermissionsMock.Set('SUPER'); + RetentionPolicyTestLibrary.RaiseOnRefreshAllowedTables(); + ClearTestData(); + InsertOneMonthRetentionPeriod(RetentionPeriod); + InsertEnabledRetentionPolicySetupForAllRecords(RetentionPolicySetup, RetentionPeriod, RetentionPolicyTestData.FieldNo("Date Field")); + InsertRetentionPolicySetupTable3(RetentionPolicySetup, RetentionPeriod, RetentionPolicyTestData3.FieldNo("Datetime Field")); + PermissionsMock.Set('Retention Pol. Admin'); + for i := 1 to RecordsTableOne do + InsertRetentionPolicyTestData('<-2M>'); + InsertRetentionPolicyTestData3('<-2M>'); + + Assert.AreEqual(RecordsTableOne, RetentionPolicyTestData.Count(), 'Incorrect number of records before applying retention policy.'); + Assert.AreEqual(1, RetentionPolicyTestData3.Count(), 'Incorrect number of records before applying retention policy.'); + + // Exercise + BindSubscription(RetentionPolicyTestLibrarySubs); + ApplyRetentionPolicy.ApplyRetentionPolicy(false); + UnbindSubscription(RetentionPolicyTestLibrarySubs); + + // Verify + Assert.AreEqual(RemainingRecordsTableOne, RetentionPolicyTestData.Count(), 'Incorrect number of records after applying retention policy.'); + if LimitReached then begin + Assert.AreEqual(1, RetentionPolicyTestData3.Count(), 'Later policies must not be processed after the record limit is reached.'); + Assert.AreEqual(1, RetentionPolicyTestLibrarySubs.GetRecordLimitExceededSubscriberCount(), 'The record limit event must be raised only once per run.'); + end else begin + Assert.RecordIsEmpty(RetentionPolicyTestData3); + Assert.AreEqual(0, RetentionPolicyTestLibrarySubs.GetRecordLimitExceededSubscriberCount(), 'The record limit event must not be raised below the limit.'); + end; + + // A new background run must process the remaining records. + ApplyRetentionPolicy.Run(); + Assert.RecordIsEmpty(RetentionPolicyTestData); + Assert.RecordIsEmpty(RetentionPolicyTestData3); + end; + local procedure InsertOneWeekRetentionPeriod(var RetentionPeriod: Record "Retention Period") begin InsertRetentionPeriod(RetentionPeriod, RetentionPeriod."Retention Period"::"1 Week");