feat(navigation): add prominent validation quickstart action

This commit is contained in:
Schubert Ferenc 2026-07-11 18:02:53 +02:00
parent 0bbcaba211
commit 9c6b184e39
28614 changed files with 4356173 additions and 23 deletions

View file

@ -0,0 +1,99 @@
from __future__ import annotations
from sqlalchemy import create_engine, func, select
from sqlalchemy.orm import Session
from app.db.base import Base
from app.models.contact import Contact
from app.models.customer import Customer, CustomerType
from app.models.device import Device
from app.models.equipment import Equipment
from app.models.validation import Validation
from app import cli as app_cli
from app.services.demo_data import DemoDataService
def session() -> Session:
engine = create_engine("sqlite+pysqlite:///:memory:")
Base.metadata.create_all(engine)
return Session(engine)
def test_demo_data_cli_parser_accepts_expected_options():
args = app_cli.build_parser().parse_args(
[
"demo-data",
"--customers",
"10",
"--devices",
"10",
"--validations",
"20",
"--reports",
"--images",
]
)
assert args.command == "demo-data"
assert args.customers == 10
assert args.devices == 10
assert args.validations == 20
assert args.reports is True
assert args.images is True
def test_demo_data_service_is_idempotent_and_creates_realistic_data(tmp_path):
db = session()
service = DemoDataService(db, upload_root=tmp_path / "uploads", report_root=tmp_path / "reports")
summary_first = service.run(customers=10, devices=10, validations=20, images=True)
assert summary_first["customers"] == 10
assert summary_first["devices"] == 10
assert summary_first["validations"] == 20
assert db.scalar(select(func.count()).select_from(Customer)) == 10
assert db.scalar(select(func.count()).select_from(Device)) == 10
assert db.scalar(select(func.count()).select_from(Equipment)) >= 6
assert db.scalar(select(func.count()).select_from(Validation)) == 20
assert db.scalar(select(func.count()).select_from(Contact)) >= 10
assert list((tmp_path / "uploads").rglob("*.svg"))
summary_second = service.run(customers=10, devices=10, validations=20, images=True)
assert summary_second["customers"] == 10
assert db.scalar(select(func.count()).select_from(Customer)) == 10
assert db.scalar(select(func.count()).select_from(Device)) == 10
assert db.scalar(select(func.count()).select_from(Validation)) == 20
def test_demo_data_reset_removes_only_demo_rows(tmp_path):
db = session()
real_customer = Customer(
customer_type=CustomerType.practice,
name="Reale Praxis",
email="real@example.com",
)
db.add(real_customer)
db.flush()
service = DemoDataService(db, upload_root=tmp_path / "uploads", report_root=tmp_path / "reports")
service.run(customers=10, devices=10, validations=20, images=True)
service.reset()
assert db.scalar(select(Customer).where(Customer.email == "real@example.com")) is not None
assert db.scalar(select(Customer).where(Customer.notes.like("%DEMO_DATA%"))) is None
assert db.scalar(select(Device).where(Device.notes.like("%DEMO_DATA%"))) is None
assert db.scalar(select(Validation).where(Validation.notes.like("%DEMO_DATA%"))) is None
def test_demo_data_cli_command_uses_sessionlocal(monkeypatch):
db = session()
monkeypatch.setattr(app_cli, "SessionLocal", lambda: db)
args = app_cli.build_parser().parse_args(["demo-data", "--customers", "10", "--devices", "10", "--validations", "20"])
exit_code = app_cli.cmd_demo_data(args)
assert exit_code == 0
assert db.scalar(select(func.count()).select_from(Customer)) == 10
assert db.scalar(select(func.count()).select_from(Device)) == 10
assert db.scalar(select(func.count()).select_from(Validation)) == 20

View file

