Files
hms/crates/erp-server/tests/integration/health_dialysis_prescription_tests.rs
iven 5941a6b764
Some checks failed
CI / rust-check (push) Has been cancelled
CI / rust-test (push) Has been cancelled
CI / frontend-build (push) Has been cancelled
CI / security-audit (push) Has been cancelled
feat(dialysis): 激活 erp-dialysis 独立模块 — 注册到 erp-server
- workspace Cargo.toml 添加 erp-dialysis 依赖声明
- erp-server 注册 DialysisModule 并挂载透析路由
- 修复权限码:health.health-data.* → health.dialysis.list/manage
- 集成测试迁移:erp_health → erp_dialysis import + DialysisState
- TestApp 新增 dialysis_state() 方法
- cargo check 通过,erp-dialysis 10 个单元测试全部通过
2026-04-28 15:21:13 +08:00

229 lines
8.7 KiB
Rust

//! erp-dialysis 透析方案管理集成测试
//!
//! 验证透析方案 CRUD、列表按患者过滤、租户隔离、乐观锁。
use erp_dialysis::dto::dialysis_prescription_dto::*;
use erp_dialysis::service::dialysis_prescription_service;
use super::test_fixture::TestApp;
fn default_create_req(patient_id: uuid::Uuid) -> CreateDialysisPrescriptionReq {
CreateDialysisPrescriptionReq {
patient_id,
dialyzer_model: Some("FX80".to_string()),
membrane_area: Some(1.8),
dialysate_potassium: Some(2.0),
dialysate_calcium: Some(1.5),
dialysate_bicarbonate: Some(35.0),
anticoagulation_type: Some("heparin".to_string()),
anticoagulation_dose: Some("2000IU".to_string()),
target_ultrafiltration_ml: Some(2000),
target_dry_weight: Some(65.0),
blood_flow_rate: Some(300),
dialysate_flow_rate: Some(500),
frequency_per_week: Some(3),
duration_minutes: Some(240),
vascular_access_type: Some("avf".to_string()),
vascular_access_location: Some("左前臂".to_string()),
effective_from: chrono::NaiveDate::from_ymd_opt(2026, 5, 1),
effective_to: None,
notes: None,
}
}
async fn seed_prescription(app: &TestApp, patient_id: uuid::Uuid) -> DialysisPrescriptionResp {
dialysis_prescription_service::create_prescription(
app.dialysis_state(), app.tenant_id(), Some(app.operator_id()),
default_create_req(patient_id),
)
.await
.expect("创建透析方案应成功")
}
// ---------------------------------------------------------------------------
// 测试 1: 创建透析方案
// ---------------------------------------------------------------------------
#[tokio::test]
async fn test_dialysis_prescription_create() {
let app = TestApp::new().await;
let patient_id = app.create_patient("透析方案患者").await;
let rx = seed_prescription(&app, patient_id).await;
assert_eq!(rx.patient_id, patient_id);
assert_eq!(rx.status, "active");
assert_eq!(rx.dialyzer_model, Some("FX80".to_string()));
assert_eq!(rx.frequency_per_week, Some(3));
assert_eq!(rx.version, 1);
}
// ---------------------------------------------------------------------------
// 测试 2: 查询透析方案
// ---------------------------------------------------------------------------
#[tokio::test]
async fn test_dialysis_prescription_get() {
let app = TestApp::new().await;
let patient_id = app.create_patient("方案查询患者").await;
let rx = seed_prescription(&app, patient_id).await;
let fetched = dialysis_prescription_service::get_prescription(
app.dialysis_state(), app.tenant_id(), rx.id,
)
.await
.expect("查询应成功");
assert_eq!(fetched.id, rx.id);
}
// ---------------------------------------------------------------------------
// 测试 3: 更新透析方案
// ---------------------------------------------------------------------------
#[tokio::test]
async fn test_dialysis_prescription_update() {
let app = TestApp::new().await;
let patient_id = app.create_patient("方案更新患者").await;
let rx = seed_prescription(&app, patient_id).await;
let updated = dialysis_prescription_service::update_prescription(
app.dialysis_state(), app.tenant_id(), rx.id,
Some(app.operator_id()),
UpdateDialysisPrescriptionReq {
blood_flow_rate: Some(350),
frequency_per_week: Some(4),
status: None,
dialyzer_model: None, membrane_area: None,
dialysate_potassium: None, dialysate_calcium: None,
dialysate_bicarbonate: None, anticoagulation_type: None,
anticoagulation_dose: None, target_ultrafiltration_ml: None,
target_dry_weight: None, dialysate_flow_rate: None,
duration_minutes: None, vascular_access_type: None,
vascular_access_location: None, effective_from: None,
effective_to: None, notes: None,
},
rx.version,
)
.await
.expect("更新应成功");
assert_eq!(updated.blood_flow_rate, Some(350));
assert_eq!(updated.frequency_per_week, Some(4));
assert_eq!(updated.version, 2);
}
// ---------------------------------------------------------------------------
// 测试 4: 列表按患者过滤
// ---------------------------------------------------------------------------
#[tokio::test]
async fn test_dialysis_prescription_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_prescription(&app, patient_a).await;
seed_prescription(&app, patient_b).await;
let list_a = dialysis_prescription_service::list_prescriptions(
app.dialysis_state(), app.tenant_id(), 1, 20, Some(patient_a), None,
)
.await
.unwrap();
assert_eq!(list_a.total, 1);
let list_b = dialysis_prescription_service::list_prescriptions(
app.dialysis_state(), app.tenant_id(), 1, 20, Some(patient_b), None,
)
.await
.unwrap();
assert_eq!(list_b.total, 1);
}
// ---------------------------------------------------------------------------
// 测试 5: 软删除
// ---------------------------------------------------------------------------
#[tokio::test]
async fn test_dialysis_prescription_soft_delete() {
let app = TestApp::new().await;
let patient_id = app.create_patient("方案删除患者").await;
let rx = seed_prescription(&app, patient_id).await;
dialysis_prescription_service::delete_prescription(
app.dialysis_state(), app.tenant_id(), rx.id,
Some(app.operator_id()), rx.version,
)
.await
.expect("删除应成功");
let result = dialysis_prescription_service::get_prescription(
app.dialysis_state(), app.tenant_id(), rx.id,
)
.await;
assert!(result.is_err(), "软删除后查询应失败");
}
// ---------------------------------------------------------------------------
// 测试 6: 租户隔离
// ---------------------------------------------------------------------------
#[tokio::test]
async fn test_dialysis_prescription_tenant_isolation() {
let app = TestApp::new().await;
let patient_id = app.create_patient("方案隔离患者").await;
seed_prescription(&app, patient_id).await;
let other_tenant = uuid::Uuid::new_v4();
let list = dialysis_prescription_service::list_prescriptions(
app.dialysis_state(), other_tenant, 1, 20, None, None,
)
.await
.unwrap();
assert_eq!(list.total, 0, "不同租户不应看到方案");
}
// ---------------------------------------------------------------------------
// 测试 7: 乐观锁冲突
// ---------------------------------------------------------------------------
#[tokio::test]
async fn test_dialysis_prescription_version_conflict() {
let app = TestApp::new().await;
let patient_id = app.create_patient("方案锁患者").await;
let rx = seed_prescription(&app, patient_id).await;
// 先更新一次
dialysis_prescription_service::update_prescription(
app.dialysis_state(), app.tenant_id(), rx.id,
Some(app.operator_id()),
UpdateDialysisPrescriptionReq {
blood_flow_rate: Some(350),
status: None, dialyzer_model: None, membrane_area: None,
dialysate_potassium: None, dialysate_calcium: None,
dialysate_bicarbonate: None, anticoagulation_type: None,
anticoagulation_dose: None, target_ultrafiltration_ml: None,
target_dry_weight: None, frequency_per_week: None,
dialysate_flow_rate: None, duration_minutes: None,
vascular_access_type: None, vascular_access_location: None,
effective_from: None, effective_to: None, notes: None,
},
rx.version,
)
.await
.unwrap();
// 用旧 version 再更新应失败
let result = dialysis_prescription_service::update_prescription(
app.dialysis_state(), app.tenant_id(), rx.id,
Some(app.operator_id()),
UpdateDialysisPrescriptionReq {
blood_flow_rate: Some(400),
status: None, dialyzer_model: None, membrane_area: None,
dialysate_potassium: None, dialysate_calcium: None,
dialysate_bicarbonate: None, anticoagulation_type: None,
anticoagulation_dose: None, target_ultrafiltration_ml: None,
target_dry_weight: None, frequency_per_week: None,
dialysate_flow_rate: None, duration_minutes: None,
vascular_access_type: None, vascular_access_location: None,
effective_from: None, effective_to: None, notes: None,
},
rx.version,
)
.await;
assert!(result.is_err(), "乐观锁冲突应返回错误");
}