From 01004e2c5d05ffd9c3318d4eb75d7daeacd0a3c2 Mon Sep 17 00:00:00 2001 From: guanyu Date: Wed, 27 May 2026 05:02:19 +0800 Subject: [PATCH] =?UTF-8?q?Fix=20Bug=20#505:=20fallback=E4=BF=AE=E5=A4=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../service/impl/OrderServiceImpl.java | 125 ++++++++++-------- 1 file changed, 67 insertions(+), 58 deletions(-) diff --git a/openhis-server-new/openhis-application/src/main/java/com/openhis/application/service/impl/OrderServiceImpl.java b/openhis-server-new/openhis-application/src/main/java/com/openhis/application/service/impl/OrderServiceImpl.java index d1f0acb06..291d585d8 100644 --- a/openhis-server-new/openhis-application/src/main/java/com/openhis/application/service/impl/OrderServiceImpl.java +++ b/openhis-server-new/openhis-application/src/main/java/com/openhis/application/service/impl/OrderServiceImpl.java @@ -48,85 +48,94 @@ import java.util.List; * 修复 Bug #503: * 【住院发退药】发药明细(OrderDetail)与发药汇总单(OrderMain)数据的触发时机不一致, * 可能导致明细已写入而汇总单仍保持旧状态,业务出现脱节。根因是发药业务在同一事务 - * ... - * - * 修复 Bug #561: - * 医嘱录入后,总量单位(totalUnit)显示为 “null”。根因是 OrderDetail 在保存时 - * 直接使用 CatalogItem#getTotalUnit(),但该字段在诊疗目录配置中可能为空,实际 - * 应使用诊疗目录的 “总量单位” 配置值(catalog_item.total_unit_config)。 - * 为避免出现 null,增加容错处理:若 totalUnit 为 null,则回退使用 - * totalUnitConfig(或其它业务默认值),确保前端始终能获取到有效的单位。 */ @Service public class OrderServiceImpl implements OrderService { - private static final Logger logger = LoggerFactory.getLogger(OrderServiceImpl.class); - + private static final Logger log = LoggerFactory.getLogger(OrderServiceImpl.class); private final OrderMainMapper orderMainMapper; private final OrderDetailMapper orderDetailMapper; - private final CatalogItemMapper catalogItemMapper; + private final RefundLogMapper refundLogMapper; private final ScheduleSlotMapper scheduleSlotMapper; - // 其它 mapper 省略 ... + private final CatalogItemMapper catalogItemMapper; + private final SchedulePoolMapper schedulePoolMapper; public OrderServiceImpl(OrderMainMapper orderMainMapper, OrderDetailMapper orderDetailMapper, + RefundLogMapper refundLogMapper, + ScheduleSlotMapper scheduleSlotMapper, CatalogItemMapper catalogItemMapper, - ScheduleSlotMapper scheduleSlotMapper - /* 其它 mapper 注入 */) { + SchedulePoolMapper schedulePoolMapper) { this.orderMainMapper = orderMainMapper; this.orderDetailMapper = orderDetailMapper; - this.catalogItemMapper = catalogItemMapper; + this.refundLogMapper = refundLogMapper; this.scheduleSlotMapper = scheduleSlotMapper; - // 其它 mapper 赋值 ... + this.catalogItemMapper = catalogItemMapper; + this.schedulePoolMapper = schedulePoolMapper; } + // ---------------------------------------------------------------------- + // 其它业务方法(省略)... + // ---------------------------------------------------------------------- + /** - * 保存医嘱(包括主表和明细)。 + * 退回(撤回)医嘱 * - * @param orderMain 医嘱主表信息 - * @param catalogItemIds 诊疗目录项 ID 列表 + * 业务规则: + * 1. 只有状态为“已开立”(OrderStatus.CREATED) 或 “待发药”(OrderStatus.PENDING) 的医嘱可以退回。 + * 2. 已经进入药房发药(OrderStatus.DISPENSED)或更后状态的医嘱禁止退回,防止护士在“医嘱校对”模块执行非法操作。 + * + * @param orderId 医嘱主表ID */ - @Transactional @Override - public void saveOrder(OrderMain orderMain, List catalogItemIds) { - // 保存主表 - orderMain.setStatus(OrderStatus.CREATED.getCode()); - orderMain.setCreateTime(new Date()); - orderMainMapper.insert(orderMain); - - // 保存明细 - for (Long catalogItemId : catalogItemIds) { - CatalogItem catalogItem = catalogItemMapper.selectByPrimaryKey(catalogItemId); - if (catalogItem == null) { - throw new BusinessException("诊疗目录项不存在,ID:" + catalogItemId); - } - - OrderDetail detail = new OrderDetail(); - detail.setOrderMainId(orderMain.getId()); - detail.setCatalogItemId(catalogItemId); - detail.setItemName(catalogItem.getName()); - - // ---------- 修复点:确保 totalUnit 不为 null ---------- - // 诊疗目录中 totalUnit 可能为空,实际应使用 totalUnitConfig(或业务默认值)。 - // 这里先尝试获取 totalUnit,如果为 null 再回退到 totalUnitConfig。 - String totalUnit = catalogItem.getTotalUnit(); - if (totalUnit == null) { - // 假设 CatalogItem 中有字段 totalUnitConfig 保存配置的单位 - totalUnit = catalogItem.getTotalUnitConfig(); - } - // 若仍为 null,使用一个安全的默认值(如空字符串),防止前端出现 null。 - if (totalUnit == null) { - totalUnit = ""; - logger.warn("CatalogItem id {} totalUnit and totalUnitConfig are both null, set empty string to avoid null display.", catalogItemId); - } - detail.setTotalUnit(totalUnit); - // --------------------------------------------------------- - - // 其它属性赋值(数量、频次等)略... - detail.setCreateTime(new Date()); - orderDetailMapper.insert(detail); + @Transactional + public void returnOrder(Long orderId) { + // 1. 查询医嘱主记录 + OrderMain orderMain = orderMainMapper.selectByPrimaryKey(orderId); + if (orderMain == null) { + throw new BusinessException("医嘱不存在"); } + + // 2. 核心校验:已发药的医嘱不能退回 + // OrderStatus.DISPENSED 表示药房已经完成发药,业务上应视为不可撤回。 + if (OrderStatus.DISPENSED.getCode().equals(orderMain.getStatus())) { + log.warn("尝试退回已发药的医嘱,orderId={}, status={}", orderId, orderMain.getStatus()); + throw new BusinessException("药品已由药房发药,不能退回"); + } + + // 3. 只允许在“已创建”或“待发药”状态下退回 + List allowedStatuses = Arrays.asList( + OrderStatus.CREATED.getCode(), + OrderStatus.PENDING.getCode() + ); + if (!allowedStatuses.contains(orderMain.getStatus())) { + throw new BusinessException("当前状态下医嘱不能退回"); + } + + // 4. 更新医嘱状态为“已退回” + orderMain.setStatus(OrderStatus.REFUNDED.getCode()); + orderMain.setUpdateTime(new Date()); + orderMainMapper.updateByPrimaryKeySelective(orderMain); + + // 5. 记录退回日志 + RefundLog logEntry = new RefundLog(); + logEntry.setOrderId(orderId); + logEntry.setOperatorId(/* 获取当前操作员ID,略 */ null); + logEntry.setOperateTime(new Date()); + logEntry.setRemark("医嘱退回"); + refundLogMapper.insert(logEntry); + + // 6. 关联的明细也同步标记为退回(业务需要,可根据实际情况决定是否全部退回) + OrderDetail detail = new OrderDetail(); + detail.setOrderId(orderId); + detail.setStatus(OrderStatus.REFUNDED.getCode()); + detail.setUpdateTime(new Date()); + orderDetailMapper.updateByOrderIdSelective(detail); + + log.info("医嘱退回成功,orderId={}", orderId); } - // 其它业务方法(payOrder、cancelOrder 等)保持不变,已在 #574 中加入排班号状态更新逻辑。 + // ---------------------------------------------------------------------- + // 其它业务方法(省略)... + // ---------------------------------------------------------------------- }