13 changed files with 503 additions and 28 deletions
@ -0,0 +1,382 @@ |
|||
package com.qs.serve.modules.tzc.service; |
|||
|
|||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; |
|||
import com.qs.serve.common.util.Assert; |
|||
import com.qs.serve.common.util.CollectionUtil; |
|||
import com.qs.serve.modules.sys.service.SysConfigService; |
|||
import com.qs.serve.modules.tbs.entity.*; |
|||
import com.qs.serve.modules.tbs.entity.dto.TbsBudgetCostResult; |
|||
import com.qs.serve.modules.tbs.mapper.TbsBudgetMapper; |
|||
import com.qs.serve.modules.tbs.mapper.TbsScheduleItemBudgetMapper; |
|||
import com.qs.serve.modules.tbs.service.TbsBudgetApplicationService; |
|||
import com.qs.serve.modules.tbs.service.TbsBudgetConditionService; |
|||
import com.qs.serve.modules.tbs.service.TbsBudgetCostItemService; |
|||
import com.qs.serve.modules.tbs.service.TbsScheduleItemBudgetService; |
|||
import com.qs.serve.modules.tzc.entity.TzcPolicy; |
|||
import com.qs.serve.modules.tzc.entity.TzcPolicyGoods; |
|||
import com.qs.serve.modules.tzc.entity.TzcPolicyItem; |
|||
import lombok.AllArgsConstructor; |
|||
import lombok.extern.slf4j.Slf4j; |
|||
import org.springframework.stereotype.Service; |
|||
|
|||
import java.math.BigDecimal; |
|||
import java.util.*; |
|||
import java.util.stream.Collectors; |
|||
|
|||
/** |
|||
* @author YenHex |
|||
* @since 2023/2/20 |
|||
*/ |
|||
@Service |
|||
@Slf4j |
|||
@AllArgsConstructor |
|||
public class TzcPolicyApplication { |
|||
|
|||
private TzcPolicyService tzcPolicyService; |
|||
private TzcPolicyGoodsService tzcPolicyGoodsService; |
|||
private TbsBudgetApplicationService budgetApplicationService; |
|||
private TbsScheduleItemBudgetService tbsScheduleItemBudgetService; |
|||
private TbsBudgetMapper tbsBudgetMapper; |
|||
private TbsScheduleItemBudgetMapper tbsScheduleItemBudgetMapper; |
|||
private TbsBudgetConditionService tbsBudgetConditionService; |
|||
private TbsBudgetCostItemService tbsBudgetCostItemService; |
|||
private SysConfigService configService; |
|||
/** |
|||
* |
|||
* @param policyId |
|||
*/ |
|||
public void commitPolicy(Long policyId){ |
|||
//
|
|||
} |
|||
|
|||
/** |
|||
* 创建费用占用结果 |
|||
* @param costApplyId 用于加载历史预算时,排除当前费用占比 |
|||
* @param policyList 政策列表 |
|||
* @param policyItemList 政策项列表 |
|||
* @param policyGoodsList 政策商品 |
|||
* @param overspend 是否支持超出预算 |
|||
* @param throwEx 是否需要抛出异常 |
|||
* @param buildTableFlag 创建表VO |
|||
* @return |
|||
*/ |
|||
public TbsBudgetCostResult buildBudgetCostResult(Long costApplyId, |
|||
List<TzcPolicy> policyList, |
|||
List<TzcPolicyItem> policyItemList, |
|||
List<TzcPolicyGoods> policyGoodsList, |
|||
Boolean overspend, |
|||
Boolean throwEx, |
|||
Boolean buildTableFlag){ |
|||
//考核期有关的预算id,判断逻辑为活动需要允许在
|
|||
List<Long> budgetIds = new ArrayList<>(); |
|||
//没有预算的活动
|
|||
Set<Long> noBudgetPolicyIds = new HashSet<>(); |
|||
//所有满足条件的考核期,用于加载历史核销费用
|
|||
List<TbsScheduleItemBudget> scheduleItemList = this.loadScheduleBudgetAndSetting(policyItemList, budgetIds, noBudgetPolicyIds); |
|||
List<String> centerIds = policyItemList.stream().map(TzcPolicyItem::getCenterId).collect(Collectors.toList()); |
|||
List<Long> subjectIds = policyItemList.stream().map(TzcPolicyItem::getSubjectId).distinct().collect(Collectors.toList()); |
|||
List<TbsBudget> budgetList; |
|||
if(budgetIds.size()>0){ |
|||
LambdaQueryWrapper<TbsBudget> budgetLqw = new LambdaQueryWrapper<>(); |
|||
budgetLqw.in(TbsBudget::getId,budgetIds); |
|||
budgetLqw.and(qw->qw.eq(TbsBudget::getSubjectId,0).or(qw2->qw2.in(TbsBudget::getSubjectId,subjectIds))); |
|||
budgetLqw.in(TbsBudget::getCenterId,centerIds); |
|||
budgetLqw.eq(TbsBudget::getBudgetState,1); |
|||
budgetList = tbsBudgetMapper.selectList(budgetLqw); |
|||
}else { |
|||
budgetList = new ArrayList<>(); |
|||
} |
|||
List<TbsBudget> noConditionBudgetList = new ArrayList<>(); |
|||
//加载预算条件和关联预算匹配,返回是否由无条件预算
|
|||
boolean budgetNoCondition = budgetApplicationService.loadConditionByBudgetsAndMatch(budgetList, noConditionBudgetList); |
|||
//预算条件需包含活动条件, Map结构:活动id->满足的预算id列表
|
|||
Map<Long,List<Long>> policyAllowBudgetIdMap = this.buildPolicyBudgetMap(policyItemList, budgetList, noConditionBudgetList); |
|||
//活动拦截
|
|||
if(!budgetNoCondition){ |
|||
this.handleNoBudgetPolicy(throwEx, overspend, policyItemList,noBudgetPolicyIds,policyAllowBudgetIdMap); |
|||
} |
|||
//统计所有占用预算金额
|
|||
Map<Long, BigDecimal> budgetItemAmountMap = new HashMap<>(scheduleItemList.size()); |
|||
//统计费用申请占用金额
|
|||
Map<Long,BigDecimal> budgetItemApplyAmountMap = new HashMap<>(scheduleItemList.size()); |
|||
for (TbsScheduleItemBudget itemBudget : scheduleItemList) { |
|||
BigDecimal budgetItemApplyAmount = tbsScheduleItemBudgetMapper.totalApplyAmount(itemBudget.getId(),costApplyId); |
|||
budgetItemApplyAmountMap.put(itemBudget.getId(),budgetItemApplyAmount); |
|||
BigDecimal budgetItemAmount = tbsScheduleItemBudgetMapper.totalCostAmount(itemBudget.getBudgetId(),itemBudget.getScheduleItemId(),costApplyId); |
|||
//因为结果为负数,需去相反数
|
|||
budgetItemAmount = budgetItemAmount==null?BigDecimal.ZERO:budgetItemAmount.negate(); |
|||
budgetItemAmountMap.put(itemBudget.getId(),budgetItemAmount); |
|||
} |
|||
//统计当前活动前置项占用预算
|
|||
Map<Long,BigDecimal> counterMap = new HashMap<>(); |
|||
//匹配预算主要方法
|
|||
final List<TbsActivityCenterGoods> actMatchList = new ArrayList<>(); |
|||
final List<TbsActivityCenterGoods> actUnMatchList = new ArrayList<>(); |
|||
for (TzcPolicyGoods policyGoods : policyGoodsList) { |
|||
// this.matchPolicyMain(policyGoods,throwEx, overspend, activityList, budgetItemAmountMap, budgetList,
|
|||
// noConditionBudgetList, counterMap, actMatchList, actUnMatchList,policyAllowBudgetIdMap,budgetItemApplyAmountMap);
|
|||
} |
|||
return null; |
|||
} |
|||
|
|||
/** |
|||
* 匹配的主要方法 |
|||
* @param policyGoods 政策商品 |
|||
* @param throwEx 预算不够时抛出异常 |
|||
* @param overspend 超值标识 |
|||
* @param policyItemList 所有政策项 |
|||
* @param budgetItemAmountMap 统计所有占用预算金额 |
|||
* @param allBudgetList 所有预算 |
|||
* @param noConditionBudgetList 没有条件的预算列表 |
|||
* @param counterMap 历史预算占用 |
|||
* @param actMatchList 匹配预算占用的费用(含超支预算) |
|||
* @param actUnMatchList 没有匹配预算的费用 |
|||
* @param activityAllowBudgetIdMap 满足当前活动项的费用idMap |
|||
* @param budgetItemApplyAmountMap 统计费用申请占用金额 |
|||
*/ |
|||
private void matchPolicyMain(TzcPolicyGoods policyGoods, |
|||
Boolean throwEx, |
|||
boolean overspend, |
|||
List<TzcPolicyItem> policyItemList, |
|||
Map<Long,BigDecimal> budgetItemAmountMap, |
|||
final List<TbsBudget> allBudgetList, |
|||
List<TbsBudget> noConditionBudgetList, |
|||
Map<Long, BigDecimal> counterMap, |
|||
final List<TzcPolicyGoods> actMatchList, |
|||
final List<TzcPolicyGoods> actUnMatchList, |
|||
final Map<Long,List<Long>> activityAllowBudgetIdMap, |
|||
Map<Long,BigDecimal> budgetItemApplyAmountMap) { |
|||
//过滤满全条件的预算
|
|||
List<Long> allowBudgetIds = activityAllowBudgetIdMap.get(policyGoods.getPolicyItemId()); |
|||
List<TbsBudget> budgetList = allBudgetList.stream().filter(obj->allowBudgetIds.contains(obj.getId())).collect(Collectors.toList()); |
|||
//PS:排序规则:优先为时间条件,其次匹配品牌条件
|
|||
//按品类条件,提取可用预算(列表已按小维度到大维度排列)
|
|||
List<TbsBudget> currentItemBudgetList = budgetApplicationService.filterMatchGoodsCondition(budgetList, policyGoods.getTargetLevelPathIds()); |
|||
//关联无条件预算
|
|||
currentItemBudgetList.addAll(noConditionBudgetList); |
|||
//提取可用预算的考核期
|
|||
List<TbsScheduleItemBudget> currentScheduleItemBudgets = new ArrayList<>(); |
|||
for (TzcPolicyItem policyItem : policyItemList) { |
|||
//忽略重叠情况
|
|||
if(!policyGoods.getPolicyItemId().equals(policyItem.getId())){ |
|||
continue; |
|||
} |
|||
//当前科目
|
|||
Long subjectId = policyItem.getSubjectId(); |
|||
//拦截非当前成本中心
|
|||
String centerId = policyItem.getCenterId(); |
|||
String centerType = policyItem.getCenterType(); |
|||
for (TbsBudget budget : currentItemBudgetList) { |
|||
if(!budget.getCenterId().equals(centerId) || |
|||
!budget.getCenterType().equals(centerType) ){ |
|||
continue; |
|||
} |
|||
if(!subjectId.equals(budget.getSubjectId())&&!budget.getSubjectId().equals(0L)){ |
|||
continue; |
|||
} |
|||
List<TbsScheduleItemBudget> scheduleItemBudgets = policyItem.getScheduleItemBudgetList(); |
|||
for (TbsScheduleItemBudget scheduleItemBudget : scheduleItemBudgets) { |
|||
if(scheduleItemBudget.getBudgetId().equals(budget.getId())){ |
|||
currentScheduleItemBudgets.add(scheduleItemBudget); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
//检测是否有是否足够预算
|
|||
// BigDecimal goodsAmount = activityCostItem.getCenterGoodsAmount();
|
|||
// if(CollectionUtil.isNotEmpty(currentScheduleItemBudgets)){
|
|||
// boolean isMatch = false;
|
|||
// for (TbsScheduleItemBudget itemBudget : currentScheduleItemBudgets) {
|
|||
// //历史费用(含申请占用金额)
|
|||
// BigDecimal totalUsed = budgetItemAmountMap.get(itemBudget.getId());
|
|||
// //当前项费用
|
|||
// BigDecimal budgetAmount = itemBudget.getBudgetAmount();
|
|||
// //前置费用
|
|||
// BigDecimal lastAmount = counterMap.get(itemBudget.getId());
|
|||
// if(lastAmount==null){
|
|||
// lastAmount = BigDecimal.ZERO;
|
|||
// }
|
|||
// //判断是否够用
|
|||
// if(budgetAmount.subtract(lastAmount).subtract(totalUsed).compareTo(goodsAmount)>0){
|
|||
// activityCostItem.setBudgetId(itemBudget.getBudgetId());
|
|||
// activityCostItem.setScheduleId(itemBudget.getScheduleId());
|
|||
// activityCostItem.setScheduleItemId(itemBudget.getScheduleItemId());
|
|||
// activityCostItem.setScheduleItemBudgetId(itemBudget.getId());
|
|||
// activityCostItem.setScheduleItemName(itemBudget.getItemName());
|
|||
// //绑定录入时可用预算
|
|||
// activityCostItem.setScheduleItemAmount(budgetAmount);
|
|||
// //剩余的可用预算
|
|||
// activityCostItem.setScheduleItemAmountUsed(totalUsed);
|
|||
// activityCostItem.setScheduleItemAmountApply(budgetItemApplyAmountMap.get(itemBudget.getId()));
|
|||
// isMatch = true;
|
|||
// //记录当前费用使用考核期费用
|
|||
// lastAmount = lastAmount.add(goodsAmount);
|
|||
// counterMap.put(itemBudget.getId(),lastAmount);
|
|||
// actMatchList.add(activityCostItem);
|
|||
// break;
|
|||
// }
|
|||
// }
|
|||
// //无匹配的预算
|
|||
// if(!isMatch){
|
|||
// if (throwEx){
|
|||
// Assert.throwEx("品类["+ activityCostItem.getTargetName()+"]预算不足");
|
|||
// }
|
|||
// if(overspend){
|
|||
// TbsScheduleItemBudget itemBudget = currentScheduleItemBudgets.get(0);
|
|||
// activityCostItem.setBudgetId(itemBudget.getBudgetId());
|
|||
// activityCostItem.setScheduleId(itemBudget.getScheduleId());
|
|||
// activityCostItem.setScheduleItemId(itemBudget.getScheduleItemId());
|
|||
// activityCostItem.setScheduleItemBudgetId(itemBudget.getId());
|
|||
// activityCostItem.setScheduleItemName(itemBudget.getItemName());
|
|||
// //记录当前费用使用考核期费用
|
|||
// BigDecimal lastAmount = counterMap.get(itemBudget.getId());
|
|||
// if(lastAmount==null){
|
|||
// lastAmount = BigDecimal.ZERO;
|
|||
// }
|
|||
// lastAmount = lastAmount.add(goodsAmount);
|
|||
// counterMap.put(itemBudget.getId(),lastAmount);
|
|||
// actMatchList.add(activityCostItem);
|
|||
// }else{
|
|||
// activityCostItem.setBudgetId(0L);
|
|||
// activityCostItem.setScheduleId(0L);
|
|||
// activityCostItem.setScheduleItemId(0L);
|
|||
// activityCostItem.setScheduleItemBudgetId(0L);
|
|||
// activityCostItem.setScheduleItemName("无");
|
|||
// actUnMatchList.add(activityCostItem);
|
|||
// }
|
|||
// }
|
|||
// }else {
|
|||
// if(throwEx){
|
|||
// Assert.throwEx("品类["+ activityCostItem.getTargetName()+"]无可用预算");
|
|||
// }
|
|||
// //添加到预算超支表
|
|||
// activityCostItem.setBudgetId(0L);
|
|||
// activityCostItem.setScheduleId(0L);
|
|||
// activityCostItem.setScheduleItemId(0L);
|
|||
// activityCostItem.setScheduleItemBudgetId(0L);
|
|||
// activityCostItem.setScheduleItemName("无");
|
|||
// actUnMatchList.add(activityCostItem);
|
|||
// }
|
|||
} |
|||
|
|||
/** |
|||
* 拦截没有预算的活动 |
|||
* @param throwEx 抛出异常 |
|||
* @param overspend 超支 |
|||
* @param policyItemList 活动列表 |
|||
* @param noBudgetPolicyIds 没有预算的活动id |
|||
* @param activityAllowBudgetIdMap 预算条件需包含活动条件, Map结构:活动id->满足的预算id列表 |
|||
*/ |
|||
private void handleNoBudgetPolicy(Boolean throwEx, boolean overspend, List<TzcPolicyItem> policyItemList, |
|||
Set<Long> noBudgetPolicyIds, |
|||
Map<Long,List<Long>> activityAllowBudgetIdMap) { |
|||
if(!overspend && throwEx && noBudgetPolicyIds.size()>0){ |
|||
for (TzcPolicyItem policyItem : policyItemList) { |
|||
for (Long policyId : noBudgetPolicyIds) { |
|||
if(policyItem.getId().equals(policyId)){ |
|||
Assert.throwEx("["+policyItem.getPolicyItemCode()+"]无可用预算"); |
|||
} |
|||
} |
|||
List<Long> budgetIds = activityAllowBudgetIdMap.get(policyItem.getId()); |
|||
if(CollectionUtil.isEmpty(budgetIds)){ |
|||
Assert.throwEx("["+policyItem.getPolicyItemCode()+"]无可用预算"); |
|||
} |
|||
} |
|||
Assert.throwEx("无可用预算"); |
|||
} |
|||
} |
|||
|
|||
/** |
|||
* 预算条件需包含活动条件, Map结构:活动id->满足的预算id列表 |
|||
* @param policyItemList |
|||
* @param budgetList |
|||
* @param noConditionBudgetList |
|||
* @return |
|||
*/ |
|||
private Map<Long, List<Long>> buildPolicyBudgetMap(List<TzcPolicyItem> policyItemList, |
|||
List<TbsBudget> budgetList, |
|||
List<TbsBudget> noConditionBudgetList) { |
|||
Map<Long, List<Long>> activityAllowBudgetIdMap = new HashMap<>(); |
|||
for (TzcPolicyItem policyItem : policyItemList) { |
|||
Long policyItemId = policyItem.getId(); |
|||
List<Long> budgetIdsOfActivity = new ArrayList<>(); |
|||
if(CollectionUtil.isEmpty(noConditionBudgetList)){ |
|||
budgetIdsOfActivity.addAll(noConditionBudgetList.stream().map(TbsBudget::getId).collect(Collectors.toList())); |
|||
} |
|||
List<TzcPolicyGoods> policyGoodsList = tzcPolicyGoodsService.listByItemId(policyItemId); |
|||
for (TbsBudget budget : budgetList) { |
|||
if(budget.getConditionFlag().equals(1)){ |
|||
List<TbsBudgetCondition> budgetConditionList = budget.getBudgetConditionList(); |
|||
boolean hasNoMatch = false; |
|||
for (TzcPolicyGoods policyGoods : policyGoodsList) { |
|||
boolean matchGoods = false; |
|||
for (TbsBudgetCondition budgetCondition : budgetConditionList) { |
|||
if(policyGoods.getTargetLevelPathIds().contains(budgetCondition.getTargetLevelPathIds())){ |
|||
matchGoods = true; |
|||
break; |
|||
} |
|||
} |
|||
if(!matchGoods){ |
|||
hasNoMatch = true; |
|||
break; |
|||
} |
|||
} |
|||
if(!hasNoMatch){ |
|||
List<Long> budgetIds = activityAllowBudgetIdMap.get(policyItemId); |
|||
if(budgetIds==null){ |
|||
budgetIds = new ArrayList<>(); |
|||
} |
|||
budgetIds.add(budget.getId()); |
|||
budgetIds.addAll(budgetIdsOfActivity); |
|||
activityAllowBudgetIdMap.put(policyItemId,budgetIds); |
|||
} |
|||
}else { |
|||
List<Long> budgetIds = activityAllowBudgetIdMap.get(policyItemId); |
|||
if(budgetIds==null){ |
|||
budgetIds = new ArrayList<>(); |
|||
} |
|||
budgetIds.add(budget.getId()); |
|||
budgetIds.addAll(budgetIdsOfActivity); |
|||
activityAllowBudgetIdMap.put(policyItemId,budgetIds); |
|||
} |
|||
} |
|||
} |
|||
return activityAllowBudgetIdMap; |
|||
} |
|||
|
|||
/** |
|||
* 1.通过活动加载所有满足条件的考核期(用于加载历史核销费用), |
|||
* 2.设置没有可用预算的活动id |
|||
* 3.设置匹配的考核期列表到活动中 |
|||
* @param policyItemList -> item设置满足条件的考核期列表 |
|||
* @param budgetIds |
|||
* @param noBudgetPolicyItemIds 没有预算的政策项ID |
|||
* @return scheduleItemList 命中的考核期列表 |
|||
*/ |
|||
public List<TbsScheduleItemBudget> loadScheduleBudgetAndSetting(List<TzcPolicyItem> policyItemList, |
|||
List<Long> budgetIds, Set<Long> noBudgetPolicyItemIds) { |
|||
List<TbsScheduleItemBudget> scheduleItemList = new ArrayList<>(); |
|||
Set<Long> budgetIdsSet = new HashSet<>(); |
|||
Map<Long,TbsScheduleItemBudget> allAllowScheduleItemTempMap = new HashMap<>(); |
|||
for (TzcPolicyItem policyItem : policyItemList) { |
|||
List<TbsScheduleItemBudget> budgetItemList = tbsScheduleItemBudgetService |
|||
.betweenDateList(policyItem.getPolicyStartDate(),policyItem.getPolicyEndDate()); |
|||
//设置关联用于后面条件过滤
|
|||
policyItem.setScheduleItemBudgetList(budgetItemList); |
|||
if(CollectionUtil.isNotEmpty(budgetItemList)){ |
|||
for (TbsScheduleItemBudget item : budgetItemList) { |
|||
budgetIdsSet.add(item.getBudgetId()); |
|||
allAllowScheduleItemTempMap.put(item.getId(),item); |
|||
} |
|||
}else { |
|||
noBudgetPolicyItemIds.add(policyItem.getId()); |
|||
} |
|||
} |
|||
for (Long tmpId : allAllowScheduleItemTempMap.keySet()) { |
|||
scheduleItemList.add(allAllowScheduleItemTempMap.get(tmpId)); |
|||
} |
|||
budgetIds.addAll(budgetIdsSet); |
|||
return scheduleItemList; |
|||
} |
|||
|
|||
} |
Loading…
Reference in new issue