diff --git a/README.md b/README.md index a5855b5..2383aeb 100644 --- a/README.md +++ b/README.md @@ -64,7 +64,9 @@ damit interne Dokumentdaten nicht unbeabsichtigt über einen Proxy laufen. SHA-256-Prüfsummen und SQLite verhindern, dass erfolgreich verarbeitete Inhalte erneut verarbeitet werden. Bestehende Zieldateien werden nicht überschrieben; bei Kollisionen wird `_02`, `_03` usw. ergänzt. Eine Prozesssperre verhindert parallele -Läufe auf derselben Installation. +Läufe auf derselben Installation. Entsteht während eines Laufs kein neuer +Protokolleintrag, wird `protokoll.xlsx` weder lokal neu erzeugt noch erneut zu +Nextcloud hochgeladen. ## Installation auf einer Linux-VM diff --git a/pyproject.toml b/pyproject.toml index e6ecc62..8c7afbd 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "hatchling.build" [project] name = "orc-renaming" -version = "0.4.0" +version = "0.4.1" description = "Lokale, datenschutzfreundliche Benennung gescannter PDF-Dokumente" readme = "README.md" requires-python = ">=3.11" diff --git a/src/orc_renaming/__init__.py b/src/orc_renaming/__init__.py index f41e660..9ca4af5 100644 --- a/src/orc_renaming/__init__.py +++ b/src/orc_renaming/__init__.py @@ -1,3 +1,3 @@ """Lokale Dokumentklassifikation und PDF-Benennung.""" -__version__ = "0.4.0" +__version__ = "0.4.1" diff --git a/src/orc_renaming/ledger.py b/src/orc_renaming/ledger.py index 8ee9bf8..874b330 100644 --- a/src/orc_renaming/ledger.py +++ b/src/orc_renaming/ledger.py @@ -91,6 +91,12 @@ class Ledger: ).fetchone() return row is not None + def entry_count(self) -> int: + row = self.connection.execute( + "SELECT COUNT(*) AS count FROM processing_log" + ).fetchone() + return int(row["count"]) + def add(self, record: ProcessingRecord) -> None: values = record.model_dump(mode="json") values["evidence"] = json.dumps( diff --git a/src/orc_renaming/pipeline.py b/src/orc_renaming/pipeline.py index 7d15a0b..fa7082b 100644 --- a/src/orc_renaming/pipeline.py +++ b/src/orc_renaming/pipeline.py @@ -301,6 +301,7 @@ class Pipeline: return status def run(self) -> dict[str, int]: + entries_before_run = self.ledger.entry_count() upload_report = ( not self.config.processing.dry_run or self.config.processing.upload_excel_in_dry_run @@ -342,6 +343,12 @@ class Pipeline: status = "error" counters[status] = counters.get(status, 0) + 1 + if self.ledger.entry_count() == entries_before_run: + LOGGER.info( + "Protokoll unverändert; Excel-Export und Nextcloud-Upload übersprungen" + ) + return counters + excel_path = ( self.config.processing.state_directory / self.config.processing.excel_filename diff --git a/tests/test_pipeline.py b/tests/test_pipeline.py index e3b1430..e8046ad 100644 --- a/tests/test_pipeline.py +++ b/tests/test_pipeline.py @@ -4,7 +4,12 @@ from datetime import date from pathlib import Path import orc_renaming.pipeline as pipeline_module -from orc_renaming.models import DocumentScope, DocumentType, ExtractionResult +from orc_renaming.models import ( + DocumentScope, + DocumentType, + ExtractionResult, + ProcessingRecord, +) from orc_renaming.normalize import result_is_complete from orc_renaming.pipeline import Pipeline from orc_renaming.webdav import RemoteFile @@ -111,6 +116,44 @@ def test_live_run_uploads_pdf_report_and_archives(config, monkeypatch) -> None: assert config.nextcloud.review_folder in folders +def test_empty_run_does_not_write_or_upload_report(config, monkeypatch) -> None: + _prepare(monkeypatch) + + with Pipeline(config) as pipeline: + pipeline.webdav.list_pdfs = lambda _folder: [] + counters = pipeline.run() + uploads = list(pipeline.webdav.uploads) + + assert counters == {} + assert uploads == [] + assert not (config.processing.state_directory / "protokoll.xlsx").exists() + + +def test_skipped_files_do_not_rewrite_report(config, monkeypatch) -> None: + _prepare(monkeypatch) + report_path = config.processing.state_directory / "protokoll.xlsx" + + with Pipeline(config) as pipeline: + pipeline.ledger.add( + ProcessingRecord( + remote_path="/Scanner/Eingang/scan001.pdf", + original_name="scan001.pdf", + checksum="abc123", + status="success", + ) + ) + pipeline.ledger.export_xlsx(report_path) + report_before = report_path.read_bytes() + + counters = pipeline.run() + uploads = list(pipeline.webdav.uploads) + report_after = report_path.read_bytes() + + assert counters == {"skipped": 1} + assert uploads == [] + assert report_after == report_before + + def test_ollama_fallback_is_only_used_after_incomplete_primary( config, monkeypatch ) -> None: