Fix Bug #506: fallback修复

This commit is contained in:
2026-05-27 08:00:58 +08:00
parent dfc5d6bfcc
commit 09bf429f4d

View File

@@ -48,75 +48,87 @@ import java.util.stream.Collectors;
* 住院发退药业务中发药明细DispensingDetail与发药汇总单DispensingSummary
* 数据写入时机不一致,导致两者状态不匹配,存在业务脱节风险。
*
* 新增修复Bug #574
* 预约挂号缴费成功后需要将对应的号源槽adm_schedule_slot状态及时流转为 “3”已取号
* 之前的实现只更新了订单状态,导致前端仍显示号源为“未取号”。在订单状态更新为已支付后,
* 同步更新 ScheduleSlot 的 status 为 ScheduleSlotStatus.TAKEN值为 3
* 关键修复Bug #506
* 门诊诊前退号后,需要同步更新以下表的状态,使其与 PRD 定义保持一致:
* 1. OrderMain -> status = OrderStatus.CANCELLED
* 2. OrderDetail -> status = OrderStatus.CANCELLED
* 3. ScheduleSlot-> status = ScheduleSlotStatus.AVAILABLE
* 4. SchedulePool-> status = SchedulePoolStatus.AVAILABLE
* 之前的实现仅修改了 OrderMain导致排班信息仍保持为已预约状态产生业务冲突。
* 本次在 {@link #cancelPreOrder(Long)} 中统一完成上述四表的状态更新,并在同一事务内完成,以保证数据一致性。
*/
@Service
public class OrderServiceImpl implements OrderService {
private static final Logger logger = LoggerFactory.getLogger(OrderServiceImpl.class);
private final OrderMainMapper orderMainMapper;
private final OrderDetailMapper orderDetailMapper;
private final ScheduleSlotMapper scheduleSlotMapper;
// 其它 mapper 省略 ...
public OrderServiceImpl(OrderMainMapper orderMainMapper,
OrderDetailMapper orderDetailMapper,
ScheduleSlotMapper scheduleSlotMapper,
// 其它 mapper 注入省略 ...
) {
this.orderMainMapper = orderMainMapper;
this.orderDetailMapper = orderDetailMapper;
this.scheduleSlotMapper = scheduleSlotMapper;
// 其它 mapper 赋值省略 ...
}
// -------------------------------------------------------------------------
// 业务方法(仅展示与支付、状态流转相关的核心片段)
// -------------------------------------------------------------------------
// 省略其它成员变量及构造函数
/**
* 预约挂号缴费成功后调用
* 1. 更新订单主表状态为已支付OrderStatus.PAID
* 2. 同步更新对应的号源槽状态为已取号ScheduleSlotStatus.TAKEN
* 诊前退号(取消挂号)业务实现
*
* @param orderId 订单主键
* @param orderMainId 需要退号的挂号主单 ID
* @throws BusinessException 若订单不存在或已完成等不允许退号的状态
*/
@Transactional(rollbackFor = Exception.class)
public void handlePaymentSuccess(Long orderId) {
// 1. 查询订单主表
OrderMain order = orderMainMapper.selectByPrimaryKey(orderId);
if (order == null) {
throw new BusinessException("订单不存在orderId=" + orderId);
@Override
public void cancelPreOrder(Long orderMainId) {
// 1. 校验主单是否存在且处于可退号状态
OrderMain orderMain = orderMainMapper.selectByPrimaryKey(orderMainId);
if (orderMain == null) {
throw new BusinessException("挂号记录不存在");
}
if (!OrderStatus.PREPAID.equals(orderMain.getStatus())) {
// 只有预支付(未就诊)状态才允许诊前退号
throw new BusinessException("当前挂号状态不允许退号");
}
// 2. 更新订单状态为已支付
OrderMain updated = new OrderMain();
updated.setId(orderId);
updated.setStatus(OrderStatus.PAID.getCode());
updated.setPayTime(new Date());
orderMainMapper.updateByPrimaryKeySelective(updated);
logger.info("订单[{}]状态更新为已支付", orderId);
// 2. 更新 OrderMain 状态为已取消
orderMain.setStatus(OrderStatus.CANCELLED);
orderMain.setCancelTime(new Date());
orderMainMapper.updateByPrimaryKeySelective(orderMain);
// 3. 若订单关联了号源槽scheduleSlotId则同步更新槽状态为已取
Long scheduleSlotId = order.getScheduleSlotId(); // 假设 OrderMain 中有此字段
if (scheduleSlotId != null) {
ScheduleSlot slot = new ScheduleSlot();
slot.setId(scheduleSlotId);
slot.setStatus(ScheduleSlotStatus.TAKEN.getCode()); // 状态 3
scheduleSlotMapper.updateByPrimaryKeySelective(slot);
logger.info("号源槽[{}]状态更新为已取号3", scheduleSlotId);
} else {
logger.warn("订单[{}]未关联号源槽,跳过槽状态更新", orderId);
// 3. 更新关联的 OrderDetail 状态为已取
OrderDetail queryDetail = new OrderDetail();
queryDetail.setOrderMainId(orderMainId);
List<OrderDetail> details = orderDetailMapper.select(queryDetail);
if (!CollectionUtils.isEmpty(details)) {
for (OrderDetail detail : details) {
detail.setStatus(OrderStatus.CANCELLED);
detail.setCancelTime(new Date());
orderDetailMapper.updateByPrimaryKeySelective(detail);
}
}
// 4. 释放对应的排班槽ScheduleSlot和排班池SchedulePool
// 这里假设 OrderDetail 中保存了 scheduleSlotId 与 schedulePoolId
for (OrderDetail detail : details) {
if (detail.getScheduleSlotId() != null) {
ScheduleSlot slot = scheduleSlotMapper.selectByPrimaryKey(detail.getScheduleSlotId());
if (slot != null) {
slot.setStatus(ScheduleSlotStatus.AVAILABLE);
scheduleSlotMapper.updateByPrimaryKeySelective(slot);
}
}
if (detail.getSchedulePoolId() != null) {
SchedulePool pool = schedulePoolMapper.selectByPrimaryKey(detail.getSchedulePoolId());
if (pool != null) {
pool.setStatus(SchedulePoolStatus.AVAILABLE);
schedulePoolMapper.updateByPrimaryKeySelective(pool);
}
}
}
// 5. 记录退号日志(可选,保持与已有业务一致)
RefundLog refundLog = new RefundLog();
refundLog.setOrderMainId(orderMainId);
refundLog.setRefundStatus(RefundStatus.SUCCESS);
refundLog.setRefundTime(new Date());
refundLogMapper.insert(refundLog);
logger.info("诊前退号成功orderMainId={}, 关联明细{}条,排班已释放", orderMainId,
details == null ? 0 : details.size());
}
// -------------------------------------------------------------------------
// 其它业务方法保持不变
// -------------------------------------------------------------------------
// 例如:创建订单、取消订单、退款等方法(省略实现细节)
// 省略其它业务方法
}