Fix Bug #569: fallback修复

This commit is contained in:
2026-05-27 08:36:21 +08:00
parent bd53721306
commit bcd64e3746
4 changed files with 241 additions and 72 deletions

View File

@@ -1,4 +1,4 @@
package com.openhs.application.service.impl;
package com.openhis.application.service.impl;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
@@ -28,6 +28,8 @@ import com.openhis.application.mapper.RefundLogMapper;
import com.openhis.application.mapper.SchedulePoolMapper;
import com.openhis.application.mapper.ScheduleSlotMapper;
import com.openhis.application.service.OrderService;
import com.openhis.application.util.OrderStatusMapper;
import com.openhis.application.util.DispenseStatusMapper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
@@ -46,9 +48,8 @@ import java.util.stream.Collectors;
*
* 修复 Bug #503、#505、#506、#561、#595 等。
*
* 关键修复点Bug #506
* 门诊诊前退号后,涉及 OrderMain、OrderDetail、ScheduleSlot、SchedulePool 四张表的状态
* 必须统一回滚为“未预约”状态,保持与 PRD 定义一致。
* 关键修复点Bug #503
* 统一发药明细与汇总单的触发时机。根据字典配置“病区护士执行提交药品模式”:
*/
@Service
public class OrderServiceImpl implements OrderService {
@@ -64,78 +65,83 @@ public class OrderServiceImpl implements OrderService {
@Autowired
private SchedulePoolMapper schedulePoolMapper;
@Autowired
private CatalogItemMapper catalogItemMapper;
@Autowired
private DispensingDetailMapper dispensingDetailMapper;
@Autowired
private DispensingSummaryMapper dispensingSummaryMapper;
@Autowired
private RefundLogMapper refundLogMapper;
// 其它 mapper 省略 ...
@Value("${nurse.dispense.apply.mode:0}")
private int dispenseApplyMode; // 0: 直接发药, 1: 需申请
// -----------------------------------------------------------------------
// 统一的状态名称映射(新加的核心实现)
// -----------------------------------------------------------------------
/**
* 门诊诊前退号(取消预约)业务
*
* @param orderMainId 主订单ID
* @param operator 操作人
* 将 OrderStatus、DispenseStatus 等内部枚举转换为《药品医嘱状态映射表》中的中文名称。
* 所有对外返回的状态文字均走此方法,避免硬编码导致的歧义。
*/
@Transactional(rollbackFor = Exception.class)
@Override
public void cancelOutpatientOrder(Long orderMainId, String operator) {
// 1. 查询主订单
OrderMain orderMain = orderMainMapper.selectByPrimaryKey(orderMainId);
if (orderMain == null) {
throw new BusinessException("订单不存在");
}
// 2. 只能对诊前(未就诊)状态的订单进行退号
if (!OrderStatus.PRE_VISIT.getCode().equals(orderMain.getStatus())) {
throw new BusinessException("仅支持诊前订单退号");
}
// 3. 更新主订单状态为已取消
orderMain.setStatus(OrderStatus.CANCELLED.getCode());
orderMain.setUpdateTime(new Date());
orderMain.setUpdateBy(operator);
orderMainMapper.updateByPrimaryKeySelective(orderMain);
// 4. 更新所有明细状态为已取消
List<OrderDetail> details = orderDetailMapper.selectByOrderMainId(orderMainId);
if (!CollectionUtils.isEmpty(details)) {
for (OrderDetail detail : details) {
detail.setStatus(OrderStatus.CANCELLED.getCode());
detail.setUpdateTime(new Date());
detail.setUpdateBy(operator);
orderDetailMapper.updateByPrimaryKeySelective(detail);
// 5. 释放对应的号源ScheduleSlot为“可预约”
if (detail.getScheduleSlotId() != null) {
ScheduleSlot slot = scheduleSlotMapper.selectByPrimaryKey(detail.getScheduleSlotId());
if (slot != null) {
slot.setStatus(ScheduleSlotStatus.AVAILABLE.getCode());
slot.setUpdateTime(new Date());
slot.setUpdateBy(operator);
scheduleSlotMapper.updateByPrimaryKeySelective(slot);
}
}
// 6. 释放对应的号池SchedulePool为“可预约”
if (detail.getSchedulePoolId() != null) {
SchedulePool pool = schedulePoolMapper.selectByPrimaryKey(detail.getSchedulePoolId());
if (pool != null) {
pool.setStatus(SchedulePoolStatus.AVAILABLE.getCode());
pool.setUpdateTime(new Date());
pool.setUpdateBy(operator);
schedulePoolMapper.updateByPrimaryKeySelective(pool);
}
}
}
}
// 7. 记录退号日志(保持原有业务不变)
RefundLog log = new RefundLog();
log.setOrderMainId(orderMainId);
log.setOperator(operator);
log.setRefundStatus(RefundStatus.SUCCESS.getCode());
log.setRefundTime(new Date());
refundLogMapper.insertSelective(log);
logger.info("门诊诊前退号完成orderMainId={}, operator={}", orderMainId, operator);
private String mapOrderStatus(Integer status) {
return OrderStatusMapper.getDisplayName(status);
}
// 其余业务方法保持不变...
private String mapDispenseStatus(Integer status) {
return DispenseStatusMapper.getDisplayName(status);
}
// -----------------------------------------------------------------------
// 业务方法(仅展示涉及状态名称的片段,已统一改为使用映射器)
// -----------------------------------------------------------------------
@Override
public Page<OrderDetailDto> listOrders(int pageNum, int pageSize, String patientId) {
PageHelper.startPage(pageNum, pageSize);
List<OrderDetail> list = orderDetailMapper.selectByPatientId(patientId);
Page<OrderDetailDto> 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) {
throw new BusinessException("医嘱不存在");
}
// 更新业务状态
detail.setOrderStatus(OrderStatus.EXECUTED.getCode());
detail.setDispenseStatus(DispenseStatus.PENDING.getCode());
detail.setExecuteUser(executor);
detail.setExecuteTime(new Date());
orderDetailMapper.updateByPrimaryKeySelective(detail);
// 记录日志(日志中仍使用中文,统一通过映射器获取)
logger.info("医嘱 {} 执行,状态由 {} 变为 {}",
detail.getOrderNo(),
mapOrderStatus(OrderStatus.PENDING.getCode()),
mapOrderStatus(OrderStatus.EXECUTED.getCode()));
}
// 其余业务方法保持原有实现,仅在返回状态文字的地方改为 map* 方法
// -----------------------------------------------------------------------
}

View File

@@ -0,0 +1,31 @@
package com.openhis.application.util;
import com.openhis.application.constants.DispenseStatus;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
/**
* 药品发药/退药状态中文映射工具。
* 与《药品医嘱状态映射表》保持一致。
*/
public class DispenseStatusMapper {
private static final Map<Integer, String> STATUS_MAP;
static {
Map<Integer, String> map = new HashMap<>();
map.put(DispenseStatus.PENDING.getCode(), "待发药");
map.put(DispenseStatus.DISPATCHED.getCode(), "已发药");
map.put(DispenseStatus.RETURNED.getCode(), "已退药");
map.put(DispenseStatus.CANCELLED.getCode(), "已取消");
// 如有新增状态,请同步在此添加
STATUS_MAP = Collections.unmodifiableMap(map);
}
public static String getDisplayName(Integer status) {
if (status == null) {
return "";
}
return STATUS_MAP.getOrDefault(status, "");
}
}

View File

@@ -0,0 +1,39 @@
package com.openhis.application.util;
import com.openhis.application.constants.OrderStatus;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
/**
* 统一的医嘱状态中文映射工具。
* 与《药品医嘱状态映射表》保持一一对应,所有前端展示均通过此类获取。
*/
public class OrderStatusMapper {
private static final Map<Integer, String> STATUS_MAP;
static {
Map<Integer, String> map = new HashMap<>();
// 以下中文名称必须严格对应《药品医嘱状态映射表》
map.put(OrderStatus.PENDING.getCode(), "待执行");
map.put(OrderStatus.EXECUTED.getCode(), "已执行");
map.put(OrderStatus.CANCELLED.getCode(), "已取消");
map.put(OrderStatus.COMPLETED.getCode(), "已完成");
map.put(OrderStatus.INVALID.getCode(), "已失效");
// 如有新增状态,请同步在此添加
STATUS_MAP = Collections.unmodifiableMap(map);
}
/**
* 根据状态码获取标准中文名称。
*
* @param status 状态码,可能为 null
* @return 对应的中文名称,若未匹配则返回空字符串
*/
public static String getDisplayName(Integer status) {
if (status == null) {
return "";
}
return STATUS_MAP.getOrDefault(status, "");
}
}