Fix: restore expected pre-2.16 scheduled workflow offset behavior (#10218)

This commit is contained in:
shamoon 2025-06-19 07:47:54 -07:00 committed by GitHub
parent 07882b918b
commit 3b069ac034
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 72 additions and 26 deletions

View File

@ -408,7 +408,7 @@ Currently, there are three events that correspond to workflow trigger 'types':
tags, doc type, or correspondent. tags, doc type, or correspondent.
4. **Scheduled**: a scheduled trigger that can be used to run workflows at a specific time. The date used can be either the document 4. **Scheduled**: a scheduled trigger that can be used to run workflows at a specific time. The date used can be either the document
added, created, updated date or you can specify a (date) custom field. You can also specify a day offset from the date (positive added, created, updated date or you can specify a (date) custom field. You can also specify a day offset from the date (positive
offsets will trigger before the date, negative offsets will trigger after). offsets will trigger after the date, negative offsets will trigger before).
The following flow diagram illustrates the three document trigger types: The following flow diagram illustrates the three document trigger types:

View File

@ -129,7 +129,7 @@
formControlName="schedule_offset_days" formControlName="schedule_offset_days"
[showAdd]="false" [showAdd]="false"
[error]="error?.schedule_offset_days" [error]="error?.schedule_offset_days"
hint="Positive values will trigger the workflow before the date, negative values after." hint="Positive values will trigger after the date, negative values before."
i18n-hint i18n-hint
></pngx-input-number> ></pngx-input-number>
</div> </div>

View File

@ -420,7 +420,7 @@ def check_scheduled_workflows():
trigger: WorkflowTrigger trigger: WorkflowTrigger
for trigger in schedule_triggers: for trigger in schedule_triggers:
documents = Document.objects.none() documents = Document.objects.none()
offset_td = datetime.timedelta(days=-trigger.schedule_offset_days) offset_td = datetime.timedelta(days=trigger.schedule_offset_days)
threshold = now - offset_td threshold = now - offset_td
logger.debug( logger.debug(
f"Trigger {trigger.id}: checking if (date + {offset_td}) <= now ({now})", f"Trigger {trigger.id}: checking if (date + {offset_td}) <= now ({now})",

View File

@ -1614,13 +1614,14 @@ class TestWorkflows(
def test_workflow_scheduled_trigger_negative_offset_customfield(self): def test_workflow_scheduled_trigger_negative_offset_customfield(self):
""" """
GIVEN: GIVEN:
- Existing workflow with SCHEDULED trigger and negative offset of -7 days (so 7 days after date) - Workflow with offset -7 (i.e., 7 days *before* the date)
- Custom field date initially set to 5 days ago trigger time = 2 days in future - doc1: value_date = 5 days ago trigger time = 12 days ago triggers
- Then updated to 8 days ago trigger time = 1 day ago - doc2: value_date = 9 days in future trigger time = 2 days in future does NOT trigger
WHEN: WHEN:
- Scheduled workflows are checked for document with custom field date 8 days in the past - Scheduled workflows are checked
THEN: THEN:
- Workflow runs and document owner is updated - doc1 has owner assigned
- doc2 remains untouched
""" """
trigger = WorkflowTrigger.objects.create( trigger = WorkflowTrigger.objects.create(
type=WorkflowTrigger.WorkflowTriggerType.SCHEDULED, type=WorkflowTrigger.WorkflowTriggerType.SCHEDULED,
@ -1640,38 +1641,49 @@ class TestWorkflows(
w.actions.add(action) w.actions.add(action)
w.save() w.save()
doc = Document.objects.create( doc1 = Document.objects.create(
title="sample test", title="doc1",
correspondent=self.c, correspondent=self.c,
original_filename="sample.pdf", original_filename="doc1.pdf",
checksum="doc1-checksum",
) )
cfi = CustomFieldInstance.objects.create( CustomFieldInstance.objects.create(
document=doc, document=doc1,
field=self.cf1, field=self.cf1,
value_date=timezone.now() - timedelta(days=5), value_date=timezone.now().date() - timedelta(days=5),
)
doc2 = Document.objects.create(
title="doc2",
correspondent=self.c,
original_filename="doc2.pdf",
checksum="doc2-checksum",
)
CustomFieldInstance.objects.create(
document=doc2,
field=self.cf1,
value_date=timezone.now().date() + timedelta(days=9),
) )
tasks.check_scheduled_workflows() tasks.check_scheduled_workflows()
doc.refresh_from_db() doc1.refresh_from_db()
self.assertIsNone(doc.owner) # has not triggered yet self.assertEqual(doc1.owner, self.user2)
cfi.value_date = timezone.now() - timedelta(days=8) doc2.refresh_from_db()
cfi.save() self.assertIsNone(doc2.owner)
tasks.check_scheduled_workflows()
doc.refresh_from_db()
self.assertEqual(doc.owner, self.user2)
def test_workflow_scheduled_trigger_negative_offset_created(self): def test_workflow_scheduled_trigger_negative_offset_created(self):
""" """
GIVEN: GIVEN:
- Existing workflow with SCHEDULED trigger and negative offset of -7 days (so 7 days after date) - Existing workflow with SCHEDULED trigger and negative offset of -7 days (so 7 days before date)
- Created date set to 8 days ago trigger time = 1 day ago and 5 days ago - doc created 8 days ago trigger time = 15 days ago triggers
- doc2 created 8 days *in the future* trigger time = 1 day in future does NOT trigger
WHEN: WHEN:
- Scheduled workflows are checked for document - Scheduled workflows are checked for document
THEN: THEN:
- Workflow runs and document owner is updated for the first document, not the second - doc is matched and owner updated
- doc2 is untouched
""" """
trigger = WorkflowTrigger.objects.create( trigger = WorkflowTrigger.objects.create(
type=WorkflowTrigger.WorkflowTriggerType.SCHEDULED, type=WorkflowTrigger.WorkflowTriggerType.SCHEDULED,
@ -1703,7 +1715,7 @@ class TestWorkflows(
correspondent=self.c, correspondent=self.c,
original_filename="sample2.pdf", original_filename="sample2.pdf",
checksum="2", checksum="2",
created=timezone.now().date() - timedelta(days=5), created=timezone.now().date() + timedelta(days=8),
) )
tasks.check_scheduled_workflows() tasks.check_scheduled_workflows()
@ -1712,6 +1724,40 @@ class TestWorkflows(
doc2.refresh_from_db() doc2.refresh_from_db()
self.assertIsNone(doc2.owner) # has not triggered yet self.assertIsNone(doc2.owner) # has not triggered yet
def test_offset_positive_means_after(self):
"""
GIVEN:
- Document created 30 days ago
- Workflow with offset +10
EXPECT:
- It triggers now, because created + 10 = 20 days ago < now
"""
doc = Document.objects.create(
title="Test doc",
created=timezone.now() - timedelta(days=30),
correspondent=self.c,
original_filename="test.pdf",
)
trigger = WorkflowTrigger.objects.create(
type=WorkflowTrigger.WorkflowTriggerType.SCHEDULED,
schedule_date_field=WorkflowTrigger.ScheduleDateField.CREATED,
schedule_offset_days=10,
)
action = WorkflowAction.objects.create(
assign_title="Doc assign owner",
assign_owner=self.user2,
)
w = Workflow.objects.create(
name="Workflow 1",
order=0,
)
w.triggers.add(trigger)
w.actions.add(action)
w.save()
tasks.check_scheduled_workflows()
doc.refresh_from_db()
self.assertEqual(doc.owner, self.user2)
def test_workflow_scheduled_filters_queryset(self): def test_workflow_scheduled_filters_queryset(self):
""" """
GIVEN: GIVEN: