mirror of
https://github.com/paperless-ngx/paperless-ngx.git
synced 2026-10-07 08:37:13 +00:00
Feature: store barcode contents, list and search them (#14276)
* Feature: store barcode contents, list and search them New setting PAPERLESS_CONSUMER_STORE_BARCODE_VALUES (off by default) stores all barcodes found during consumption with the document: page, type and content. They are listed on the metadata tab with a copy button, returned by the documents API and searchable with barcodes: in the advanced search. Versions keep their own barcodes, reprocessing reads them again. Refs #9898 * Tests: cover the remaining barcode branches Covers unchanged and failing barcode reads on reprocessing, unsupported files and DocumentBarcode.__str__, and uses toHaveLength in the barcode list spec as suggested by SonarCloud. * Address review: keep barcodes when they can't be read, format choices - Reprocessing and new versions keep the stored barcodes when the file can't be scanned or the scan fails, and replace them atomically. - Format is a TextChoices of the zxing-cpp formats, with a test. - Shared scan code, latest_version helper, TypedDict, serializer reuse. - Barcodes in the split manifest, export/import tests, pytest-style tests. * Barcode tests: TIFF reprocess, format check both ways, fixtures - Reprocessing a TIFF with TIFF support off keeps the stored barcodes. - The format test also fails when zxing-cpp drops a format. - Fixtures in place of the sample dir mixin, plugin-level disabled test. - Format labels aren't translated, OpenAPI enum named BarcodeFormatEnum. * Review: module-level zxing reader, shorter barcode docs - read_barcodes_zxing is a module-level function used by scan_pdf. - Drop the trivial __str__ test, mark it no cover. - Shorten the barcode docs and remove the duplicate in configuration.md. * Fix header * Use utility class * Return barcodes from the metadata endpoint only Drop the barcodes field and its prefetches from the document serializer, as agreed in the review. Also remove the now empty component stylesheet. --------- Co-authored-by: shamoon <4887959+shamoon@users.noreply.github.com>
This commit is contained in:
1 parent
312684aef3
commit
62cc31fbdb
37 files changed
+1196
-80
No files matched your search
@@ -0,0 +1,95 @@
|
||||
"""Stored barcode contents in the search index.
|
||||
|
||||
Barcodes are a JSON field like notes and custom fields: barcodes: resolves to
|
||||
barcodes.value:, and a plain query without the prefix does not look at them.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
import pytest
|
||||
|
||||
from documents.models import DocumentBarcode
|
||||
from paperless_testing.factories import DocumentBarcodeFactory
|
||||
from paperless_testing.factories import DocumentFactory
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from collections.abc import Callable
|
||||
|
||||
from documents.models import Document
|
||||
from documents.search._backend import TantivyBackend
|
||||
|
||||
pytestmark = [pytest.mark.search, pytest.mark.django_db]
|
||||
|
||||
|
||||
class TestBarcodeSearch:
|
||||
@pytest.fixture
|
||||
def with_barcodes(self, backend: TantivyBackend) -> Document:
|
||||
document = DocumentFactory(title="Letter", content="x")
|
||||
DocumentBarcodeFactory(
|
||||
document=document,
|
||||
value="WIFI:T:WPA;S:Guest-WLAN;P:crocodile123;;",
|
||||
)
|
||||
DocumentBarcodeFactory(
|
||||
document=document,
|
||||
page=2,
|
||||
value="DE89370400440532013000",
|
||||
format=DocumentBarcode.Format.CODE128,
|
||||
)
|
||||
backend.add_or_update(document)
|
||||
return document
|
||||
|
||||
def test_bare_barcodes_prefix_searches_values(
|
||||
self,
|
||||
with_barcodes: Document,
|
||||
index_document: Callable[..., Document],
|
||||
matched_ids: Callable[[str], set[int]],
|
||||
) -> None:
|
||||
"""
|
||||
GIVEN:
|
||||
- A document with stored barcodes, and a decoy document whose
|
||||
content (not a barcode) contains the same word
|
||||
WHEN:
|
||||
- A bare "barcodes:" prefix query is run
|
||||
THEN:
|
||||
- Only the document whose barcode matches is returned, also for a
|
||||
part of a barcode between separators
|
||||
"""
|
||||
index_document(title="Decoy", content="crocodile123 in the text")
|
||||
|
||||
assert matched_ids("barcodes:crocodile123") == {with_barcodes.pk}
|
||||
assert matched_ids("barcodes.value:DE89370400440532013000") == {
|
||||
with_barcodes.pk,
|
||||
}
|
||||
|
||||
def test_barcodes_format_subpath(
|
||||
self,
|
||||
with_barcodes: Document,
|
||||
matched_ids: Callable[[str], set[int]],
|
||||
) -> None:
|
||||
"""
|
||||
GIVEN:
|
||||
- A document with a QR code and a Code 128 barcode
|
||||
WHEN:
|
||||
- The format subpath is queried
|
||||
THEN:
|
||||
- The document is found by its barcode formats
|
||||
"""
|
||||
assert matched_ids("barcodes.format:qrcode") == {with_barcodes.pk}
|
||||
assert matched_ids("barcodes.format:aztec") == set()
|
||||
|
||||
def test_plain_query_ignores_barcodes(
|
||||
self,
|
||||
with_barcodes: Document,
|
||||
matched_ids: Callable[[str], set[int]],
|
||||
) -> None:
|
||||
"""
|
||||
GIVEN:
|
||||
- A document with a barcode value not found in its text
|
||||
WHEN:
|
||||
- The value is searched without a field prefix
|
||||
THEN:
|
||||
- Nothing is found, as with notes and custom fields
|
||||
"""
|
||||
assert matched_ids("crocodile123") == set()
|
||||
Reference in new issue
Block a user