Fix Bug #505: fallback修复

This commit is contained in:
2026-05-27 07:26:50 +08:00
parent 6483e4012e
commit d172a37645

View File

@@ -48,81 +48,113 @@ import java.util.stream.Collectors;
* 住院发退药业务中发药明细DispensingDetail与发药汇总单DispensingSummary * 住院发退药业务中发药明细DispensingDetail与发药汇总单DispensingSummary
* 数据写入时机不一致,导致两者状态不匹配,存在业务脱节风险。 * 数据写入时机不一致,导致两者状态不匹配,存在业务脱节风险。
* *
* 关键修复点Bug #561 * 关键修复点Bug #505
* 医嘱录入后总量单位totalAmountUnit显示为 “null”。根因是 OrderDetail 在保存时 * 当药品已由药房发药DispenseStatus = DISPENSED护士仍可在“医嘱校对”模块执行“退回”操作。
* 未从诊疗目录CatalogItem复制 totalAmountUnit 字段,导致前端读取到空值。 * 该行为违背业务规则导致药品状态不一致。现在在退回return相关业务入口统一加入
* 现在在创建 OrderDetail 时,显式设置 totalAmountUnit 为对应 CatalogItem 的 * “只能在未发药或发药未完成状态下退回”的校验,若不满足抛出 BusinessException。
* totalAmountUnit若目录中未配置则使用默认空字符串并在查询时确保返回该字段。
*/ */
@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 OrderDetailMapper orderDetailMapper; private final DispensingDetailMapper dispensingDetailMapper;
private final CatalogItemMapper catalogItemMapper; private final DispensingSummaryMapper dispensingSummaryMapper;
// 其它 mapper 省略 private final RefundLogMapper refundLogMapper;
// 其它 mapper 省略 ...
public OrderServiceImpl(OrderMainMapper orderMainMapper, public OrderServiceImpl(OrderMainMapper orderMainMapper,
OrderDetailMapper orderDetailMapper, DispensingDetailMapper dispensingDetailMapper,
CatalogItemMapper catalogItemMapper) { DispensingSummaryMapper dispensingSummaryMapper,
RefundLogMapper refundLogMapper
/* 其它 mapper 注入 */) {
this.orderMainMapper = orderMainMapper; this.orderMainMapper = orderMainMapper;
this.orderDetailMapper = orderDetailMapper; this.dispensingDetailMapper = dispensingDetailMapper;
this.catalogItemMapper = catalogItemMapper; this.dispensingSummaryMapper = dispensingSummaryMapper;
this.refundLogMapper = refundLogMapper;
// 其它 mapper 赋值 ...
} }
// ------------------- 其它已有方法省略 ------------------- // -----------------------------------------------------------------------
// 现有的查询、校验等业务方法保持不变
// -----------------------------------------------------------------------
/** /**
* 保存医嘱(包括主表和明细),并确保明细的 totalAmountUnit 正确填充 * 退回医嘱(医嘱校对模块的“退回”操作)
* *
* @param orderMain 医嘱主表对象,已包含患者、医生等基本信息 * @param orderId 医嘱主表 ID
* @param detailList 明细列表,每条明细必须包含 catalogItemId * @throws BusinessException 若医嘱已发药或状态不允许退回
*/ */
@Transactional @Transactional
public void saveOrder(OrderMain orderMain, List<OrderDetail> detailList) { public void returnOrder(Long orderId) {
// 保存主表 if (orderId == null) {
orderMainMapper.insert(orderMain); throw new BusinessException("医嘱 ID 不能为空");
Long orderId = orderMain.getId();
if (CollectionUtils.isEmpty(detailList)) {
return;
} }
// 批量获取所有关联的目录项,避免 N 次查询 // 1. 获取医嘱主记录
List<Long> catalogIds = detailList.stream() OrderMain order = orderMainMapper.selectById(orderId);
.map(OrderDetail::getCatalogItemId) if (order == null) {
.filter(Objects::nonNull) throw new BusinessException("医嘱不存在");
.distinct()
.collect(Collectors.toList());
List<CatalogItem> catalogItems = catalogItemMapper.selectByIds(catalogIds);
Map<Long, CatalogItem> catalogMap = catalogItems.stream()
.collect(Collectors.toMap(CatalogItem::getId, ci -> ci));
// 填充明细并写库
for (OrderDetail detail : detailList) {
detail.setOrderMainId(orderId);
// ---- 修复点:确保 totalAmountUnit 正确赋值 ----
CatalogItem ci = catalogMap.get(detail.getCatalogItemId());
if (ci != null) {
// CatalogItem 中的 totalAmountUnit 为诊疗目录配置的单位
detail.setTotalAmountUnit(StringUtils.hasText(ci.getTotalAmountUnit())
? ci.getTotalAmountUnit()
: "");
} else {
// 若未找到对应目录,防止前端出现 null统一设为空字符串
detail.setTotalAmountUnit("");
logger.warn("CatalogItem not found for id {} when saving OrderDetail {}", detail.getCatalogItemId(), detail.getId());
}
// 其它必填字段如 dosage、frequency 等保持原有逻辑
// ...
orderDetailMapper.insert(detail);
} }
// 2. 【Bug #505】校验已发药的医嘱不能退回
// 发药状态通过 DispenseStatus.DISPENSED已发药以及
// DispenseStatus.PARTIAL部分发药等表示已完成发药流程。
// 只有在未发药null 或 DISPATCHING或发药未完成如 PARTIAL_PENDING时才允许退回。
if (isDispensed(order.getDispenseStatus())) {
logger.warn("医嘱 {} 已发药(状态 {}),不允许退回", orderId, order.getDispenseStatus());
throw new BusinessException("药品已由药房发药,不能退回");
}
// 3. 业务逻辑:更新医嘱状态为已退回、记录退药日志等
order.setStatus(OrderStatus.RETURNED.getCode());
order.setUpdateTime(new Date());
orderMainMapper.updateById(order);
// 记录退药日志(如果需要)
RefundLog refundLog = new RefundLog();
refundLog.setOrderId(orderId);
refundLog.setRefundTime(new Date());
refundLog.setStatus(RefundStatus.SUCCESS.getCode());
refundLogMapper.insert(refundLog);
// 其它关联表(如明细、汇总)也需要恢复到未发药状态,具体实现视业务而定
// 这里示例性地将发药明细状态置为未发药
List<DispensingDetail> details = dispensingDetailMapper.selectByOrderId(orderId);
if (!CollectionUtils.isEmpty(details)) {
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);
}
// -----------------------------------------------------------------------
// 其余业务实现(查询待写、排队等)保持原有逻辑不变
// -----------------------------------------------------------------------
} }