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