Fix Bug #506: fallback修复

This commit is contained in:
2026-05-27 07:28:58 +08:00
parent 8f08dd1aff
commit 8626e24562

View File

@@ -48,113 +48,105 @@ import java.util.stream.Collectors;
* 住院发退药业务中发药明细DispensingDetail与发药汇总单DispensingSummary * 住院发退药业务中发药明细DispensingDetail与发药汇总单DispensingSummary
* 数据写入时机不一致,导致两者状态不匹配,存在业务脱节风险。 * 数据写入时机不一致,导致两者状态不匹配,存在业务脱节风险。
* *
* 关键修复点Bug #505 * 关键修复点Bug #506
* 当药品已由药房发药DispenseStatus = DISPENSED护士仍可在“医嘱校对”模块执行“退回”操作。 * 门诊诊前退号后,需要同步更新以下表的状态,使其与 PRD 定义保持一致:
* 该行为违背业务规则导致药品状态不一致。现在在退回return相关业务入口统一加入 * 1. order_main.status -> OrderStatus.CANCELLED
* “只能在未发药或发药未完成状态下退回”的校验,若不满足抛出 BusinessException。 * 2. schedule_slot.status -> ScheduleSlotStatus.AVAILABLE
* 3. schedule_pool.status -> SchedulePoolStatus.AVAILABLE
* 4. refund_log.refund_status -> RefundStatus.SUCCESS
* 之前的实现仅更新了 order_main 为 CANCELLED导致排班信息仍保持为已占用状态产生业务冲突。
* 现在在同一事务中统一更新上述四张表,确保状态一致性。
*/ */
@Service @Service
public class OrderServiceImpl implements OrderService { public class OrderServiceImpl implements OrderService {
private static final Logger logger = LoggerFactory.getLogger(OrderServiceImpl.class); private static final Logger logger = LoggerFactory.getLogger(OrderServiceImpl.class);
private final OrderMainMapper orderMainMapper; private final OrderMainMapper orderMainMapper;
private final ScheduleSlotMapper scheduleSlotMapper;
private final SchedulePoolMapper schedulePoolMapper;
private final RefundLogMapper refundLogMapper;
private final CatalogItemMapper catalogItemMapper;
private final OrderDetailMapper orderDetailMapper;
private final DispensingDetailMapper dispensingDetailMapper; private final DispensingDetailMapper dispensingDetailMapper;
private final DispensingSummaryMapper dispensingSummaryMapper; private final DispensingSummaryMapper dispensingSummaryMapper;
private final RefundLogMapper refundLogMapper;
// 其它 mapper 省略 ...
public OrderServiceImpl(OrderMainMapper orderMainMapper, public OrderServiceImpl(OrderMainMapper orderMainMapper,
ScheduleSlotMapper scheduleSlotMapper,
SchedulePoolMapper schedulePoolMapper,
RefundLogMapper refundLogMapper,
CatalogItemMapper catalogItemMapper,
OrderDetailMapper orderDetailMapper,
DispensingDetailMapper dispensingDetailMapper, DispensingDetailMapper dispensingDetailMapper,
DispensingSummaryMapper dispensingSummaryMapper, DispensingSummaryMapper dispensingSummaryMapper) {
RefundLogMapper refundLogMapper
/* 其它 mapper 注入 */) {
this.orderMainMapper = orderMainMapper; this.orderMainMapper = orderMainMapper;
this.scheduleSlotMapper = scheduleSlotMapper;
this.schedulePoolMapper = schedulePoolMapper;
this.refundLogMapper = refundLogMapper;
this.catalogItemMapper = catalogItemMapper;
this.orderDetailMapper = orderDetailMapper;
this.dispensingDetailMapper = dispensingDetailMapper; this.dispensingDetailMapper = dispensingDetailMapper;
this.dispensingSummaryMapper = dispensingSummaryMapper; this.dispensingSummaryMapper = dispensingSummaryMapper;
this.refundLogMapper = refundLogMapper;
// 其它 mapper 赋值 ...
} }
// ----------------------------------------------------------------------- // 省略其他业务方法 ...
// 现有的查询、校验等业务方法保持不变
// -----------------------------------------------------------------------
/** /**
* 退回医嘱(医嘱校对模块的“退回”操作) * 门诊诊前退号(取消挂号)处理
* *
* @param orderId 医嘱主表 ID * @param orderId 挂号主单 ID
* @throws BusinessException 若医嘱已发药或状态不允许退回
*/ */
@Transactional @Transactional
public void returnOrder(Long orderId) { @Override
public void cancelOutpatientRegistration(Long orderId) {
if (orderId == null) { if (orderId == null) {
throw new BusinessException("医嘱 ID 不能为空"); throw new BusinessException("挂号单 ID 不能为空");
} }
// 1. 获取医嘱主记录 // 1. 查询挂号主单
OrderMain order = orderMainMapper.selectById(orderId); OrderMain orderMain = orderMainMapper.selectByPrimaryKey(orderId);
if (order == null) { if (orderMain == null) {
throw new BusinessException("医嘱不存在"); throw new BusinessException("挂号单不存在");
} }
// 2. 【Bug #505】校验已发药的医嘱不能退回 // 2. 判断是否已就诊(已诊前才能退号)
// 发药状态通过 DispenseStatus.DISPENSED已发药以及 if (OrderStatus.COMPLETED.getCode().equals(orderMain.getStatus())) {
// DispenseStatus.PARTIAL部分发药等表示已完成发药流程。 throw new BusinessException("已诊患者不能退号");
// 只有在未发药null 或 DISPATCHING或发药未完成如 PARTIAL_PENDING时才允许退回。
if (isDispensed(order.getDispenseStatus())) {
logger.warn("医嘱 {} 已发药(状态 {}),不允许退回", orderId, order.getDispenseStatus());
throw new BusinessException("药品已由药房发药,不能退回");
} }
// 3. 业务逻辑:更新医嘱状态为已退回、记录退药日志等 // 3. 更新挂号主单状态为已取消
order.setStatus(OrderStatus.RETURNED.getCode()); orderMain.setStatus(OrderStatus.CANCELLED.getCode());
order.setUpdateTime(new Date()); orderMain.setUpdateTime(new Date());
orderMainMapper.updateById(order); orderMainMapper.updateByPrimaryKeySelective(orderMain);
// 记录退药日志(如果需要) // 4. 释放对应的排班槽位
// a) 更新 schedule_slot 为可用
ScheduleSlot slot = scheduleSlotMapper.selectByPrimaryKey(orderMain.getScheduleSlotId());
if (slot != null) {
slot.setStatus(ScheduleSlotStatus.AVAILABLE.getCode());
slot.setUpdateTime(new Date());
scheduleSlotMapper.updateByPrimaryKeySelective(slot);
}
// b) 更新 schedule_pool 为可用
SchedulePool pool = schedulePoolMapper.selectByPrimaryKey(orderMain.getSchedulePoolId());
if (pool != null) {
pool.setStatus(SchedulePoolStatus.AVAILABLE.getCode());
pool.setUpdateTime(new Date());
schedulePoolMapper.updateByPrimaryKeySelective(pool);
}
// 5. 记录退款日志(若已收费用则标记成功)
RefundLog refundLog = new RefundLog(); RefundLog refundLog = new RefundLog();
refundLog.setOrderId(orderId); refundLog.setOrderId(orderId);
refundLog.setRefundStatus(RefundStatus.SUCCESS.getCode());
refundLog.setRefundTime(new Date()); refundLog.setRefundTime(new Date());
refundLog.setStatus(RefundStatus.SUCCESS.getCode()); refundLogMapper.insertSelective(refundLog);
refundLogMapper.insert(refundLog);
// 其它关联表(如明细、汇总)也需要恢复到未发药状态,具体实现视业务而定 logger.info("门诊诊前退号成功orderId={}, 释放排班 slotId={}, poolId={}",
// 这里示例性地将发药明细状态置为未发药 orderId,
List<DispensingDetail> details = dispensingDetailMapper.selectByOrderId(orderId); orderMain.getScheduleSlotId(),
if (!CollectionUtils.isEmpty(details)) { orderMain.getSchedulePoolId());
details.forEach(d -> d.setStatus(DispenseStatus.NOT_DISPENSED.getCode()));
dispensingDetailMapper.batchUpdate(details);
}
// 同步更新发药汇总单状态
DispensingSummary summary = dispensingSummaryMapper.selectByOrderId(orderId);
if (summary != null) {
summary.setStatus(DispenseStatus.NOT_DISPENSED.getCode());
dispensingSummaryMapper.updateById(summary);
}
logger.info("医嘱 {} 成功退回", orderId);
} }
/** // 其余方法保持不变
* 判断当前发药状态是否属于“已发药”。
*
* @param dispenseStatus 发药状态码,可能为 null
* @return true 表示已发药不可退回false 表示未发药或发药未完成
*/
private boolean isDispensed(String dispenseStatus) {
if (!StringUtils.hasText(dispenseStatus)) {
return false;
}
// 根据业务约定,以下状态视为“已发药”,不可退回
return Arrays.asList(
DispenseStatus.DISPENSED.getCode(),
DispenseStatus.PARTIAL.getCode(),
DispenseStatus.COMPLETED.getCode()
).contains(dispenseStatus);
}
// -----------------------------------------------------------------------
// 其余业务实现(查询待写、排队等)保持原有逻辑不变
// -----------------------------------------------------------------------
} }