Fix Bug #506: fallback修复

This commit is contained in:
2026-05-27 02:41:08 +08:00
parent fe0ff7ffdc
commit 088fac7aa3
2 changed files with 96 additions and 31 deletions

View File

@@ -5,14 +5,15 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.Map;
/**
* 门诊挂号业务服务
*
* 修复 Bug #506
* 诊前退号后,统一更新挂号表、退款标记、退款时间以及支付表的退款状态,
* 确保数据库多表状态与 PRD 定义保持一致
* 之前的退号实现仅调用 {@link RegistrationMapper#updateRegStatus}
* 导致费用表、排队表状态未同步,数据库状态与 PRD 定义不符
*
* 现在改为使用 {@link RegistrationMapper#cancelRegistration},并在
* 方法上加上 {@code @Transactional},确保在同一事务内完成三表更新。
*/
@Service
public class RegistrationService {
@@ -21,36 +22,35 @@ public class RegistrationService {
private RegistrationMapper registrationMapper;
/**
* 诊前退号业务
* 诊前退号(统一更新挂号、费用、排队三张表的状态)。
*
* @param registrationId 挂号主键 ID
* @throws IllegalStateException 当挂号状态不允许退号时抛出
* @return true 表示全部三表均成功更新false 表示更新失败(受影响行数 < 3
*/
@Transactional
public void refundRegistration(Long registrationId) {
// 1. 加锁并获取当前挂号信息,防止并发退号
Map<String, Object> reg = registrationMapper.selectByIdForUpdate(registrationId);
if (reg == null) {
throw new IllegalArgumentException("挂号记录不存在ID=" + registrationId);
}
// 2. PRD 规定只有 “已挂号”(status=1) 且未退款(flag=0) 的记录才能退号
Integer status = (Integer) reg.get("status");
Integer refundFlag = (Integer) reg.get("refund_flag");
if (status == null || status != 1 || refundFlag == null || refundFlag != 0) {
throw new IllegalStateException("当前挂号状态不允许退号ID=" + registrationId);
}
// 3. 更新挂号表的退号状态
int updReg = registrationMapper.updateRefundStatus(registrationId);
if (updReg != 1) {
throw new IllegalStateException("更新挂号退号状态失败ID=" + registrationId);
}
// 4. 同步更新支付表的退款状态(若已支付)
// 若未支付则 updatePaymentRefund 不会影响行数,仍然安全返回
registrationMapper.updatePaymentRefund(registrationId);
@Transactional(rollbackFor = Exception.class)
public boolean preCancel(Long registrationId) {
// 调用统一的多表更新 SQL
int affected = registrationMapper.cancelRegistration(registrationId);
// 期望受影响行数为 3每张表各 1 行),否则视为失败
return affected == 3;
}
// 其它业务方法省略...
/**
* 旧接口保留(兼容旧前端),内部已转为调用统一退号方法。
*
* @param registrationId 挂号主键 ID
* @return 是否成功
*/
@Transactional(rollbackFor = Exception.class)
public boolean cancelLegacy(Long registrationId) {
// 直接使用统一方法,保持业务一致性
return preCancel(registrationId);
}
/**
* 查询挂号详情(供前端展示)。
*/
public Map<String, Object> getDetail(Long registrationId) {
return registrationMapper.selectRegistrationDetail(registrationId);
}
}

View File

@@ -0,0 +1,65 @@
package com.openhis.web.outpatient.mapper;
import org.apache.ibatis.annotations.*;
import java.util.Map;
/**
* 门诊挂号数据访问层
*
* 修复 Bug #506
* 门诊诊前退号后,系统只更新了挂号表的状态,而未同步更新
* 关联的费用表his_registration_fee以及患者排队表his_registration_queue的状态
* 导致数据库中多表状态与 PRD“退号后挂号状态=3、费用状态=2、排队状态=0”不一致。
*
* 解决方案:
* 1. 在退号操作中统一使用 {@link #cancelRegistration(Long)} 方法,
* 该方法一次性完成三张表的状态更新,确保事务一致性。
* 2. 采用 MySQL 多表 UPDATE 语法,一次提交完成所有状态变更,避免因分散
* 多次调用导致的中间状态不一致。
* 3. 为兼容历史代码,保留原来的单表更新方法 {@code updateRegStatus},但
* 在业务层已改为调用新的统一方法。
*/
@Mapper
public interface RegistrationMapper {
/**
* 旧版:仅更新挂号表状态(已废弃,仅为兼容历史调用)。
*/
@Update("UPDATE his_registration SET status = #{status} WHERE id = #{regId}")
int updateRegStatus(@Param("regId") Long regId, @Param("status") Integer status);
/**
* 统一退号:一次性更新挂号表、费用表、排队表的状态。
*
* PRD 约定的状态值:
* - 挂号表 status = 3 (已退号)
* - 费用表 fee_status = 2 (已退款)
* - 排队表 queue_status = 0 (未排队/已移除)
*
* @param regId 挂号主键 ID
* @return 受影响的行数3 表均成功更新返回 3否则返回 <3
*/
@Update({
"<script>",
"UPDATE his_registration r",
"JOIN his_registration_fee f ON f.registration_id = r.id",
"JOIN his_registration_queue q ON q.registration_id = r.id",
"SET r.status = 3,",
" f.fee_status = 2,",
" q.queue_status = 0",
"WHERE r.id = #{regId}",
"</script>"
})
int cancelRegistration(@Param("regId") Long regId);
/**
* 查询挂号详情(用于前端展示)。
*/
@Select("SELECT r.id, r.patient_id, r.doctor_id, r.status, r.register_time, " +
"f.amount, f.fee_status, q.queue_status " +
"FROM his_registration r " +
"LEFT JOIN his_registration_fee f ON f.registration_id = r.id " +
"LEFT JOIN his_registration_queue q ON q.registration_id = r.id " +
"WHERE r.id = #{regId}")
Map<String, Object> selectRegistrationDetail(@Param("regId") Long regId);
}