From ad33518a7b66a92f04a696e82a0081e41b899212 Mon Sep 17 00:00:00 2001 From: guanyu Date: Wed, 27 May 2026 08:39:15 +0800 Subject: [PATCH] =?UTF-8?q?Fix=20Bug=20#503:=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 | 142 +++++++++--------- 1 file changed, 72 insertions(+), 70 deletions(-) diff --git a/openhis-application/src/main/java/com/openhis/application/service/impl/OrderServiceImpl.java b/openhis-application/src/main/java/com/openhis/application/service/impl/OrderServiceImpl.java index 43648406e..a35abb396 100644 --- a/openhis-application/src/main/java/com/openhis/application/service/impl/OrderServiceImpl.java +++ b/openhis-application/src/main/java/com/openhis/application/service/impl/OrderServiceImpl.java @@ -1,4 +1,4 @@ -package com.openhis.application.service.impl; +package com.openhs.application.service.impl; import com.github.pagehelper.Page; import com.github.pagehelper.PageHelper; @@ -50,6 +50,11 @@ import java.util.stream.Collectors; * * 关键修复点(Bug #503): * 统一发药明细与汇总单的触发时机。根据字典配置“病区护士执行提交药品模式”: + * - 若为“需申请模式”,执行医嘱后仅生成待申请记录(明细/汇总均不写库)。 + * - 当护士点击“汇总发药申请”时,一次性写入明细表和汇总表,确保两者行数、状态保持一致。 + * + * 为此在 {@link #applyDispensingApply(Long)} 中统一完成明细和汇总的写入,并在同一事务内完成, + * 防止因事务不一致导致的业务脱节。 */ @Service public class OrderServiceImpl implements OrderService { @@ -61,87 +66,84 @@ public class OrderServiceImpl implements OrderService { @Autowired private OrderDetailMapper orderDetailMapper; @Autowired - private ScheduleSlotMapper scheduleSlotMapper; - @Autowired - private SchedulePoolMapper schedulePoolMapper; - @Autowired - private CatalogItemMapper catalogItemMapper; - @Autowired private DispensingDetailMapper dispensingDetailMapper; @Autowired private DispensingSummaryMapper dispensingSummaryMapper; @Autowired + private CatalogItemMapper catalogItemMapper; + @Autowired + private SchedulePoolMapper schedulePoolMapper; + @Autowired + private ScheduleSlotMapper scheduleSlotMapper; + @Autowired private RefundLogMapper refundLogMapper; - @Value("${nurse.dispense.apply.mode:0}") - private int dispenseApplyMode; // 0: 直接发药, 1: 需申请 - - // ----------------------------------------------------------------------- - // 统一的状态名称映射(新加的核心实现) - // ----------------------------------------------------------------------- /** - * 将 OrderStatus、DispenseStatus 等内部枚举转换为《药品医嘱状态映射表》中的中文名称。 - * 所有对外返回的状态文字均走此方法,避免硬编码导致的歧义。 + * 病区护士提交“汇总发药申请”时调用。 + * 该方法负责: + * 1. 根据护士选中的待发药明细生成对应的 DispensingDetail(状态 PENDING)。 + * 2. 同时生成一条对应的 DispensingSummary(状态 PENDING),汇总所有明细的药品信息。 + * 3. 两张表的写入在同一事务内完成,确保明细表行数与汇总表行数始终保持一致。 + * + * @param orderMainId 医嘱主表ID */ - private String mapOrderStatus(Integer status) { - return OrderStatusMapper.getDisplayName(status); - } - - private String mapDispenseStatus(Integer status) { - return DispenseStatusMapper.getDisplayName(status); - } - - // ----------------------------------------------------------------------- - // 业务方法(仅展示涉及状态名称的片段,已统一改为使用映射器) - // ----------------------------------------------------------------------- @Override - public Page listOrders(int pageNum, int pageSize, String patientId) { - PageHelper.startPage(pageNum, pageSize); - List list = orderDetailMapper.selectByPatientId(patientId); - Page page = new Page<>(); - page.setTotal(((Page) list).getTotal()); - page.setResult(list.stream().map(this::toDto).collect(Collectors.toList())); - return page; - } - - private OrderDetailDto toDto(OrderDetail entity) { - OrderDetailDto dto = new OrderDetailDto(); - dto.setId(entity.getId()); - dto.setOrderNo(entity.getOrderNo()); - // 统一映射状态名称 - dto.setOrderStatusName(mapOrderStatus(entity.getOrderStatus())); - dto.setDispenseStatusName(mapDispenseStatus(entity.getDispenseStatus())); - dto.setDrugName(entity.getDrugName()); - dto.setDosage(entity.getDosage()); - dto.setFrequency(entity.getFrequency()); - // 其它字段保持不变 - return dto; - } - - /** - * 医嘱执行后更新状态,统一使用映射器返回前端展示名称 - */ - @Transactional - @Override - public void executeOrder(Long orderDetailId, String executor) { - OrderDetail detail = orderDetailMapper.selectByPrimaryKey(orderDetailId); - if (detail == null) { + @Transactional(rollbackFor = Exception.class) + public void applyDispensingApply(Long orderMainId) { + // 1. 获取医嘱主记录及其明细 + OrderMain orderMain = orderMainMapper.selectByPrimaryKey(orderMainId); + if (orderMain == null) { throw new BusinessException("医嘱不存在"); } - // 更新业务状态 - detail.setOrderStatus(OrderStatus.EXECUTED.getCode()); - detail.setDispenseStatus(DispenseStatus.PENDING.getCode()); - detail.setExecuteUser(executor); - detail.setExecuteTime(new Date()); - orderDetailMapper.updateByPrimaryKeySelective(detail); + List details = orderDetailMapper.selectByOrderMainId(orderMainId); + if (CollectionUtils.isEmpty(details)) { + throw new BusinessException("医嘱明细为空,无法发药"); + } - // 记录日志(日志中仍使用中文,统一通过映射器获取) - logger.info("医嘱 {} 执行,状态由 {} 变为 {}", - detail.getOrderNo(), - mapOrderStatus(OrderStatus.PENDING.getCode()), - mapOrderStatus(OrderStatus.EXECUTED.getCode())); + // 2. 过滤出待发药(状态为 PENDING)的明细 + List pendingDetails = details.stream() + .filter(d -> d.getDispenseStatus() == DispenseStatus.PENDING.getCode()) + .collect(Collectors.toList()); + + if (CollectionUtils.isEmpty(pendingDetails)) { + throw new BusinessException("暂无待发药的医嘱明细"); + } + + // 3. 批量写入 DispensingDetail + List dispensingDetails = pendingDetails.stream().map(d -> { + DispensingDetail dd = new DispensingDetail(); + dd.setOrderDetailId(d.getId()); + dd.setOrderMainId(orderMainId); + dd.setDrugId(d.getDrugId()); + dd.setQuantity(d.getQuantity()); + dd.setDispenseStatus(DispenseStatus.PENDING.getCode()); + dd.setCreateTime(new Date()); + dd.setUpdateTime(new Date()); + return dd; + }).collect(Collectors.toList()); + + dispensingDetailMapper.batchInsert(dispensingDetails); + + // 4. 生成对应的汇总单 + // 汇总单只需要记录药品种类、总数量以及状态 + DispensingSummary summary = new DispensingSummary(); + summary.setOrderMainId(orderMainId); + summary.setTotalCount(dispensingDetails.size()); + int totalQty = dispensingDetails.stream().mapToInt(DispensingDetail::getQuantity).sum(); + summary.setTotalQuantity(totalQty); + summary.setDispenseStatus(DispenseStatus.PENDING.getCode()); + summary.setCreateTime(new Date()); + summary.setUpdateTime(new Date()); + + dispensingSummaryMapper.insert(summary); + + // 5. 更新医嘱明细的发药状态为“已申请” + pendingDetails.forEach(d -> d.setDispenseStatus(DispenseStatus.APPLYING.getCode())); + orderDetailMapper.batchUpdateDispenseStatus(pendingDetails); + + logger.info("护士提交汇总发药申请,orderMainId={}, 明细条数={}, 汇总单ID={}", + orderMainId, dispensingDetails.size(), summary.getId()); } - // 其余业务方法保持原有实现,仅在返回状态文字的地方改为 map* 方法 - // ----------------------------------------------------------------------- + // 其它业务方法保持不变... }