import pytest from django.urls import reverse from review_agent.models import ( Conversation, FileSummaryBatch, FileSummaryItem, RegulatoryArtifact, RegulatoryNotificationRecord, RegulatoryReviewBatch, WorkflowNodeRun, ) pytestmark = pytest.mark.django_db def test_workspace_renders_regulatory_workflow_card(client, django_user_model): user = django_user_model.objects.create_user(username="owner", password="pass") conversation = Conversation.objects.create(user=user, title="会话") summary = FileSummaryBatch.objects.create( conversation=conversation, user=user, batch_no="FS-OK", status=FileSummaryBatch.Status.SUCCESS, ) regulatory = RegulatoryReviewBatch.objects.create( conversation=conversation, user=user, source_summary_batch=summary, batch_no="RR-CARD", status=RegulatoryReviewBatch.Status.SUCCESS, risk_summary={"blocking": 1, "high": 1}, ) WorkflowNodeRun.objects.create( workflow_type="regulatory_review", workflow_batch_id=regulatory.pk, node_group="regulatory_review", node_code="risk_assess", node_name="风险评估", status=WorkflowNodeRun.Status.SUCCESS, progress=100, ) client.force_login(user) response = client.get(f"{reverse('home')}?conversation={conversation.pk}") content = response.content.decode("utf-8") assert "RR-CARD" in content assert 'data-workflow-type="regulatory_review"' in content assert "阻断项 1" in content assert "风险评估" in content assert "data-regulatory-status-url-template" in content def test_workspace_renders_condition_confirmation_form(client, django_user_model): user = django_user_model.objects.create_user(username="owner", password="pass") conversation = Conversation.objects.create(user=user, title="会话") summary = FileSummaryBatch.objects.create( conversation=conversation, user=user, batch_no="FS-OK", status=FileSummaryBatch.Status.SUCCESS, ) regulatory = RegulatoryReviewBatch.objects.create( conversation=conversation, user=user, source_summary_batch=summary, batch_no="RR-WAIT", status=RegulatoryReviewBatch.Status.WAITING_USER, condition_json={ "confirmed": False, "candidates": { "product_category": { "label": "产品类别", "input_type": "select", "options": ["体外诊断试剂", "医疗器械", "其他"], "suggested": "体外诊断试剂", }, "product_name": { "label": "产品名称", "input_type": "text", "suggested": "甲胎蛋白检测试剂盒", }, }, }, ) WorkflowNodeRun.objects.create( workflow_type="regulatory_review", workflow_batch_id=regulatory.pk, node_group="condition_confirm", node_code="condition_confirm", node_name="适用条件确认", status=WorkflowNodeRun.Status.WAITING_USER, progress=50, ) client.force_login(user) response = client.get(f"{reverse('home')}?conversation={conversation.pk}") content = response.content.decode("utf-8") assert "适用条件确认" in content assert "data-condition-confirm-form" in content assert "体外诊断试剂" in content assert "甲胎蛋白检测试剂盒" in content form_index = content.index("data-condition-confirm-form") summary_index = content.index('id="summaryPanel"') assert form_index < summary_index assert "data-condition-confirm-form" not in content[summary_index:] def test_workspace_refreshes_incomplete_condition_confirmation_candidates(client, settings, tmp_path, django_user_model): settings.MEDIA_ROOT = tmp_path user = django_user_model.objects.create_user(username="owner", password="pass") conversation = Conversation.objects.create(user=user, title="会话") summary = FileSummaryBatch.objects.create( conversation=conversation, user=user, batch_no="FS-OK", status=FileSummaryBatch.Status.SUCCESS, product_name="第1章 监管信息", ) application = tmp_path / "application.txt" application.write_text( "卡尤迪生物科技宜兴有限公司申请境内第三类体外诊断试剂" "呼吸道合胞病毒、肺炎支原体核酸检测试剂盒(荧光PCR法)产品注册。", encoding="utf-8", ) FileSummaryItem.objects.create( batch=summary, file_index=1, directory_level="第1章 监管信息", file_name="符合标准的清单.txt", file_type="txt", relative_path="第1章 监管信息/符合标准的清单.txt", storage_path=str(application), ) RegulatoryReviewBatch.objects.create( conversation=conversation, user=user, source_summary_batch=summary, batch_no="RR-WAIT-EMPTY", status=RegulatoryReviewBatch.Status.WAITING_USER, condition_json={ "confirmed": False, "candidates": { "product_category": {"label": "产品类别", "input_type": "select", "options": ["其他"], "suggested": "其他"}, "product_name": {"label": "产品名称", "input_type": "text", "suggested": ""}, }, }, ) client.force_login(user) response = client.get(f"{reverse('home')}?conversation={conversation.pk}") content = response.content.decode("utf-8") assert "体外诊断试剂" in content assert "呼吸道合胞病毒、肺炎支原体核酸检测试剂盒(荧光PCR法)" in content def test_workspace_renders_rectification_actions_and_summaries(client, tmp_path, django_user_model): user = django_user_model.objects.create_user(username="owner", password="pass") conversation = Conversation.objects.create(user=user, title="会话") summary = FileSummaryBatch.objects.create( conversation=conversation, user=user, batch_no="FS-OK", status=FileSummaryBatch.Status.SUCCESS, ) regulatory = RegulatoryReviewBatch.objects.create( conversation=conversation, user=user, source_summary_batch=summary, batch_no="RR-RECTIFY", status=RegulatoryReviewBatch.Status.SUCCESS, ) record_path = tmp_path / "review_record.json" record_path.write_text('{"items":[{"status":"review_passed"}]}', encoding="utf-8") RegulatoryArtifact.objects.create( batch=regulatory, artifact_type=RegulatoryArtifact.ArtifactType.JSON, name="review_record.json", storage_path=str(record_path), metadata={"artifact": "review_record"}, ) RegulatoryNotificationRecord.objects.create( batch=regulatory, channel=RegulatoryNotificationRecord.Channel.MOCK, target="法规整改负责人", status=RegulatoryNotificationRecord.Status.SENT, payload={"title": "缺少申请表"}, ) client.force_login(user) response = client.get(f"{reverse('home')}?conversation={conversation.pk}") content = response.content.decode("utf-8") assert "data-rectification-action=\"full-review\"" in content assert "data-rectification-action=\"issue-review\"" in content assert "通知 1" in content assert "复核记录 1" in content def test_frontend_selects_status_url_by_workflow_type(): script = open("static/js/app.js", encoding="utf-8").read() assert "workflow_type" in script assert "data-regulatory-status-url-template" in script assert "statusUrlForWorkflow" in script assert "bindConditionConfirmForms" in script assert "data-condition-confirm-form" in script assert "ensureConditionConfirmationCard" in script assert "condition_confirmation" in script assert "bindRectificationActionButtons" in script assert "data-rectification-action" in script def test_frontend_polls_regulatory_workflow_with_explicit_workflow_type(): script = open("static/js/app.js", encoding="utf-8").read() assert "function startWorkflowPolling(batchId, workflow_type)" in script assert "startWorkflowPolling(payload.batch_id, payload.workflow_type)" in script assert 'startWorkflowPolling(batchId, "regulatory_review")' in script assert 'workflow_type || (card ? card.getAttribute("data-workflow-type") || "file_summary" : "file_summary")' in script def test_frontend_keeps_single_condition_confirmation_prompt(): script = open("static/js/app.js", encoding="utf-8").read() assert "data-condition-confirmation-card" in script assert "removeStaleConditionConfirmationCards" in script assert '[data-condition-confirmation-card]' in script