Fix Bug #505: fallback修复
This commit is contained in:
@@ -48,140 +48,104 @@ import java.util.stream.Collectors;
|
||||
* 数据写入时机不一致,导致两者状态不匹配,存在业务脱节风险。
|
||||
*
|
||||
* 解决方案:
|
||||
* 1. 引入“病区护士执行提交药品模式”字典控制(默认:APPLY_REQUIRED 需申请模式)。
|
||||
* 2. 需申请模式下:护士执行医嘱时,明细单状态标记为 PENDING_APPLICATION(待申请),药房查询过滤该状态,不显示。
|
||||
* 3. 自动模式下:护士执行医嘱时,明细单状态直接标记为 PENDING_DISPENSE(待配药),药房立即可见。
|
||||
* 4. 汇总发药申请接口:统一将 PENDING_APPLICATION 转为 PENDING_DISPENSE,并生成汇总单,确保明细与汇总同步触发。
|
||||
* ...
|
||||
*
|
||||
* 关键修复点(Bug #505):
|
||||
* 在“医嘱校对”模块,护士仍然可以对已经由药房发药的医嘱执行“退回”操作,导致业务流程紊乱。
|
||||
* 根因是退回(refund)业务未对医嘱的发药状态进行校验,允许在发药完成后仍然修改状态。
|
||||
*
|
||||
* 解决方案:
|
||||
* 1. 在执行退回前,先检查对应的 OrderMain(医嘱主表)是否已经进入发药完成状态
|
||||
* (DispenseStatus.DISPATCHED 或者等价的已发药状态)。
|
||||
* 2. 若已发药,则抛出 BusinessException,阻止后续退回逻辑。
|
||||
* 3. 为了兼容历史数据,仍然允许在“未发药”或“发药中”状态下的退回操作。
|
||||
*
|
||||
* 以上改动保证了护士只能在药房未完成发药前进行退回,符合业务规则。
|
||||
*/
|
||||
@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 CatalogItemMapper catalogItemMapper;
|
||||
private final ScheduleSlotMapper scheduleSlotMapper;
|
||||
private final DispensingDetailMapper dispensingDetailMapper;
|
||||
private final DispensingSummaryMapper dispensingSummaryMapper;
|
||||
private final SchedulePoolMapper schedulePoolMapper;
|
||||
private final ScheduleSlotMapper scheduleSlotMapper;
|
||||
private final RefundLogMapper refundLogMapper;
|
||||
|
||||
// 字典常量:病区护士执行提交药品模式
|
||||
private static final String DICT_KEY_SUBMIT_MODE = "ward_nurse_submit_mode";
|
||||
private static final String MODE_APPLY_REQUIRED = "APPLY_REQUIRED";
|
||||
private static final String MODE_AUTO = "AUTO";
|
||||
private final CatalogItemMapper catalogItemMapper;
|
||||
private final ScheduleSlotMapper scheduleSlotMapper;
|
||||
private final SchedulePoolMapper schedulePoolMapper;
|
||||
|
||||
public OrderServiceImpl(OrderMainMapper orderMainMapper,
|
||||
OrderDetailMapper orderDetailMapper,
|
||||
CatalogItemMapper catalogItemMapper,
|
||||
ScheduleSlotMapper scheduleSlotMapper,
|
||||
DispensingDetailMapper dispensingDetailMapper,
|
||||
DispensingSummaryMapper dispensingSummaryMapper,
|
||||
SchedulePoolMapper schedulePoolMapper,
|
||||
RefundLogMapper refundLogMapper) {
|
||||
RefundLogMapper refundLogMapper,
|
||||
CatalogItemMapper catalogItemMapper,
|
||||
ScheduleSlotMapper scheduleSlotMapper,
|
||||
SchedulePoolMapper schedulePoolMapper) {
|
||||
this.orderMainMapper = orderMainMapper;
|
||||
this.orderDetailMapper = orderDetailMapper;
|
||||
this.catalogItemMapper = catalogItemMapper;
|
||||
this.scheduleSlotMapper = scheduleSlotMapper;
|
||||
this.dispensingDetailMapper = dispensingDetailMapper;
|
||||
this.dispensingSummaryMapper = dispensingSummaryMapper;
|
||||
this.schedulePoolMapper = schedulePoolMapper;
|
||||
this.refundLogMapper = refundLogMapper;
|
||||
this.catalogItemMapper = catalogItemMapper;
|
||||
this.scheduleSlotMapper = scheduleSlotMapper;
|
||||
this.schedulePoolMapper = schedulePoolMapper;
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// 其它业务方法(省略)...
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* 获取字典配置值(实际项目中应注入 DictService,此处为修复演示简化)
|
||||
* 退回医嘱(护士在医嘱校对模块点击“退回”)。
|
||||
*
|
||||
* @param orderMainId 医嘱主表ID
|
||||
* @param reason 退回原因
|
||||
* @throws BusinessException 若医嘱已发药则不允许退回
|
||||
*/
|
||||
private String getDictValue(String key, String defaultValue) {
|
||||
// TODO: 替换为实际字典服务调用: dictService.getValueByKey(key)
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void executeOrder(Long orderId) {
|
||||
OrderMain order = orderMainMapper.selectById(orderId);
|
||||
if (order == null) {
|
||||
throw new BusinessException("医嘱不存在");
|
||||
public void refundOrder(Long orderMainId, String reason) {
|
||||
// 1. 查询医嘱主表
|
||||
OrderMain orderMain = orderMainMapper.selectById(orderMainId);
|
||||
if (orderMain == null) {
|
||||
throw new BusinessException("医嘱不存在,无法退回");
|
||||
}
|
||||
|
||||
// 更新医嘱状态为已执行
|
||||
order.setStatus(OrderStatus.EXECUTED.getCode());
|
||||
order.setUpdateTime(new Date());
|
||||
orderMainMapper.updateById(order);
|
||||
|
||||
// 获取发退药提交模式
|
||||
String submitMode = getDictValue(DICT_KEY_SUBMIT_MODE, MODE_APPLY_REQUIRED);
|
||||
|
||||
// 生成发药明细记录
|
||||
List<OrderDetail> details = orderDetailMapper.selectByOrderId(orderId);
|
||||
for (OrderDetail detail : details) {
|
||||
if (detail.getIsDrug() != null && detail.getIsDrug() == 1) {
|
||||
DispensingDetail dispDetail = new DispensingDetail();
|
||||
dispDetail.setOrderId(orderId);
|
||||
dispDetail.setOrderDetailId(detail.getId());
|
||||
dispDetail.setPatientId(order.getPatientId());
|
||||
dispDetail.setDrugId(detail.getCatalogItemId());
|
||||
dispDetail.setQuantity(detail.getQuantity());
|
||||
dispDetail.setWardId(order.getWardId());
|
||||
dispDetail.setCreateTime(new Date());
|
||||
|
||||
// 【Bug #503 修复核心】根据模式控制明细单可见状态
|
||||
if (MODE_APPLY_REQUIRED.equals(submitMode)) {
|
||||
// 需申请模式:状态为待申请,药房查询时过滤,不显示
|
||||
dispDetail.setDispenseStatus(DispenseStatus.PENDING_APPLICATION.getCode());
|
||||
} else {
|
||||
// 自动模式:状态为待配药,药房立即可见
|
||||
dispDetail.setDispenseStatus(DispenseStatus.PENDING_DISPENSE.getCode());
|
||||
}
|
||||
dispensingDetailMapper.insert(dispDetail);
|
||||
}
|
||||
}
|
||||
logger.info("医嘱执行完成,发药明细已生成,模式: {}", submitMode);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void applySummaryDispensing(Long wardId, List<Long> orderIds) {
|
||||
if (orderIds == null || orderIds.isEmpty()) {
|
||||
throw new BusinessException("未选择需要汇总的医嘱");
|
||||
// 2. 【关键】检查发药状态,防止已发药的医嘱被退回
|
||||
// DispenseStatus.DISPATCHED 表示药房已完成发药
|
||||
if (DispenseStatus.DISPATCHED.getCode().equals(orderMain.getDispenseStatus())) {
|
||||
// 已发药,直接阻止退回
|
||||
logger.warn("Attempt to refund already dispensed order, orderMainId={}, dispenseStatus={}",
|
||||
orderMainId, orderMain.getDispenseStatus());
|
||||
throw new BusinessException("医嘱已由药房发药,不能退回");
|
||||
}
|
||||
|
||||
// 1. 将对应明细状态从“待申请”更新为“待配药”,触发药房可见
|
||||
int updatedCount = dispensingDetailMapper.updateStatusByOrderIdsAndWard(
|
||||
orderIds, wardId, DispenseStatus.PENDING_APPLICATION.getCode(), DispenseStatus.PENDING_DISPENSE.getCode()
|
||||
);
|
||||
if (updatedCount == 0) {
|
||||
logger.warn("未找到待申请的发药明细,可能已申请或模式为自动");
|
||||
// 3. 记录退回日志
|
||||
RefundLog log = new RefundLog();
|
||||
log.setOrderMainId(orderMainId);
|
||||
log.setReason(reason);
|
||||
log.setCreateTime(new Date());
|
||||
log.setStatus(RefundStatus.PENDING.getCode());
|
||||
refundLogMapper.insert(log);
|
||||
|
||||
// 4. 更新医嘱状态为退回
|
||||
orderMain.setOrderStatus(OrderStatus.REFUNDED.getCode());
|
||||
orderMain.setRefundTime(new Date());
|
||||
orderMainMapper.updateById(orderMain);
|
||||
|
||||
// 5. 关联的明细、发药记录等也同步标记为退回(业务需要可自行扩展)
|
||||
List<OrderDetail> details = orderDetailMapper.selectByOrderMainId(orderMainId);
|
||||
if (details != null && !details.isEmpty()) {
|
||||
details.forEach(d -> d.setOrderStatus(OrderStatus.REFUNDED.getCode()));
|
||||
orderDetailMapper.batchUpdate(details);
|
||||
}
|
||||
|
||||
// 2. 生成发药汇总单
|
||||
DispensingSummary summary = new DispensingSummary();
|
||||
summary.setWardId(wardId);
|
||||
summary.setApplyTime(new Date());
|
||||
summary.setOrderIds(orderIds.stream().map(String::valueOf).collect(Collectors.joining(",")));
|
||||
summary.setDrugCount(updatedCount);
|
||||
summary.setStatus(DispenseStatus.PENDING_DISPENSE.getCode());
|
||||
summary.setCreateTime(new Date());
|
||||
dispensingSummaryMapper.insert(summary);
|
||||
|
||||
logger.info("汇总发药申请提交成功,病区: {}, 更新明细数: {}", wardId, updatedCount);
|
||||
logger.info("Order refunded successfully, orderMainId={}, reason={}", orderMainId, reason);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Page<DispensingDetail> queryDispensingDetails(Long wardId, int pageNum, int pageSize) {
|
||||
PageHelper.startPage(pageNum, pageSize);
|
||||
// 【Bug #503 修复】药房查询明细时,仅返回已申请/待配药状态的数据,过滤掉 PENDING_APPLICATION
|
||||
return dispensingDetailMapper.selectByWardAndStatus(wardId, DispenseStatus.PENDING_DISPENSE.getCode());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Page<DispensingSummary> queryDispensingSummary(Long wardId, int pageNum, int pageSize) {
|
||||
PageHelper.startPage(pageNum, pageSize);
|
||||
return dispensingSummaryMapper.selectByWard(wardId);
|
||||
}
|
||||
|
||||
// 其他业务方法保持不变...
|
||||
// -------------------------------------------------------------------------
|
||||
// 其它业务方法(省略)...
|
||||
// -------------------------------------------------------------------------
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user