Phase 4 — Dead-letter 重试 + 内容推送 + 安全加固: - erp-core: retry_dead_letters() 定时重试 + PII payload 脱敏 - erp-core: audit_service 哈希链定时验证 + 写入失败告警 - erp-health: article.published 消费者匹配 patient_tag 推送消息 - erp-health: care_plan 事件消费者 (激活通知 + 完成积分) Phase 5 — 患者批量操作 + 咨询增强 + 护理事件: - patient: batch_import_patients + bind_by_phone + refer_patient - consultation: rate_session 满意度评价 (rating + feedback) - consent: patient_sign_consent 患者端签署 - validation: source 枚举 (7值) + relationship 枚举 (7值) + 12 单元测试 Phase 6 — 咨询文件上传 + AI 引用标注: - consultation_message: media_id 附件上传端点 - ai_suggestion: references JSONB + [ref:id] 格式引用标注 - AI system prompt 增加引用指令 + output_parser 提取逻辑 迁移: 000161 (media_id + references) + 000162 (rating + feedback) 集成测试: consultation/follow_up/pii_encryption 新字段同步修复 讨论文档: 2026-05-20-business-process-brainstorm.md (10域审核报告)
246 lines
7.5 KiB
Rust
246 lines
7.5 KiB
Rust
//! erp-health 咨询管理集成测试
|
|
//!
|
|
//! 验证咨询会话 CRUD、消息收发、会话关闭、未读计数、租户隔离。
|
|
|
|
use erp_health::dto::consultation_dto::*;
|
|
use erp_health::service::consultation_service;
|
|
|
|
use super::test_fixture::TestApp;
|
|
|
|
/// 创建测试用会话(无医护)
|
|
async fn seed_session(app: &TestApp, patient_id: uuid::Uuid) -> SessionResp {
|
|
consultation_service::create_session(
|
|
app.health_state(),
|
|
app.tenant_id(),
|
|
Some(app.operator_id()),
|
|
CreateSessionReq {
|
|
patient_id,
|
|
doctor_id: None,
|
|
consultation_type: None,
|
|
},
|
|
)
|
|
.await
|
|
.expect("创建会话应成功")
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// 测试 1: 创建会话(带医护)
|
|
// ---------------------------------------------------------------------------
|
|
#[tokio::test]
|
|
async fn test_consultation_session_create() {
|
|
let app = TestApp::new().await;
|
|
let patient_id = app.create_patient("咨询患者").await;
|
|
let doctor_id = app.create_doctor("咨询医生").await;
|
|
|
|
let session = consultation_service::create_session(
|
|
app.health_state(),
|
|
app.tenant_id(),
|
|
Some(app.operator_id()),
|
|
CreateSessionReq {
|
|
patient_id,
|
|
doctor_id: Some(doctor_id),
|
|
consultation_type: Some("doctor".to_string()),
|
|
},
|
|
)
|
|
.await
|
|
.expect("创建会话应成功");
|
|
|
|
assert_eq!(session.patient_id, patient_id);
|
|
assert_eq!(session.doctor_id, Some(doctor_id));
|
|
assert_eq!(session.consultation_type, "doctor");
|
|
assert_eq!(session.status, "waiting");
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// 测试 2: 查询会话
|
|
// ---------------------------------------------------------------------------
|
|
#[tokio::test]
|
|
async fn test_consultation_session_get() {
|
|
let app = TestApp::new().await;
|
|
let patient_id = app.create_patient("查询患者").await;
|
|
|
|
let session = seed_session(&app, patient_id).await;
|
|
|
|
let fetched =
|
|
consultation_service::get_session(app.health_state(), app.tenant_id(), session.id)
|
|
.await
|
|
.expect("查询应成功");
|
|
assert_eq!(fetched.id, session.id);
|
|
assert_eq!(fetched.status, "waiting");
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// 测试 3: 列表按患者过滤
|
|
// ---------------------------------------------------------------------------
|
|
#[tokio::test]
|
|
async fn test_consultation_session_list_by_patient() {
|
|
let app = TestApp::new().await;
|
|
let patient_a = app.create_patient("列表患者A").await;
|
|
let patient_b = app.create_patient("列表患者B").await;
|
|
|
|
seed_session(&app, patient_a).await;
|
|
seed_session(&app, patient_a).await;
|
|
seed_session(&app, patient_b).await;
|
|
|
|
let list_a = consultation_service::list_sessions(
|
|
app.health_state(),
|
|
app.tenant_id(),
|
|
1,
|
|
20,
|
|
None,
|
|
Some(patient_a),
|
|
None,
|
|
)
|
|
.await
|
|
.unwrap();
|
|
assert_eq!(list_a.total, 2);
|
|
|
|
let list_b = consultation_service::list_sessions(
|
|
app.health_state(),
|
|
app.tenant_id(),
|
|
1,
|
|
20,
|
|
None,
|
|
Some(patient_b),
|
|
None,
|
|
)
|
|
.await
|
|
.unwrap();
|
|
assert_eq!(list_b.total, 1);
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// 测试 4: 发送消息
|
|
// ---------------------------------------------------------------------------
|
|
#[tokio::test]
|
|
async fn test_consultation_message_send() {
|
|
let app = TestApp::new().await;
|
|
let patient_id = app.create_patient("消息患者").await;
|
|
|
|
let session = seed_session(&app, patient_id).await;
|
|
|
|
let msg = consultation_service::create_message(
|
|
app.health_state(),
|
|
app.tenant_id(),
|
|
Some(app.operator_id()),
|
|
app.operator_id(),
|
|
"doctor".to_string(),
|
|
CreateMessageReq {
|
|
session_id: session.id,
|
|
content_type: Some("text".to_string()),
|
|
content: "您好,有什么可以帮您?".to_string(),
|
|
media_id: None,
|
|
},
|
|
)
|
|
.await
|
|
.expect("发送消息应成功");
|
|
|
|
assert_eq!(msg.session_id, session.id);
|
|
assert_eq!(msg.content, "您好,有什么可以帮您?");
|
|
assert_eq!(msg.sender_role, "doctor");
|
|
assert!(!msg.is_read);
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// 测试 5: 查询消息列表
|
|
// ---------------------------------------------------------------------------
|
|
#[tokio::test]
|
|
async fn test_consultation_message_list() {
|
|
let app = TestApp::new().await;
|
|
let patient_id = app.create_patient("消息列表患者").await;
|
|
|
|
let session = seed_session(&app, patient_id).await;
|
|
|
|
for i in 0..3 {
|
|
consultation_service::create_message(
|
|
app.health_state(),
|
|
app.tenant_id(),
|
|
Some(app.operator_id()),
|
|
app.operator_id(),
|
|
"doctor".to_string(),
|
|
CreateMessageReq {
|
|
session_id: session.id,
|
|
content_type: None,
|
|
content: format!("消息{}", i + 1),
|
|
media_id: None,
|
|
},
|
|
)
|
|
.await
|
|
.unwrap();
|
|
}
|
|
|
|
let messages = consultation_service::list_messages(
|
|
app.health_state(),
|
|
app.tenant_id(),
|
|
session.id,
|
|
1,
|
|
20,
|
|
None,
|
|
)
|
|
.await
|
|
.expect("查询消息应成功");
|
|
|
|
assert_eq!(messages.total, 3);
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// 测试 6: 关闭会话
|
|
// ---------------------------------------------------------------------------
|
|
#[tokio::test]
|
|
async fn test_consultation_session_close() {
|
|
let app = TestApp::new().await;
|
|
let patient_id = app.create_patient("关闭患者").await;
|
|
|
|
let session = seed_session(&app, patient_id).await;
|
|
assert_eq!(session.status, "waiting");
|
|
|
|
let closed = consultation_service::close_session(
|
|
app.health_state(),
|
|
app.tenant_id(),
|
|
session.id,
|
|
Some(app.operator_id()),
|
|
session.version,
|
|
)
|
|
.await
|
|
.expect("关闭应成功");
|
|
assert_eq!(closed.status, "closed");
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// 测试 7: 租户隔离
|
|
// ---------------------------------------------------------------------------
|
|
#[tokio::test]
|
|
async fn test_consultation_session_tenant_isolation() {
|
|
let app = TestApp::new().await;
|
|
let patient_id = app.create_patient("隔离患者").await;
|
|
|
|
let session = seed_session(&app, patient_id).await;
|
|
|
|
let other_tenant = uuid::Uuid::new_v4();
|
|
let result =
|
|
consultation_service::get_session(app.health_state(), other_tenant, session.id).await;
|
|
assert!(result.is_err(), "不同租户不应看到此会话");
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// 测试 8: 无效患者创建会话返回错误
|
|
// ---------------------------------------------------------------------------
|
|
#[tokio::test]
|
|
async fn test_consultation_session_invalid_patient() {
|
|
let app = TestApp::new().await;
|
|
let fake_patient = uuid::Uuid::new_v4();
|
|
|
|
let result = consultation_service::create_session(
|
|
app.health_state(),
|
|
app.tenant_id(),
|
|
None,
|
|
CreateSessionReq {
|
|
patient_id: fake_patient,
|
|
doctor_id: None,
|
|
consultation_type: None,
|
|
},
|
|
)
|
|
.await;
|
|
assert!(result.is_err(), "无效患者应返回错误");
|
|
}
|