From 7604a0b583c32982552c9964a1ecaa8825bdb9a1 Mon Sep 17 00:00:00 2001 From: shamoon <4887959+shamoon@users.noreply.github.com> Date: Fri, 19 Dec 2025 20:05:34 -0800 Subject: [PATCH] Fix: prevent ASN collisions for merge operations (#11634) --- src/documents/barcodes.py | 6 +++++- src/documents/bulk_edit.py | 2 ++ src/documents/consumer.py | 6 +++--- src/documents/data_models.py | 3 +++ src/documents/tests/test_bulk_edit.py | 3 +++ src/documents/tests/test_consumer.py | 8 ++++++++ 6 files changed, 24 insertions(+), 4 deletions(-) diff --git a/src/documents/barcodes.py b/src/documents/barcodes.py index 9054475f4..f3c693edf 100644 --- a/src/documents/barcodes.py +++ b/src/documents/barcodes.py @@ -186,7 +186,11 @@ class BarcodePlugin(ConsumeTaskPlugin): # Update/overwrite an ASN if possible # After splitting, as otherwise each split document gets the same ASN - if self.settings.barcode_enable_asn and (located_asn := self.asn) is not None: + if ( + self.settings.barcode_enable_asn + and not self.metadata.skip_asn + and (located_asn := self.asn) is not None + ): logger.info(f"Found ASN in barcode: {located_asn}") self.metadata.asn = located_asn diff --git a/src/documents/bulk_edit.py b/src/documents/bulk_edit.py index 73cc47990..219947d09 100644 --- a/src/documents/bulk_edit.py +++ b/src/documents/bulk_edit.py @@ -433,6 +433,8 @@ def merge( if user is not None: overrides.owner_id = user.id + # Avoid copying or detecting ASN from merged PDFs to prevent collision + overrides.skip_asn = True logger.info("Adding merged document to the task queue.") diff --git a/src/documents/consumer.py b/src/documents/consumer.py index 86641a243..2c1cf025b 100644 --- a/src/documents/consumer.py +++ b/src/documents/consumer.py @@ -696,7 +696,7 @@ class ConsumerPlugin( pk=self.metadata.storage_path_id, ) - if self.metadata.asn is not None: + if self.metadata.asn is not None and not self.metadata.skip_asn: document.archive_serial_number = self.metadata.asn if self.metadata.owner_id: @@ -812,8 +812,8 @@ class ConsumerPreflightPlugin( """ Check that if override_asn is given, it is unique and within a valid range """ - if self.metadata.asn is None: - # check not necessary in case no ASN gets set + if self.metadata.skip_asn or self.metadata.asn is None: + # if skip is set or ASN is None return # Validate the range is above zero and less than uint32_t max # otherwise, Whoosh can't handle it in the index diff --git a/src/documents/data_models.py b/src/documents/data_models.py index 7f98a1f05..ffb816053 100644 --- a/src/documents/data_models.py +++ b/src/documents/data_models.py @@ -30,6 +30,7 @@ class DocumentMetadataOverrides: change_users: list[int] | None = None change_groups: list[int] | None = None custom_fields: dict | None = None + skip_asn: bool = False def update(self, other: "DocumentMetadataOverrides") -> "DocumentMetadataOverrides": """ @@ -49,6 +50,8 @@ class DocumentMetadataOverrides: self.storage_path_id = other.storage_path_id if other.owner_id is not None: self.owner_id = other.owner_id + if other.skip_asn: + self.skip_asn = True # merge if self.tag_ids is None: diff --git a/src/documents/tests/test_bulk_edit.py b/src/documents/tests/test_bulk_edit.py index e1379386f..769ff9d66 100644 --- a/src/documents/tests/test_bulk_edit.py +++ b/src/documents/tests/test_bulk_edit.py @@ -602,11 +602,13 @@ class TestPDFActions(DirectoriesMixin, TestCase): expected_filename, ) self.assertEqual(consume_file_args[1].title, None) + self.assertTrue(consume_file_args[1].skip_asn) # With metadata_document_id overrides result = bulk_edit.merge(doc_ids, metadata_document_id=metadata_document_id) consume_file_args, _ = mock_consume_file.call_args self.assertEqual(consume_file_args[1].title, "A (merged)") + self.assertTrue(consume_file_args[1].skip_asn) self.assertEqual(result, "OK") @@ -647,6 +649,7 @@ class TestPDFActions(DirectoriesMixin, TestCase): expected_filename, ) self.assertEqual(consume_file_args[1].title, None) + self.assertTrue(consume_file_args[1].skip_asn) delete_documents_args, _ = mock_delete_documents.call_args self.assertEqual( diff --git a/src/documents/tests/test_consumer.py b/src/documents/tests/test_consumer.py index 6387b5e95..63d6f8f5b 100644 --- a/src/documents/tests/test_consumer.py +++ b/src/documents/tests/test_consumer.py @@ -412,6 +412,14 @@ class TestConsumer( self.assertEqual(document.archive_serial_number, 123) self._assert_first_last_send_progress() + def testMetadataOverridesSkipAsnPropagation(self): + overrides = DocumentMetadataOverrides() + incoming = DocumentMetadataOverrides(skip_asn=True) + + overrides.update(incoming) + + self.assertTrue(overrides.skip_asn) + def testOverrideTitlePlaceholders(self): c = Correspondent.objects.create(name="Correspondent Name") dt = DocumentType.objects.create(name="DocType Name")