批量红冲;

This commit is contained in:
王奎兴
2026-09-11 16:36:23 +08:00
parent 0ca8548c06
commit 6613eeb3fb
3 changed files with 53 additions and 21 deletions
@@ -658,7 +658,7 @@ public class BillManageApplicationService {
if (ObjectUtil.isNull(loginUser)) { if (ObjectUtil.isNull(loginUser)) {
throw new DigitalLogisticsException(UserError.TIMEOUT); throw new DigitalLogisticsException(UserError.TIMEOUT);
} }
if (billManageDTO.getBillManageId() == null) { if (StringUtils.isEmpty(billManageDTO.getBillManageIds())) {
throw new ServiceException("账单id不能为空"); throw new ServiceException("账单id不能为空");
} }
return billManageDomainService.redFlushBill(billManageDTO); return billManageDomainService.redFlushBill(billManageDTO);
@@ -764,25 +764,48 @@ public class BillManageDomainService {
/** /**
* 应收账单红冲:生成一条金额为负数的红冲账单对冲原账单,不操作收款单等数据 * 应收账单红冲:生成金额为负数的红冲账单对冲原账单,不操作收款单等数据(支持批量)
*/ */
public Boolean redFlushBill(BillManageDTO billManageDTO) { public Boolean redFlushBill(BillManageDTO billManageDTO) {
LoginUser loginUser = SecurityUtils.getLoginUser(); LoginUser loginUser = SecurityUtils.getLoginUser();
if (ObjectUtil.isNull(loginUser)) { if (ObjectUtil.isNull(loginUser)) {
throw new DigitalLogisticsException(UserError.TIMEOUT); throw new DigitalLogisticsException(UserError.TIMEOUT);
} }
if (null == billManageDTO.getBillManageId()) { if (StringUtils.isEmpty(billManageDTO.getBillManageIds())) {
throw new ServiceException("账单id不能为空"); throw new ServiceException("账单id不能为空");
} }
BillManage originalBill = billManageService.getById(billManageDTO.getBillManageId()); Set<Long> billManageIdSet = Stream.of(billManageDTO.getBillManageIds().split(",")).filter(StringUtils::isNotEmpty).map(String::trim).map(Long::valueOf).collect(Collectors.toSet());
if (null == originalBill || ObjectUtil.equal(originalBill.getDelFlag(), 2)) { if (billManageIdSet.size() == 0) {
throw new ServiceException("账单信息未找到,请刷新后重试"); throw new ServiceException("账单id不能为空");
} }
//查询账单信息
LambdaQueryWrapper<BillManage> queryWrapperBill = new LambdaQueryWrapper<>();
queryWrapperBill.in(BillManage::getBillManageId, billManageIdSet);
queryWrapperBill.eq(BillManage::getDelFlag, 1);
List<BillManage> billManageList = billManageService.list(queryWrapperBill);
if (null == billManageList || billManageList.size() == 0) {
throw new ServiceException("账单信息未找到");
}
if (billManageList.size() != billManageIdSet.size()) {
throw new ServiceException("部分账单信息未找到,请刷新后重试");
}
//逐个账单红冲,任一账单校验不通过时事务整体回滚
Boolean flag = true;
for (BillManage originalBill : billManageList) {
flag = redFlushSingleBill(originalBill, billManageDTO.getRedFlushRemark(), loginUser) && flag;
}
return flag;
}
/**
* 红冲单个账单:生成金额为负数的红冲账单对冲原账单,同步镜像计费流水与账单明细
*/
private Boolean redFlushSingleBill(BillManage originalBill, String redFlushRemark, LoginUser loginUser) {
if (ObjectUtil.equal(originalBill.getBillType(), 2)) { if (ObjectUtil.equal(originalBill.getBillType(), 2)) {
throw new ServiceException("仅支持应收账单红冲"); throw new ServiceException("账单" + originalBill.getBillNumber() + "为付款账单,仅支持应收账单红冲");
} }
if (!ObjectUtil.equal(originalBill.getBillState(), 5)) { if (!ObjectUtil.equal(originalBill.getBillState(), 5)) {
throw new ServiceException("仅已收款状态的账单可以红冲,请刷新后重试"); throw new ServiceException("账单" + originalBill.getBillNumber() + "不是已收款状态,仅已收款状态的账单可以红冲,请刷新后重试");
} }
//校验账单是否已红冲,避免重复生成红冲账单 //校验账单是否已红冲,避免重复生成红冲账单
BillOperationLogDO redFlushLogQuery = new BillOperationLogDO(); BillOperationLogDO redFlushLogQuery = new BillOperationLogDO();
@@ -790,7 +813,7 @@ public class BillManageDomainService {
redFlushLogQuery.setOperationType(13); redFlushLogQuery.setOperationType(13);
List<BillOperationLogPO> redFlushLogList = billOperationLogDomainService.queryList(redFlushLogQuery); List<BillOperationLogPO> redFlushLogList = billOperationLogDomainService.queryList(redFlushLogQuery);
if (null != redFlushLogList && redFlushLogList.stream().anyMatch(info -> ObjectUtil.equal(info.getDelFlag(), 1))) { if (null != redFlushLogList && redFlushLogList.stream().anyMatch(info -> ObjectUtil.equal(info.getDelFlag(), 1))) {
throw new ServiceException("账单已红冲,不能重复红冲"); throw new ServiceException("账单" + originalBill.getBillNumber() + "已红冲,不能重复红冲");
} }
//生成红冲账单编号 //生成红冲账单编号
String billNumber = OrderSequence.getOrderCode("ZD"); String billNumber = OrderSequence.getOrderCode("ZD");
@@ -832,8 +855,8 @@ public class BillManageDomainService {
redBill.setSkNcId(null); redBill.setSkNcId(null);
//红冲原因写入账单备注 //红冲原因写入账单备注
String billRemark = "红冲原账单编号:" + originalBill.getBillNumber(); String billRemark = "红冲原账单编号:" + originalBill.getBillNumber();
if (StringUtils.isNotEmpty(billManageDTO.getRedFlushRemark())) { if (StringUtils.isNotEmpty(redFlushRemark)) {
billRemark = billRemark + ",红冲原因:" + billManageDTO.getRedFlushRemark(); billRemark = billRemark + ",红冲原因:" + redFlushRemark;
} }
redBill.setBillRemark(billRemark); redBill.setBillRemark(billRemark);
redBill.setDelFlag(1); redBill.setDelFlag(1);
@@ -18,6 +18,7 @@ import com.mhd.bms.infrastructure.utils.UniqueKeyUtil;
import com.mhd.bms.interfaces.dto.billingStatement.BillingStatementDTO; import com.mhd.bms.interfaces.dto.billingStatement.BillingStatementDTO;
import com.mhd.bms.interfaces.dto.billManage.BillManageExportVO; import com.mhd.bms.interfaces.dto.billManage.BillManageExportVO;
import com.mhd.common.core.exception.ServiceException; import com.mhd.common.core.exception.ServiceException;
import com.mhd.common.core.utils.StringUtils;
import com.mhd.common.core.utils.poi.ExcelUtil; import com.mhd.common.core.utils.poi.ExcelUtil;
import com.mhd.common.log.annotation.Log; import com.mhd.common.log.annotation.Log;
import com.mhd.common.log.enums.BusinessType; import com.mhd.common.log.enums.BusinessType;
@@ -400,18 +401,26 @@ public class BillManageApi extends BaseController{
@PostMapping("/redFlushBill") @PostMapping("/redFlushBill")
public AjaxResult redFlushBill(@RequestBody BillManageDTO billManageDTO) public AjaxResult redFlushBill(@RequestBody BillManageDTO billManageDTO)
{ {
if(billManageDTO.getBillManageId() == null){ if(!StringUtils.isNotEmpty(billManageDTO.getBillManageIds())){
throw new ServiceException("账单id不能为空"); throw new ServiceException("账单id不能为空");
} }
//加锁 //批量加锁
RLock lock = null; RedissonMultiLock redissonMultiLock = null;
RedisLockTypeEnum redisLockTypeEnum = RedisLockTypeEnum.BMS; boolean lockFlag = false;
String key = redisLockTypeEnum.getUniqueKey(UniqueKeyUtil.getBillingKey(String.valueOf(billManageDTO.getBillManageId())));
try { try {
lock = redisLock.getRLock(key); RedisLockTypeEnum redisLockTypeEnum = RedisLockTypeEnum.BMS;
List<RLock> locks = new ArrayList<>();
Set<String> billIdSet = Stream.of(billManageDTO.getBillManageIds().split(",")).filter(StringUtils::isNotEmpty).map(String::trim).collect(Collectors.toSet());
billIdSet.forEach(x -> {
//获取唯一key值
String key = redisLockTypeEnum.getUniqueKey(UniqueKeyUtil.getBillingKey(x));
locks.add(redisLock.getRLock(key));
});
redissonMultiLock = new RedissonMultiLock(locks.toArray(new RLock[billIdSet.size()]));
//尝试获取锁 不等待 持有锁10分钟 //尝试获取锁 不等待 持有锁10分钟
if (!lock.tryLock(-1, 10, TimeUnit.MINUTES)) { lockFlag = redissonMultiLock.tryLock(-1, 10, TimeUnit.MINUTES);
lock = null; if (!lockFlag) {
redissonMultiLock = null;
throw new ServiceException("账单正在操作中,请稍后重试"); throw new ServiceException("账单正在操作中,请稍后重试");
} }
log.info("红冲账单加锁成功"); log.info("红冲账单加锁成功");
@@ -420,8 +429,8 @@ public class BillManageApi extends BaseController{
}catch (Exception e){ }catch (Exception e){
return AjaxResult.error("红冲账单失败:"+e.getMessage()); return AjaxResult.error("红冲账单失败:"+e.getMessage());
} finally { } finally {
if (lock != null && lock.isHeldByCurrentThread()){ if (redissonMultiLock != null && lockFlag){
lock.unlock(); redissonMultiLock.unlock();
log.info("红冲账单释放锁成功"); log.info("红冲账单释放锁成功");
} }
} }