from __future__ import annotations import os from types import SimpleNamespace os.environ.setdefault("QT_QPA_PLATFORM", "offscreen") import pytest from PySide6.QtCore import QPoint, Qt from PySide6.QtWidgets import QApplication, QDialog, QTabWidget, QWidget from doctor_workstation.ui.dialogs.prescription import PrescriptionEditorDialog @pytest.fixture(scope="module") def application() -> QApplication: return QApplication.instance() or QApplication([]) def _repository() -> SimpleNamespace: return SimpleNamespace(list_medicines=lambda **_kwargs: {"lists": [], "count": 0}) def _seed() -> dict[str, object]: return { "id": 502, "diagnosis_id": 301, "appointment_id": 401, "patient_name": "林晓岚", "phone": "13800138000", "gender": 0, "age": 34, "visit_no": "1K00000401", "tongue": "面色少华", "tongue_image": "舌淡红、苔薄白", "pulse": "脉细", "pulse_condition": "沉取无力", "clinical_diagnosis": "气阴两虚", "doctor_name": "陈医生", "herbs": [ {"medicine_id": 11, "name": "黄芪", "dosage": 15, "formula_type": "主方"}, {"medicine_id": 12, "name": "党参", "dosage": 12, "formula_type": "主方"}, {"medicine_id": 13, "name": "白术", "dosage": 10, "formula_type": "主方"}, {"medicine_id": 14, "name": "茯苓", "dosage": 12, "formula_type": "主方"}, {"medicine_id": 15, "name": "酸枣仁", "dosage": 9, "formula_type": "辅方"}, ], } def _show(editor: PrescriptionEditorDialog, application: QApplication) -> None: editor.show() for _ in range(5): application.processEvents() def test_editor_is_a_fixed_header_body_footer_right_drawer( application: QApplication, ) -> None: host = QWidget() host.resize(1440, 900) host.show() editor = PrescriptionEditorDialog( _repository(), _seed(), current_user=SimpleNamespace(id=7, name="陈医生"), parent=host, ) _show(editor, application) origin = host.mapToGlobal(QPoint(0, 0)) assert editor.windowFlags() & Qt.WindowType.FramelessWindowHint assert editor.width() == 860 assert editor.height() == host.height() assert editor.x() + editor.width() == origin.x() + host.width() assert editor.y() == origin.y() assert editor.save_button.text() == "确定" assert editor.windowTitle() == "新增处方" assert not editor.findChildren(QTabWidget) assert editor.body_scroll.verticalScrollBar().maximum() > 0 assert editor.body_scroll.horizontalScrollBar().maximum() == 0 section_tops = [section.geometry().top() for section in editor.section_widgets] assert section_tops == sorted(section_tops) assert [section.parentWidget() for section in editor.section_widgets] == [ editor.body_content ] * 5 header_y = editor.header.mapToGlobal(QPoint(0, 0)).y() footer_y = editor.footer.mapToGlobal(QPoint(0, 0)).y() editor.body_scroll.verticalScrollBar().setValue( editor.body_scroll.verticalScrollBar().maximum() ) application.processEvents() assert editor.header.mapToGlobal(QPoint(0, 0)).y() == header_y assert editor.footer.mapToGlobal(QPoint(0, 0)).y() == footer_y editor.close() host.close() application.processEvents() def test_drawer_uses_full_width_on_a_narrow_host(application: QApplication) -> None: host = QWidget() host.resize(760, 720) host.show() editor = PrescriptionEditorDialog(_repository(), _seed(), parent=host) _show(editor, application) origin = host.mapToGlobal(QPoint(0, 0)) assert editor.width() == host.width() assert editor.x() == origin.x() assert editor.body_scroll.horizontalScrollBar().maximum() == 0 assert editor.herbs.table_mode assert editor.add_main_button.text() == "添加主方药材" editor.close() host.close() application.processEvents() def test_decoction_usage_fields_pack_without_a_hidden_column_gap( application: QApplication, ) -> None: host = QWidget() host.resize(1440, 900) host.show() source = _seed() source["prescription_type"] = "饮片" editor = PrescriptionEditorDialog(_repository(), source, parent=host) _show(editor, application) assert editor._main_decoction_field.isVisible() assert editor._main_bags_field.isVisible() assert editor._main_bag_field.isHidden() assert editor._main_dosage_field.y() == editor._main_decoction_field.y() gap = editor._main_decoction_field.x() - ( editor._main_dosage_field.x() + editor._main_dosage_field.width() ) assert 0 <= gap <= 24 assert abs(editor._main_dosage_field.width() - editor._main_decoction_field.width()) < 40 assert editor.cancel_button.x() < editor.save_button.x() editor.close() host.close() application.processEvents() def test_duplicate_warning_and_admin_dto_survive_the_visual_restructure( application: QApplication, ) -> None: source = _seed() source["herbs"] = [ {"medicine_id": 11, "name": "黄芪", "dosage": 15, "formula_type": "主方"}, {"medicine_id": 11, "name": " 黄芪 ", "dosage": 9, "formula_type": "辅方"}, ] editor = PrescriptionEditorDialog( _repository(), source, mode="edit", current_user=SimpleNamespace(id=7, name="陈医生"), ) editor.signature._has_strokes = True payload = editor.payload() assert payload["id"] == 502 assert payload["diagnosis_id"] == 301 assert payload["herbs"][0]["formula_type"] == "主方" assert payload["herbs"][1]["formula_type"] == "辅方" assert all(bool(row.property("duplicate")) for row in editor.herbs.rows) assert "存在重复药名" in editor.herb_summary.text() editor.accept() assert editor.result() == QDialog.DialogCode.Accepted editor.close() application.processEvents() def test_locked_template_rows_keep_the_existing_mutation_contract( application: QApplication, ) -> None: source = _seed() source["herbs"] = [ { "medicine_id": 11, "name": "黄芪", "dosage": 15, "formula_type": "主方", "locked": True, } ] editor = PrescriptionEditorDialog(_repository(), source) assert editor.herbs.locked assert not editor.add_main_button.isEnabled() assert not editor.add_aux_button.isEnabled() assert editor.import_library_button.isEnabled() assert editor.paste_button.isEnabled() assert not editor.herbs.rows[0].medicine.isEnabled() assert not editor.herbs.rows[0].dosage.isEnabled() assert editor.herbs.rows[0].remove_button.isHidden() assert editor.payload()["herbs"][0]["locked"] is True editor.close() application.processEvents()