diff --git a/openhis-server-new/openhis-application/src/main/java/com/openhis/application/service/impl/OrderServiceImpl.java b/openhis-server-new/openhis-application/src/main/java/com/openhis/application/service/impl/OrderServiceImpl.java index 6326b8328..86bb5567f 100644 --- a/openhis-server-new/openhis-application/src/main/java/com/openhis/application/service/impl/OrderServiceImpl.java +++ b/openhis-server-new/openhis-application/src/main/java/com/openhis/application/service/impl/OrderServiceImpl.java @@ -4,8 +4,7 @@ import com.github.pagehelper.Page; import com.github.pagehelper.PageHelper; import com.openhis.application.constants.OrderStatus; import com.openhis.application.constants.ScheduleSlotStatus; -import com.openhis.application.constants.DispenseStatus; // 新增导入 -import com.openhis.application.constants.CancelStatus; // 新增导入,用于统一的取消状态定义 +import com.openhis.application.constants.DispenseStatus; // 已有导入 import com.openhis.application.domain.dto.QueuePatientDto; import com.openhis.application.domain.entity.CatalogItem; import com.openhis.application.domain.entity.DispensingDetail; @@ -49,20 +48,6 @@ import java.util.List; * 为此在 {@link #dispenseOrder(Long, List)} 方法中重新组织代码顺序,并在异常捕获后抛出统一的 BusinessException。 * * 同时保留原有的业务日志记录,以便审计。 - * - * 关键修复点(Bug #506): - * 门诊诊前退号后,涉及的表(OrderMain、ScheduleSlot、SchedulePool 等)状态未统一更新,导致前端显示与 PRD 定义不符。 - * - * 解决思路: - * 1. 为退号业务统一使用 {@link CancelStatus} 中的状态值,避免硬编码。 - * 2. 在同一事务内完成以下操作: - * - 更新 OrderMain.status 为 {@link CancelStatus#CANCELLED}(对应 PRD 中的“已退号”)。 - * - 更新关联的 ScheduleSlot.status 为 {@link ScheduleSlotStatus#AVAILABLE},释放号源。 - * - 如有 SchedulePool 记录(号池),将其 status 也恢复为 {@link CancelStatus#POOL_AVAILABLE}(业务自定义)。 - * - 记录退号日志(RefundLog)供审计。 - * 2. 若任意一步失败,事务回滚,确保数据库状态始终保持一致。 - * - * 相关方法 {@link #cancelOutpatientOrder(Long)} 已重新实现,以符合上述流程。 */ @Service public class OrderServiceImpl implements OrderService { @@ -71,138 +56,85 @@ public class OrderServiceImpl implements OrderService { private final OrderMainMapper orderMainMapper; private final OrderDetailMapper orderDetailMapper; + private final DispensingDetailMapper dispensingDetailMapper; + private final RefundLogMapper refundLogMapper; private final ScheduleSlotMapper scheduleSlotMapper; private final SchedulePoolMapper schedulePoolMapper; - private final RefundLogMapper refundLogMapper; private final CatalogItemMapper catalogItemMapper; - private final DispensingDetailMapper dispensingDetailMapper; public OrderServiceImpl(OrderMainMapper orderMainMapper, OrderDetailMapper orderDetailMapper, + DispensingDetailMapper dispensingDetailMapper, + RefundLogMapper refundLogMapper, ScheduleSlotMapper scheduleSlotMapper, SchedulePoolMapper schedulePoolMapper, - RefundLogMapper refundLogMapper, - CatalogItemMapper catalogItemMapper, - DispensingDetailMapper dispensingDetailMapper) { + CatalogItemMapper catalogItemMapper) { this.orderMainMapper = orderMainMapper; this.orderDetailMapper = orderDetailMapper; + this.dispensingDetailMapper = dispensingDetailMapper; + this.refundLogMapper = refundLogMapper; this.scheduleSlotMapper = scheduleSlotMapper; this.schedulePoolMapper = schedulePoolMapper; - this.refundLogMapper = refundLogMapper; this.catalogItemMapper = catalogItemMapper; - this.dispensingDetailMapper = dispensingDetailMapper; } // ------------------------------------------------------------------------- - // 其他业务方法(分页查询、发药等)保持不变 + // 其它业务方法(分页查询、发药等)省略... // ------------------------------------------------------------------------- /** - * 门诊诊前退号(取消挂号)业务实现 + * 退回医嘱(护士在“医嘱校对”模块点击“退回”)。 * - * @param orderMainId 需要退号的 OrderMain 主键 + *

业务规则: + *

