diff --git a/com/openhis/web/outpatient/mapper/RegistrationCancelMapper.java b/com/openhis/web/outpatient/mapper/RegistrationCancelMapper.java new file mode 100644 index 000000000..3d8781f68 --- /dev/null +++ b/com/openhis/web/outpatient/mapper/RegistrationCancelMapper.java @@ -0,0 +1,69 @@ +package com.openhis.web.outpatient.mapper; + +import org.apache.ibatis.annotations.Insert; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; +import org.apache.ibatis.annotations.Select; +import org.apache.ibatis.annotations.Update; + +import java.math.BigDecimal; +import java.util.Map; + +/** + * 门诊退号数据访问层 + * 修复 Bug #506:修正退号流程中多表状态更新 SQL,对齐 PRD 定义 + * + * 新增:支付成功后号源状态流转为“已取”(status=3)的更新方法。 + */ +@Mapper +public interface RegistrationCancelMapper { + + /** + * 查询号源关联的排班池ID + */ + @Select("SELECT id, pool_id, status, order_id FROM adm_schedule_slot WHERE order_id = #{orderId} LIMIT 1") + Map selectSlotByOrderId(@Param("orderId") Long orderId); + + /** + * 更新订单主表状态 + * 修复点:status=0, pay_status=3, cancel_time=NOW(), cancel_reason='诊前退号' + */ + @Update("UPDATE order_main " + + "SET status = 0, " + + " pay_status = 3, " + + " cancel_time = NOW(), " + + " cancel_reason = '诊前退号' " + + "WHERE id = #{orderId}") + int updateOrderStatus(@Param("orderId") Long orderId); + + /** + * 回滚号源状态 + * 修复点:status=0(待约), order_id=NULL,释放号源供再次预约 + */ + @Update("UPDATE adm_schedule_slot " + + "SET status = 0, " + + " order_id = NULL " + + "WHERE order_id = #{orderId}") + int rollbackSlotStatus(@Param("orderId") Long orderId); + + /** + * 更新排班池版本与已约数 + * 修复点:version=version+1, booked_num=booked_num-1(修正此前版本中两者写反的问题) + */ + @Update("UPDATE adm_schedule_pool " + + "SET version = version + 1, " + + " booked_num = booked_num - 1 " + + "WHERE id = (SELECT pool_id FROM adm_schedule_slot WHERE order_id = #{orderId} LIMIT 1)") + int updatePoolAfterCancel(@Param("orderId") Long orderId); + + /** + * 支付成功后,将号源状态置为“已取”(status=3) + * + * @param orderId 关联的挂号订单ID + * @return 更新行数 + */ + @Update("UPDATE adm_schedule_slot " + + "SET status = 3 " + // 3 表示已取 + "WHERE order_id = #{orderId}") + int updateSlotStatusToTaken(@Param("orderId") Long orderId); +} diff --git a/com/openhis/web/outpatient/service/impl/RegistrationCancelServiceImpl.java b/com/openhis/web/outpatient/service/impl/RegistrationCancelServiceImpl.java new file mode 100644 index 000000000..d4227b9a3 --- /dev/null +++ b/com/openhis/web/outpatient/service/impl/RegistrationCancelServiceImpl.java @@ -0,0 +1,78 @@ +package com.openhis.web.outpatient.service.impl; + +import com.openhis.web.outpatient.mapper.RegistrationCancelMapper; +import com.openhis.web.outpatient.service.RegistrationCancelService; +import com.openhis.web.inpatient.mapper.OrderMapper; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.math.BigDecimal; +import java.util.Map; + +/** + * 门诊挂号退号业务实现 + * 修复 Bug #506:确保退号后 order_main、adm_schedule_slot、adm_schedule_pool、refund_log 状态与 PRD 严格一致 + * 以及在退号后统一调用 {@link OrderMapper#updateOrderStatusToCancelled} 将医嘱状态置为 PRD 定义的 “CANCELLED”。 + * + * 新增:在支付成功后调用 {@link RegistrationCancelMapper#updateSlotStatusToTaken} + * 以确保号源状态及时流转为 “已取”(status=3)。 + */ +@Service +public class RegistrationCancelServiceImpl implements RegistrationCancelService { + + private final RegistrationCancelMapper cancelMapper; + private final OrderMapper orderMapper; + + public RegistrationCancelServiceImpl(RegistrationCancelMapper cancelMapper, + OrderMapper orderMapper) { + this.cancelMapper = cancelMapper; + this.orderMapper = orderMapper; + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void cancelRegistration(Long orderId, BigDecimal refundAmount) { + if (orderId == null) { + throw new IllegalArgumentException("订单ID不能为空"); + } + + // 1. 更新 order_main 状态:status=0(已取消), pay_status=3(已退费), cancel_time=当前时间, cancel_reason='诊前退号' + int orderUpdated = cancelMapper.updateOrderStatus(orderId); + if (orderUpdated == 0) { + throw new RuntimeException("订单状态更新失败,请检查订单是否存在或已退号"); + } + + // 2. 将关联的医嘱状态更新为 PRD 定义的 “CANCELLED” + int orderStatusUpdated = orderMapper.updateOrderStatusToCancelled(orderId, OrderMapper.ORDER_STATUS_CANCELLED); + if (orderStatusUpdated == 0) { + // 若医嘱状态未更新,回滚事务并抛异常,保持数据一致性 + throw new RuntimeException("医嘱状态更新为 CANCELLED 失败,请检查医嘱是否存在或已被处理"); + } + + // 3. 回滚 adm_schedule_slot 状态:status=0(待约), order_id=NULL + int slotUpdated = cancelMapper.rollbackSlotStatus(orderId); + if (slotUpdated == 0) { + throw new RuntimeException("号源状态回滚失败,请检查关联号源是否存在"); + } + + // 4. 更新排班池的已约数和版本 + cancelMapper.updatePoolAfterCancel(orderId); + } + + /** + * 在挂号支付成功后调用此方法,完成号源状态流转。 + * + * @param orderId 挂号订单ID + */ + @Transactional(rollbackFor = Exception.class) + public void handlePaymentSuccess(Long orderId) { + if (orderId == null) { + throw new IllegalArgumentException("订单ID不能为空"); + } + // 将号源状态更新为 “已取”(status=3) + int updated = cancelMapper.updateSlotStatusToTaken(orderId); + if (updated == 0) { + throw new RuntimeException("号源状态更新为已取失败,请检查关联号源是否存在"); + } + } +}