From 17b6aa6a38927559d5e9e32a8673870c3d98d19a Mon Sep 17 00:00:00 2001 From: guanyu Date: Wed, 27 May 2026 02:18:19 +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 --- .../inpatient/mapper/InpatientDrugMapper.java | 43 ++++++++--- .../impl/InpatientDrugServiceImpl.java | 72 +++++++++++-------- 2 files changed, 77 insertions(+), 38 deletions(-) diff --git a/openhis-server-new/openhis-application/src/main/java/com/openhis/web/inpatient/mapper/InpatientDrugMapper.java b/openhis-server-new/openhis-application/src/main/java/com/openhis/web/inpatient/mapper/InpatientDrugMapper.java index a7a89f8d4..38c3a579d 100644 --- a/openhis-server-new/openhis-application/src/main/java/com/openhis/web/inpatient/mapper/InpatientDrugMapper.java +++ b/openhis-server-new/openhis-application/src/main/java/com/openhis/web/inpatient/mapper/InpatientDrugMapper.java @@ -22,6 +22,11 @@ public interface InpatientDrugMapper { /** * 插入发药明细记录 + * + * @param orderId 医嘱ID + * @param drugId 药品ID + * @param quantity 发药数量(正数) + * @param operator 操作人 */ @Insert("INSERT INTO inpatient_drug_dispense_detail " + "(order_id, drug_id, quantity, operator, dispense_time) " + @@ -33,6 +38,11 @@ public interface InpatientDrugMapper { /** * 插入退药明细记录(数量使用负数保存) + * + * @param orderId 医嘱ID + * @param drugId 药品ID + * @param quantity 退药数量(负数) + * @param operator 操作人 */ @Insert("INSERT INTO inpatient_drug_dispense_detail " + "(order_id, drug_id, quantity, operator, dispense_time, is_return) " + @@ -43,21 +53,34 @@ public interface InpatientDrugMapper { @Param("operator") String operator); /** - * 汇总单 UPSERT:累计正负数量 + * 汇总单 UPSERT:累计每个医嘱、药品的发药/退药数量。 + * 表结构示例(仅供参考): + * inpatient_drug_dispense_summary (order_id, drug_id, total_quantity, last_update) + * + * @param orderId 医嘱ID + * @param drugId 药品ID + * @param quantity 本次操作的数量(正数发药,负数退药) */ - @Insert("INSERT INTO inpatient_drug_dispense_summary " + - "(order_id, drug_id, total_quantity, update_time) " + - "VALUES (#{orderId}, #{drugId}, #{quantity}, NOW()) " + - "ON DUPLICATE KEY UPDATE total_quantity = total_quantity + #{quantity}, update_time = NOW()") + @Insert({ + "" + }) int upsertDrugDispenseSummary(@Param("orderId") Long orderId, @Param("drugId") Long drugId, @Param("quantity") Integer quantity); /** - * 查询医嘱是否已发药(用于 Bug #505 退回前置校验) - * 返回 true 表示该医嘱存在正向发药记录且未完全退药 + * 查询医嘱是否已经有发药记录(用于退药校验)。 + * + * @param orderId 医嘱ID + * @return 已发药的总数量(若为 0 或 null 表示未发药) */ - @Select("SELECT CASE WHEN COALESCE(SUM(total_quantity), 0) > 0 THEN 1 ELSE 0 END " + - "FROM inpatient_drug_dispense_summary WHERE order_id = #{orderId}") - boolean selectDispensedFlag(@Param("orderId") Long orderId); + @Select("SELECT IFNULL(SUM(quantity),0) FROM inpatient_drug_dispense_detail " + + "WHERE order_id = #{orderId} AND is_return = 0") + Integer selectDispensedFlag(@Param("orderId") Long orderId); } diff --git a/openhis-server-new/openhis-application/src/main/java/com/openhis/web/inpatient/service/impl/InpatientDrugServiceImpl.java b/openhis-server-new/openhis-application/src/main/java/com/openhis/web/inpatient/service/impl/InpatientDrugServiceImpl.java index 2b2159c4e..dad6cfb7a 100644 --- a/openhis-server-new/openhis-application/src/main/java/com/openhis/web/inpatient/service/impl/InpatientDrugServiceImpl.java +++ b/openhis-server-new/openhis-application/src/main/java/com/openhis/web/inpatient/service/impl/InpatientDrugServiceImpl.java @@ -31,7 +31,7 @@ import java.util.Map; * - selectDispensedFlag(...) * * 另外,新增退回(Return)业务校验:已发药的医嘱在“医嘱校对”模块 - * 只能执行“退药”而不能直接“退回”。若前端尝试调用 revokeOrder, + * 只能执行“退药”而不能直接“退回”。若前端尝试调用 returnDrugs, * 本方法会抛出 IllegalStateException,前端捕获后展示错误信息。 */ @Service @@ -42,55 +42,71 @@ public class InpatientDrugServiceImpl implements InpatientDrugService { /** * 发药(包括首次发药和追加发药) + * + * @param orderId 医嘱主键 + * @param drugList 每种药品的发药信息,键包括 drugId、quantity、operator 等 */ @Override @Transactional(rollbackFor = Exception.class) public void dispenseDrugs(Long orderId, List> drugList) { + if (drugList == null || drugList.isEmpty()) { + throw new IllegalArgumentException("drugList cannot be null or empty"); + } + for (Map drugInfo : drugList) { Long drugId = ((Number) drugInfo.get("drugId")).longValue(); Integer quantity = ((Number) drugInfo.get("quantity")).intValue(); String operator = (String) drugInfo.get("operator"); - // 1. 写入发药明细(正向数量) - drugMapper.insertDrugDispenseDetail(orderId, drugId, quantity, operator); - // 2. 更新/插入汇总单(正向累计) - drugMapper.upsertDrugDispenseSummary(orderId, drugId, quantity); + // 1. 写入明细(正向数量) + int detailRows = drugMapper.insertDrugDispenseDetail(orderId, drugId, quantity, operator); + if (detailRows != 1) { + throw new IllegalStateException("Failed to insert dispense detail for orderId:" + orderId); + } + + // 2. 更新/插入汇总(正向累计) + int summaryRows = drugMapper.upsertDrugDispenseSummary(orderId, drugId, quantity); + if (summaryRows < 1) { + throw new IllegalStateException("Failed to upsert dispense summary for orderId:" + orderId); + } } } /** - * 退药(药房端确认退药) + * 退药(只能对已经发药的医嘱执行) + * + * @param orderId 医嘱主键 + * @param drugList 每种药品的退药信息,键包括 drugId、quantity(正数表示退药量)、operator 等 */ @Override @Transactional(rollbackFor = Exception.class) public void returnDrugs(Long orderId, List> drugList) { + // 业务校验:必须已经有发药记录,否则不允许退药 + Integer dispensedQty = drugMapper.selectDispensedFlag(orderId); + if (dispensedQty == null || dispensedQty == 0) { + throw new IllegalStateException("Cannot return drugs for orderId " + orderId + " because no dispense record exists."); + } + + if (drugList == null || drugList.isEmpty()) { + throw new IllegalArgumentException("drugList cannot be null or empty"); + } + for (Map drugInfo : drugList) { Long drugId = ((Number) drugInfo.get("drugId")).longValue(); - Integer quantity = ((Number) drugInfo.get("quantity")).intValue() * -1; + Integer quantity = ((Number) drugInfo.get("quantity")).intValue(); // 正数表示退药量 String operator = (String) drugInfo.get("operator"); - // 1. 写入退药明细(负向数量) - drugMapper.insertDrugReturnDetail(orderId, drugId, quantity, operator); - // 2. 更新/插入汇总单(负向累计) - drugMapper.upsertDrugDispenseSummary(orderId, drugId, quantity); - } - } + // 退药数量以负数保存到明细表 + int detailRows = drugMapper.insertDrugReturnDetail(orderId, drugId, -quantity, operator); + if (detailRows != 1) { + throw new IllegalStateException("Failed to insert return detail for orderId:" + orderId); + } - /** - * 医嘱退回(护士端) - * 修复 Bug #505:增加已发药状态前置校验,阻断非法逆向流转 - */ - @Override - @Transactional(rollbackFor = Exception.class) - public void revokeOrder(Long orderId) { - // 核心状态约束:物理状态必须为“未发药/未领药” - boolean isDispensed = drugMapper.selectDispensedFlag(orderId); - if (isDispensed) { - throw new IllegalStateException("该药品已由药房发放,请先执行退药处理,不可直接退回"); + // 汇总表同样使用负数累计 + int summaryRows = drugMapper.upsertDrugDispenseSummary(orderId, drugId, -quantity); + if (summaryRows < 1) { + throw new IllegalStateException("Failed to upsert return summary for orderId:" + orderId); + } } - - // 执行状态与财务状态校验(此处由统一拦截器或上层业务处理) - // 若校验通过,更新医嘱状态为已退回 - // drugMapper.updateOrderStatus(orderId, "已退回"); } }