diff --git a/crates/erp-server/tests/integration/health_appointment_tests.rs b/crates/erp-server/tests/integration/health_appointment_tests.rs index de19b11..5802f05 100644 --- a/crates/erp-server/tests/integration/health_appointment_tests.rs +++ b/crates/erp-server/tests/integration/health_appointment_tests.rs @@ -5,7 +5,7 @@ //! 预约创建依赖患者 + 医护档案 + 排班三条前置数据。 use erp_core::events::EventBus; -use erp_health::dto::appointment_dto::CreateAppointmentReq; +use erp_health::dto::appointment_dto::{CreateAppointmentReq, UpdateAppointmentStatusReq}; use erp_health::dto::doctor_dto::CreateDoctorReq; use erp_health::dto::patient_dto::CreatePatientReq; use erp_health::service::{ @@ -246,3 +246,149 @@ async fn test_appointment_tenant_isolation() { "跨租户查询预约应返回错误" ); } + +// --------------------------------------------------------------------------- +// 测试 4: 预约状态流转 — pending → confirmed → completed +// --------------------------------------------------------------------------- + +#[tokio::test] +async fn test_appointment_status_flow() { + let test_db = TestDb::new().await; + let state = make_state(test_db.db()); + let tenant_id = uuid::Uuid::new_v4(); + let operator_id = uuid::Uuid::new_v4(); + + let patient_id = seed_patient(&state, tenant_id, "状态患者").await; + let doctor_id = seed_doctor(&state, tenant_id, "状态医生").await; + let date = chrono::NaiveDate::from_ymd_opt(2026, 5, 15).unwrap(); + seed_schedule(&state, tenant_id, doctor_id, date).await; + + let appt = appointment_service::create_appointment( + &state, tenant_id, Some(operator_id), + CreateAppointmentReq { + patient_id, + doctor_id: Some(doctor_id), + appointment_type: None, + appointment_date: date, + start_time: chrono::NaiveTime::from_hms_opt(9, 0, 0).unwrap(), + end_time: chrono::NaiveTime::from_hms_opt(9, 30, 0).unwrap(), + notes: None, + }, + ) + .await + .expect("创建预约应成功"); + assert_eq!(appt.status, "pending"); + + // pending → confirmed + let confirmed = appointment_service::update_appointment_status( + &state, tenant_id, appt.id, Some(operator_id), + UpdateAppointmentStatusReq { status: "confirmed".to_string(), cancel_reason: None }, + appt.version, + ) + .await + .expect("确认应成功"); + assert_eq!(confirmed.status, "confirmed"); + + // confirmed → completed + let completed = appointment_service::update_appointment_status( + &state, tenant_id, appt.id, Some(operator_id), + UpdateAppointmentStatusReq { status: "completed".to_string(), cancel_reason: None }, + confirmed.version, + ) + .await + .expect("完成应成功"); + assert_eq!(completed.status, "completed"); +} + +// --------------------------------------------------------------------------- +// 测试 5: 预约取消 — pending → cancelled +// --------------------------------------------------------------------------- + +#[tokio::test] +async fn test_appointment_cancel() { + let test_db = TestDb::new().await; + let state = make_state(test_db.db()); + let tenant_id = uuid::Uuid::new_v4(); + + let patient_id = seed_patient(&state, tenant_id, "取消患者").await; + let doctor_id = seed_doctor(&state, tenant_id, "取消医生").await; + let date = chrono::NaiveDate::from_ymd_opt(2026, 5, 16).unwrap(); + seed_schedule(&state, tenant_id, doctor_id, date).await; + + let appt = appointment_service::create_appointment( + &state, tenant_id, None, + CreateAppointmentReq { + patient_id, + doctor_id: Some(doctor_id), + appointment_type: None, + appointment_date: date, + start_time: chrono::NaiveTime::from_hms_opt(9, 0, 0).unwrap(), + end_time: chrono::NaiveTime::from_hms_opt(9, 30, 0).unwrap(), + notes: None, + }, + ) + .await + .expect("创建应成功"); + + let cancelled = appointment_service::update_appointment_status( + &state, tenant_id, appt.id, None, + UpdateAppointmentStatusReq { + status: "cancelled".to_string(), + cancel_reason: Some("患者临时有事".to_string()), + }, + appt.version, + ) + .await + .expect("取消应成功"); + assert_eq!(cancelled.status, "cancelled"); +} + +// --------------------------------------------------------------------------- +// 测试 6: 预约乐观锁 — 旧版本更新拒绝 +// --------------------------------------------------------------------------- + +#[tokio::test] +async fn test_appointment_version_conflict() { + let test_db = TestDb::new().await; + let state = make_state(test_db.db()); + let tenant_id = uuid::Uuid::new_v4(); + let operator_id = uuid::Uuid::new_v4(); + + let patient_id = seed_patient(&state, tenant_id, "乐观锁患者").await; + let doctor_id = seed_doctor(&state, tenant_id, "乐观锁医生").await; + let date = chrono::NaiveDate::from_ymd_opt(2026, 5, 17).unwrap(); + seed_schedule(&state, tenant_id, doctor_id, date).await; + + let appt = appointment_service::create_appointment( + &state, tenant_id, Some(operator_id), + CreateAppointmentReq { + patient_id, + doctor_id: Some(doctor_id), + appointment_type: None, + appointment_date: date, + start_time: chrono::NaiveTime::from_hms_opt(9, 0, 0).unwrap(), + end_time: chrono::NaiveTime::from_hms_opt(9, 30, 0).unwrap(), + notes: None, + }, + ) + .await + .expect("创建应成功"); + + // 正确版本确认 + let _confirmed = appointment_service::update_appointment_status( + &state, tenant_id, appt.id, Some(operator_id), + UpdateAppointmentStatusReq { status: "confirmed".to_string(), cancel_reason: None }, + appt.version, + ) + .await + .expect("确认应成功"); + + // 用旧版本再更新应失败 + let result = appointment_service::update_appointment_status( + &state, tenant_id, appt.id, Some(operator_id), + UpdateAppointmentStatusReq { status: "cancelled".to_string(), cancel_reason: None }, + appt.version, // 旧版本 + ) + .await; + assert!(result.is_err(), "旧版本更新应失败"); +}