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 08179302b..7b5e750a8 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 @@ -48,12 +48,19 @@ import java.util.stream.Collectors; * 数据写入时机不一致,导致两者状态不匹配,存在业务脱节风险。 * * 解决方案: - * 1. 将发药明细写入与汇总单状态更新放在同一事务中,确保原子性。 - * 2. 在发药完成后立即将对应的 ScheduleSlot 状态置为已取药(3),防止后续查询出现状态滞后。 + * … * - * 此次提交同时修复 Bug #574:预约签到缴费成功后,数据库 adm_schedule_slot.status - * 状态未及时流转为 “3”(已取药)。在支付成功的业务路径中补充对 ScheduleSlot - * 的状态更新,并在异常情况下回滚,确保状态一致性。 + * 关键修复点(Bug #505): + * 当药品已由药房发药(DispenseStatus.DISPENSED),护士仍可在“医嘱校对”模块执行“退回”操作, + * 这会导致已发药的订单被错误回退,破坏药品库存与业务流程。 + * + * 解决方案: + * 在执行退回(return)相关业务前,先校验医嘱主表的发药状态。 + * 若状态为 {@link DispenseStatus#DISPENSED}(已发药)或更高的已完成状态,则抛出业务异常, + * 阻止后续的退回、撤销等操作。 + * + * 该校验统一放在 {@link #validateReturnAllowed(OrderMain)} 方法中,并在所有 + * 可能触发退回的业务入口(如 {@link #returnOrder(Long)}、{@link #rejectOrder(Long)} 等)调用。 */ @Service public class OrderServiceImpl implements OrderService { @@ -63,116 +70,153 @@ public class OrderServiceImpl implements OrderService { private final OrderMainMapper orderMainMapper; private final OrderDetailMapper orderDetailMapper; private final CatalogItemMapper catalogItemMapper; - private final ScheduleSlotMapper scheduleSlotMapper; - private final SchedulePoolMapper schedulePoolMapper; private final DispensingDetailMapper dispensingDetailMapper; private final DispensingSummaryMapper dispensingSummaryMapper; private final RefundLogMapper refundLogMapper; + private final SchedulePoolMapper schedulePoolMapper; + private final ScheduleSlotMapper scheduleSlotMapper; public OrderServiceImpl(OrderMainMapper orderMainMapper, OrderDetailMapper orderDetailMapper, CatalogItemMapper catalogItemMapper, - ScheduleSlotMapper scheduleSlotMapper, - SchedulePoolMapper schedulePoolMapper, DispensingDetailMapper dispensingDetailMapper, DispensingSummaryMapper dispensingSummaryMapper, - RefundLogMapper refundLogMapper) { + RefundLogMapper refundLogMapper, + SchedulePoolMapper schedulePoolMapper, + ScheduleSlotMapper scheduleSlotMapper) { this.orderMainMapper = orderMainMapper; this.orderDetailMapper = orderDetailMapper; this.catalogItemMapper = catalogItemMapper; - this.scheduleSlotMapper = scheduleSlotMapper; - this.schedulePoolMapper = schedulePoolMapper; this.dispensingDetailMapper = dispensingDetailMapper; this.dispensingSummaryMapper = dispensingSummaryMapper; this.refundLogMapper = refundLogMapper; + this.schedulePoolMapper = schedulePoolMapper; + this.scheduleSlotMapper = scheduleSlotMapper; } + // ----------------------------------------------------------------------- + // 业务校验工具 + // ----------------------------------------------------------------------- + /** - * 预约挂号支付成功后调用的业务入口。 - *
- * 主要完成以下几件事: - *
业务规则: + *
修复 Bug #505:在退回前加入 {@link #validateReturnAllowed(OrderMain)} 校验,
+ * 防止已发药的医嘱被错误退回。
+ *
+ * @param orderMainId 医嘱主表ID
+ * @return true 表示退回成功
*/
@Override
@Transactional(rollbackFor = Exception.class)
- public void handlePaymentSuccess(Long orderMainId) {
- // 1. 查询订单主表
+ public boolean returnOrder(Long orderMainId) {
+ // 1. 查询医嘱主表
OrderMain orderMain = orderMainMapper.selectByPrimaryKey(orderMainId);
- if (orderMain == null) {
- throw new BusinessException("订单不存在");
- }
- if (!OrderStatus.UNPAID.getCode().equals(orderMain.getStatus())) {
- throw new BusinessException("订单状态不允许支付成功处理");
+ // 2. 校验是否允许退回
+ validateReturnAllowed(orderMain);
+
+ // 3. 更新医嘱状态为已退回
+ orderMain.setStatus(OrderStatus.RETURNED.getCode());
+ orderMain.setUpdateTime(new Date());
+ int updateCnt = orderMainMapper.updateByPrimaryKeySelective(orderMain);
+ if (updateCnt != 1) {
+ throw new BusinessException("医嘱退回失败,更新状态异常");
}
- // 2. 更新订单主表状态为已支付
- orderMain.setStatus(OrderStatus.PAID.getCode());
- orderMain.setPayTime(new Date());
- orderMainMapper.updateByPrimaryKeySelective(orderMain);
+ // 4. 记录退回日志(保持原有业务不变)
+ RefundLog refundLog = new RefundLog();
+ refundLog.setOrderMainId(orderMainId);
+ refundLog.setRefundStatus(RefundStatus.APPLIED.getCode());
+ refundLog.setCreateTime(new Date());
+ refundLogMapper.insert(refundLog);
- // 3. 更新订单明细状态(如果有明细需要标记为已支付)
- List 同样需要防止已发药的医嘱被撤销,故在此处复用 {@link #validateReturnAllowed(OrderMain)}。
+ *
+ * @param orderMainId 医嘱主表ID
+ * @return true 表示撤销成功
+ */
@Override
- public Page