31 changed files with 1047 additions and 44 deletions
@ -0,0 +1,17 @@ |
|||
package com.qs.serve.modules.tbs.common; |
|||
|
|||
/** |
|||
* @author YenHex |
|||
* @since 2022/12/6 |
|||
*/ |
|||
public interface TbsActivityState { |
|||
|
|||
/** |
|||
* 活动状态:0-待核销;1-审批中;2-完成;3-冻结 |
|||
*/ |
|||
Integer STATE_0_Todo = 0; |
|||
Integer STATE_1_Checking = 1; |
|||
Integer STATE_1_Finished = 2; |
|||
Integer STATE_1_Baning = 3; |
|||
|
|||
} |
@ -0,0 +1,108 @@ |
|||
package com.qs.serve.modules.tbs.common.util; |
|||
|
|||
import com.qs.serve.common.util.CollectionUtil; |
|||
import com.qs.serve.common.util.CopierUtil; |
|||
import com.qs.serve.modules.tbs.entity.TbsActivityCenterGoods; |
|||
import com.qs.serve.modules.tbs.entity.TbsBudgetCostItem; |
|||
import org.jetbrains.annotations.NotNull; |
|||
|
|||
import java.math.BigDecimal; |
|||
import java.math.RoundingMode; |
|||
import java.time.LocalDate; |
|||
import java.time.temporal.TemporalAdjusters; |
|||
import java.util.*; |
|||
|
|||
/** |
|||
* @author YenHex |
|||
* @since 2022/12/5 |
|||
*/ |
|||
public class TbsBudgetCostUtil { |
|||
|
|||
/** |
|||
* 统计费用占用历史 |
|||
* @param budgetCostItems |
|||
* @return |
|||
*/ |
|||
public static BigDecimal totalHisCost(List<TbsBudgetCostItem> budgetCostItems){ |
|||
BigDecimal total = BigDecimal.ZERO; |
|||
if(CollectionUtil.isNotEmpty(budgetCostItems)){ |
|||
for (TbsBudgetCostItem item : budgetCostItems) { |
|||
total = total.add(item.getMonthAmount()); |
|||
} |
|||
} |
|||
return total; |
|||
} |
|||
|
|||
/** |
|||
* 拆分条件 |
|||
* @param path |
|||
* @param paths |
|||
*/ |
|||
public static void buildPaths(String path, Set<String> paths){ |
|||
if(path.contains("_")){ |
|||
String subPath = path.substring(0,path.lastIndexOf("_")); |
|||
paths.add(subPath); |
|||
buildPaths(subPath,paths); |
|||
} |
|||
} |
|||
|
|||
public static void main(String[] args) { |
|||
String aa = "1_9_3_4_5_6"; |
|||
Set<String> stringSet = new LinkedHashSet<>(); |
|||
buildPaths(aa,stringSet); |
|||
stringSet.forEach(System.out::println); |
|||
} |
|||
|
|||
/** |
|||
* 按月份创建预算占用明细 |
|||
* @param centerGoodsList |
|||
* @return |
|||
*/ |
|||
@NotNull |
|||
public static List<TbsBudgetCostItem> createBudgetCostItems(List<TbsActivityCenterGoods> centerGoodsList) { |
|||
List<TbsBudgetCostItem> budgetCostItems = new ArrayList<>(); |
|||
for (TbsActivityCenterGoods centerGoods : centerGoodsList) { |
|||
//按月份拆分
|
|||
LocalDate actStartDate = centerGoods.getActStartDate(); |
|||
LocalDate itemStartDate = centerGoods.getActStartDate(); |
|||
LocalDate actEndDate = centerGoods.getActEndDate(); |
|||
int days = actEndDate.getDayOfYear() - actStartDate.getDayOfYear() + 1; |
|||
int count = Math.max(days / 28, 2); |
|||
BigDecimal totalAmount = centerGoods.getCenterGoodsAmount(); |
|||
BigDecimal balance = centerGoods.getCenterGoodsAmount(); |
|||
for (int i = 0; i < count ; i++) { |
|||
if(itemStartDate.getDayOfYear() > actEndDate.getDayOfYear()){ |
|||
break; |
|||
} |
|||
LocalDate itemLastDay = itemStartDate.with(TemporalAdjusters.lastDayOfMonth()); |
|||
boolean isEnd = false; |
|||
if(itemLastDay.getDayOfYear() >= actEndDate.getDayOfYear()){ |
|||
itemLastDay = actEndDate; |
|||
isEnd = true; |
|||
} |
|||
int daysOfMonth = itemStartDate.getDayOfYear()-itemLastDay.getDayOfYear()+1; |
|||
BigDecimal currentItemAmount; |
|||
if(isEnd){ |
|||
currentItemAmount = balance; |
|||
}else { |
|||
currentItemAmount = BigDecimal.valueOf(daysOfMonth) |
|||
.divide(BigDecimal.valueOf(days), RoundingMode.HALF_UP) |
|||
.multiply(totalAmount); |
|||
balance = balance.subtract(currentItemAmount); |
|||
} |
|||
//构建明细项
|
|||
TbsBudgetCostItem budgetCostItem = CopierUtil.copy(centerGoods,new TbsBudgetCostItem()); |
|||
budgetCostItem.setId(null); |
|||
budgetCostItem.setCenterGoodItemId(centerGoods.getId()); |
|||
budgetCostItem.setItemStartDate(itemStartDate); |
|||
budgetCostItem.setItemEndDate(itemLastDay); |
|||
budgetCostItem.setMonthAmount(currentItemAmount); |
|||
budgetCostItems.add(budgetCostItem); |
|||
//跨月份重新赋值
|
|||
itemStartDate = itemLastDay.plusDays(1); |
|||
} |
|||
} |
|||
return budgetCostItems; |
|||
} |
|||
|
|||
} |
@ -0,0 +1,227 @@ |
|||
package com.qs.serve.modules.tbs.entity; |
|||
|
|||
import java.time.LocalDate; |
|||
import java.io.Serializable; |
|||
import java.math.BigDecimal; |
|||
import java.time.LocalDateTime; |
|||
|
|||
import com.baomidou.mybatisplus.annotation.*; |
|||
import com.fasterxml.jackson.annotation.JsonFormat; |
|||
import com.fasterxml.jackson.annotation.JsonIgnore; |
|||
import com.fasterxml.jackson.annotation.JsonProperty; |
|||
import lombok.Data; |
|||
import org.hibernate.validator.constraints.Length; |
|||
import org.springframework.format.annotation.DateTimeFormat; |
|||
|
|||
import javax.validation.constraints.NotNull; |
|||
import javax.validation.constraints.NotBlank; |
|||
import java.util.List; |
|||
/** |
|||
* 预算费用明细 实体类 |
|||
* @author YenHex |
|||
* @since 2022-12-02 |
|||
*/ |
|||
@Data |
|||
@TableName("tbs_budget_cost_item") |
|||
public class TbsBudgetCostItem implements Serializable { |
|||
|
|||
private static final long serialVersionUID = 1L; |
|||
|
|||
/** id */ |
|||
@TableId(type = IdType.AUTO) |
|||
private Long id; |
|||
|
|||
/** 成本明细编码 */ |
|||
@Length(max = 30,message = "成本明细编码长度不能超过30字") |
|||
private String centerGoodsCode; |
|||
|
|||
/** 费用申请id */ |
|||
@NotNull(message = "费用申请id不能为空") |
|||
private Long costApplyId; |
|||
|
|||
/** 活动id */ |
|||
@NotNull(message = "活动id不能为空") |
|||
private Long activityId; |
|||
|
|||
/** 科目id */ |
|||
@NotNull(message = "科目id不能为空") |
|||
private Long subjectId; |
|||
|
|||
/** 科目编码 */ |
|||
@NotBlank(message = "科目编码不能为空") |
|||
@Length(max = 50,message = "科目编码长度不能超过50字") |
|||
private String subjectCode; |
|||
|
|||
/** 科目名称 */ |
|||
@NotBlank(message = "科目名称不能为空") |
|||
@Length(max = 50,message = "科目名称长度不能超过50字") |
|||
private String subjectName; |
|||
|
|||
/** 成本中心类型 */ |
|||
@NotBlank(message = "成本中心类型不能为空") |
|||
@Length(max = 50,message = "成本中心类型长度不能超过50字") |
|||
private String centerType; |
|||
|
|||
/** 成本中心id */ |
|||
@NotBlank(message = "成本中心id不能为空") |
|||
@Length(max = 32,message = "成本中心id长度不能超过32字") |
|||
private String centerId; |
|||
|
|||
/** 成本中心编码 */ |
|||
@NotBlank(message = "成本中心编码不能为空") |
|||
@Length(max = 50,message = "成本中心编码长度不能超过50字") |
|||
private String centerCode; |
|||
|
|||
/** 成本中心名称 */ |
|||
@NotBlank(message = "成本中心名称不能为空") |
|||
@Length(max = 50,message = "成本中心名称长度不能超过50字") |
|||
private String centerName; |
|||
|
|||
/** 成本中心金额 */ |
|||
@NotNull(message = "成本中心金额不能为空") |
|||
private BigDecimal centerAmount; |
|||
|
|||
/** 成本中心占比 */ |
|||
@NotNull(message = "成本中心占比不能为空") |
|||
private BigDecimal centerRate; |
|||
|
|||
/** 费用额度 */ |
|||
@NotNull(message = "费用额度不能为空") |
|||
private BigDecimal centerGoodsAmount; |
|||
|
|||
/** 费用占比 */ |
|||
@NotNull(message = "费用占比不能为空") |
|||
private BigDecimal centerGoodsRate; |
|||
|
|||
/** 目标类型(brand、category、series、spu、sku) */ |
|||
@NotBlank(message = "目标类型(brand、category、series、spu、sku)不能为空") |
|||
@Length(max = 30,message = "目标类型(brand、category、series、spu、sku)长度不能超过30字") |
|||
private String targetType; |
|||
|
|||
/** 目标id */ |
|||
@NotNull(message = "目标id不能为空") |
|||
private Long targetId; |
|||
|
|||
/** 目标编码 */ |
|||
@NotBlank(message = "目标编码不能为空") |
|||
@Length(max = 30,message = "目标编码长度不能超过30字") |
|||
private String targetCode; |
|||
|
|||
/** 目标名称 */ |
|||
@NotBlank(message = "目标名称不能为空") |
|||
@Length(max = 30,message = "目标名称长度不能超过30字") |
|||
private String targetName; |
|||
|
|||
/** 目标等级路径 */ |
|||
@Length(max = 600,message = "目标等级路径长度不能超过600字") |
|||
private String targetLevelPathIds; |
|||
|
|||
/** 目标等级路径 */ |
|||
@Length(max = 600,message = "目标等级路径长度不能超过600字") |
|||
private String targetLevelPathNames; |
|||
|
|||
/** 备注 */ |
|||
@Length(max = 255,message = "备注长度不能超过255字") |
|||
private String remark; |
|||
|
|||
/** 创建时间 */ |
|||
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") |
|||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone = "GMT+8") |
|||
@TableField(fill = FieldFill.INSERT) |
|||
private LocalDateTime createTime; |
|||
|
|||
/** 最后更新时间 */ |
|||
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") |
|||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone = "GMT+8") |
|||
@TableField(fill = FieldFill.UPDATE) |
|||
private LocalDateTime updateTime; |
|||
|
|||
/** 所属租户 */ |
|||
@JsonIgnore |
|||
@JsonProperty |
|||
private String tenantId; |
|||
|
|||
/** 创建人 */ |
|||
@TableField(fill = FieldFill.INSERT) |
|||
private String createBy; |
|||
|
|||
/** 更新人 */ |
|||
@TableField(fill = FieldFill.UPDATE) |
|||
private String updateBy; |
|||
|
|||
/** 逻辑删除标记(0:显示;1:隐藏) */ |
|||
@JsonIgnore |
|||
@JsonProperty |
|||
private String delFlag; |
|||
|
|||
/** 活动开始时间 */ |
|||
@NotNull(message = "活动开始时间不能为空") |
|||
@DateTimeFormat(pattern = "yyyy-MM-dd") |
|||
@JsonFormat(pattern = "yyyy-MM-dd",timezone = "GMT+8") |
|||
private LocalDate actStartDate; |
|||
|
|||
/** 活动结束时间 */ |
|||
@NotNull(message = "活动结束时间不能为空") |
|||
@DateTimeFormat(pattern = "yyyy-MM-dd") |
|||
@JsonFormat(pattern = "yyyy-MM-dd",timezone = "GMT+8") |
|||
private LocalDate actEndDate; |
|||
|
|||
/** 预算开始时间 */ |
|||
@NotNull(message = "预算开始时间不能为空") |
|||
@DateTimeFormat(pattern = "yyyy-MM-dd") |
|||
@JsonFormat(pattern = "yyyy-MM-dd",timezone = "GMT+8") |
|||
private LocalDate preStartDate; |
|||
|
|||
/** 预算结束时间 */ |
|||
@NotNull(message = "预算结束时间不能为空") |
|||
@DateTimeFormat(pattern = "yyyy-MM-dd") |
|||
@JsonFormat(pattern = "yyyy-MM-dd",timezone = "GMT+8") |
|||
private LocalDate preEndDate; |
|||
|
|||
/** 预计核销时间 */ |
|||
@DateTimeFormat(pattern = "yyyy-MM-dd") |
|||
@JsonFormat(pattern = "yyyy-MM-dd",timezone = "GMT+8") |
|||
private LocalDate preCheckDate; |
|||
|
|||
/** 预算开始时间 */ |
|||
@NotNull(message = "预算开始时间不能为空") |
|||
@DateTimeFormat(pattern = "yyyy-MM-dd") |
|||
@JsonFormat(pattern = "yyyy-MM-dd",timezone = "GMT+8") |
|||
private LocalDate itemStartDate; |
|||
|
|||
/** 预算结束时间 */ |
|||
@NotNull(message = "预算结束时间不能为空") |
|||
@DateTimeFormat(pattern = "yyyy-MM-dd") |
|||
@JsonFormat(pattern = "yyyy-MM-dd",timezone = "GMT+8") |
|||
private LocalDate itemEndDate; |
|||
|
|||
/** 月份占用金额 */ |
|||
@NotNull(message = "月份占用金额不能为空") |
|||
private BigDecimal monthAmount; |
|||
|
|||
/** 预算id */ |
|||
@NotNull(message = "预算id不能为空") |
|||
private Long budgetId; |
|||
|
|||
/** 考核id */ |
|||
@NotNull(message = "考核id不能为空") |
|||
private Long scheduleId; |
|||
|
|||
/** 考核期项id */ |
|||
@NotNull(message = "考核期项id不能为空") |
|||
private Long scheduleItemId; |
|||
|
|||
/** 费用考核期项id */ |
|||
@NotNull(message = "费用考核期项id不能为空") |
|||
private Long scheduleItemBudgetId; |
|||
|
|||
/** TbsActivityCenterGoods的id */ |
|||
private Long centerGoodItemId; |
|||
|
|||
|
|||
/** 请忽略,后端传输参数 */ |
|||
@TableField(exist = false) |
|||
private List<TbsScheduleItemBudget> tempScheduleItemDtoList; |
|||
|
|||
} |
|||
|
@ -0,0 +1,46 @@ |
|||
package com.qs.serve.modules.tbs.entity.dto; |
|||
|
|||
import com.baomidou.mybatisplus.annotation.IdType; |
|||
import com.baomidou.mybatisplus.annotation.TableId; |
|||
import com.fasterxml.jackson.annotation.JsonFormat; |
|||
import lombok.Data; |
|||
import org.hibernate.validator.constraints.Length; |
|||
import org.springframework.format.annotation.DateTimeFormat; |
|||
|
|||
import javax.validation.constraints.NotBlank; |
|||
import javax.validation.constraints.NotNull; |
|||
import java.math.BigDecimal; |
|||
import java.time.LocalDateTime; |
|||
|
|||
/** |
|||
* @author YenHex |
|||
* @since 2022/12/5 |
|||
*/ |
|||
@Data |
|||
public class TbsBudgetAmountResult { |
|||
|
|||
/** id */ |
|||
private Long scheduleItemBudgetId; |
|||
|
|||
/** 考核id */ |
|||
private Long scheduleId; |
|||
|
|||
/** 考核项id */ |
|||
private Long scheduleItemId; |
|||
|
|||
/** 考核编码 */ |
|||
private String itemName; |
|||
|
|||
/** 开始时间 */ |
|||
private LocalDateTime startDate; |
|||
|
|||
/** 结束时间 */ |
|||
private LocalDateTime endDate; |
|||
|
|||
/** 预算id */ |
|||
private Long budgetId; |
|||
|
|||
/** 预算金额 */ |
|||
private BigDecimal budgetAmount; |
|||
|
|||
} |
@ -0,0 +1,14 @@ |
|||
package com.qs.serve.modules.tbs.mapper; |
|||
|
|||
import com.baomidou.mybatisplus.core.mapper.BaseMapper; |
|||
import com.qs.serve.modules.tbs.entity.TbsBudgetCostItem; |
|||
|
|||
/** |
|||
* 预算费用明细 Mapper |
|||
* @author YenHex |
|||
* @date 2022-12-02 |
|||
*/ |
|||
public interface TbsBudgetCostItemMapper extends BaseMapper<TbsBudgetCostItem> { |
|||
|
|||
} |
|||
|
@ -0,0 +1,293 @@ |
|||
package com.qs.serve.modules.tbs.service; |
|||
|
|||
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.service.BmsSupplierService; |
|||
import com.qs.serve.modules.seeyon.service.SeeYonService; |
|||
import com.qs.serve.modules.sys.service.SysConfigService; |
|||
import com.qs.serve.modules.sys.service.SysUserService; |
|||
import com.qs.serve.modules.tbs.common.util.TbsBudgetCostUtil; |
|||
import com.qs.serve.modules.tbs.entity.*; |
|||
import lombok.AllArgsConstructor; |
|||
import lombok.extern.slf4j.Slf4j; |
|||
import org.jetbrains.annotations.NotNull; |
|||
import org.springframework.stereotype.Service; |
|||
|
|||
import java.math.BigDecimal; |
|||
import java.time.temporal.ChronoField; |
|||
import java.util.*; |
|||
import java.util.stream.Collectors; |
|||
|
|||
/** |
|||
* 预算应用层服务 |
|||
* @author YenHex |
|||
* @since 2022/12/6 |
|||
*/ |
|||
@Slf4j |
|||
@Service |
|||
@AllArgsConstructor |
|||
public class TbsBudgetApplicationService { |
|||
|
|||
private TbsCostApplyService tbsCostApplyService; |
|||
private TbsActivityService tbsActivityService; |
|||
private TbsActivityCenterGoodsService tbsActivityCenterGoodsService; |
|||
private TbsScheduleItemBudgetService tbsScheduleItemBudgetService; |
|||
|
|||
private TbsBudgetService tbsBudgetService; |
|||
private TbsBudgetConditionService tbsBudgetConditionService; |
|||
private TbsBudgetCostItemService tbsBudgetCostItemService; |
|||
|
|||
private BmsSupplierService bmsSupplierService; |
|||
|
|||
private SysUserService sysUserService; |
|||
private SysConfigService configService; |
|||
|
|||
private SeeYonService seeYonService; |
|||
|
|||
/** |
|||
* |
|||
* @param costApplyId |
|||
* @param throwEx 是否需要抛出异常 |
|||
*/ |
|||
public void commit(Long costApplyId,Boolean throwEx){ |
|||
//允许超出预算标识
|
|||
boolean overspend = configService.getByKey(SysConfigKey.TbsBudgetOverspend).getConfigValue().equals("1"); |
|||
//加载待核销活动
|
|||
List<TbsActivity> activityList = tbsActivityService.listByCostApplyIdAndTodoState(costApplyId); |
|||
//考核期有关的预算id,判断逻辑为活动需要允许在
|
|||
List<Long> budgetIds = new ArrayList<>(); |
|||
//没有预算的活动
|
|||
List<Long> noBudgetActivityIds = new ArrayList<>(); |
|||
//所有满足条件的考核期,用于加载历史核销费用
|
|||
List<TbsScheduleItemBudget> scheduleItemList = this.loadScheduleBudgetAndSetting(activityList, budgetIds, noBudgetActivityIds); |
|||
//加载预算占用历史
|
|||
List<Long> scheduleItemBudgetIds = scheduleItemList.stream().map(TbsScheduleItemBudget::getId).collect(Collectors.toList()); |
|||
List<TbsBudgetCostItem> hisBudgetCostItemList = tbsBudgetCostItemService.listByScheduleItemBudgetIds(scheduleItemBudgetIds); |
|||
Map<Long,List<TbsBudgetCostItem>> hisCostGroupByItemBudget = hisBudgetCostItemList.stream() |
|||
.collect(Collectors.groupingBy(TbsBudgetCostItem::getScheduleItemBudgetId)); |
|||
// 构建预算费用占用明细
|
|||
List<TbsActivityCenterGoods> centerGoodsList = tbsActivityCenterGoodsService.listByCostApplyId(costApplyId); |
|||
// 加载所有条件
|
|||
List<TbsBudget> budgetList = tbsBudgetService.listByIds(budgetIds); |
|||
List<TbsBudget> noConditionBudgetList = new ArrayList<>(); |
|||
boolean budgetNoCondition = this.loadConditionByBudgetsAndMatch(budgetList, noConditionBudgetList); |
|||
//活动拦截
|
|||
this.handleNoBudgetActivity(throwEx, overspend, activityList, noBudgetActivityIds, budgetNoCondition); |
|||
//统计当前活动前置项占用预算
|
|||
Map<Long,BigDecimal> counterMap = new HashMap<>(); |
|||
//匹配预算主要方法
|
|||
final List<TbsActivityCenterGoods> actMatchList = new ArrayList<>(); |
|||
final List<TbsActivityCenterGoods> actUnMatchList = new ArrayList<>(); |
|||
for (TbsActivityCenterGoods activityCostItem : centerGoodsList) { |
|||
this.matchActivityMain(activityCostItem,throwEx, overspend, activityList, hisCostGroupByItemBudget, budgetList, noConditionBudgetList, counterMap, actMatchList, actUnMatchList); |
|||
} |
|||
List<TbsBudgetCostItem> budgetCostItems1 = TbsBudgetCostUtil.createBudgetCostItems(actMatchList); |
|||
List<TbsBudgetCostItem> budgetCostItems2 = TbsBudgetCostUtil.createBudgetCostItems(actUnMatchList); |
|||
} |
|||
|
|||
/** |
|||
* 匹配的主要方法 |
|||
* @param activityCostItem |
|||
* @param throwEx |
|||
* @param overspend |
|||
* @param activityList |
|||
* @param hisCostGroupByItemBudget 历史费用组 |
|||
* @param budgetList |
|||
* @param noConditionBudgetList |
|||
* @param counterMap |
|||
* @param actMatchList |
|||
* @param actUnMatchList |
|||
*/ |
|||
private void matchActivityMain(TbsActivityCenterGoods activityCostItem, |
|||
Boolean throwEx, |
|||
boolean overspend, |
|||
List<TbsActivity> activityList, |
|||
Map<Long, List<TbsBudgetCostItem>> hisCostGroupByItemBudget, |
|||
List<TbsBudget> budgetList, |
|||
List<TbsBudget> noConditionBudgetList, |
|||
Map<Long, BigDecimal> counterMap, |
|||
final List<TbsActivityCenterGoods> actMatchList, |
|||
final List<TbsActivityCenterGoods> actUnMatchList) { |
|||
//PS:排序规则:优先匹配品牌条件,其次为时间条件
|
|||
//按品类条件,提取可用预算(列表已按小维度到大维度排列)
|
|||
List<TbsBudget> currentItemBudgetList = this.filterMatchGoodsCondition(budgetList, activityCostItem); |
|||
//关联无条件预算
|
|||
currentItemBudgetList.addAll(noConditionBudgetList); |
|||
//提取可用预算的考核期
|
|||
List<TbsScheduleItemBudget> currentScheduleItemBudgets = new ArrayList<>(); |
|||
for (TbsActivity activity : activityList) { |
|||
for (TbsBudget budget : currentItemBudgetList) { |
|||
List<TbsScheduleItemBudget> scheduleItemBudgets = activity.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 = 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()+"]预算不足"); |
|||
} |
|||
} |
|||
actMatchList.add(activityCostItem); |
|||
}else { |
|||
if(throwEx){ |
|||
Assert.throwEx("品类["+ activityCostItem.getTargetName()+"]无可用预算"); |
|||
} |
|||
if(overspend){ |
|||
//添加到预算超支表
|
|||
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 activityList 活动列表 |
|||
* @param noBudgetActivityIds 没有预算的活动id |
|||
* @param budgetNoCondition 标识,没有条件的预算 |
|||
*/ |
|||
private void handleNoBudgetActivity(Boolean throwEx, boolean overspend, List<TbsActivity> activityList, List<Long> noBudgetActivityIds, boolean budgetNoCondition) { |
|||
if(!overspend && !budgetNoCondition && throwEx && noBudgetActivityIds.size()>0){ |
|||
for (Long activityId : noBudgetActivityIds) { |
|||
for (TbsActivity activity : activityList) { |
|||
if(activity.getId().equals(activityId)){ |
|||
Assert.throwEx("活动["+activity.getActivityCode()+"]无可用预算"); |
|||
} |
|||
} |
|||
} |
|||
Assert.throwEx("活动无可用预算"); |
|||
} |
|||
} |
|||
|
|||
/** |
|||
* 1.通过活动加载所有满足条件的考核期(用于加载历史核销费用), |
|||
* 2.设置没有可用预算的活动id |
|||
* 3.设置匹配的考核期列表到活动中 |
|||
* @param activityList |
|||
* @param budgetIds |
|||
* @param noBudgetActivityIds |
|||
*/ |
|||
public List<TbsScheduleItemBudget> loadScheduleBudgetAndSetting(List<TbsActivity> activityList, List<Long> budgetIds, List<Long> noBudgetActivityIds) { |
|||
List<TbsScheduleItemBudget> scheduleItemList = new ArrayList<>(); |
|||
Set<Long> budgetIdsSet = new HashSet<>(); |
|||
Map<Long,TbsScheduleItemBudget> allAllowScheduleItemTempMap = new HashMap<>(); |
|||
for (TbsActivity activity : activityList) { |
|||
List<TbsScheduleItemBudget> budgetItemList = tbsScheduleItemBudgetService |
|||
.betweenDateList(activity.getPreStartDate(),activity.getPreEndDate()); |
|||
activity.setScheduleItemBudgetList(budgetItemList); |
|||
if(CollectionUtil.isNotEmpty(budgetItemList)){ |
|||
for (TbsScheduleItemBudget item : budgetItemList) { |
|||
budgetIdsSet.add(item.getBudgetId()); |
|||
allAllowScheduleItemTempMap.put(item.getId(),item); |
|||
} |
|||
}else { |
|||
noBudgetActivityIds.add(activity.getId()); |
|||
} |
|||
} |
|||
for (Long tmpId : allAllowScheduleItemTempMap.keySet()) { |
|||
scheduleItemList.add(allAllowScheduleItemTempMap.get(tmpId)); |
|||
} |
|||
budgetIds.addAll(budgetIdsSet); |
|||
return scheduleItemList; |
|||
} |
|||
} |
@ -0,0 +1,19 @@ |
|||
package com.qs.serve.modules.tbs.service; |
|||
|
|||
import com.baomidou.mybatisplus.extension.service.IService; |
|||
import com.qs.serve.modules.tbs.entity.TbsBudgetCostItem; |
|||
|
|||
import java.util.List; |
|||
|
|||
/** |
|||
* 预算费用明细 服务接口 |
|||
* @author YenHex |
|||
* @date 2022-12-02 |
|||
*/ |
|||
public interface TbsBudgetCostItemService extends IService<TbsBudgetCostItem> { |
|||
|
|||
|
|||
|
|||
List<TbsBudgetCostItem> listByScheduleItemBudgetIds(List<Long> ids); |
|||
} |
|||
|
@ -0,0 +1,32 @@ |
|||
package com.qs.serve.modules.tbs.service.impl; |
|||
|
|||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; |
|||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; |
|||
import lombok.AllArgsConstructor; |
|||
import lombok.extern.slf4j.Slf4j; |
|||
import org.springframework.stereotype.Service; |
|||
import com.qs.serve.modules.tbs.entity.TbsBudgetCostItem; |
|||
import com.qs.serve.modules.tbs.service.TbsBudgetCostItemService; |
|||
import com.qs.serve.modules.tbs.mapper.TbsBudgetCostItemMapper; |
|||
|
|||
import java.util.List; |
|||
|
|||
/** |
|||
* 预算费用明细 服务实现类 |
|||
* @author YenHex |
|||
* @since 2022-12-02 |
|||
*/ |
|||
@Slf4j |
|||
@Service |
|||
@AllArgsConstructor |
|||
public class TbsBudgetCostItemServiceImpl extends ServiceImpl<TbsBudgetCostItemMapper,TbsBudgetCostItem> implements TbsBudgetCostItemService { |
|||
|
|||
@Override |
|||
public List<TbsBudgetCostItem> listByScheduleItemBudgetIds(List<Long> ids) { |
|||
LambdaQueryWrapper<TbsBudgetCostItem> costLqw = new LambdaQueryWrapper<>(); |
|||
costLqw.in(TbsBudgetCostItem::getScheduleItemBudgetId,ids); |
|||
return this.list(costLqw); |
|||
} |
|||
|
|||
} |
|||
|
Loading…
Reference in new issue