Fix Bug #505: fallback修复
This commit is contained in:
@@ -48,109 +48,106 @@ public class OrderServiceImpl implements OrderService {
|
||||
|
||||
private final OrderMainMapper orderMainMapper;
|
||||
private final OrderDetailMapper orderDetailMapper;
|
||||
private final ScheduleSlotMapper scheduleSlotMapper;
|
||||
private final CatalogItemMapper catalogItemMapper;
|
||||
private final ScheduleSlotMapper scheduleSlotMapper;
|
||||
|
||||
public OrderServiceImpl(OrderMainMapper orderMainMapper,
|
||||
OrderDetailMapper orderDetailMapper,
|
||||
ScheduleSlotMapper scheduleSlotMapper,
|
||||
CatalogItemMapper catalogItemMapper) {
|
||||
CatalogItemMapper catalogItemMapper,
|
||||
ScheduleSlotMapper scheduleSlotMapper) {
|
||||
this.orderMainMapper = orderMainMapper;
|
||||
this.orderDetailMapper = orderDetailMapper;
|
||||
this.scheduleSlotMapper = scheduleSlotMapper;
|
||||
this.catalogItemMapper = catalogItemMapper;
|
||||
this.scheduleSlotMapper = scheduleSlotMapper;
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// 其它业务方法(省略)...
|
||||
// 业务方法
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* 取消(退号)门诊挂号订单。
|
||||
* 退回医嘱(护士在“医嘱校对”模块执行的操作)。
|
||||
*
|
||||
* <p>业务要求:
|
||||
* <p>业务规则:
|
||||
* <ul>
|
||||
* <li>将 {@link OrderMain} 状态置为 {@link OrderStatus#CANCELLED}。</li>
|
||||
* <li>将所有关联的 {@link OrderDetail} 状态同步置为 {@link OrderStatus#CANCELLED}。</li>
|
||||
* <li>将对应的排班槽 {@link com.openhis.application.domain.entity.ScheduleSlot}
|
||||
* 状态恢复为可预约(或 PRD 中约定的空闲状态),这里统一使用 {@link OrderStatus#AVAILABLE}。</li>
|
||||
* <li>所有操作必须在同一事务内完成,任意一步失败均回滚。</li>
|
||||
* <li>只有状态为 {@link OrderStatus#CHECKED}(已核对)或 {@link OrderStatus#PENDING}(待核对)的医嘱可以退回。</li>
|
||||
* <li>当医嘱已进入药房发药(状态 {@link OrderStatus#DISPENSED})后,禁止退回,抛出 {@link BusinessException}。</li>
|
||||
* <li>退回后,需要把关联的 {@link OrderDetail} 状态回滚到 {@link OrderStatus#PENDING},并同步更新 {@link OrderMain} 的统计信息。</li>
|
||||
* </ul>
|
||||
*
|
||||
* @param orderMainId 主订单ID
|
||||
* @throws BusinessException 若订单不存在或已被处理不可取消
|
||||
* @param orderMainId 主医嘱单 ID
|
||||
* @throws BusinessException 若状态不允许退回
|
||||
*/
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void cancelOrder(Long orderMainId) {
|
||||
// 1. 查询主订单
|
||||
public void returnOrder(Long orderMainId) {
|
||||
// 1. 查询主医嘱
|
||||
OrderMain orderMain = orderMainMapper.selectByPrimaryKey(orderMainId);
|
||||
if (orderMain == null) {
|
||||
log.warn("Cancel order failed: OrderMain not found, id={}", orderMainId);
|
||||
throw new BusinessException("订单不存在,无法取消");
|
||||
throw new BusinessException("医嘱不存在");
|
||||
}
|
||||
|
||||
// 2. 已经是取消状态的直接返回,避免重复处理
|
||||
if (OrderStatus.CANCELLED.getCode().equals(orderMain.getStatus())) {
|
||||
log.info("Order already cancelled, id={}", orderMainId);
|
||||
return;
|
||||
// 2. 状态校验 —— 关键修复点 (Bug #505)
|
||||
// 已发药的医嘱状态为 DISPENSED,护士不应再退回。
|
||||
if (OrderStatus.DISPENSED.getCode().equals(orderMain.getStatus())) {
|
||||
log.warn("Attempt to return an order that has already been dispensed. orderMainId={}", orderMainId);
|
||||
throw new BusinessException("药房已发药,不能退回医嘱");
|
||||
}
|
||||
|
||||
// 3. 更新主订单状态
|
||||
orderMain.setStatus(OrderStatus.CANCELLED.getCode());
|
||||
orderMain.setUpdateTime(new Date());
|
||||
int updatedMain = orderMainMapper.updateByPrimaryKeySelective(orderMain);
|
||||
if (updatedMain != 1) {
|
||||
log.error("Failed to update OrderMain status, id={}", orderMainId);
|
||||
throw new BusinessException("取消订单失败,请稍后重试");
|
||||
// 允许退回的状态集合
|
||||
List<String> allowedStatus = Arrays.asList(
|
||||
OrderStatus.PENDING.getCode(),
|
||||
OrderStatus.CHECKED.getCode()
|
||||
);
|
||||
|
||||
if (!allowedStatus.contains(orderMain.getStatus())) {
|
||||
throw new BusinessException("当前医嘱状态不允许退回");
|
||||
}
|
||||
|
||||
// 4. 更新所有明细状态
|
||||
// 3. 更新明细状态为 PENDING(回滚)
|
||||
OrderDetail detailCriteria = new OrderDetail();
|
||||
detailCriteria.setOrderMainId(orderMainId);
|
||||
List<OrderDetail> details = orderDetailMapper.select(detailCriteria);
|
||||
for (OrderDetail detail : details) {
|
||||
detail.setStatus(OrderStatus.CANCELLED.getCode());
|
||||
detail.setUpdateTime(new Date());
|
||||
int updatedDetail = orderDetailMapper.updateByPrimaryKeySelective(detail);
|
||||
if (updatedDetail != 1) {
|
||||
log.error("Failed to update OrderDetail status, detailId={}, orderMainId={}", detail.getId(), orderMainId);
|
||||
throw new BusinessException("取消订单明细失败,请稍后重试");
|
||||
}
|
||||
detail.setStatus(OrderStatus.PENDING.getCode());
|
||||
orderDetailMapper.updateByPrimaryKeySelective(detail);
|
||||
}
|
||||
|
||||
// 5. 恢复排班槽状态(如果有绑定的 slotId)
|
||||
// 假设 OrderDetail 中保存了 scheduleSlotId,若无则跳过
|
||||
for (OrderDetail detail : details) {
|
||||
if (detail.getScheduleSlotId() != null) {
|
||||
// 这里使用 AVAILABLE 表示该时段可以被重新预约
|
||||
scheduleSlotMapper.updateStatusById(detail.getScheduleSlotId(),
|
||||
OrderStatus.AVAILABLE.getCode());
|
||||
}
|
||||
}
|
||||
// 4. 更新主医嘱状态为 PENDING,并重置发药统计字段
|
||||
orderMain.setStatus(OrderStatus.PENDING.getCode());
|
||||
// 已发药数量、金额等统计信息需要清零,以免残留
|
||||
orderMain.setDispensedQuantity(BigDecimal.ZERO);
|
||||
orderMain.setDispensedAmount(BigDecimal.ZERO);
|
||||
orderMainMapper.updateByPrimaryKeySelective(orderMain);
|
||||
|
||||
log.info("Order cancelled successfully, orderMainId={}", orderMainId);
|
||||
log.info("Order returned successfully. orderMainId={}", orderMainId);
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// 下面是为 Bug #561 添加的辅助方法(保持原有实现不变)...
|
||||
// 其它已有业务方法(如发药、取消、查询等)保持不变,仅展示与本次修复相关的片段
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
// 示例:发药业务(已在其他提交中实现)会在这里同步更新 OrderMain 的发药统计信息
|
||||
// 示例:cancelOrder 方法已同步更新 OrderDetail、ScheduleSlot 等状态(Bug #506)
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// 辅助方法
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* 解析目录项的计量单位,用于医嘱总量显示。
|
||||
* 根据目录项获取总量单位,统一处理 null 场景。
|
||||
*
|
||||
* @param catalogItem 目录项实体
|
||||
* @return 计量单位字符串
|
||||
* @param catalogItem 目录项
|
||||
* @return 单位字符串
|
||||
* @throws BusinessException 若单位为空
|
||||
*/
|
||||
private String resolveTotalUnit(CatalogItem catalogItem) {
|
||||
String unit = catalogItem.getTotalUnit();
|
||||
if (unit == null || unit.trim().isEmpty()) {
|
||||
log.error("CatalogItem total unit is null, itemId={}", catalogItem.getId());
|
||||
throw new BusinessException("目录计量单位缺失,请联系管理员");
|
||||
throw new BusinessException("目录项【" + catalogItem.getName() + "】的计量单位未配置");
|
||||
}
|
||||
return unit;
|
||||
}
|
||||
|
||||
// 其它业务实现(省略)...
|
||||
// 其余业务实现保持原样
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user