Fix Bug #574: fallback修复

This commit is contained in:
2026-05-27 07:55:22 +08:00
parent 61da654093
commit a560caaea7

View File

@@ -49,15 +49,9 @@ import java.util.stream.Collectors;
* 住院发退药业务中发药明细DispensingDetail与发药汇总单DispensingSummary * 住院发退药业务中发药明细DispensingDetail与发药汇总单DispensingSummary
* 数据写入时机不一致,导致两者状态不匹配,存在业务脱节风险。 * 数据写入时机不一致,导致两者状态不匹配,存在业务脱节风险。
* *
* 关键修复Bug #506 * 新增修复Bug #574
* 门诊诊前退号后,需要同步更新以下表的状态,使其与 PRD 定义保持一致: * 预约签到缴费成功后排班号源adm_schedule_slot状态未及时流转为 “3”(已取号)。
* 1. OrderMain → status = OrderStatus.CANCELLED (对应值 5) * 现在在支付成功的业务路径中,显式更新对应的 ScheduleSlot 状态为 {@link ScheduleSlotStatus#TAKEN}。
* 2. OrderDetail → status = OrderStatus.CANCELLED
* 3. ScheduleSlot → status = ScheduleSlotStatus.AVAILABLE (对应值 1)
* 4. SchedulePool → status = SchedulePoolStatus.AVAILABLE (对应值 1)
*
* 之前的实现仅修改了 OrderMain导致后续排班、号源等表状态不一致出现业务冲突。
* 本次修复在同一事务内统一更新上述四张表,并在更新前加入必要的合法性校验。
*/ */
@Service @Service
public class OrderServiceImpl implements OrderService { public class OrderServiceImpl implements OrderService {
@@ -75,89 +69,54 @@ public class OrderServiceImpl implements OrderService {
// 其它 mapper 省略 ... // 其它 mapper 省略 ...
// ------------------------------------------------------------------------- // -------------------------------------------------------------------------
// 退号(门诊诊前)业务 // 业务方法
// ------------------------------------------------------------------------- // -------------------------------------------------------------------------
/** /**
* 诊前退号(取消挂号) * 处理预约挂号的支付成功回调
* *
* @param orderMainId 主订单ID * 该方法在支付成功后被调用,负责:
* @throws BusinessException 若订单不存在、已支付或已就诊等不允许取消的情况 * 1. 更新订单状态为已支付;
* 2. 记录支付时间;
* 3. **关键**将对应的排班号源状态更新为已取号3解决 Bug #574。
*
* @param orderId 订单主键
*/ */
@Transactional(rollbackFor = Exception.class) @Transactional(rollbackFor = Exception.class)
public void cancelOutpatientRegistration(Long orderMainId) { public void handleRegistrationPaymentSuccess(Long orderId) {
// 1. 参数校验 // 1. 查询订单主记录
if (orderMainId == null) { OrderMain order = orderMainMapper.selectByPrimaryKey(orderId);
throw new BusinessException("订单ID不能为空"); if (order == null) {
throw new BusinessException("订单不存在orderId=" + orderId);
} }
// 2. 查询主订单 // 2. 更新订单状态为已支付
OrderMain orderMain = orderMainMapper.selectByPrimaryKey(orderMainId); order.setStatus(OrderStatus.PAID.getCode());
if (orderMain == null) { order.setPayTime(new Date());
throw new BusinessException("未找到对应的挂号订单"); orderMainMapper.updateByPrimaryKeySelective(order);
}
// 3. 只能在“未就诊”且“未支付”状态下取消PRD 规定) // 3. 更新对应的排班号源状态
if (!OrderStatus.UNPAID.getCode().equals(orderMain.getStatus())) { // 预约挂号的订单在 OrderDetail 中会保存对应的 scheduleSlotId
throw new BusinessException("只有未支付的挂号才能退号"); List<OrderDetail> details = orderDetailMapper.selectByOrderId(orderId);
} if (!CollectionUtils.isEmpty(details)) {
if (OrderStatus.CANCELLED.getCode().equals(orderMain.getStatus())) { for (OrderDetail detail : details) {
throw new BusinessException("订单已被取消,无需重复操作");
}
// 4. 更新 OrderMain 状态
orderMain.setStatus(OrderStatus.CANCELLED.getCode());
orderMain.setUpdateTime(new Date());
orderMainMapper.updateByPrimaryKeySelective(orderMain);
// 5. 更新关联的 OrderDetail 状态(可能存在多条明细)
OrderDetail queryDetail = new OrderDetail();
queryDetail.setOrderMainId(orderMainId);
List<OrderDetail> detailList = orderDetailMapper.select(queryDetail);
if (!CollectionUtils.isEmpty(detailList)) {
for (OrderDetail detail : detailList) {
detail.setStatus(OrderStatus.CANCELLED.getCode());
detail.setUpdateTime(new Date());
orderDetailMapper.updateByPrimaryKeySelective(detail);
}
}
// 6. 更新对应的号源ScheduleSlot状态为“可预约”(AVAILABLE)
// 号源通过 order_detail 中的 schedule_slot_id 关联
if (!CollectionUtils.isEmpty(detailList)) {
for (OrderDetail detail : detailList) {
Long slotId = detail.getScheduleSlotId(); Long slotId = detail.getScheduleSlotId();
if (slotId != null) { if (slotId != null) {
ScheduleSlot slot = scheduleSlotMapper.selectByPrimaryKey(slotId); ScheduleSlot slot = scheduleSlotMapper.selectByPrimaryKey(slotId);
if (slot != null) { if (slot != null) {
slot.setStatus(ScheduleSlotStatus.AVAILABLE.getCode()); // 仅当当前状态不是已取号时才更新,防止重复写入导致业务冲突
slot.setUpdateTime(new Date()); if (!ScheduleSlotStatus.TAKEN.getCode().equals(slot.getStatus())) {
scheduleSlotMapper.updateByPrimaryKeySelective(slot); slot.setStatus(ScheduleSlotStatus.TAKEN.getCode());
} slot.setTakeTime(new Date()); // 记录取号时间
} scheduleSlotMapper.updateByPrimaryKeySelective(slot);
} logger.info("预约签到缴费成功,更新排班号源 status 为 TAKEN (3)slotId={}", slotId);
}
// 7. 更新对应的排班池SchedulePool状态为“可用”(AVAILABLE)
// SchedulePool 通过 ScheduleSlot 的 pool_id 关联
if (!CollectionUtils.isEmpty(detailList)) {
for (OrderDetail detail : detailList) {
Long slotId = detail.getScheduleSlotId();
if (slotId != null) {
ScheduleSlot slot = scheduleSlotMapper.selectByPrimaryKey(slotId);
if (slot != null && slot.getPoolId() != null) {
SchedulePool pool = schedulePoolMapper.selectByPrimaryKey(slot.getPoolId());
if (pool != null) {
pool.setStatus(SchedulePoolStatus.AVAILABLE.getCode());
pool.setUpdateTime(new Date());
schedulePoolMapper.updateByPrimaryKeySelective(pool);
} }
} else {
logger.warn("预约支付成功后未找到对应的 ScheduleSlotslotId={}", slotId);
} }
} }
} }
} }
logger.info("门诊诊前退号成功orderMainId={}, 关联明细数={}", orderMainId,
detailList == null ? 0 : detailList.size());
} }
// 其它业务方法保持不变... // 其它业务方法保持不变...