6 changed files with 411 additions and 26 deletions
@ -0,0 +1,362 @@ |
|||
package com.qs.serve.modules.tbs.service; |
|||
|
|||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; |
|||
import com.qs.serve.common.model.consts.SysConfigKey; |
|||
import com.qs.serve.common.util.Assert; |
|||
import com.qs.serve.common.util.CollectionUtil; |
|||
import com.qs.serve.modules.bms.entity.BmsSubject; |
|||
import com.qs.serve.modules.bms.entity.BmsSupplier; |
|||
import com.qs.serve.modules.bms.service.BmsSupplierService; |
|||
import com.qs.serve.modules.goods.entity.dto.TbsCenterDto; |
|||
import com.qs.serve.modules.sys.service.SysConfigService; |
|||
import com.qs.serve.modules.tbs.common.TbsGoodsType; |
|||
import com.qs.serve.modules.tbs.common.util.TbsBudgetCostUtil; |
|||
import com.qs.serve.modules.tbs.entity.*; |
|||
import com.qs.serve.modules.tbs.entity.bo.TbsActivityBo; |
|||
import com.qs.serve.modules.tbs.entity.dto.TbsBudgetCostResult; |
|||
import com.qs.serve.modules.tbs.entity.vo.TbsBudgetTableVo; |
|||
import com.qs.serve.modules.tbs.mapper.TbsActivityGoodsMapper; |
|||
import com.qs.serve.modules.tbs.mapper.TbsActivityMapper; |
|||
import com.qs.serve.modules.tbs.mapper.TbsBudgetMapper; |
|||
import com.qs.serve.modules.tbs.service.impl.TbsActivityServiceImpl; |
|||
import lombok.AllArgsConstructor; |
|||
import lombok.extern.slf4j.Slf4j; |
|||
import org.checkerframework.checker.units.qual.A; |
|||
import org.jetbrains.annotations.NotNull; |
|||
import org.springframework.stereotype.Service; |
|||
|
|||
import java.math.BigDecimal; |
|||
import java.util.*; |
|||
import java.util.stream.Collectors; |
|||
|
|||
/** |
|||
* 预算应用层服务 |
|||
* @author YenHex |
|||
* @since 2022/12/6 |
|||
*/ |
|||
@Slf4j |
|||
@Service |
|||
@AllArgsConstructor |
|||
public class TbsActivityApplicationService { |
|||
|
|||
private TbsScheduleItemBudgetService tbsScheduleItemBudgetService; |
|||
private TbsBudgetMapper tbsBudgetMapper; |
|||
private TbsBudgetConditionService tbsBudgetConditionService; |
|||
private TbsBudgetCostItemService tbsBudgetCostItemService; |
|||
private SysConfigService configService; |
|||
private TbsActivityServiceImpl activityService; |
|||
private final BmsSupplierService supplierService; |
|||
|
|||
/** |
|||
* 对比预算 |
|||
* @param throwEx |
|||
* @param activityBo |
|||
* @return |
|||
*/ |
|||
public TbsBudgetCostResult matchBudgetCostResult(Boolean throwEx, TbsActivityBo activityBo){ |
|||
BmsSupplier supplier = supplierService.getById(activityBo.getSupplierId()); |
|||
//允许超出预算标识
|
|||
boolean overspend = configService.getByKey(SysConfigKey.TbsBudgetOverspend).getConfigValue().equals("1"); |
|||
//考核期有关的预算id,判断逻辑为活动需要允许在
|
|||
List<Long> budgetIds = new ArrayList<>(); |
|||
//所有满足条件的考核期,用于加载历史核销费用
|
|||
List<TbsScheduleItemBudget> scheduleItemList = this.loadScheduleBudgetAndSetting(activityBo, budgetIds); |
|||
if(budgetIds.size()<1&&throwEx){ |
|||
Assert.throwEx("无匹配的预算"); |
|||
} |
|||
if(budgetIds.size()<1){ |
|||
TbsBudgetCostResult result = new TbsBudgetCostResult(); |
|||
result.setState(0); |
|||
return result; |
|||
} |
|||
//加载预算占用历史
|
|||
List<Long> scheduleItemBudgetIds = scheduleItemList.stream().map(TbsScheduleItemBudget::getId).collect(Collectors.toList()); |
|||
List<TbsBudgetCostItem> hisBudgetCostItemList = tbsBudgetCostItemService.listByScheduleItemBudgetIds(scheduleItemBudgetIds,null); |
|||
Map<Long,List<TbsBudgetCostItem>> hisCostGroupByItemBudget = hisBudgetCostItemList.stream() |
|||
.collect(Collectors.groupingBy(TbsBudgetCostItem::getScheduleItemBudgetId)); |
|||
List<TbsActivityGoods> activityGoodsList = activityService.buildActGoodsList(activityBo,null,null); |
|||
//构建预算费用占用明细
|
|||
Map<Long, BmsSubject> subjectMap = new HashMap<>(); |
|||
List<TbsActivitySubject> activitySubjects = new ArrayList<>(); |
|||
List<TbsActivityCenter> activityCenterList = new ArrayList<>(); |
|||
Map<String, TbsCenterDto> centerDtoMap = new HashMap<>(); |
|||
activityService.initSubjectAndCenter(activityBo,subjectMap,centerDtoMap,activitySubjects,activityCenterList,null,null); |
|||
Map<String,BigDecimal> checkAmountMap = new HashMap<>(); |
|||
List<TbsActivityCenterGoods> activityCenterGoodsList = new ArrayList<>(); |
|||
activityService.initCenterGoods(activityBo,subjectMap,centerDtoMap,checkAmountMap,activityGoodsList,activityCenterGoodsList,null,new TbsActivity(),supplier); |
|||
// 加载所有条件
|
|||
LambdaQueryWrapper<TbsBudget> budgetLqw = new LambdaQueryWrapper<>(); |
|||
budgetLqw.in(TbsBudget::getId,budgetIds); |
|||
budgetLqw.eq(TbsBudget::getBudgetState,1); |
|||
List<TbsBudget> budgetList = tbsBudgetMapper.selectList(budgetLqw); |
|||
|
|||
List<TbsBudget> noConditionBudgetList = new ArrayList<>(); |
|||
boolean budgetNoCondition = this.loadConditionByBudgetsAndMatch(budgetList, noConditionBudgetList); |
|||
//预算条件需包含活动条件, Map结构:活动id->满足的预算id列表
|
|||
List<Long> activityAllowBudgetIds = this.buildActivityBudgetMap(activityCenterGoodsList, budgetList, noConditionBudgetList); |
|||
//活动拦截
|
|||
this.handleNoBudgetActivity(throwEx, overspend, budgetNoCondition,activityAllowBudgetIds); |
|||
//统计当前活动前置项占用预算
|
|||
Map<Long,BigDecimal> counterMap = new HashMap<>(); |
|||
//匹配预算主要方法
|
|||
final List<TbsActivityCenterGoods> actMatchList = new ArrayList<>(); |
|||
final List<TbsActivityCenterGoods> actUnMatchList = new ArrayList<>(); |
|||
for (TbsActivityCenterGoods activityCostItem : activityCenterGoodsList) { |
|||
this.matchActivityMain(activityCostItem,throwEx, overspend, scheduleItemList, hisCostGroupByItemBudget, budgetList, |
|||
noConditionBudgetList, counterMap, actMatchList, actUnMatchList,activityAllowBudgetIds); |
|||
} |
|||
List<TbsBudgetCostItem> budgetMatchList = actMatchList.stream() |
|||
.map(TbsActivityCenterGoods::toBudgetCostItem).collect(Collectors.toList()); |
|||
List<TbsBudgetCostItem> budgetUnMatchList = actUnMatchList.stream() |
|||
.map(TbsActivityCenterGoods::toBudgetCostItem).collect(Collectors.toList()); |
|||
TbsBudgetCostResult result = new TbsBudgetCostResult(); |
|||
result.setState(1); |
|||
result.setBudgetMatchList(budgetMatchList); |
|||
result.setBudgetUnMatchList(budgetUnMatchList); |
|||
return result; |
|||
} |
|||
|
|||
/** |
|||
* 预算条件需包含活动条件, Map结构:活动id->满足的预算id列表 |
|||
* @param centerGoodsList |
|||
* @param budgetList |
|||
* @param noConditionBudgetList |
|||
* @return |
|||
*/ |
|||
private List<Long> buildActivityBudgetMap(List<TbsActivityCenterGoods> centerGoodsList, |
|||
List<TbsBudget> budgetList, |
|||
List<TbsBudget> noConditionBudgetList) { |
|||
List<Long> budgetIdsOfActivity = new ArrayList<>(); |
|||
if(CollectionUtil.isEmpty(noConditionBudgetList)){ |
|||
budgetIdsOfActivity.addAll(noConditionBudgetList.stream().map(TbsBudget::getId).collect(Collectors.toList())); |
|||
} |
|||
Map<String,List<TbsActivityCenterGoods>> activityCenterGoodsListMap = centerGoodsList.stream().collect(Collectors.groupingBy(a->a.getTargetType()+":"+a.getTargetId())); |
|||
for (TbsBudget budget : budgetList) { |
|||
if(budget.getConditionFlag().equals(1)){ |
|||
List<TbsBudgetCondition> budgetConditionList = budget.getBudgetConditionList(); |
|||
boolean hasNoMatch = false; |
|||
for (String key : activityCenterGoodsListMap.keySet()) { |
|||
List<TbsActivityCenterGoods> centerGoods = activityCenterGoodsListMap.get(key); |
|||
TbsActivityCenterGoods activityCenterGoods = centerGoods.get(0); |
|||
boolean matchGoods = false; |
|||
for (TbsBudgetCondition budgetCondition : budgetConditionList) { |
|||
if(activityCenterGoods.getTargetLevelPathIds().contains(budgetCondition.getTargetLevelPathIds())){ |
|||
matchGoods = true; |
|||
break; |
|||
} |
|||
} |
|||
if(!matchGoods){ |
|||
hasNoMatch = true; |
|||
break; |
|||
} |
|||
} |
|||
if(!hasNoMatch){ |
|||
budgetIdsOfActivity.add(budget.getId()); |
|||
} |
|||
} |
|||
} |
|||
return budgetIdsOfActivity; |
|||
} |
|||
|
|||
|
|||
|
|||
/** |
|||
* 匹配的主要方法 |
|||
* @param activityCostItem 活动项 |
|||
* @param throwEx 预算不够时抛出异常 |
|||
* @param overspend 超值标识 |
|||
* @param scheduleItemBudgets 时间区间条件 |
|||
* @param hisCostGroupByItemBudget 历史费用组 |
|||
* @param allBudgetList 所有预算 |
|||
* @param noConditionBudgetList 没有条件的预算列表 |
|||
* @param counterMap 历史预算占用 |
|||
* @param actMatchList 匹配预算占用的费用(含超支预算) |
|||
* @param actUnMatchList 没有匹配预算的费用 |
|||
* @param activityAllowBudgetIds 满足当前活动项的费用idMap |
|||
*/ |
|||
private void matchActivityMain(TbsActivityCenterGoods activityCostItem, |
|||
Boolean throwEx, |
|||
boolean overspend, |
|||
List<TbsScheduleItemBudget> scheduleItemBudgets, |
|||
Map<Long, List<TbsBudgetCostItem>> hisCostGroupByItemBudget, |
|||
final List<TbsBudget> allBudgetList, |
|||
List<TbsBudget> noConditionBudgetList, |
|||
Map<Long, BigDecimal> counterMap, |
|||
final List<TbsActivityCenterGoods> actMatchList, |
|||
final List<TbsActivityCenterGoods> actUnMatchList, |
|||
final List<Long> activityAllowBudgetIds) { |
|||
//过滤满全条件的预算
|
|||
List<Long> allowBudgetIds = activityAllowBudgetIds; |
|||
List<TbsBudget> budgetList = allBudgetList.stream().filter(obj->allowBudgetIds.contains(obj.getId())).collect(Collectors.toList()); |
|||
//PS:排序规则:优先为时间条件,其次匹配品牌条件
|
|||
//按品类条件,提取可用预算(列表已按小维度到大维度排列)
|
|||
List<TbsBudget> currentItemBudgetList = this.filterMatchGoodsCondition(budgetList, activityCostItem); |
|||
//关联无条件预算
|
|||
currentItemBudgetList.addAll(noConditionBudgetList); |
|||
//提取可用预算的考核期
|
|||
List<TbsScheduleItemBudget> currentScheduleItemBudgets = new ArrayList<>(); |
|||
for (TbsBudget budget : currentItemBudgetList) { |
|||
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 = TbsBudgetCostUtil.totalHisCost(hisCostGroupByItemBudget.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()); |
|||
isMatch = true; |
|||
//记录当前费用使用考核期费用
|
|||
lastAmount = lastAmount.add(goodsAmount); |
|||
counterMap.put(itemBudget.getId(),lastAmount); |
|||
break; |
|||
} |
|||
} |
|||
//无匹配的预算
|
|||
if(!isMatch){ |
|||
if(overspend){ |
|||
TbsScheduleItemBudget itemBudget = currentScheduleItemBudgets.get(0); |
|||
activityCostItem.setBudgetId(itemBudget.getBudgetId()); |
|||
activityCostItem.setScheduleId(itemBudget.getScheduleId()); |
|||
activityCostItem.setScheduleItemId(itemBudget.getScheduleItemId()); |
|||
activityCostItem.setScheduleItemBudgetId(itemBudget.getId()); |
|||
//记录当前费用使用考核期费用
|
|||
BigDecimal lastAmount = counterMap.get(itemBudget.getId()); |
|||
if(lastAmount==null){ |
|||
lastAmount = BigDecimal.ZERO; |
|||
} |
|||
lastAmount = lastAmount.add(goodsAmount); |
|||
counterMap.put(itemBudget.getId(),lastAmount); |
|||
}else if (throwEx){ |
|||
Assert.throwEx("品类["+ activityCostItem.getTargetName()+"]预算不足"); |
|||
} |
|||
activityCostItem.setBudgetId(0L); |
|||
activityCostItem.setScheduleId(0L); |
|||
activityCostItem.setScheduleItemId(0L); |
|||
activityCostItem.setScheduleItemBudgetId(0L); |
|||
} |
|||
actMatchList.add(activityCostItem); |
|||
}else { |
|||
if(throwEx){ |
|||
Assert.throwEx("品类["+ activityCostItem.getTargetName()+"]无可用预算"); |
|||
} |
|||
if(overspend){ |
|||
//添加到预算超支表
|
|||
activityCostItem.setBudgetId(0L); |
|||
activityCostItem.setScheduleId(0L); |
|||
activityCostItem.setScheduleItemId(0L); |
|||
activityCostItem.setScheduleItemBudgetId(0L); |
|||
actUnMatchList.add(activityCostItem); |
|||
} |
|||
} |
|||
} |
|||
|
|||
/** |
|||
* 按品类条件,提取可用预算 |
|||
* @param budgetList |
|||
* @param activityCostItem |
|||
* @return |
|||
*/ |
|||
@NotNull |
|||
private List<TbsBudget> filterMatchGoodsCondition(List<TbsBudget> budgetList,TbsActivityCenterGoods activityCostItem) { |
|||
String levelPath = activityCostItem.getTargetLevelPathIds(); |
|||
Set<String> levelPathSet = new LinkedHashSet<>(); |
|||
levelPathSet.add(levelPath); |
|||
TbsBudgetCostUtil.buildPaths(levelPath,levelPathSet); |
|||
List<TbsBudget> currentItemBudgetList = new ArrayList<>(); |
|||
for (TbsBudget budget : budgetList) { |
|||
if(budget.getConditionFlag().equals(1)){ |
|||
List<TbsBudgetCondition> budgetConditionListByBudget = budget.getBudgetConditionList(); |
|||
boolean unMatch = true; |
|||
for (String conditionString : levelPathSet) { |
|||
if(unMatch){ |
|||
for (TbsBudgetCondition budgetCondition : budgetConditionListByBudget) { |
|||
if(budgetCondition.getTargetLevelPathIds().contains(conditionString)){ |
|||
currentItemBudgetList.add(budget); |
|||
unMatch = false; |
|||
break; |
|||
} |
|||
} |
|||
} |
|||
} |
|||
} |
|||
} |
|||
return currentItemBudgetList; |
|||
} |
|||
|
|||
/** |
|||
* 1.加载所有的条件 |
|||
* 2.匹配初无条件预算 |
|||
* 3.预算条件关联到预算对象中 |
|||
* @param budgetList |
|||
* @param noConditionBudgetList |
|||
* @return 含有无条件预算标识 |
|||
*/ |
|||
private boolean loadConditionByBudgetsAndMatch( List<TbsBudget> budgetList, List<TbsBudget> noConditionBudgetList) { |
|||
boolean budgetNoCondition = false; |
|||
for (TbsBudget budget : budgetList) { |
|||
if(budget.getConditionFlag().equals(1)){ |
|||
List<TbsBudgetCondition> budgetConditionListByBudgetId = tbsBudgetConditionService.getByBudgetId(budget.getId()); |
|||
budget.setBudgetConditionList(budgetConditionListByBudgetId); |
|||
}else { |
|||
budgetNoCondition = true; |
|||
noConditionBudgetList.add(budget); |
|||
} |
|||
} |
|||
return budgetNoCondition; |
|||
} |
|||
|
|||
/** |
|||
* 拦截没有预算的活动 |
|||
* @param throwEx 抛出异常 |
|||
* @param overspend 超支 |
|||
* @param budgetNoCondition 标识,没有条件的预算 |
|||
*/ |
|||
private void handleNoBudgetActivity(Boolean throwEx, boolean overspend, |
|||
boolean budgetNoCondition, |
|||
List<Long> activityAllowBudgetIds) { |
|||
if(!overspend && !budgetNoCondition && throwEx ){ |
|||
Assert.throwEx("活动无可用预算"); |
|||
} |
|||
if(throwEx){ |
|||
if(activityAllowBudgetIds.size()<1){ |
|||
Assert.throwEx("活动无可用预算"); |
|||
} |
|||
} |
|||
} |
|||
|
|||
/** |
|||
* 1.通过活动加载所有满足条件的考核期(用于加载历史核销费用), |
|||
* 2.设置匹配的考核期列表到活动中 |
|||
* @param budgetIds |
|||
*/ |
|||
public List<TbsScheduleItemBudget> loadScheduleBudgetAndSetting(TbsActivityBo activityBo, |
|||
List<Long> budgetIds) { |
|||
Set<Long> budgetIdsSet = new HashSet<>(); |
|||
List<TbsScheduleItemBudget> budgetItemList = tbsScheduleItemBudgetService |
|||
.betweenDateList(activityBo.getPreStartDate(),activityBo.getPreEndDate()); |
|||
if(CollectionUtil.isNotEmpty(budgetItemList)){ |
|||
for (TbsScheduleItemBudget item : budgetItemList) { |
|||
budgetIdsSet.add(item.getBudgetId()); |
|||
} |
|||
} |
|||
budgetIds.addAll(budgetIdsSet); |
|||
return budgetItemList; |
|||
} |
|||
} |
Loading…
Reference in new issue