From f3f90cefe266c135f3db58e2e37eb8f73d729ecb Mon Sep 17 00:00:00 2001 From: shamoon <4887959+shamoon@users.noreply.github.com> Date: Mon, 4 Nov 2024 21:26:03 -0800 Subject: [PATCH] Use explicit recurring interval --- src-ui/messages.xlf | 150 ++++++++++-------- .../workflow-edit-dialog.component.html | 11 +- .../workflow-edit-dialog.component.ts | 4 + src-ui/src/app/data/workflow-trigger.ts | 2 + ...ger_schedule_date_custom_field_and_more.py | 13 +- src/documents/models.py | 9 ++ src/documents/serialisers.py | 1 + src/documents/tasks.py | 12 +- src/documents/tests/test_workflows.py | 12 +- 9 files changed, 135 insertions(+), 79 deletions(-) diff --git a/src-ui/messages.xlf b/src-ui/messages.xlf index 5090f871b..8774c83b8 100644 --- a/src-ui/messages.xlf +++ b/src-ui/messages.xlf @@ -1182,19 +1182,19 @@ src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html - 191 + 200 src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html - 210 + 219 src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html - 277 + 286 src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html - 296 + 305 src/app/components/common/input/permissions/permissions-form/permissions-form.component.html @@ -1217,19 +1217,19 @@ src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html - 199 + 208 src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html - 218 + 227 src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html - 285 + 294 src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html - 304 + 313 src/app/components/common/input/permissions/permissions-form/permissions-form.component.html @@ -1255,11 +1255,11 @@ src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html - 224 + 233 src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html - 310 + 319 src/app/components/common/input/permissions/permissions-form/permissions-form.component.html @@ -3558,7 +3558,7 @@ src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html - 154 + 163 @@ -3968,7 +3968,7 @@ src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html - 179 + 188 @@ -3986,7 +3986,7 @@ src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html - 180 + 189 @@ -4401,287 +4401,301 @@ 126 - - Recurring - - src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html - 127 - - - - Repeat the trigger after the offset. - - src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html - 127 - - Relative to src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html - 130 + 129 Delay custom field src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html - 134 + 133 Custom field to use for date. src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html - 134 + 133 + + + + Recurring + + src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html + 139 + + + + Trigger is recurring. + + src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html + 139 + + + + Recurring interval days + + src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html + 143 + + + + Repeat the trigger every n days. + + src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html + 143 Trigger for documents that match all filters specified below. src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html - 139 + 148 Filter filename src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html - 142 + 151 Apply to documents that match this filename. Wildcards such as *.pdf or *invoice* are allowed. Case insensitive. src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html - 142 + 151 Filter sources src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html - 144 + 153 Filter path src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html - 145 + 154 Apply to documents that match this path. Wildcards specified as * are allowed. Case-normalized.</a> src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html - 145 + 154 Filter mail rule src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html - 146 + 155 Apply to documents consumed via this mail rule. src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html - 146 + 155 Content matching algorithm src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html - 149 + 158 Content matching pattern src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html - 151 + 160 Has any of tags src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html - 160 + 169 Has correspondent src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html - 161 + 170 Has document type src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html - 162 + 171 Action type src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html - 172 + 181 Assign title src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html - 177 + 186 Can include some placeholders, see <a target='_blank' href='https://docs.paperless-ngx.com/usage/#workflows'>documentation</a>. src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html - 177 + 186 Assign tags src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html - 178 + 187 Assign storage path src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html - 181 + 190 Assign custom fields src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html - 182 + 191 Assign owner src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html - 185 + 194 Assign view permissions src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html - 187 + 196 Assign edit permissions src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html - 206 + 215 Remove tags src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html - 233 + 242 Remove all src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html - 234 + 243 src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html - 240 + 249 src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html - 246 + 255 src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html - 252 + 261 src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html - 258 + 267 src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html - 265 + 274 src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html - 271 + 280 Remove correspondents src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html - 239 + 248 Remove document types src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html - 245 + 254 Remove storage paths src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html - 251 + 260 Remove custom fields src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html - 257 + 266 Remove owners src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html - 264 + 273 Remove permissions src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html - 270 + 279 View permissions src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html - 273 + 282 Edit permissions src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html - 292 + 301 diff --git a/src-ui/src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html b/src-ui/src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html index 3e8ac3e77..907af6c9e 100644 --- a/src-ui/src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html +++ b/src-ui/src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html @@ -124,7 +124,6 @@
-
@@ -135,6 +134,16 @@
}
+
+
+ +
+
+ @if (formGroup.get('schedule_is_recurring').value === true) { + + } +
+
}

Trigger for documents that match all filters specified below.