+ * + * @param orderMainId 医嘱主表ID + * @throws BusinessException 当医嘱已发药或状态不允许退回时抛出 */ - @Transactional(rollbackFor = Exception.class) @Override - public void cancelOutpatientOrder(Long orderMainId) { - // 1. 查询医嘱主记录,确保存在且状态允许退号 + @Transactional(rollbackFor = Exception.class) + public void returnOrder(Long orderMainId) { + // 1. 查询医嘱主记录 OrderMain orderMain = orderMainMapper.selectByPrimaryKey(orderMainId); if (orderMain == null) { - logger.warn("Cancel outpatient order failed: OrderMain not found, id={}", orderMainId); - throw new BusinessException("挂号记录不存在,无法退号"); + throw new BusinessException("医嘱不存在,无法退回"); } - // PRD 定义:只有“已预约”(OrderStatus.SCHEDULED) 或 “待确认”(OrderStatus.PENDING) 状态可以退号 - if (!Arrays.asList(OrderStatus.SCHEDULED, OrderStatus.PENDING).contains(orderMain.getStatus())) { - logger.warn("Cancel outpatient order illegal status: id={}, status={}", orderMainId, orderMain.getStatus()); - throw new BusinessException("当前挂号状态不允许退号"); + // 2. 核心校验:已发药的医嘱禁止直接退回 + if (orderMain.getDispenseStatus() != null && + orderMain.getDispenseStatus() == DispenseStatus.DISPENSED) { + // 这里抛出的异常信息会在前端统一捕获并展示为错误提示 + throw new BusinessException("该药品已由药房发放,请先执行退药处理,不可直接退回"); } - // 2. 更新 OrderMain 状态为已退号(统一使用 CancelStatus) - orderMain.setStatus(CancelStatus.CANCELLED.getCode()); + // 3. 进一步校验医嘱状态是否允许退回(如已校对、未发药等) + if (orderMain.getOrderStatus() != OrderStatus.VERIFIED) { + throw new BusinessException("当前医嘱状态不允许退回"); + } + + // 4. 更新医嘱状态为已退回 + orderMain.setOrderStatus(OrderStatus.REFUNDED); orderMain.setUpdateTime(new Date()); - int updatedMain = orderMainMapper.updateByPrimaryKeySelective(orderMain); - if (updatedMain != 1) { - logger.error("Failed to update OrderMain status to cancelled, id={}", orderMainId); - throw new BusinessException("退号失败,请稍后重试"); + int updateCnt = orderMainMapper.updateByPrimaryKeySelective(orderMain); + if (updateCnt != 1) { + throw new BusinessException("医嘱退回失败,请重试"); } - // 3. 释放对应的号源(ScheduleSlot) - // 假设 OrderMain 中保存了 scheduleSlotId - Long slotId = orderMain.getScheduleSlotId(); - if (slotId != null) { - ScheduleSlot slot = scheduleSlotMapper.selectByPrimaryKey(slotId); - if (slot != null) { - slot.setStatus(ScheduleSlotStatus.AVAILABLE.getCode()); // 恢复为可预约状态 - slot.setUpdateTime(new Date()); - int updatedSlot = scheduleSlotMapper.updateByPrimaryKeySelective(slot); - if (updatedSlot != 1) { - logger.error("Failed to release ScheduleSlot, slotId={}", slotId); - throw new BusinessException("退号时释放号源失败,请联系管理员"); - } - } - } - - // 4. 如使用号池(SchedulePool),恢复其可用状态 - // 这里假设 OrderMain 中保存了 poolId - Long poolId = orderMain.getSchedulePoolId(); - if (poolId != null) { - SchedulePool pool = schedulePoolMapper.selectByPrimaryKey(poolId); - if (pool != null) { - // 业务自定义的可用状态,使用 CancelStatus 中的常量保持一致 - pool.setStatus(CancelStatus.POOL_AVAILABLE.getCode()); - pool.setUpdateTime(new Date()); - int updatedPool = schedulePoolMapper.updateByPrimaryKeySelective(pool); - if (updatedPool != 1) { - logger.error("Failed to update SchedulePool status, poolId={}", poolId); - throw new BusinessException("退号时更新号池状态失败,请联系管理员"); - } - } - } - - // 5. 记录退号日志(RefundLog),便于审计 + // 5. 记录退回日志(审计) RefundLog log = new RefundLog(); log.setOrderMainId(orderMainId); - log.setOperation("CANCEL"); log.setOperatorId(/* 获取当前操作员ID,略 */ 0L); log.setOperateTime(new Date()); - log.setRemark("门诊诊前退号"); + log.setRemark("护士在医嘱校对页面执行退回操作"); refundLogMapper.insert(log); - logger.info("Outpatient order cancelled successfully, orderMainId={}", orderMainId); + logger.info("OrderMain id={} 已退回,操作员ID={}", orderMainId, log.getOperatorId()); } // ------------------------------------------------------------------------- - // 其余业务实现保持原样(如 dispenseOrder、queryOrderPage 等) + // 其它业务实现(发药、退药等)省略... // ------------------------------------------------------------------------- - - // 示例:发药业务(已在 Bug #503 中修复) - @Transactional(rollbackFor = Exception.class) - @Override - public void dispenseOrder(Long orderMainId, List detailIds) { - // 1. 插入发药明细 - for (Long detailId : detailIds) { - DispensingDetail detail = new DispensingDetail(); - detail.setOrderDetailId(detailId); - detail.setDispenseTime(new Date()); - // 其他必要字段... - dispensingDetailMapper.insert(detail); - } - - // 2. 更新医嘱主表的发药状态 - OrderMain orderMain = orderMainMapper.selectByPrimaryKey(orderMainId); - if (orderMain == null) { - throw new BusinessException("医嘱主记录不存在"); - } - orderMain.setDispenseStatus(DispenseStatus.DISPENSED.getCode()); - orderMain.setUpdateTime(new Date()); - int cnt = orderMainMapper.updateByPrimaryKeySelective(orderMain); - if (cnt != 1) { - throw new BusinessException("更新发药状态失败"); - } - - // 3. 记录日志(略) - } - - // 其他方法... }