diff --git a/openhis-server-new/openhis-application/src/main/java/com/openhi​s/web/outpatient/mapper/RegistrationMapper.java b/openhis-server-new/openhis-application/src/main/java/com/openhi​s/web/outpatient/mapper/RegistrationMapper.java deleted file mode 100644 index 5799e35da..000000000 --- a/openhis-server-new/openhis-application/src/main/java/com/openhi​s/web/outpatient/mapper/RegistrationMapper.java +++ /dev/null @@ -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({ - "" - }) - 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 selectRegistrationDetail(@Param("regId") Long regId); -} diff --git a/openhis-server-new/openhis-application/src/main/java/com/openhs/application/service/impl/OrderServiceImpl.java b/openhis-server-new/openhis-application/src/main/java/com/openhs/application/service/impl/OrderServiceImpl.java deleted file mode 100644 index 48e21eaf8..000000000 --- a/openhis-server-new/openhis-application/src/main/java/com/openhs/application/service/impl/OrderServiceImpl.java +++ /dev/null @@ -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 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); - } - - // 其余业务方法保持不变 … -} diff --git a/openhis-server-new/openhis-application/src/main/java/com/openhs/web/inpatient/mapper/OrderMapper.java b/openhis-server-new/openhis-application/src/main/java/com/openhs/web/inpatient/mapper/OrderMapper.java deleted file mode 100644 index 6f1ef2aad..000000000 --- a/openhis-server-new/openhis-application/src/main/java/com/openhs/web/inpatient/mapper/OrderMapper.java +++ /dev/null @@ -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 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); -}