style(orion): align report header footer and page layout
This commit is contained in:
parent
302e542fda
commit
503b343070
40 changed files with 2010 additions and 148 deletions
|
|
@ -1,6 +1,7 @@
|
|||
from __future__ import annotations
|
||||
|
||||
from datetime import date
|
||||
from pathlib import Path
|
||||
|
||||
from sqlalchemy import create_engine
|
||||
from sqlalchemy.orm import Session
|
||||
|
|
@ -14,6 +15,9 @@ from app.models.validation import Validation, ValidationStatus
|
|||
from app.services.validation_workflow import ValidationWorkflowService
|
||||
from app.schemas.domain import ValidationCreate
|
||||
from app.modules.orion.service import OrionReportService
|
||||
from app.modules.orion.assets import SCHUBAMED_LOGO_PATH, schubamed_logo_uri
|
||||
from app.modules.orion.template_service import ReportTemplateService
|
||||
from app.modules.helios.service import HeliosImportService
|
||||
|
||||
|
||||
def session() -> Session:
|
||||
|
|
@ -219,7 +223,217 @@ def test_orion_renders_reference_main_chapters(tmp_path):
|
|||
|
||||
html = OrionReportService(db, tmp_path).render_html(validation.id)
|
||||
|
||||
assert "1. Funktionsqualifikation" in html
|
||||
assert "2.2 Pruefmittel" in html
|
||||
assert "4. Ergebnisse der Validierung" in html
|
||||
assert "9. Kalibrierzertifikate" in html
|
||||
assert "1 Funktionsqualifikation" in html
|
||||
assert "2.2 Prüfmittel" in html
|
||||
assert "4 Ergebnisse der Validierung" in html
|
||||
assert "9. Werkskalibrierzertifikate Sensoren" in html
|
||||
|
||||
|
||||
def test_orion_renders_uploaded_images_as_real_images(tmp_path):
|
||||
db = session()
|
||||
customer, location, device = seed(db)
|
||||
validation = valid_validation(customer, location, device)
|
||||
validation.attachments = [
|
||||
{
|
||||
"category": "Beladung",
|
||||
"filename": "beladung.png",
|
||||
"content_type": "image/png",
|
||||
"description": "Beladungsmuster Testlauf 1",
|
||||
"order": 1,
|
||||
"url": "/uploads/validations/example/beladung.png",
|
||||
}
|
||||
]
|
||||
db.add(validation)
|
||||
db.flush()
|
||||
|
||||
html = OrionReportService(db, tmp_path).render_html(validation.id)
|
||||
|
||||
assert '<img class="report-image"' in html
|
||||
assert "http://localhost:8000/uploads/validations/example/beladung.png" in html
|
||||
assert "Abbildung 1: Beladungsmuster Testlauf 1" in html
|
||||
|
||||
|
||||
def test_weasyprint_renders_minimal_pdf_bytes():
|
||||
from weasyprint import HTML
|
||||
|
||||
pdf_bytes = HTML(string="<html><body><h1>Orion PDF Test</h1></body></html>").write_pdf()
|
||||
|
||||
assert pdf_bytes.startswith(b"%PDF")
|
||||
assert len(pdf_bytes) > 1024
|
||||
|
||||
|
||||
def test_orion_renders_real_pdf_with_logo(tmp_path):
|
||||
db = session()
|
||||
customer, location, device = seed(db)
|
||||
validation = valid_validation(customer, location, device)
|
||||
db.add(validation)
|
||||
db.flush()
|
||||
|
||||
assert SCHUBAMED_LOGO_PATH.exists()
|
||||
html = OrionReportService(db, tmp_path).render_html(validation.id)
|
||||
pdf_path = OrionReportService(db, tmp_path).render_pdf(validation.id)
|
||||
|
||||
assert schubamed_logo_uri() in html
|
||||
assert "Neutraler Logo-Platzhalter" not in html
|
||||
assert pdf_path.read_bytes().startswith(b"%PDF")
|
||||
assert pdf_path.stat().st_size > 1024
|
||||
|
||||
|
||||
def test_orion_header_footer_layout_markers_are_rendered(tmp_path):
|
||||
db = session()
|
||||
customer, location, device = seed(db)
|
||||
validation = valid_validation(customer, location, device)
|
||||
validation.report_number = "SV-2026-00005"
|
||||
db.add(validation)
|
||||
db.flush()
|
||||
|
||||
html = OrionReportService(db, tmp_path).render_html(validation.id)
|
||||
|
||||
assert 'class="report-header"' in html
|
||||
assert 'class="report-header-brand"' in html
|
||||
assert "SCHUBAMED®" in html
|
||||
assert "Aufbereitung mit System" in html
|
||||
assert "SV-2026-00005" in html
|
||||
assert "Version" in html
|
||||
assert "Datum" in html
|
||||
assert 'class="report-footer"' in html
|
||||
assert "Validation Suite" in html
|
||||
assert "Seite" in html
|
||||
assert "page-count" in html
|
||||
|
||||
|
||||
def test_orion_layout_css_reserves_header_footer_space():
|
||||
css = Path("app/modules/orion/templates/report.css").read_text(encoding="utf-8")
|
||||
|
||||
assert "margin: 34mm 18mm 24mm 18mm" in css
|
||||
assert "position: running(report-header)" in css
|
||||
assert "position: running(report-footer)" in css
|
||||
assert "grid-template-columns: 1fr 54mm" in css
|
||||
assert "height: 24mm" in css
|
||||
assert "height: 20mm" in css
|
||||
assert "font-size: 22pt" in css
|
||||
assert "counter(pages)" in css
|
||||
|
||||
|
||||
def test_reference_template_textblocks_and_checklists_are_loaded():
|
||||
db = session()
|
||||
bundle = ReportTemplateService(db).ensure_default_template()
|
||||
|
||||
assert bundle.template.template_key == "small_steam_sterilizer_initial_validation"
|
||||
assert ReportTemplateService(db).reference_path.exists()
|
||||
assert {"summary", "bq_goal", "legal", "performance"} <= set(bundle.text_blocks)
|
||||
assert len(bundle.checklists) >= 6
|
||||
assert any(item.title == "Beschreibung Sterilisator" for item in bundle.checklists)
|
||||
|
||||
|
||||
def test_orion_contains_required_reference_sections_and_three_runs(tmp_path):
|
||||
db = session()
|
||||
customer, location, device = seed(db)
|
||||
validation = valid_validation(customer, location, device)
|
||||
db.add(validation)
|
||||
db.flush()
|
||||
|
||||
html = OrionReportService(db, tmp_path).render_html(validation.id)
|
||||
|
||||
for title in [
|
||||
"Zusammenfassendes Ergebnis der Validierung",
|
||||
"1.1 Anlass und Ziel der Prüfung",
|
||||
"1.2 Gesetzliche Grundlagen",
|
||||
"3.2 Standardbeladung – Testlauf 1",
|
||||
"3.3 Standardbeladung – Testlauf 2",
|
||||
"3.4 Standardbeladung – Testlauf 3",
|
||||
]:
|
||||
assert title in html
|
||||
assert "Neutraler Logo-Platzhalter" not in html
|
||||
assert "report-header-brand" in html
|
||||
|
||||
|
||||
def test_orion_appends_pdf_attachments(tmp_path):
|
||||
from pypdf import PdfReader, PdfWriter
|
||||
|
||||
db = session()
|
||||
customer, location, device = seed(db)
|
||||
validation = valid_validation(customer, location, device)
|
||||
attachment_path = tmp_path / "anlage.pdf"
|
||||
writer = PdfWriter()
|
||||
writer.add_blank_page(width=200, height=200)
|
||||
with attachment_path.open("wb") as handle:
|
||||
writer.write(handle)
|
||||
validation.attachments = [
|
||||
{
|
||||
"category": "Kalibrierschein",
|
||||
"filename": "anlage.pdf",
|
||||
"content_type": "application/pdf",
|
||||
"description": "Anlage",
|
||||
"order": 1,
|
||||
"storage_path": str(attachment_path),
|
||||
}
|
||||
]
|
||||
db.add(validation)
|
||||
db.flush()
|
||||
|
||||
pdf_path = OrionReportService(db, tmp_path).render_pdf(validation.id)
|
||||
|
||||
assert len(PdfReader(str(pdf_path)).pages) >= 2
|
||||
|
||||
|
||||
def test_winlog_pdf_import_preview_and_confirmation(tmp_path):
|
||||
from weasyprint import HTML
|
||||
|
||||
db = session()
|
||||
customer, location, device = seed(db)
|
||||
validation = valid_validation(customer, location, device)
|
||||
db.add(validation)
|
||||
db.flush()
|
||||
pdf_bytes = HTML(
|
||||
string="<p>Vakuumtest</p><p>Programm: Vakuum</p><p>Leckrate: 0,1</p><p>Ergebnis: bestanden</p>"
|
||||
).write_pdf()
|
||||
|
||||
preview = HeliosImportService(db, tmp_path).save_winlog_pdf(
|
||||
validation.id, "winlog.pdf", pdf_bytes
|
||||
)
|
||||
|
||||
assert preview["status"] == "VORSCHAU_BEREIT"
|
||||
assert preview["sha256"]
|
||||
assert any(value["field_name"] == "leak_rate" for value in preview["values"])
|
||||
first = preview["values"][0]
|
||||
confirmed = HeliosImportService(db, tmp_path).confirm_values(
|
||||
preview["id"], [{"id": first["id"], "confirmed": True, "corrected_value": "korrigiert"}]
|
||||
)
|
||||
assert confirmed["status"] == "BESTAETIGT"
|
||||
|
||||
|
||||
def test_unreadable_winlog_pdf_does_not_crash(tmp_path):
|
||||
db = session()
|
||||
customer, location, device = seed(db)
|
||||
validation = valid_validation(customer, location, device)
|
||||
db.add(validation)
|
||||
db.flush()
|
||||
|
||||
preview = HeliosImportService(db, tmp_path).save_winlog_pdf(
|
||||
validation.id, "broken.pdf", b"not a pdf"
|
||||
)
|
||||
|
||||
assert preview["status"] in {"FEHLER", "NUR_ANLAGE"}
|
||||
assert preview["values"] == []
|
||||
|
||||
|
||||
def test_confirmed_measurements_appear_in_orion_report(tmp_path):
|
||||
from weasyprint import HTML
|
||||
|
||||
db = session()
|
||||
customer, location, device = seed(db)
|
||||
validation = valid_validation(customer, location, device)
|
||||
db.add(validation)
|
||||
db.flush()
|
||||
pdf_bytes = HTML(string="<p>Testlauf 1</p><p>Leckrate: 0,2</p>").write_pdf()
|
||||
preview = HeliosImportService(db, tmp_path).save_winlog_pdf(validation.id, "winlog.pdf", pdf_bytes)
|
||||
leak_rate = next(value for value in preview["values"] if value["field_name"] == "leak_rate")
|
||||
HeliosImportService(db, tmp_path).confirm_values(
|
||||
preview["id"], [{"id": leak_rate["id"], "confirmed": True}]
|
||||
)
|
||||
|
||||
html = OrionReportService(db, tmp_path).render_html(validation.id)
|
||||
|
||||
assert "leak_rate" in html
|
||||
assert "0,2" in html
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue