diff --git a/src/documents/tests/test_workflows.py b/src/documents/tests/test_workflows.py index 329ed0af0..f3dace48f 100644 --- a/src/documents/tests/test_workflows.py +++ b/src/documents/tests/test_workflows.py @@ -2938,6 +2938,69 @@ class TestWorkflows( self.assertFalse(doc.tags.filter(pk=self.t1.pk).exists()) self.assertTrue(doc.tags.filter(pk=self.t2.pk).exists()) + def test_document_updated_workflow_assignment_storage_path_persists_with_tag_assignment( + self, + ) -> None: + """ + GIVEN: + - A document updated workflow filtered on a tag + - One assignment action assigns a storage path, a second (later-ordered) + assignment action adds a tag + WHEN: + - The document is updated and the workflow is triggered + THEN: + - Both the tag and the storage path are persisted + """ + trigger = WorkflowTrigger.objects.create( + type=WorkflowTrigger.WorkflowTriggerType.DOCUMENT_UPDATED, + ) + trigger.filter_has_tags.add(self.t1) + assign_storage_path = WorkflowAction.objects.create( + type=WorkflowAction.WorkflowActionType.ASSIGNMENT, + assign_storage_path=self.sp, + order=0, + ) + assign_tag = WorkflowAction.objects.create( + type=WorkflowAction.WorkflowActionType.ASSIGNMENT, + order=1, + ) + assign_tag.assign_tags.add(self.t2) + assign_tag.save() + + workflow = Workflow.objects.create( + name="Workflow assign storage path then tag", + order=0, + ) + workflow.triggers.add(trigger) + workflow.actions.add(assign_storage_path, assign_tag) + workflow.save() + + doc = Document.objects.create( + title="sample test", + mime_type="application/pdf", + checksum="assign-tag-and-storage-path", + original_filename="sample.pdf", + ) + generated = generate_unique_filename(doc) + destination = (settings.ORIGINALS_DIR / generated).resolve() + create_source_path_directory(destination) + shutil.copy(self.SAMPLE_DIR / "simple.pdf", destination) + Document.objects.filter(pk=doc.pk).update(filename=generated.as_posix()) + doc.refresh_from_db() + doc.tags.set([self.t1]) + + superuser = User.objects.create_superuser("superuser") + self.client.force_authenticate(user=superuser) + self.client.patch( + f"/api/documents/{doc.id}/", + {"title": "user update to trigger workflow"}, + format="json", + ) + + doc.refresh_from_db() + self.assertEqual(doc.storage_path, self.sp) + self.assertTrue(doc.tags.filter(pk=self.t2.pk).exists()) + def test_removal_action_document_updated_removeall(self) -> None: """ GIVEN: diff --git a/src/documents/workflows/mutations.py b/src/documents/workflows/mutations.py index 7dbb317a8..7d33bc545 100644 --- a/src/documents/workflows/mutations.py +++ b/src/documents/workflows/mutations.py @@ -24,7 +24,11 @@ def apply_assignment_to_document( action: WorkflowAction, annotated with 'has_assign_*' boolean fields """ if action.has_assign_tags: - document.add_nested_tags(action.assign_tags.all()) + # Apply to a freshly-fetched instance rather than the shared `document`. + # Document.tags.add() fires an m2m_changed signal that ultimately calls + # instance.refresh_from_db(), which would discard any other unsaved + # assignment fields (e.g. storage_path) already staged on `document`. + Document.objects.get(pk=document.pk).add_nested_tags(action.assign_tags.all()) if action.assign_correspondent: document.correspondent = action.assign_correspondent