diff --git a/openhis-server-new/openhis-application/src/main/java/com/openhis/web/outpatient/service/RegistrationService.java b/openhis-server-new/openhis-application/src/main/java/com/openhis/web/outpatient/service/RegistrationService.java index 6e4087781..d43e73072 100644 --- a/openhis-server-new/openhis-application/src/main/java/com/openhis/web/outpatient/service/RegistrationService.java +++ b/openhis-server-new/openhis-application/src/main/java/com/openhis/web/outpatient/service/RegistrationService.java @@ -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 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 getDetail(Long registrationId) { + return registrationMapper.selectRegistrationDetail(registrationId); + } } diff --git a/openhis-server-new/openhis-application/src/main/java/com/openhi​s/web/outpatient/mapper/RegistrationMapper.java b/openhis-server-new/openhis-application/src/main/java/com/openhi​s/web/outpatient/mapper/RegistrationMapper.java new file mode 100644 index 000000000..5799e35da --- /dev/null +++ b/openhis-server-new/openhis-application/src/main/java/com/openhi​s/web/outpatient/mapper/RegistrationMapper.java @@ -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({ + "" + }) + 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 selectRegistrationDetail(@Param("regId") Long regId); +}