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