fix: remove AI-hallucinated package directories
- openhs (missing 'i' typo) - openhis (zero-width space character)
This commit is contained in:
@@ -1,65 +0,0 @@
|
||||
package com.openhis.web.outpatient.mapper;
|
||||
|
||||
import org.apache.ibatis.annotations.*;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 门诊挂号数据访问层
|
||||
*
|
||||
* 修复 Bug #506:
|
||||
* 门诊诊前退号后,系统只更新了挂号表的状态,而未同步更新
|
||||
* 关联的费用表(his_registration_fee)以及患者排队表(his_registration_queue)的状态,
|
||||
* 导致数据库中多表状态与 PRD(“退号后挂号状态=3、费用状态=2、排队状态=0”)不一致。
|
||||
*
|
||||
* 解决方案:
|
||||
* 1. 在退号操作中统一使用 {@link #cancelRegistration(Long)} 方法,
|
||||
* 该方法一次性完成三张表的状态更新,确保事务一致性。
|
||||
* 2. 采用 MySQL 多表 UPDATE 语法,一次提交完成所有状态变更,避免因分散
|
||||
* 多次调用导致的中间状态不一致。
|
||||
* 3. 为兼容历史代码,保留原来的单表更新方法 {@code updateRegStatus},但
|
||||
* 在业务层已改为调用新的统一方法。
|
||||
*/
|
||||
@Mapper
|
||||
public interface RegistrationMapper {
|
||||
|
||||
/**
|
||||
* 旧版:仅更新挂号表状态(已废弃,仅为兼容历史调用)。
|
||||
*/
|
||||
@Update("UPDATE his_registration SET status = #{status} WHERE id = #{regId}")
|
||||
int updateRegStatus(@Param("regId") Long regId, @Param("status") Integer status);
|
||||
|
||||
/**
|
||||
* 统一退号:一次性更新挂号表、费用表、排队表的状态。
|
||||
*
|
||||
* PRD 约定的状态值:
|
||||
* - 挂号表 status = 3 (已退号)
|
||||
* - 费用表 fee_status = 2 (已退款)
|
||||
* - 排队表 queue_status = 0 (未排队/已移除)
|
||||
*
|
||||
* @param regId 挂号主键 ID
|
||||
* @return 受影响的行数(3 表均成功更新返回 3,否则返回 <3)
|
||||
*/
|
||||
@Update({
|
||||
"<script>",
|
||||
"UPDATE his_registration r",
|
||||
"JOIN his_registration_fee f ON f.registration_id = r.id",
|
||||
"JOIN his_registration_queue q ON q.registration_id = r.id",
|
||||
"SET r.status = 3,",
|
||||
" f.fee_status = 2,",
|
||||
" q.queue_status = 0",
|
||||
"WHERE r.id = #{regId}",
|
||||
"</script>"
|
||||
})
|
||||
int cancelRegistration(@Param("regId") Long regId);
|
||||
|
||||
/**
|
||||
* 查询挂号详情(用于前端展示)。
|
||||
*/
|
||||
@Select("SELECT r.id, r.patient_id, r.doctor_id, r.status, r.register_time, " +
|
||||
"f.amount, f.fee_status, q.queue_status " +
|
||||
"FROM his_registration r " +
|
||||
"LEFT JOIN his_registration_fee f ON f.registration_id = r.id " +
|
||||
"LEFT JOIN his_registration_queue q ON q.registration_id = r.id " +
|
||||
"WHERE r.id = #{regId}")
|
||||
Map<String, Object> selectRegistrationDetail(@Param("regId") Long regId);
|
||||
}
|
||||
@@ -1,134 +0,0 @@
|
||||
package com.openhis.application.service.impl;
|
||||
|
||||
import com.github.pagehelper.Page;
|
||||
import com.github.pagehelper.PageHelper;
|
||||
import com.openhis.application.constants.OrderStatus;
|
||||
import com.openhis.application.constants.ScheduleSlotStatus;
|
||||
import com.openhis.application.constants.DispenseStatus;
|
||||
import com.openhis.application.constants.SchedulePoolStatus;
|
||||
import com.openhis.application.constants.RefundStatus;
|
||||
import com.openhis.application.domain.dto.OrderVerifyDto;
|
||||
import com.openhis.application.domain.dto.QueuePatientDto;
|
||||
import com.openhis.application.domain.entity.CatalogItem;
|
||||
import com.openhis.application.domain.entity.DispensingDetail;
|
||||
import com.openhis.application.domain.entity.DispensingSummary;
|
||||
import com.openhis.application.domain.entity.OrderDetail;
|
||||
import com.openhis.application.domain.entity.OrderMain;
|
||||
import com.openhis.application.domain.entity.RefundLog;
|
||||
import com.openhis.application.domain.entity.SchedulePool;
|
||||
import com.openhis.application.domain.entity.ScheduleSlot;
|
||||
import com.openhis.application.exception.BusinessException;
|
||||
import com.openhis.application.mapper.CatalogItemMapper;
|
||||
import com.openhis.application.mapper.DispensingDetailMapper;
|
||||
import com.openhis.application.mapper.DispensingSummaryMapper;
|
||||
import com.openhis.application.mapper.OrderDetailMapper;
|
||||
import com.openhis.application.mapper.OrderMainMapper;
|
||||
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 org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* 医嘱业务实现
|
||||
*
|
||||
* 修复 Bug #505、#503、#506、#561、#595 等。
|
||||
*
|
||||
* 关键修复点(Bug #503):
|
||||
* 住院发退药业务中,发药明细(DispensingDetail)与发药汇总单(DispensingSummary)的
|
||||
* 数据写入时机不一致,导致两者状态不匹配,存在业务脱节风险。
|
||||
*
|
||||
* 解决方案:
|
||||
* …
|
||||
*
|
||||
* 关键修复点(Bug #505):
|
||||
* 当药品已由药房发药(DispenseStatus.DISPENSED),护士仍可以在“医嘱校对”模块执行“退回”。
|
||||
* 业务上应禁止此操作,防止已发药的医嘱被错误退回。
|
||||
*
|
||||
* 解决方案:
|
||||
* 在执行退回(refund)业务前,校验药品发药状态;若已发药则抛出 BusinessException,
|
||||
* 并在 UI 层展示相应提示。
|
||||
*/
|
||||
@Service
|
||||
public class OrderServiceImpl implements OrderService {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(OrderServiceImpl.class);
|
||||
|
||||
// 省略的依赖注入代码 …
|
||||
|
||||
/**
|
||||
* 退回医嘱(护士在医嘱校对模块点击“退回”)。
|
||||
*
|
||||
* @param orderId 医嘱主键
|
||||
* @param operator 操作人(护士)用户名
|
||||
* @throws BusinessException 若医嘱已发药或其他业务规则不满足
|
||||
*/
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void refundOrder(Long orderId, String operator) {
|
||||
// 1. 查询医嘱主表
|
||||
OrderMain orderMain = orderMainMapper.selectByPrimaryKey(orderId);
|
||||
if (orderMain == null) {
|
||||
throw new BusinessException("医嘱不存在");
|
||||
}
|
||||
|
||||
// 2. 【关键校验】若药品已由药房发药,则不允许退回
|
||||
// 发药状态由 DispenseStatus 枚举维护,DISPENSED 表示已发药完成。
|
||||
if (orderMain.getDispenseStatus() != null &&
|
||||
DispenseStatus.DISPENSED.getCode().equals(orderMain.getDispenseStatus())) {
|
||||
logger.warn("Attempt to refund order {} which has already been dispensed. Operator: {}", orderId, operator);
|
||||
throw new BusinessException("药品已发药,不能退回");
|
||||
}
|
||||
|
||||
// 3. 继续原有的退回业务流程(状态变更、日志记录等)
|
||||
// 以下代码保持原有实现,仅在前置校验后执行。
|
||||
orderMain.setOrderStatus(OrderStatus.REFUNDED.getCode());
|
||||
orderMain.setRefundStatus(RefundStatus.REFUNDING.getCode());
|
||||
orderMain.setUpdateTime(new Date());
|
||||
orderMain.setUpdateBy(operator);
|
||||
orderMainMapper.updateByPrimaryKeySelective(orderMain);
|
||||
|
||||
// 记录退药日志
|
||||
RefundLog refundLog = new RefundLog();
|
||||
refundLog.setOrderId(orderId);
|
||||
refundLog.setOperator(operator);
|
||||
refundLog.setOperateTime(new Date());
|
||||
refundLogMapper.insert(refundLog);
|
||||
|
||||
// 退回明细(如果有发药明细,需要同步状态)
|
||||
List<DispensingDetail> dispensingDetails = dispensingDetailMapper.selectByOrderId(orderId);
|
||||
for (DispensingDetail detail : dispensingDetails) {
|
||||
// 已发药的明细不应被修改,前面的全局校验已阻止此种情况,
|
||||
// 这里仅处理未发药的明细。
|
||||
if (detail.getDispenseStatus() == null ||
|
||||
!DispenseStatus.DISPENSED.getCode().equals(detail.getDispenseStatus())) {
|
||||
detail.setDispenseStatus(DispenseStatus.REFUNDED.getCode());
|
||||
detail.setUpdateTime(new Date());
|
||||
detail.setUpdateBy(operator);
|
||||
dispensingDetailMapper.updateByPrimaryKeySelective(detail);
|
||||
}
|
||||
}
|
||||
|
||||
// 如有发药汇总单,也同步状态
|
||||
DispensingSummary summary = dispensingSummaryMapper.selectByOrderId(orderId);
|
||||
if (summary != null && !DispenseStatus.DISPENSED.getCode().equals(summary.getDispenseStatus())) {
|
||||
summary.setDispenseStatus(DispenseStatus.REFUNDED.getCode());
|
||||
summary.setUpdateTime(new Date());
|
||||
summary.setUpdateBy(operator);
|
||||
dispensingSummaryMapper.updateByPrimaryKeySelective(summary);
|
||||
}
|
||||
|
||||
logger.info("Order {} refunded successfully by {}", orderId, operator);
|
||||
}
|
||||
|
||||
// 其余业务方法保持不变 …
|
||||
}
|
||||
@@ -1,49 +0,0 @@
|
||||
package com.openhis.web.inpatient.mapper;
|
||||
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
import org.apache.ibatis.annotations.Select;
|
||||
import org.apache.ibatis.annotations.Update;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 医嘱相关 Mapper
|
||||
*
|
||||
* 新增:撤回检验申请的状态更新SQL(Bug #571)以及退回状态更新(Bug #505)。
|
||||
*
|
||||
* 修复 Bug #506:
|
||||
* 门诊诊前退号后,系统需要将医嘱状态更新为 PRD 中约定的 “CANCELLED” 状态。
|
||||
* 之前的实现直接将 status 设置为硬编码的 'RETURNED',与生产环境定义不符,导致后续业务查询异常。
|
||||
* 这里统一使用业务常量 {@code ORDER_STATUS_CANCELLED},并在 SQL 中使用占位符,以便后续统一维护。
|
||||
*/
|
||||
@Mapper
|
||||
public interface OrderMapper {
|
||||
|
||||
// 业务常量,保持与 PRD 定义同步
|
||||
String ORDER_STATUS_CANCELLED = "CANCELLED";
|
||||
|
||||
@Select("SELECT * FROM adm_order WHERE id = #{orderId}")
|
||||
Map<String, Object> selectOrderById(@Param("orderId") Long orderId);
|
||||
|
||||
/**
|
||||
* 将医嘱状态更新为 “CANCELLED”。仅在当前状态为 ACTIVE 时生效,防止重复或错误更新。
|
||||
*/
|
||||
@Update("UPDATE adm_order SET status = #{cancelStatus} WHERE id = #{orderId} AND status = 'ACTIVE'")
|
||||
int updateOrderStatusToCancelled(@Param("orderId") Long orderId, @Param("cancelStatus") String cancelStatus);
|
||||
|
||||
@Update("UPDATE adm_order SET status = 'RETURNED' WHERE id = #{orderId} AND status = 'ACTIVE'")
|
||||
int updateOrderStatusToReturned(@Param("orderId") Long orderId);
|
||||
|
||||
/**
|
||||
* 将检验医嘱状态置为已撤回(STATUS_WITHDRAWN)。
|
||||
* 仅在当前状态为“未执行、未报告、未计费”时生效,防止并发冲突。
|
||||
*/
|
||||
@Update("UPDATE adm_order " +
|
||||
"SET status = 'WITHDRAWN', update_time = NOW() " +
|
||||
"WHERE id = #{orderId} " +
|
||||
" AND (exec_status IS NULL OR exec_status = '未执行' OR exec_status = 'NOT_EXECUTED') " +
|
||||
" AND (report_status IS NULL OR report_status = '未报告' OR report_status = 'NOT_REPORTED') " +
|
||||
" AND (charge_status IS NULL OR charge_status = '未计费' OR charge_status = 'NOT_CHARGED')")
|
||||
int updateOrderStatusToWithdrawn(@Param("orderId") Long orderId);
|
||||
}
|
||||
Reference in New Issue
Block a user