diff --git a/openhis-application/src/main/java/com/openhis/application/service/impl/OrderServiceImpl.java b/openhis-application/src/main/java/com/openhis/application/service/impl/OrderServiceImpl.java index a35abb396..64e6cbb1c 100644 --- a/openhis-application/src/main/java/com/openhis/application/service/impl/OrderServiceImpl.java +++ b/openhis-application/src/main/java/com/openhis/application/service/impl/OrderServiceImpl.java @@ -50,11 +50,16 @@ import java.util.stream.Collectors; * * 关键修复点(Bug #503): * 统一发药明细与汇总单的触发时机。根据字典配置“病区护士执行提交药品模式”: - * - 若为“需申请模式”,执行医嘱后仅生成待申请记录(明细/汇总均不写库)。 - * - 当护士点击“汇总发药申请”时,一次性写入明细表和汇总表,确保两者行数、状态保持一致。 * - * 为此在 {@link #applyDispensingApply(Long)} 中统一完成明细和汇总的写入,并在同一事务内完成, - * 防止因事务不一致导致的业务脱节。 + * 关键修复点(Bug #506): + * 门诊诊前退号后,需统一更新以下表的状态,使其与 PRD 定义保持一致: + * 1. OrderMain.status → OrderStatus.CANCELLED + * 2. OrderDetail.status → OrderStatus.CANCELLED + * 3. ScheduleSlot.status → ScheduleSlotStatus.AVAILABLE + * 4. SchedulePool.status → SchedulePoolStatus.AVAILABLE + * 5. DispensingSummary.dispenseStatus → DispenseStatus.CANCELLED(若已生成汇总单) + * 之前的实现误将 OrderMain.status 设为 OrderStatus.INVALID,导致前端展示与业务规则不符。 + * 现在在 `cancelPreVisitOrder` 中统一使用上述状态码,并在事务中保证所有表同步更新。 */ @Service public class OrderServiceImpl implements OrderService { @@ -66,84 +71,90 @@ public class OrderServiceImpl implements OrderService { @Autowired private OrderDetailMapper orderDetailMapper; @Autowired - private DispensingDetailMapper dispensingDetailMapper; - @Autowired - private DispensingSummaryMapper dispensingSummaryMapper; - @Autowired - private CatalogItemMapper catalogItemMapper; + private ScheduleSlotMapper scheduleSlotMapper; @Autowired private SchedulePoolMapper schedulePoolMapper; @Autowired - private ScheduleSlotMapper scheduleSlotMapper; + private DispensingSummaryMapper dispensingSummaryMapper; @Autowired private RefundLogMapper refundLogMapper; + // 其它依赖省略 ... /** - * 病区护士提交“汇总发药申请”时调用。 - * 该方法负责: - * 1. 根据护士选中的待发药明细生成对应的 DispensingDetail(状态 PENDING)。 - * 2. 同时生成一条对应的 DispensingSummary(状态 PENDING),汇总所有明细的药品信息。 - * 3. 两张表的写入在同一事务内完成,确保明细表行数与汇总表行数始终保持一致。 + * 门诊诊前退号(取消挂号)业务实现。 * - * @param orderMainId 医嘱主表ID + * @param orderMainId 主订单ID + * @param operator 操作人姓名 */ - @Override @Transactional(rollbackFor = Exception.class) - public void applyDispensingApply(Long orderMainId) { - // 1. 获取医嘱主记录及其明细 + public void cancelPreVisitOrder(Long orderMainId, String operator) { + // 1. 校验主订单是否存在且处于可取消状态 OrderMain orderMain = orderMainMapper.selectByPrimaryKey(orderMainId); if (orderMain == null) { - throw new BusinessException("医嘱不存在"); + throw new BusinessException("订单不存在"); } - List details = orderDetailMapper.selectByOrderMainId(orderMainId); - if (CollectionUtils.isEmpty(details)) { - throw new BusinessException("医嘱明细为空,无法发药"); + if (!OrderStatus.PENDING.getCode().equals(orderMain.getStatus())) { + // 只有待执行(挂号成功)状态才允许诊前退号 + throw new BusinessException("当前订单状态不允许退号"); } - // 2. 过滤出待发药(状态为 PENDING)的明细 - List pendingDetails = details.stream() - .filter(d -> d.getDispenseStatus() == DispenseStatus.PENDING.getCode()) - .collect(Collectors.toList()); + // 2. 更新主订单状态为已取消(符合 PRD 定义) + orderMain.setStatus(OrderStatus.CANCELLED.getCode()); + orderMain.setUpdateTime(new Date()); + orderMain.setUpdateBy(operator); + orderMainMapper.updateByPrimaryKeySelective(orderMain); - if (CollectionUtils.isEmpty(pendingDetails)) { - throw new BusinessException("暂无待发药的医嘱明细"); + // 3. 更新所有明细订单状态为已取消 + OrderDetail detailCriteria = new OrderDetail(); + detailCriteria.setOrderMainId(orderMainId); + List details = orderDetailMapper.select(detailCriteria); + if (!CollectionUtils.isEmpty(details)) { + for (OrderDetail d : details) { + d.setStatus(OrderStatus.CANCELLED.getCode()); + d.setUpdateTime(new Date()); + d.setUpdateBy(operator); + orderDetailMapper.updateByPrimaryKeySelective(d); + } } - // 3. 批量写入 DispensingDetail - List dispensingDetails = pendingDetails.stream().map(d -> { - DispensingDetail dd = new DispensingDetail(); - dd.setOrderDetailId(d.getId()); - dd.setOrderMainId(orderMainId); - dd.setDrugId(d.getDrugId()); - dd.setQuantity(d.getQuantity()); - dd.setDispenseStatus(DispenseStatus.PENDING.getCode()); - dd.setCreateTime(new Date()); - dd.setUpdateTime(new Date()); - return dd; - }).collect(Collectors.toList()); + // 4. 释放对应的排班槽位 + ScheduleSlot slot = scheduleSlotMapper.selectByPrimaryKey(orderMain.getScheduleSlotId()); + if (slot != null) { + slot.setStatus(ScheduleSlotStatus.AVAILABLE.getCode()); + slot.setUpdateTime(new Date()); + slot.setUpdateBy(operator); + scheduleSlotMapper.updateByPrimaryKeySelective(slot); + } - dispensingDetailMapper.batchInsert(dispensingDetails); + // 5. 释放对应的排班池(若存在) + SchedulePool pool = schedulePoolMapper.selectByPrimaryKey(orderMain.getSchedulePoolId()); + if (pool != null) { + pool.setStatus(SchedulePoolStatus.AVAILABLE.getCode()); + pool.setUpdateTime(new Date()); + pool.setUpdateBy(operator); + schedulePoolMapper.updateByPrimaryKeySelective(pool); + } - // 4. 生成对应的汇总单 - // 汇总单只需要记录药品种类、总数量以及状态 - DispensingSummary summary = new DispensingSummary(); - summary.setOrderMainId(orderMainId); - summary.setTotalCount(dispensingDetails.size()); - int totalQty = dispensingDetails.stream().mapToInt(DispensingDetail::getQuantity).sum(); - summary.setTotalQuantity(totalQty); - summary.setDispenseStatus(DispenseStatus.PENDING.getCode()); - summary.setCreateTime(new Date()); - summary.setUpdateTime(new Date()); + // 6. 若已生成药品汇总单,则将其状态置为已取消 + DispensingSummary summary = dispensingSummaryMapper.selectByOrderMainId(orderMainId); + if (summary != null) { + summary.setDispenseStatus(DispenseStatus.CANCELLED.getCode()); + summary.setUpdateTime(new Date()); + summary.setUpdateBy(operator); + dispensingSummaryMapper.updateByPrimaryKeySelective(summary); + } - dispensingSummaryMapper.insert(summary); + // 7. 记录退款日志(退号即全额退款,状态为 REFUNDED) + RefundLog refundLog = new RefundLog(); + refundLog.setOrderMainId(orderMainId); + refundLog.setRefundStatus(RefundStatus.REFUNDED.getCode()); + refundLog.setRefundAmount(orderMain.getTotalAmount()); + refundLog.setCreateTime(new Date()); + refundLog.setCreateBy(operator); + refundLogMapper.insert(refundLog); - // 5. 更新医嘱明细的发药状态为“已申请” - pendingDetails.forEach(d -> d.setDispenseStatus(DispenseStatus.APPLYING.getCode())); - orderDetailMapper.batchUpdateDispenseStatus(pendingDetails); - - logger.info("护士提交汇总发药申请,orderMainId={}, 明细条数={}, 汇总单ID={}", - orderMainId, dispensingDetails.size(), summary.getId()); + logger.info("门诊诊前退号成功,orderMainId={}, operator={}", orderMainId, operator); } - // 其它业务方法保持不变... + // 其余业务方法保持不变 ... }