506 门诊挂号:门诊诊前退号后,数据库多表状态值变更与 PRD 定义不符
CommonConstants.AppointmentOrderStatus 常量 → OrderStatus 枚举重构 新增枚举:0=患者取消 / 1=有效 / 2=系统取消 / 3=已完成 退号流程加乐观锁防并发,slot 状态改回待约,退号日志独立事务 修复 XML 中 Integer 比较用字符串的问题 Bug #411 — 诊室过滤栏从科室下拉框改为诊室按钮组
This commit is contained in:
@@ -10,7 +10,7 @@ import com.openhis.clinical.service.ITicketService;
|
||||
import com.openhis.web.appointmentmanage.appservice.ITicketAppService;
|
||||
import com.openhis.web.appointmentmanage.dto.TicketDto;
|
||||
import com.openhis.common.constant.CommonConstants.SlotStatus;
|
||||
import com.openhis.common.constant.CommonConstants.AppointmentOrderStatus;
|
||||
import com.openhis.common.enums.OrderStatus;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
@@ -198,10 +198,11 @@ public class TicketAppServiceImpl implements ITicketAppService {
|
||||
if (SlotStatus.CHECKED_IN.equals(slotStatus)) {
|
||||
dto.setStatus("已取号");
|
||||
} else if (SlotStatus.BOOKED.equals(slotStatus)) {
|
||||
if (AppointmentOrderStatus.CHECKED_IN.equals(raw.getOrderStatus())) {
|
||||
dto.setStatus("已取号");
|
||||
} else if (AppointmentOrderStatus.RETURNED.equals(raw.getOrderStatus())) {
|
||||
// order_main.status: 0=患者取消(已退号) 2=系统取消 其余=已预约
|
||||
if (OrderStatus.PATIENT_CANCELLED.getValue().equals(raw.getOrderStatus())) {
|
||||
dto.setStatus("已退号");
|
||||
} else if (OrderStatus.SYSTEM_CANCELLED.getValue().equals(raw.getOrderStatus())) {
|
||||
dto.setStatus("系统取消");
|
||||
} else {
|
||||
dto.setStatus("已预约");
|
||||
}
|
||||
@@ -372,10 +373,11 @@ public class TicketAppServiceImpl implements ITicketAppService {
|
||||
if (SlotStatus.CHECKED_IN.equals(slotStatus)) {
|
||||
dto.setStatus("已取号");
|
||||
} else if (SlotStatus.BOOKED.equals(slotStatus)) {
|
||||
if (AppointmentOrderStatus.CHECKED_IN.equals(raw.getOrderStatus())) {
|
||||
dto.setStatus("已取号");
|
||||
} else if (AppointmentOrderStatus.RETURNED.equals(raw.getOrderStatus())) {
|
||||
// order_main.status: 0=患者取消(已退号) 2=系统取消 其余=已预约
|
||||
if (OrderStatus.PATIENT_CANCELLED.getValue().equals(raw.getOrderStatus())) {
|
||||
dto.setStatus("已退号");
|
||||
} else if (OrderStatus.SYSTEM_CANCELLED.getValue().equals(raw.getOrderStatus())) {
|
||||
dto.setStatus("系统取消");
|
||||
} else {
|
||||
dto.setStatus("已预约");
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ package com.openhis.web.chargemanage.appservice.impl;
|
||||
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
|
||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.core.common.core.domain.R;
|
||||
@@ -329,16 +330,14 @@ public class OutpatientRegistrationAppServiceImpl implements IOutpatientRegistra
|
||||
}
|
||||
}
|
||||
|
||||
// 如果本次门诊挂号来自预约签到,同步把预约订单与号源槽位状态改为已退号
|
||||
// 退费成功后,同步回滚预约订单状态及号源;同时移除分诊队列
|
||||
Long refundOrderMainId = null;
|
||||
if (result != null && result.getCode() == 200) {
|
||||
syncAppointmentReturnStatus(byId, cancelRegPaymentDto.getReason());
|
||||
|
||||
// 同步移除分诊队列中的记录
|
||||
refundOrderMainId = syncAppointmentReturnStatus(byId, cancelRegPaymentDto.getReason());
|
||||
removeTriageQueueItem(byId.getId());
|
||||
}
|
||||
|
||||
// 记录退号日志
|
||||
recordRefundLog(cancelRegPaymentDto, byId, result, paymentRecon);
|
||||
// 退号日志独立事务写入,无论退费成功与否均记录
|
||||
recordRefundLog(cancelRegPaymentDto, byId, result, paymentRecon, refundOrderMainId);
|
||||
|
||||
// 2025/05/05 该处保存费用项后,会通过统一收费处理进行收费
|
||||
return R.ok(paymentRecon, MessageUtils.createMessage(PromptMsgConstant.Common.M00004, new Object[] {"退号"}));
|
||||
@@ -435,8 +434,6 @@ public class OutpatientRegistrationAppServiceImpl implements IOutpatientRegistra
|
||||
// 通过患者、科室、日期查找关联的预约订单
|
||||
LambdaQueryWrapper<Order> queryWrapper = new LambdaQueryWrapper<Order>()
|
||||
.eq(Order::getPatientId, encounter.getPatientId())
|
||||
.in(Order::getStatus, CommonConstants.AppointmentOrderStatus.BOOKED,
|
||||
CommonConstants.AppointmentOrderStatus.CHECKED_IN)
|
||||
.orderByDesc(Order::getUpdateTime)
|
||||
.orderByDesc(Order::getCreateTime)
|
||||
.last("LIMIT 1");
|
||||
@@ -590,20 +587,25 @@ public class OutpatientRegistrationAppServiceImpl implements IOutpatientRegistra
|
||||
}
|
||||
|
||||
/**
|
||||
* 同步预约号源状态为已退号。
|
||||
* 说明:
|
||||
* 1) 门诊退号主流程不依赖该步骤成功与否,因此此方法内部异常仅记录日志,不向上抛出。
|
||||
* 2) 通过患者、科室、日期以及状态筛选最近一条预约订单,尽量避免误匹配。
|
||||
* 诊前退号:回滚预约订单、号源槽位、号源池统计。
|
||||
*
|
||||
* <p>处理四件事:
|
||||
* <ol>
|
||||
* <li>order_main → status=0(患者取消), pay_status=3(已退费), 写入取消时间和原因</li>
|
||||
* <li>adm_schedule_slot → status=0(待约), order_id=NULL(释放号源)</li>
|
||||
* <li>adm_schedule_pool → 重算统计值 + version+1</li>
|
||||
* <li>返回 order_main.id 供 refund_log 关联</li>
|
||||
* </ol>
|
||||
*
|
||||
* <p>异常仅记录日志不向上抛,不影响主流程返回成功。
|
||||
*/
|
||||
private void syncAppointmentReturnStatus(Encounter encounter, String reason) {
|
||||
private Long syncAppointmentReturnStatus(Encounter encounter, String reason) {
|
||||
if (encounter == null || encounter.getPatientId() == null) {
|
||||
return;
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
LambdaQueryWrapper<Order> queryWrapper = new LambdaQueryWrapper<Order>()
|
||||
.eq(Order::getPatientId, encounter.getPatientId())
|
||||
.in(Order::getStatus, CommonConstants.AppointmentOrderStatus.BOOKED,
|
||||
CommonConstants.AppointmentOrderStatus.CHECKED_IN)
|
||||
.orderByDesc(Order::getUpdateTime)
|
||||
.orderByDesc(Order::getCreateTime)
|
||||
.last("LIMIT 1");
|
||||
@@ -625,35 +627,55 @@ public class OutpatientRegistrationAppServiceImpl implements IOutpatientRegistra
|
||||
|
||||
Order appointmentOrder = orderService.getOne(queryWrapper, false);
|
||||
if (appointmentOrder == null) {
|
||||
return;
|
||||
return null;
|
||||
}
|
||||
|
||||
Date now = new Date();
|
||||
if (!CommonConstants.AppointmentOrderStatus.RETURNED.equals(appointmentOrder.getStatus())) {
|
||||
Order updateOrder = new Order();
|
||||
updateOrder.setId(appointmentOrder.getId());
|
||||
updateOrder.setStatus(CommonConstants.AppointmentOrderStatus.RETURNED);
|
||||
updateOrder.setPayStatus(0);
|
||||
updateOrder.setCancelTime(now);
|
||||
updateOrder.setCancelReason("门诊退号");
|
||||
updateOrder.setUpdateTime(now);
|
||||
orderService.updateById(updateOrder);
|
||||
// 只有有效订单(1)才能退号
|
||||
if (!OrderStatus.ACTIVE.getValue().equals(appointmentOrder.getStatus())) {
|
||||
log.warn("退号跳过:订单状态非有效, orderId={}, status={}",
|
||||
appointmentOrder.getId(), appointmentOrder.getStatus());
|
||||
return null;
|
||||
}
|
||||
|
||||
// 乐观锁更新:WHERE version = 旧值,防并发重复退号
|
||||
boolean updated = orderService.update(
|
||||
new LambdaUpdateWrapper<Order>()
|
||||
.set(Order::getStatus, OrderStatus.PATIENT_CANCELLED.getValue())
|
||||
.set(Order::getPayStatus, PaymentStatus.REFUND_ALL.getValue())
|
||||
.set(Order::getCancelTime, new Date())
|
||||
.set(Order::getCancelReason,
|
||||
StringUtils.isNotEmpty(reason) ? reason : "诊前退号")
|
||||
.set(Order::getUpdateTime, new Date())
|
||||
.setSql("version = version + 1")
|
||||
.eq(Order::getId, appointmentOrder.getId())
|
||||
.eq(Order::getVersion, appointmentOrder.getVersion())
|
||||
);
|
||||
if (!updated) {
|
||||
log.warn("退号乐观锁冲突,订单已被其他操作修改, orderId={}", appointmentOrder.getId());
|
||||
return null;
|
||||
}
|
||||
|
||||
Long slotId = appointmentOrder.getSlotId();
|
||||
if (slotId == null) {
|
||||
return;
|
||||
return appointmentOrder.getId();
|
||||
}
|
||||
|
||||
int slotRows = scheduleSlotMapper.updateSlotStatus(slotId, CommonConstants.SlotStatus.RETURNED);
|
||||
int slotRows = scheduleSlotMapper.updateSlotStatus(slotId, CommonConstants.SlotStatus.AVAILABLE);
|
||||
if (slotRows > 0) {
|
||||
Long poolId = scheduleSlotMapper.selectPoolIdBySlotId(slotId);
|
||||
if (poolId != null) {
|
||||
schedulePoolMapper.refreshPoolStats(poolId);
|
||||
schedulePoolMapper.update(null,
|
||||
new LambdaUpdateWrapper<SchedulePool>()
|
||||
.setSql("version = version + 1")
|
||||
.set(SchedulePool::getUpdateTime, new Date())
|
||||
.eq(SchedulePool::getId, poolId));
|
||||
}
|
||||
}
|
||||
return appointmentOrder.getId();
|
||||
} catch (Exception e) {
|
||||
log.warn("同步预约号源已退号状态失败, encounterId={}", encounter.getId(), e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -672,22 +694,29 @@ public class OutpatientRegistrationAppServiceImpl implements IOutpatientRegistra
|
||||
}
|
||||
|
||||
/**
|
||||
* 记录退号日志
|
||||
* 记录退号日志(独立事务)。
|
||||
*
|
||||
* <p>REQUIRES_NEW 确保即使主事务回滚,退号审计日志也不丢失。
|
||||
* orderMainId 优先使用 order_main.id,若退费失败则 fallback 到 encounterId。
|
||||
*
|
||||
* @param cancelRegPaymentDto 退号请求对象
|
||||
* @param encounter 就诊信息
|
||||
* @param result 退号结果
|
||||
* @param paymentRecon 支付对账信息
|
||||
* @param orderMainId 预约订单主键(order_main.id),用于关联业务数据
|
||||
*/
|
||||
@Transactional(propagation = Propagation.REQUIRES_NEW)
|
||||
public void recordRefundLog(CancelRegPaymentDto cancelRegPaymentDto,
|
||||
Encounter encounter,
|
||||
R<?> result,
|
||||
PaymentReconciliation paymentRecon) {
|
||||
PaymentReconciliation paymentRecon,
|
||||
Long orderMainId) {
|
||||
RefundLog refundLog = new RefundLog();
|
||||
try {
|
||||
// 1. 订单ID(唯一)
|
||||
String orderId = String.valueOf(cancelRegPaymentDto.getEncounterId());
|
||||
// 1. 订单ID(关联 order_main.id)
|
||||
String orderId = orderMainId != null
|
||||
? String.valueOf(orderMainId)
|
||||
: String.valueOf(cancelRegPaymentDto.getEncounterId());
|
||||
refundLog.setOrderId(orderId);
|
||||
|
||||
// 已存在则不重复插入(防止唯一约束异常)
|
||||
|
||||
@@ -1991,7 +1991,7 @@ public class PaymentRecServiceImpl implements IPaymentRecService {
|
||||
Order appointmentOrder = iOrderService.getOne(
|
||||
new LambdaQueryWrapper<Order>()
|
||||
.eq(Order::getPatientId, encounterFormData.getPatientId())
|
||||
.eq(Order::getStatus, CommonConstants.AppointmentOrderStatus.CHECKED_IN)
|
||||
.eq(Order::getStatus, OrderStatus.ACTIVE.getValue()) // 有效订单(1)
|
||||
.eq(Order::getDeleteFlag, "0")
|
||||
.orderByDesc(Order::getCreateTime)
|
||||
.last("LIMIT 1")
|
||||
@@ -2114,11 +2114,11 @@ public class PaymentRecServiceImpl implements IPaymentRecService {
|
||||
Long queuePoolId = null;
|
||||
Long queueSlotId = null;
|
||||
try {
|
||||
// 查询患者当天的待签到预约订单(status = 1 或 2 表示已预约或已取号)
|
||||
// 查询患者当天有效订单(1);已取消(0/2)和已完成(3)的不参与排队
|
||||
Order order = iOrderService.getOne(
|
||||
new LambdaQueryWrapper<Order>()
|
||||
.eq(Order::getPatientId, encounter.getPatientId())
|
||||
.in(Order::getStatus, 1, 2) // 1=BOOKED 已预约, 2=CHECKED_IN 已取号
|
||||
.eq(Order::getStatus, OrderStatus.ACTIVE.getValue()) // 有效(1)
|
||||
.eq(Order::getDeleteFlag, "0")
|
||||
.orderByDesc(Order::getCreateTime)
|
||||
.last("LIMIT 1")
|
||||
|
||||
Reference in New Issue
Block a user