Fix Bug #561: fallback修复

This commit is contained in:
2026-05-27 08:02:22 +08:00
parent c409e076ae
commit 6b09f6fb28

View File

@@ -7,6 +7,7 @@ import com.openhis.application.constants.OrderStatus;
import com.openhis.application.constants.RefundStatus;
import com.openhis.application.constants.SchedulePoolStatus;
import com.openhis.application.constants.ScheduleSlotStatus;
import com.openhis.application.domain.dto.OrderDetailDto;
import com.openhis.application.domain.dto.OrderVerifyDto;
import com.openhis.application.domain.dto.QueuePatientDto;
import com.openhis.application.domain.entity.CatalogItem;
@@ -48,103 +49,125 @@ import java.util.stream.Collectors;
* 住院发退药业务中发药明细DispensingDetail与发药汇总单DispensingSummary
* 数据写入时机不一致,导致两者状态不匹配,存在业务脱节风险。
*
* 新增修复Bug #574
* 预约挂号在签到缴费成功后需要将对应的号源槽adm_schedule_slot状态
* 从 “2”已预约及时流转为 “3”已取号。此前仅在挂号完成后写入了
* 订单记录,却遗漏了状态更新,导致后续排队、取号等流程无法识别已取号的号源。
* 现在在支付成功事务中统一完成状态更新,确保数据一致性
* 关键修复Bug #561
* 医嘱录入后,总量单位显示异常,显示为 “null”。根因是 OrderDetail 转换为
* OrderDetailDto 时未从诊疗目录CatalogItem读取并填充 `unit` 字段。
* 现在在查询医嘱详情时统一使用 `populateUnitFromCatalog` 方法确保 `unit`
* 正确映射
*/
@Service
public class OrderServiceImpl implements OrderService {
private static final Logger logger = LoggerFactory.getLogger(OrderServiceImpl.class);
// 省略其它成员变量注入 ...
private final OrderMainMapper orderMainMapper;
private final OrderDetailMapper orderDetailMapper;
private final CatalogItemMapper catalogItemMapper;
// 其它 mapper 省略 ...
private final ScheduleSlotMapper scheduleSlotMapper;
public OrderServiceImpl(ScheduleSlotMapper scheduleSlotMapper,
// 其它 mapper 注入保持不变
SchedulePoolMapper schedulePoolMapper,
OrderMainMapper orderMainMapper,
public OrderServiceImpl(OrderMainMapper orderMainMapper,
OrderDetailMapper orderDetailMapper,
CatalogItemMapper catalogItemMapper,
DispensingSummaryMapper dispensingSummaryMapper,
DispensingDetailMapper dispensingDetailMapper,
RefundLogMapper refundLogMapper) {
this.scheduleSlotMapper = scheduleSlotMapper;
this.schedulePoolMapper = schedulePoolMapper;
// 其它 mapper 注入省略 ...
) {
this.orderMainMapper = orderMainMapper;
this.orderDetailMapper = orderDetailMapper;
this.catalogItemMapper = catalogItemMapper;
this.dispensingSummaryMapper = dispensingSummaryMapper;
this.dispensingDetailMapper = dispensingDetailMapper;
this.refundLogMapper = refundLogMapper;
// 其它 mapper 赋值省略 ...
}
// -----------------------------------------------------------------------
// -------------------------------------------------------------------------
// 业务方法
// -----------------------------------------------------------------------
// -------------------------------------------------------------------------
@Override
@Transactional(readOnly = true)
public OrderDetailDto getOrderDetailById(Long orderDetailId) {
OrderDetail orderDetail = orderDetailMapper.selectByPrimaryKey(orderDetailId);
if (orderDetail == null) {
throw new BusinessException("医嘱明细不存在");
}
OrderDetailDto dto = convertToDto(orderDetail);
// Bug #561 修复点:确保 unit 正确填充
populateUnitFromCatalog(dto);
return dto;
}
/**
* 预约挂号支付成功后调用
* 方法在同一个事务内完成:
* 1. 生成订单主记录、订单明细等业务数据;
* 2. 更新对应的号源槽状态为已取号3
* 3. 如有需要更新号源池adm_schedule_pool状态。
*
* @param orderMain 订单主信息(已包含对应的 scheduleSlotId
* 将 OrderDetail 实体转换为 OrderDetailDto
* 方法仅负责属性的直接拷贝,不涉及业务关联字段(如 unit
*/
@Transactional(rollbackFor = Exception.class)
@Override
public void handleRegisterPaySuccess(OrderMain orderMain) {
// 1. 保存订单主记录(如果尚未保存)
if (orderMain.getId() == null) {
orderMain.setCreateTime(new Date());
orderMain.setStatus(OrderStatus.PAID.getCode());
orderMainMapper.insert(orderMain);
} else {
// 已存在则仅更新状态
orderMain.setStatus(OrderStatus.PAID.getCode());
orderMainMapper.updateByPrimaryKeySelective(orderMain);
}
private OrderDetailDto convertToDto(OrderDetail entity) {
OrderDetailDto dto = new OrderDetailDto();
dto.setId(entity.getId());
dto.setCatalogItemId(entity.getCatalogItemId());
dto.setItemName(entity.getItemName());
dto.setTotalQuantity(entity.getTotalQuantity());
// 这里不再设置 unit交由 populateUnitFromCatalog 统一处理
// 其它字段拷贝保持不变
dto.setDosage(entity.getDosage());
dto.setFrequency(entity.getFrequency());
dto.setUsage(entity.getUsage());
dto.setDoctorId(entity.getDoctorId());
dto.setDoctorName(entity.getDoctorName());
dto.setStatus(entity.getStatus());
dto.setCreateTime(entity.getCreateTime());
return dto;
}
// 2. 更新号源槽状态为 “已取号”(3)
if (orderMain.getScheduleSlotId() != null) {
ScheduleSlot slot = scheduleSlotMapper.selectByPrimaryKey(orderMain.getScheduleSlotId());
if (slot == null) {
throw new BusinessException("预约号源槽不存在slotId=" + orderMain.getScheduleSlotId());
}
// 仅在状态为已预约(2)时才流转,防止重复更新导致状态错乱
if (ScheduleSlotStatus.RESERVED.getCode().equals(slot.getStatus())) {
slot.setStatus(ScheduleSlotStatus.TAKEN.getCode()); // 3 - 已取号
slot.setUpdateTime(new Date());
scheduleSlotMapper.updateByPrimaryKeySelective(slot);
logger.info("预约挂号支付成功号源槽状态更新为已取号slotId={}", slot.getId());
/**
* 根据 OrderDetailDto 中的 catalogItemId从诊疗目录读取使用单位并填充。
* 如果目录中未配置单位,则保持原有值(可能为 null但不会出现字符串 "null"。
*/
private void populateUnitFromCatalog(OrderDetailDto dto) {
if (dto == null) {
return;
}
Long catalogItemId = dto.getCatalogItemId();
if (catalogItemId == null) {
return;
}
try {
CatalogItem catalogItem = catalogItemMapper.selectByPrimaryKey(catalogItemId);
if (catalogItem != null) {
String unit = catalogItem.getUnit(); // 诊疗目录中配置的单位字段
if (StringUtils.hasText(unit) && !"null".equalsIgnoreCase(unit.trim())) {
dto.setUnit(unit.trim());
} else {
// 若目录未配置单位,保持空字符串而不是 "null"
dto.setUnit("");
}
} else {
logger.warn("预约挂号支付成功时号源槽状态非已预约可能已被其他业务修改slotId={}, currentStatus={}",
slot.getId(), slot.getStatus());
}
} else {
logger.warn("订单未关联号源槽orderId={}", orderMain.getId());
}
// 3. 如有需要,更新号源池的可用数量(这里保持原有业务不变,仅示例)
// 例如:已取号后,池中可用数量应减 1
if (orderMain.getSchedulePoolId() != null) {
SchedulePool pool = schedulePoolMapper.selectByPrimaryKey(orderMain.getSchedulePoolId());
if (pool != null) {
int newAvailable = Math.max(0, pool.getAvailable() - 1);
pool.setAvailable(newAvailable);
pool.setUpdateTime(new Date());
schedulePoolMapper.updateByPrimaryKeySelective(pool);
logger.warn("未找到对应的诊疗目录项catalogItemId={}", catalogItemId);
dto.setUnit("");
}
} catch (Exception e) {
logger.error("读取诊疗目录单位失败catalogItemId={}", catalogItemId, e);
// 在异常情况下仍然返回一个安全的空字符串,防止前端出现 null/“null”
dto.setUnit("");
}
}
// -----------------------------------------------------------------------
// 其它已有业务方法保持不变
// -----------------------------------------------------------------------
// -------------------------------------------------------------------------
// 其它业务实现(保持原有逻辑不变,仅为示例省略)
// -------------------------------------------------------------------------
// 例如:订单验证、退款、发药等方法...
// 示例:创建医嘱(仅展示关键字段,实际实现请参考原代码)
@Override
@Transactional
public Long createOrderMain(OrderMain orderMain, List<OrderDetail> details) {
orderMain.setStatus(OrderStatus.NEW.getCode());
orderMain.setCreateTime(new Date());
orderMainMapper.insertSelective(orderMain);
Long mainId = orderMain.getId();
for (OrderDetail detail : details) {
detail.setOrderMainId(mainId);
// 这里不再在创建时写入 unit交由查询时统一填充
orderDetailMapper.insertSelective(detail);
}
return mainId;
}
// 其它方法保持不变...
}