217 收费工作站-》门诊收费:【确认收费】报错“打印失败”
220 门诊医生站:新增耗材收费项目医嘱单价/总金额未显示正确的值
This commit is contained in:
@@ -641,11 +641,13 @@ public class DoctorStationAdviceAppServiceImpl implements IDoctorStationAdviceAp
|
||||
.collect(Collectors.toList());
|
||||
// 就诊id
|
||||
Long encounterId = adviceSaveList.get(0).getEncounterId();
|
||||
iChargeItemService.update(new LambdaUpdateWrapper<ChargeItem>()
|
||||
.set(ChargeItem::getStatusEnum, ChargeItemStatus.PLANNED.getValue())
|
||||
.eq(ChargeItem::getEncounterId, encounterId)
|
||||
.eq(ChargeItem::getStatusEnum, ChargeItemStatus.DRAFT.getValue())
|
||||
.in(ChargeItem::getServiceId, requestIds));
|
||||
|
||||
// 使用安全的更新方法,避免并发冲突
|
||||
iChargeItemService.updateChargeStatusByConditionSafe(
|
||||
encounterId,
|
||||
ChargeItemStatus.DRAFT.getValue(),
|
||||
ChargeItemStatus.PLANNED.getValue(),
|
||||
requestIds);
|
||||
}
|
||||
|
||||
// 数据变更后清理相关缓存
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
*/
|
||||
package com.openhis.web.doctorstation.controller;
|
||||
|
||||
import com.core.common.annotation.RepeatSubmit;
|
||||
import com.core.common.core.domain.R;
|
||||
import com.openhis.common.enums.AdviceOpType;
|
||||
import com.openhis.common.enums.Whether;
|
||||
@@ -85,6 +86,7 @@ public class DoctorStationAdviceController {
|
||||
* @return 结果
|
||||
*/
|
||||
@PostMapping(value = "/sign-advice")
|
||||
@RepeatSubmit(interval = 5000, message = "请勿重复签发医嘱,请稍候再试")
|
||||
public R<?> signAdvice(@RequestBody AdviceSaveParam adviceSaveParam) {
|
||||
return iDoctorStationAdviceAppService.saveAdvice(adviceSaveParam, AdviceOpType.SIGN_ADVICE.getCode());
|
||||
}
|
||||
|
||||
@@ -79,6 +79,11 @@ public class RequestBaseDto {
|
||||
@JsonSerialize(using = ToStringSerializer.class)
|
||||
private Long chargeItemId;
|
||||
|
||||
/**
|
||||
* 医嘱定义对应表名
|
||||
*/
|
||||
private String adviceTableName;
|
||||
|
||||
/**
|
||||
* 医嘱名称
|
||||
*/
|
||||
|
||||
@@ -394,7 +394,7 @@ public class MedicalDeviceDispenseAppServiceImpl implements IMedicalDeviceDispen
|
||||
}
|
||||
List<ChargeItem> chargeItemList = chargeItemService.listByIds(chargeItemIds);
|
||||
if (chargeItemList == null || chargeItemList.isEmpty()) {
|
||||
return R.fail(MessageUtils.createMessage(PromptMsgConstant.Common.M00007, null));
|
||||
return R.fail("未查询到耗材收费项目信息");
|
||||
}
|
||||
|
||||
// 获取发申请id列表
|
||||
|
||||
@@ -58,12 +58,32 @@ public interface IChargeItemService extends IService<ChargeItem> {
|
||||
|
||||
/**
|
||||
* 更新收费状态
|
||||
*
|
||||
*
|
||||
* @param chargeItemIdList 收费项目id集合
|
||||
* @param value 状态值
|
||||
*/
|
||||
void updatePaymentStatus(List<Long> chargeItemIdList, Integer value);
|
||||
|
||||
/**
|
||||
* 安全更新收费项目状态(按条件更新,避免并发冲突)
|
||||
*
|
||||
* @param encounterId 就诊ID
|
||||
* @param fromStatusEnum 原状态
|
||||
* @param toStatusEnum 目标状态
|
||||
* @param serviceIds 服务ID列表
|
||||
*/
|
||||
void updateChargeStatusByCondition(Long encounterId, Integer fromStatusEnum, Integer toStatusEnum, List<Long> serviceIds);
|
||||
|
||||
/**
|
||||
* 安全批量更新收费项目状态(逐个更新,避免并发冲突)
|
||||
*
|
||||
* @param encounterId 就诊ID
|
||||
* @param fromStatusEnum 原状态
|
||||
* @param toStatusEnum 目标状态
|
||||
* @param serviceIds 服务ID列表
|
||||
*/
|
||||
void updateChargeStatusByConditionSafe(Long encounterId, Integer fromStatusEnum, Integer toStatusEnum, List<Long> serviceIds);
|
||||
|
||||
/**
|
||||
* 根据表名和id删除费用项
|
||||
*
|
||||
|
||||
@@ -22,12 +22,14 @@ import com.openhis.administration.service.IChargeItemService;
|
||||
import com.openhis.common.enums.*;
|
||||
import com.openhis.common.utils.EnumUtils;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.BeanUtils;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
@@ -38,6 +40,7 @@ import java.util.stream.Collectors;
|
||||
*/
|
||||
@Service
|
||||
@AllArgsConstructor
|
||||
@Slf4j
|
||||
public class ChargeItemServiceImpl extends ServiceImpl<ChargeItemMapper, ChargeItem> implements IChargeItemService {
|
||||
|
||||
@Autowired
|
||||
@@ -130,10 +133,93 @@ public class ChargeItemServiceImpl extends ServiceImpl<ChargeItemMapper, ChargeI
|
||||
*/
|
||||
@Override
|
||||
public void updatePaymentStatus(List<Long> chargeItemIdList, Integer value) {
|
||||
baseMapper.update(
|
||||
new ChargeItem().setStatusEnum(value).setPerformerId(SecurityUtils.getLoginUser().getPractitionerId()),
|
||||
new LambdaUpdateWrapper<ChargeItem>().in(ChargeItem::getId, chargeItemIdList).eq(ChargeItem::getDeleteFlag,
|
||||
DelFlag.NO.getCode()));
|
||||
if (chargeItemIdList == null || chargeItemIdList.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 逐个更新,避免并发冲突
|
||||
for (Long chargeItemId : chargeItemIdList) {
|
||||
int retryCount = 0;
|
||||
final int maxRetries = 3;
|
||||
|
||||
while (retryCount < maxRetries) {
|
||||
try {
|
||||
// 先查询当前状态,确保更新操作的安全性
|
||||
ChargeItem currentChargeItem = baseMapper.selectById(chargeItemId);
|
||||
|
||||
if (currentChargeItem == null) {
|
||||
log.warn("收费项目不存在,ID: {}", chargeItemId);
|
||||
break; // 项目不存在,跳出重试循环
|
||||
}
|
||||
|
||||
// 检查当前状态是否已经是目标状态,避免不必要的更新
|
||||
if (currentChargeItem.getStatusEnum().equals(value)) {
|
||||
log.debug("收费项目已是目标状态,跳过更新,ID: {}, 状态: {}", chargeItemId, value);
|
||||
break; // 已是目标状态,跳出重试循环
|
||||
}
|
||||
|
||||
// 使用精确的条件更新,包括当前状态,防止并发更新冲突
|
||||
int updatedRows = baseMapper.update(
|
||||
new ChargeItem()
|
||||
.setStatusEnum(value)
|
||||
.setPerformerId(SecurityUtils.getLoginUser().getPractitionerId()),
|
||||
new LambdaUpdateWrapper<ChargeItem>()
|
||||
.eq(ChargeItem::getId, chargeItemId)
|
||||
.eq(ChargeItem::getStatusEnum, currentChargeItem.getStatusEnum()) // 使用当前状态作为条件
|
||||
.eq(ChargeItem::getDeleteFlag, DelFlag.NO.getCode()));
|
||||
|
||||
// 如果成功更新了行数,跳出重试循环
|
||||
if (updatedRows > 0) {
|
||||
log.debug("收费项目状态更新成功,ID: {}, 状态: {}", chargeItemId, value);
|
||||
break; // 成功更新,跳出重试循环
|
||||
} else {
|
||||
log.warn("收费项目更新失败,可能已被其他事务更改,ID: {}, 目标状态: {},重试次数: {}",
|
||||
chargeItemId, value, retryCount + 1);
|
||||
|
||||
// 增加重试计数
|
||||
retryCount++;
|
||||
|
||||
// 如果达到最大重试次数,检查最终状态
|
||||
if (retryCount >= maxRetries) {
|
||||
ChargeItem finalChargeItem = baseMapper.selectById(chargeItemId);
|
||||
if (finalChargeItem != null && finalChargeItem.getStatusEnum().equals(value)) {
|
||||
log.debug("收费项目最终已是目标状态,ID: {}", chargeItemId);
|
||||
break; // 最终状态符合预期,跳出重试循环
|
||||
} else {
|
||||
log.warn("收费项目状态更新失败,达到最大重试次数,ID: {}, 期望状态: {}, 当前状态: {}",
|
||||
chargeItemId, value, finalChargeItem != null ? finalChargeItem.getStatusEnum() : "NULL");
|
||||
break; // 达到最大重试次数,跳出重试循环
|
||||
}
|
||||
} else {
|
||||
// 短暂延迟后重试,避免过于频繁的重试
|
||||
try {
|
||||
Thread.sleep(10); // 10毫秒延迟
|
||||
} catch (InterruptedException ie) {
|
||||
Thread.currentThread().interrupt();
|
||||
break; // 中断线程,跳出重试循环
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error("更新收费项目状态失败,ID: {}, 状态: {},重试次数: {}", chargeItemId, value, retryCount + 1, e);
|
||||
|
||||
retryCount++;
|
||||
if (retryCount >= maxRetries) {
|
||||
log.error("更新收费项目状态失败,达到最大重试次数,ID: {}, 状态: {}", chargeItemId, value, e);
|
||||
// 不抛出异常,以避免整个事务回滚
|
||||
break; // 达到最大重试次数,跳出重试循环
|
||||
}
|
||||
|
||||
// 短暂延迟后重试
|
||||
try {
|
||||
Thread.sleep(10);
|
||||
} catch (InterruptedException ie) {
|
||||
Thread.currentThread().interrupt();
|
||||
break; // 中断线程,跳出重试循环
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -324,4 +410,130 @@ public class ChargeItemServiceImpl extends ServiceImpl<ChargeItemMapper, ChargeI
|
||||
});
|
||||
return costDetails;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateChargeStatusByCondition(Long encounterId, Integer fromStatusEnum, Integer toStatusEnum, List<Long> serviceIds) {
|
||||
if (serviceIds == null || serviceIds.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 使用逐个更新的方式,避免批量更新的并发问题
|
||||
for (Long serviceId : serviceIds) {
|
||||
try {
|
||||
int updatedRows = baseMapper.update(
|
||||
new ChargeItem().setStatusEnum(toStatusEnum),
|
||||
new LambdaUpdateWrapper<ChargeItem>()
|
||||
.eq(ChargeItem::getEncounterId, encounterId)
|
||||
.eq(ChargeItem::getStatusEnum, fromStatusEnum) // 确保原状态匹配
|
||||
.eq(ChargeItem::getServiceId, serviceId)
|
||||
.eq(ChargeItem::getDeleteFlag, DelFlag.NO.getCode())
|
||||
);
|
||||
|
||||
// 如果没有更新任何行,可能是因为状态已经被其他事务更改
|
||||
if (updatedRows == 0) {
|
||||
log.warn("收费项目状态更新失败或无变化,encounterId: {}, serviceId: {}, 原状态: {}, 目标状态: {}",
|
||||
encounterId, serviceId, fromStatusEnum, toStatusEnum);
|
||||
|
||||
// 查询当前状态以供调试
|
||||
List<ChargeItem> currentChargeItems = baseMapper.selectList(
|
||||
new LambdaQueryWrapper<ChargeItem>()
|
||||
.eq(ChargeItem::getEncounterId, encounterId)
|
||||
.eq(ChargeItem::getServiceId, serviceId)
|
||||
.eq(ChargeItem::getDeleteFlag, DelFlag.NO.getCode())
|
||||
);
|
||||
|
||||
for (ChargeItem item : currentChargeItems) {
|
||||
log.info("收费项目当前状态,ID: {}, 状态: {}", item.getId(), item.getStatusEnum());
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error("更新收费项目状态失败,encounterId: {}, serviceId: {}, 原状态: {}, 目标状态: {}",
|
||||
encounterId, serviceId, fromStatusEnum, toStatusEnum, e);
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateChargeStatusByConditionSafe(Long encounterId, Integer fromStatusEnum, Integer toStatusEnum, List<Long> serviceIds) {
|
||||
if (serviceIds == null || serviceIds.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 使用逐个更新的方式,避免批量更新的并发问题
|
||||
for (Long serviceId : serviceIds) {
|
||||
int retryCount = 0;
|
||||
final int maxRetries = 3;
|
||||
|
||||
while (retryCount < maxRetries) {
|
||||
try {
|
||||
// 先查询当前符合条件的收费项目
|
||||
List<ChargeItem> chargeItems = baseMapper.selectList(
|
||||
new LambdaQueryWrapper<ChargeItem>()
|
||||
.eq(ChargeItem::getEncounterId, encounterId)
|
||||
.eq(ChargeItem::getStatusEnum, fromStatusEnum)
|
||||
.eq(ChargeItem::getServiceId, serviceId)
|
||||
.eq(ChargeItem::getDeleteFlag, DelFlag.NO.getCode())
|
||||
);
|
||||
|
||||
if (chargeItems.isEmpty()) {
|
||||
log.debug("未找到符合条件的收费项目,encounterId: {}, serviceId: {}, 原状态: {}",
|
||||
encounterId, serviceId, fromStatusEnum);
|
||||
break; // 没有符合条件的项目,跳出重试循环
|
||||
}
|
||||
|
||||
// 对每个符合条件的收费项目进行更新
|
||||
for (ChargeItem chargeItem : chargeItems) {
|
||||
int updatedRows = baseMapper.update(
|
||||
new ChargeItem().setStatusEnum(toStatusEnum),
|
||||
new LambdaUpdateWrapper<ChargeItem>()
|
||||
.eq(ChargeItem::getId, chargeItem.getId())
|
||||
.eq(ChargeItem::getStatusEnum, fromStatusEnum) // 确保原状态匹配
|
||||
.eq(ChargeItem::getDeleteFlag, DelFlag.NO.getCode())
|
||||
);
|
||||
|
||||
if (updatedRows > 0) {
|
||||
log.debug("收费项目状态更新成功,ID: {}, 从状态: {} 到状态: {}",
|
||||
chargeItem.getId(), fromStatusEnum, toStatusEnum);
|
||||
} else {
|
||||
log.warn("收费项目状态更新失败,ID: {}, 从状态: {} 到状态: {}",
|
||||
chargeItem.getId(), fromStatusEnum, toStatusEnum);
|
||||
|
||||
// 检查项目当前状态
|
||||
ChargeItem currentChargeItem = baseMapper.selectById(chargeItem.getId());
|
||||
if (currentChargeItem != null) {
|
||||
log.debug("收费项目当前状态,ID: {}, 状态: {}", currentChargeItem.getId(), currentChargeItem.getStatusEnum());
|
||||
|
||||
// 如果已经是目标状态,则认为更新成功
|
||||
if (currentChargeItem.getStatusEnum().equals(toStatusEnum)) {
|
||||
log.debug("收费项目已是目标状态,ID: {}", currentChargeItem.getId());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 成功更新,跳出重试循环
|
||||
break;
|
||||
} catch (Exception e) {
|
||||
retryCount++;
|
||||
log.warn("收费项目状态更新失败,encounterId: {}, serviceId: {}, 原状态: {}, 目标状态: {},重试次数: {}",
|
||||
encounterId, serviceId, fromStatusEnum, toStatusEnum, retryCount, e);
|
||||
|
||||
if (retryCount >= maxRetries) {
|
||||
log.error("收费项目状态更新失败,达到最大重试次数,encounterId: {}, serviceId: {}, 原状态: {}, 目标状态: {}",
|
||||
encounterId, serviceId, fromStatusEnum, toStatusEnum, e);
|
||||
// 不抛出异常,以避免影响整体流程
|
||||
} else {
|
||||
// 短暂延迟后重试
|
||||
try {
|
||||
Thread.sleep(10);
|
||||
} catch (InterruptedException ie) {
|
||||
Thread.currentThread().interrupt();
|
||||
break; // 中断线程,跳出重试循环
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user