diff --git a/src-ui/src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.ts b/src-ui/src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.ts index cba00bc38..646085105 100644 --- a/src-ui/src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.ts +++ b/src-ui/src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.ts @@ -346,6 +346,9 @@ export class WorkflowEditDialogComponent ), schedule_offset_days: new FormControl(trigger.schedule_offset_days), schedule_is_recurring: new FormControl(trigger.schedule_is_recurring), + schedule_recurring_interval_days: new FormControl( + trigger.schedule_recurring_interval_days + ), schedule_date_field: new FormControl(trigger.schedule_date_field), schedule_date_custom_field: new FormControl( trigger.schedule_date_custom_field @@ -450,6 +453,7 @@ export class WorkflowEditDialogComponent is_insensitive: true, schedule_offset_days: 0, schedule_is_recurring: false, + schedule_recurring_interval_days: 1, schedule_date_field: ScheduleDateField.Added, schedule_date_custom_field: null, } diff --git a/src-ui/src/app/data/workflow-trigger.ts b/src-ui/src/app/data/workflow-trigger.ts index c782d0903..12f76b7a3 100644 --- a/src-ui/src/app/data/workflow-trigger.ts +++ b/src-ui/src/app/data/workflow-trigger.ts @@ -47,6 +47,8 @@ export interface WorkflowTrigger extends ObjectWithId { schedule_is_recurring?: boolean + schedule_recurring_interval_days?: number + schedule_date_field?: ScheduleDateField schedule_date_custom_field?: number // CustomField.id diff --git a/src/documents/migrations/1057_workflowtrigger_schedule_date_custom_field_and_more.py b/src/documents/migrations/1057_workflowtrigger_schedule_date_custom_field_and_more.py index 6acd5c1e7..fa3e68100 100644 --- a/src/documents/migrations/1057_workflowtrigger_schedule_date_custom_field_and_more.py +++ b/src/documents/migrations/1057_workflowtrigger_schedule_date_custom_field_and_more.py @@ -1,5 +1,6 @@ -# Generated by Django 5.1.1 on 2024-10-24 04:15 +# Generated by Django 5.1.1 on 2024-11-05 05:19 +import django.core.validators import django.db.models.deletion import django.utils.timezone from django.db import migrations @@ -57,6 +58,16 @@ class Migration(migrations.Migration): verbose_name="schedule offset days", ), ), + migrations.AddField( + model_name="workflowtrigger", + name="schedule_recurring_interval_days", + field=models.PositiveIntegerField( + default=1, + help_text="The number of days between recurring schedule triggers.", + validators=[django.core.validators.MinValueValidator(1)], + verbose_name="schedule recurring delay in days", + ), + ), migrations.AlterField( model_name="workflowtrigger", name="type", diff --git a/src/documents/models.py b/src/documents/models.py index 582985470..6366dab03 100644 --- a/src/documents/models.py +++ b/src/documents/models.py @@ -1121,6 +1121,15 @@ class WorkflowTrigger(models.Model): ), ) + schedule_recurring_interval_days = models.PositiveIntegerField( + _("schedule recurring delay in days"), + default=1, + validators=[MinValueValidator(1)], + help_text=_( + "The number of days between recurring schedule triggers.", + ), + ) + schedule_date_field = models.CharField( _("schedule date field"), max_length=20, diff --git a/src/documents/serialisers.py b/src/documents/serialisers.py index 04e2867be..84cab229c 100644 --- a/src/documents/serialisers.py +++ b/src/documents/serialisers.py @@ -1754,6 +1754,7 @@ class WorkflowTriggerSerializer(serializers.ModelSerializer): "filter_has_document_type", "schedule_offset_days", "schedule_is_recurring", + "schedule_recurring_interval_days", "schedule_date_field", "schedule_date_custom_field", ] diff --git a/src/documents/tasks.py b/src/documents/tasks.py index bd6a1e716..1ddd631d9 100644 --- a/src/documents/tasks.py +++ b/src/documents/tasks.py @@ -397,14 +397,16 @@ def check_scheduled_workflows(): trigger.schedule_is_recurring and workflow_runs.exists() and ( - workflow_runs.last().run_at > timezone.now() - offset_td - or workflow_runs.last().run_at - > timezone.now() - timedelta(days=1) + workflow_runs.last().run_at + > timezone.now() + - timedelta( + days=trigger.schedule_recurring_interval_days, + ) ) ): - # schedule is recurring but the last run was within the offset or within 24 hours of the last run + # schedule is recurring but the last run was within the number of recurring interval days logger.debug( - f"Skipping document {document} for recurring workflow {workflow} as the last run was within the offset", + f"Skipping document {document} for recurring workflow {workflow} as the last run was within the recurring interval", ) continue run_workflows( diff --git a/src/documents/tests/test_workflows.py b/src/documents/tests/test_workflows.py index fd7db1041..03de5e1c9 100644 --- a/src/documents/tests/test_workflows.py +++ b/src/documents/tests/test_workflows.py @@ -1526,8 +1526,8 @@ class TestWorkflows(DirectoriesMixin, FileSystemAssertsMixin, APITestCase): def test_workflow_scheduled_trigger_too_early(self): """ GIVEN: - - Existing workflow with SCHEDULED trigger and offset of 30 days - - Workflow run date is 20 days ago + - Existing workflow with SCHEDULED trigger and recurring interval of 7 days + - Workflow run date is 6 days ago WHEN: - Scheduled workflows are checked THEN: @@ -1538,6 +1538,7 @@ class TestWorkflows(DirectoriesMixin, FileSystemAssertsMixin, APITestCase): schedule_offset_days=30, schedule_date_field=WorkflowTrigger.ScheduleDateField.CREATED, schedule_is_recurring=True, + schedule_recurring_interval_days=7, ) action = WorkflowAction.objects.create( assign_title="Doc assign owner", @@ -1562,12 +1563,15 @@ class TestWorkflows(DirectoriesMixin, FileSystemAssertsMixin, APITestCase): workflow=w, document=doc, type=WorkflowTrigger.WorkflowTriggerType.SCHEDULED, - run_at=timezone.now() - timedelta(days=20), + run_at=timezone.now() - timedelta(days=6), ) with self.assertLogs(level="DEBUG") as cm: tasks.check_scheduled_workflows() - self.assertIn("last run was within the offset", " ".join(cm.output)) + self.assertIn( + "last run was within the recurring interval", + " ".join(cm.output), + ) doc.refresh_from_db() self.assertIsNone(doc.owner)