@ -20,10 +20,11 @@ from app.models.validation import Validation, ValidationStatus
from app.services.validation_workflow import ValidationWorkflowService
from app.services.auth_service import AuthService
from app.services.reference_masterdata import ReferenceMasterdataImportService
from app.services.quickstart_service import QuickStartService
from app.api.v1.auth import login as auth_login
from app.api.v1 import domain as domain_api
from app.schemas.auth import LoginRequest
from app.schemas.domain import UserCreate, UserUpdate, ValidationCreate
from app.schemas.domain import QuickStartCreateRequest, UserCreate, UserUpdate, 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 REPORT_SECTIONS, ReportTemplateService
@ -277,6 +278,36 @@ def test_user_list_pagination_and_filters_work():
assert role_filtered["items"][0].role == UserRole.ADMIN.value
def test_paginated_lists_expose_pages_for_masterdata_and_validations():
db = session()
customer, location, device = seed(db)
db.add(valid_validation(customer, location, device))
db.flush()
customers = domain_api.list_customers(params={"page": 1, "page_size": 20, "search": None}, session=db)
devices = domain_api.list_devices(params={"page": 1, "page_size": 20, "search": None}, session=db)
validations = domain_api.list_validations(
search=None,
page=1,
page_size=20,
sort_by="created_at",
sort_order="desc",
status=None,
customer_id=None,
device_id=None,
validation_type=None,
result=None,
date_from=None,
date_to=None,
overdue_only=False,
session=db,
)
assert customers["pages"] == 1
assert devices["pages"] == 1
assert validations["pages"] == 1
def test_admin_can_create_users_with_supported_roles():
db = session()
admin = User(
@ -636,6 +667,144 @@ def test_reference_masterdata_import_can_create_validation():
assert validation.status == ValidationStatus.draft.value
def test_quickstart_customer_data_and_validation_creation():
db = session()
reference = next(
candidate
for parent in Path(__file__).resolve().parents
if (candidate := parent / "docs/reference/reports/Erstvalidierung_Dr.Durmaz_Steri_12-25.docx").exists()
)
ReferenceMasterdataImportService(db).import_reference_docx(reference, create_validation=True)
customer = db.scalar(select(Customer).where(Customer.name == "Urologische Praxis Dr. Durmaz"))
assert customer is not None
customer_data = QuickStartService(db).customer_data(customer.id)
assert customer_data.locations
assert customer_data.contacts
assert customer_data.devices
assert customer_data.validations
admin = User(
email="quickstart-admin@schubamed.de",
first_name="Quickstart",
last_name="Admin",
role=UserRole.ADMIN.value,
password_hash="hash",
is_active=True,
must_change_password=False,
)
db.add(admin)
db.flush()
created = QuickStartService(db).create_validation(
QuickStartCreateRequest(
customer_id=customer.id,
location_id=customer_data.locations[0].id,
contact_id=customer_data.contacts[0].id,
device_id=customer_data.devices[0].id,
validation_type="Erstvalidierung",
),
examiner=admin,
)
db.commit()
assert created.id is not None
assert created.status == ValidationStatus.draft.value
assert created.customer_id == customer.id
assert created.examiner_id == admin.id
assert created.documentation_checklist
assert created.programs
assert created.loading_patterns
def test_quickstart_auto_selects_single_customer_masterdata():
db = session()
customer, location, device = seed(db)
contact = seed_contact(db, customer)
admin = User(
email="single-data-admin@schubamed.de",
first_name="Quickstart",
last_name="Admin",
role=UserRole.ADMIN.value,
password_hash="hash",
is_active=True,
must_change_password=False,
)
db.add(admin)
db.flush()
created = QuickStartService(db).create_validation(
QuickStartCreateRequest(
customer_id=customer.id,
validation_type="Erstvalidierung",
),
examiner=admin,
)
assert created.customer_id == customer.id
assert created.location_id == location.id
assert created.contact_id == contact.id
assert created.device_id == device.id
def test_quickstart_device_last_validation_returns_latest_completed_validation():
db = session()
customer, location, device = seed(db)
draft = valid_validation(customer, location, device)
draft.status = ValidationStatus.draft.value
completed = valid_validation(customer, location, device)
completed.report_number = "VAL-PAST"
completed.status = ValidationStatus.completed.value
completed.performed_on = date(2026, 1, 1)
db.add_all([draft, completed])
db.flush()
summary = QuickStartService(db).device_last_validation(device.id)
assert summary is not None
assert summary.report_number == "VAL-PAST"
assert summary.device_id == device.id
def test_quickstart_revalidation_copies_structured_data_but_not_measurements():
db = session()
customer, location, device = seed(db)
admin = User(
email="revalidation-admin@schubamed.de",
first_name="Quickstart",
last_name="Admin",
role=UserRole.ADMIN.value,
password_hash="hash",
is_active=True,
must_change_password=False,
)
base = valid_validation(customer, location, device)
base.status = ValidationStatus.approved.value
base.documentation_checklist = [{"text": "Prüfung A", "value": "yes"}]
base.performance_checklist = [{"text": "Prüfung B", "value": "no"}]
base.programs = [{"name": "Vakuumtest", "selected": True}]
base.loading_patterns = [{"run": 1, "pattern": "Standard", "description": "Basis", "images": ["x"]}]
base.measurement_data = [{"field": "temperatur"}]
base.attachments = [{"filename": "bild.png"}]
db.add_all([admin, base])
db.flush()
created = QuickStartService(db).create_validation(
QuickStartCreateRequest(
customer_id=customer.id,
device_id=device.id,
validation_type="Revalidierung",
),
examiner=admin,
)
assert created.previous_validation_id == base.id
assert created.version == 2
assert created.documentation_checklist == base.documentation_checklist
assert created.performance_checklist == base.performance_checklist
assert created.programs == base.programs
assert created.loading_patterns == base.loading_patterns
assert created.measurement_data == []
assert created.attachments == []
def test_revalidation_date_uses_calendar_months():
db = session()
customer, location, device = seed(db)