Bah, deal with ASNs

This commit is contained in:
shamoon
2026-08-18 13:25:16 -07:00
parent d0ba5d7745
commit 95a2aa9a6e
3 changed files with 74 additions and 2 deletions
+24 -2
View File
@@ -651,11 +651,19 @@ def merge_as_versions(
or 0
)
# A version gives up its ASN
source_asns = [
documents_by_id[source_id].archive_serial_number
for source_id in source_ids
if documents_by_id[source_id].archive_serial_number is not None
]
for source_id in source_ids:
source_document = documents_by_id[source_id]
next_version_index += 1
source_document.root_document = root_document
source_document.version_index = next_version_index
source_document.archive_serial_number = None
update_fields = [
"root_document",
"version_index",
@@ -664,11 +672,25 @@ def merge_as_versions(
if version_label is not None:
source_document.version_label = version_label
update_fields.append("version_label")
source_document.archive_serial_number = None
source_document.save(update_fields=update_fields)
root_update_fields = ["modified"]
if source_asns and root_document.archive_serial_number is None:
# If a version had one, hand the ASN over, the same as merge() does
root_document.archive_serial_number = source_asns.pop(0)
root_update_fields.append("archive_serial_number")
logger.info(
f"Document {root_document.id} took archive serial number "
f"{root_document.archive_serial_number} from a document merged into it",
)
if source_asns:
logger.warning(
f"Archive serial number(s) {source_asns} were removed by merging "
f"those documents as versions of document {root_document.id}",
)
root_document.modified = timezone.now()
root_document.save(update_fields=["modified"])
root_document.save(update_fields=root_update_fields)
for source_id in source_ids:
remove_document_from_index.apply_async(args=[source_id])
@@ -223,6 +223,8 @@ class TestMergeDocumentsAsVersions(TestCase):
self.assertEqual(source1.version_index, 4)
self.assertIsNone(source1.archive_serial_number)
self.assertIsNone(source2.archive_serial_number)
# The root had no ASN of its own, so it takes the first one
self.assertEqual(root.archive_serial_number, 1)
self.assertGreater(root.modified, original_modified)
self.assertEqual(existing_version.root_document_id, root.id)
@@ -238,6 +240,52 @@ class TestMergeDocumentsAsVersions(TestCase):
[source1.id, source2.id],
)
@mock.patch("documents.bulk_edit.DocumentsStatusManager")
@mock.patch("documents.bulk_edit.bulk_update_documents.apply_async")
@mock.patch("documents.bulk_edit.remove_document_from_index.apply_async")
def test_root_keeps_its_own_archive_serial_number(self, *_mocks) -> None:
root = Document.objects.create(
checksum="A",
title="Root",
archive_serial_number=1,
)
source = Document.objects.create(
checksum="B",
title="Source",
archive_serial_number=2,
)
with self.assertLogs("paperless.bulk_edit", level="WARNING") as logs:
merge_as_versions([root.id, source.id], root_document_id=root.id)
root.refresh_from_db()
source.refresh_from_db()
self.assertEqual(root.archive_serial_number, 1)
self.assertIsNone(source.archive_serial_number)
# Dropping an ASN is not silent
self.assertIn("[2]", logs.output[0])
@mock.patch("documents.bulk_edit.DocumentsStatusManager")
@mock.patch("documents.bulk_edit.bulk_update_documents.apply_async")
@mock.patch("documents.bulk_edit.remove_document_from_index.apply_async")
def test_root_without_asn_takes_the_source_archive_serial_number(
self,
*_mocks,
) -> None:
root = Document.objects.create(checksum="A", title="Root")
source = Document.objects.create(
checksum="B",
title="Source",
archive_serial_number=7,
)
merge_as_versions([root.id, source.id], root_document_id=root.id)
root.refresh_from_db()
source.refresh_from_db()
self.assertEqual(root.archive_serial_number, 7)
self.assertIsNone(source.archive_serial_number)
@mock.patch("documents.bulk_edit.DocumentsStatusManager")
@mock.patch("documents.bulk_edit.bulk_update_documents.apply_async")
@mock.patch("documents.bulk_edit.remove_document_from_index.apply_async")