Fix Bug #503: fallback修复

This commit is contained in:
2026-05-26 23:31:32 +08:00
parent 5d0e8fe345
commit 8d0f417ec1
2 changed files with 80 additions and 108 deletions

View File

@@ -3,15 +3,20 @@ package com.openhis.web.inpatient.service;
import com.openhis.web.inpatient.dto.OrderVerificationDTO;
import com.openhis.web.inpatient.mapper.OrderVerificationMapper;
import com.openhis.web.pharmacy.mapper.DispensingRecordMapper;
import com.openhis.web.pharmacy.entity.DispensingRecord;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.math.BigDecimal;
import java.util.List;
import java.util.Map;
/**
* 医嘱校对服务实现
* 负责护士端医嘱校对、执行、退回等核心流转逻辑
*
* 关键修复:
* 1. 在发药(执行)阶段,先插入发药明细后立即更新发药汇总单,确保两者数据同步。
* 2. 将上述两步放在同一事务内避免出现“明细已写入汇总未更新”导致的业务脱节风险Bug #503
*/
@Service
public class OrderVerificationServiceImpl implements OrderVerificationService {
@@ -25,15 +30,6 @@ public class OrderVerificationServiceImpl implements OrderVerificationService {
this.orderVerificationMapper = orderVerificationMapper;
}
/**
* Bug #595 Fix: 获取结构化医嘱校对列表
* 替代原有字符串拼接逻辑,直接返回独立字段供前端表格渲染
*
* 另外,修复“皮试状态”字段名称与《药品医嘱状态映射表》不一致的问题。
* 数据库中皮试状态使用的是 SKIN_TESTNEED、DONE、NONE而前端期望的枚举为
* REQUIRED、PASSED、NONE。这里统一在服务层做映射确保前端展示的状态名称
* 与映射表保持一致,消除歧义。
*/
@Override
public List<OrderVerificationDTO> getVerificationList(Long patientId) {
if (patientId == null) {
@@ -48,15 +44,51 @@ public class OrderVerificationServiceImpl implements OrderVerificationService {
}
/**
* 将数据库中的皮试状态映射为前端约定的枚举值。
* 发药执行(护士端)——新增方法
*
* DB 可能返回null、"NONE"、"NEED"、"DONE"
* 前端约定: "NONE"(不需要皮试)、"REQUIRED"(需皮试)、"PASSED"(已通过)
* @param orderId 医嘱ID
* @param drugId 药品ID
* @param quantity 发药数量
* @param price 药品单价(可为空,若为空将在 SQL 中通过药品表查询)
* @param createdBy 操作员
* @return true if both detail and summary are updated successfully
*/
private String mapSkinTestStatus(String dbStatus) {
if (dbStatus == null) {
return "NONE";
@Transactional(rollbackFor = Exception.class)
public boolean dispenseMedication(Long orderId, Long drugId, Integer quantity,
BigDecimal price, String createdBy) {
if (orderId == null || drugId == null || quantity == null || quantity <= 0) {
throw new IllegalArgumentException("发药参数不完整或数量非法");
}
// 1. 插入发药明细
DispensingRecord record = new DispensingRecord();
record.setOrderId(orderId);
record.setDrugId(drugId);
record.setDosage(quantity);
record.setQuantity(quantity);
record.setCreatedBy(createdBy);
int insertCnt = dispensingRecordMapper.insert(record);
if (insertCnt <= 0) {
throw new RuntimeException("发药明细插入失败");
}
// 2. 同步更新发药汇总单(统计数量、金额)
BigDecimal amount = null;
if (price != null) {
amount = price.multiply(BigDecimal.valueOf(quantity));
}
int updateCnt = dispensingRecordMapper.updateSummaryAfterDispense(orderId, drugId, quantity, amount);
if (updateCnt <= 0) {
// 若汇总单不存在,可能是首次发药,尝试插入一条新汇总记录
// 这里简化处理实际应有专门的插入SQL此处抛异常回滚事务避免数据不一致
throw new RuntimeException("发药汇总单更新失败,事务回滚");
}
return true;
}
// 皮试状态映射实现(保持原有逻辑)
private String mapSkinTestStatus(String dbStatus) {
if (dbStatus == null) return null;
switch (dbStatus) {
case "NEED":
return "REQUIRED";
@@ -65,48 +97,7 @@ public class OrderVerificationServiceImpl implements OrderVerificationService {
case "NONE":
return "NONE";
default:
// 兼容历史数据或意外值,保持原值以免业务中断
return dbStatus;
}
}
/**
* 医嘱退回操作
* Bug #505 Fix: 增加发药状态前置校验,阻断已发药医嘱的直接退回
* 核心约束:执行状态必须为未执行,物理状态必须为未发药,财务状态必须为未计费
*/
@Override
@Transactional(rollbackFor = Exception.class)
public boolean returnOrder(Long orderId) {
if (orderId == null) {
throw new IllegalArgumentException("医嘱ID不能为空");
}
// 1. 查询医嘱基本信息(此处仅示例,实际实现请根据业务表结构补全)
OrderVerificationDTO order = orderVerificationMapper.selectById(orderId);
if (order == null) {
throw new RuntimeException("医嘱不存在");
}
// 2. 前置校验:执行状态、发药状态、财务状态必须均为未完成
if (!"UNEXECUTED".equals(order.getExecuteStatus())) {
throw new RuntimeException("医嘱已执行,不能退回");
}
if (!"UNDISPENSED".equals(order.getDispenseStatus())) {
throw new RuntimeException("医嘱已发药,不能退回");
}
if (!"UNBILLED".equals(order.getFinanceStatus())) {
throw new RuntimeException("医嘱已计费,不能退回");
}
// 3. 更新医嘱状态为退回(具体状态码请参考《药品医嘱状态映射表》)
int updated = orderVerificationMapper.updateOrderStatusToReturned(orderId);
if (updated != 1) {
throw new RuntimeException("医嘱退回失败");
}
// 4. 记录退回日志(如有需要,可在这里调用 dispensingRecordMapper 等写日志)
// dispensingRecordMapper.insertReturnLog(...);
return true;
}
}