diff --git a/app/modules/bank_statement_analyzer/service.py b/app/modules/bank_statement_analyzer/service.py index 6336da0..b7e59d9 100644 --- a/app/modules/bank_statement_analyzer/service.py +++ b/app/modules/bank_statement_analyzer/service.py @@ -272,16 +272,9 @@ def _process_job(job_id: str) -> None: "financial_year": job.financial_year or "", "classification_enabled": job.classification_enabled, } - for path in paths: - try: - path.unlink(missing_ok=True) - except OSError: - pass - input_dir = Path(job.job_directory) / "Input" - try: - input_dir.rmdir() - except OSError: - pass + # Keep the original uploaded statements until the job expiry time. + # This applies equally to completed and failed jobs and allows the + # uploader to reproduce parser issues during the 24-hour retention window. job.output_file = str(output) job.summary_json = json.dumps(summary) job.status = "completed" @@ -399,6 +392,36 @@ def list_user_jobs(user_id: int, limit: int = 25) -> list[BankStatementAnalysisJ db.close() +def original_statement_files(job: BankStatementAnalysisJob) -> list[Path]: + """Return retained input PDFs that still belong to the job directory.""" + job_root = Path(job.job_directory).resolve() + input_root = (job_root / "Input").resolve() + try: + configured = [Path(value).resolve() for value in json.loads(job.input_files_json or "[]")] + except (TypeError, ValueError, json.JSONDecodeError): + configured = [] + + retained: list[Path] = [] + for path in configured: + try: + path.relative_to(input_root) + except ValueError: + continue + if path.is_file() and path.suffix.lower() == ".pdf": + retained.append(path) + return retained + + +def get_owned_original_statement(user_id: int, job_id: str, file_index: int) -> tuple[BankStatementAnalysisJob, Path] | None: + job = get_owned_job(user_id, job_id) + if not job or job.status not in {"completed", "failed"}: + return None + files = original_statement_files(job) + if file_index < 1 or file_index > len(files): + return None + return job, files[file_index - 1] + + def job_view(job: BankStatementAnalysisJob) -> dict: return { "id": job.id, @@ -415,6 +438,11 @@ def job_view(job: BankStatementAnalysisJob) -> dict: "estimated_wait": estimated_wait(job), "summary": _summary(job), "download_ready": job.status == "completed" and bool(job.output_file) and Path(job.output_file).is_file(), + "original_files": [ + {"index": index, "name": path.name} + for index, path in enumerate(original_statement_files(job), start=1) + ], + "originals_retained": job.status in {"completed", "failed"} and bool(original_statement_files(job)), } diff --git a/app/modules/bank_statement_analyzer/templates/bank_statement_analyzer/index.html b/app/modules/bank_statement_analyzer/templates/bank_statement_analyzer/index.html index ecb5cc6..02a6f93 100644 --- a/app/modules/bank_statement_analyzer/templates/bank_statement_analyzer/index.html +++ b/app/modules/bank_statement_analyzer/templates/bank_statement_analyzer/index.html @@ -13,21 +13,14 @@
@@ -37,8 +30,8 @@The workbook remains available until {{ active_job.expires_at or '24 hours after completion' }}.
The workbook and original statement{{ 's' if active_job.file_count != 1 else '' }} remain available until {{ active_job.expires_at or '24 hours after completion' }}.
Original statement{{ 's are' if active_job.file_count != 1 else ' is' }} retained until {{ active_job.expires_at or '24 hours after failure' }} for debugging.
{% endif %}Analyze another statementQueued, processing, completed and failed bank-statement analyses.
| Submitted | Bank | Files | Status | Estimate / Expiry | Action |
|---|---|---|---|---|---|
| {{ item.submitted_at }} | {{ item.selected_bank|replace('_',' ')|title }} | {{ item.file_count }} | {{ item.status|title }}{% if item.queue_position %} Queue position {{ item.queue_position }} {% endif %} | {% if item.status in ['queued','processing'] %}{{ item.estimated_wait }}{% elif item.status == 'completed' %}Available for 24 hours{% else %}{{ item.error_message[:80] }}{% endif %} | |
| No analysis jobs yet. | |||||
Queued, processing, completed and failed bank-statement analyses.
| Submitted | Bank | Files | Status | Estimate / Expiry | Action |
|---|---|---|---|---|---|
| {{ item.submitted_at }} | {{ item.selected_bank|replace('_',' ')|title }} | {{ item.file_count }} | {{ item.status|title }}{% if item.queue_position %} Queue position {{ item.queue_position }} {% endif %} | {% if item.status in ['queued','processing'] %}{{ item.estimated_wait }}{% elif item.status == 'completed' %}Workbook and statements available until {{ item.expires_at or '24 hours' }}{% elif item.status == 'failed' %}Statements retained until {{ item.expires_at or '24 hours' }}{% else %}{{ item.error_message[:80] }}{% endif %} | View{% if item.download_ready %}Download Excel{% endif %}{% for file in item.original_files %}Statement {{ file.index }}{% endfor %}{% if item.status != 'processing' %}{% endif %} |
| No analysis jobs yet. | |||||