package com.ydtech.modules.admin.service.impl; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.ydtech.core.page.HttpResult; import com.ydtech.modules.admin.model.dto.PayAmountExcel; import com.ydtech.modules.admin.model.dto.ReceivableExcel; import com.ydtech.modules.admin.model.report.profitAnalysis.ProfitAnalysisDto; import com.ydtech.modules.admin.model.report.profitAnalysis.ProfitAnalysisQueryDto; import com.ydtech.modules.admin.service.ProfitAnalysisService; import com.ydtech.modules.admin.utils.SliceUpDateUtil; import com.ydtech.modules.console.dao.ProfitAnalysisMapper; import com.ydtech.modules.fnc.dao.InsPlyIncomeMapper; import com.ydtech.modules.inv.dao.InvAccountExpensesMapper; import com.ydtech.modules.inv.dao.InvAccountMapper; import com.ydtech.modules.inv.model.InvAccount; import com.ydtech.modules.inv.model.InvAccountCardVo; import com.ydtech.modules.inv.model.InvAccountExpenses; import com.ydtech.modules.inv.utils.EasyExcelUtils; import com.ydtech.utils.BigDecimalUtils; import org.apache.commons.lang3.ObjectUtils; import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; import java.io.IOException; import java.math.BigDecimal; import java.math.RoundingMode; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; import java.util.*; import java.util.stream.Collectors; import java.util.stream.Stream; /** * @version * @author: hxl * @Date: 2024/7/1 11:36 * @Description: 控制台-运营数据 */ @Service public class ProfitAnalysisServiceImpl implements ProfitAnalysisService { @Autowired private InvAccountMapper invAccountMapper; @Autowired private InsPlyIncomeMapper insPlyIncomeMapper; @Autowired private ProfitAnalysisMapper profitAnalysisMapper; @Autowired private InvAccountExpensesMapper invAccountExpensesMapper; @Value("${upload.file.path}") private String uploadPath; @Value("${upload.file.url}") private String uploadUrl; /** * @version * @author: hxl * @Date: 2024/7/31 17:42 * @Description: 查询利润数据 */ @Override public List queryPage(ProfitAnalysisQueryDto profitAnalysisQueryDto) { HashMap dateMapByType = getDateMapByType(profitAnalysisQueryDto.getDateType(), profitAnalysisQueryDto.getYear()); profitAnalysisQueryDto.setBeginDate(dateMapByType.get("startDate")); profitAnalysisQueryDto.setEndDate(dateMapByType.get("endDate")); List list = insPlyIncomeMapper.queryPage(profitAnalysisQueryDto); return list; } /** * @version * @author: whp * @Date: 2024/8/16 15:35 * @Description: 查询利润分析统计 */ @Override public List getProfitAnalysisQueryList(ProfitAnalysisQueryDto profitAnalysisQueryDto) { HashMap dateMapByType = getDateMapByType(profitAnalysisQueryDto.getDateType(), profitAnalysisQueryDto.getYear()); profitAnalysisQueryDto.setBeginDate(dateMapByType.get("startDate")); profitAnalysisQueryDto.setEndDate(dateMapByType.get("endDate")); List profitAnalysisQueryList = insPlyIncomeMapper.getProfitAnalysisQueryList(profitAnalysisQueryDto); if(!profitAnalysisQueryList.isEmpty()){ for (ProfitAnalysisDto profitAnalysisDto : profitAnalysisQueryList) { BigDecimal variableCost = BigDecimal.ZERO; String yearAndMonth = profitAnalysisDto.getYearAndMonth(); profitAnalysisQueryDto.setYearAndMonth(yearAndMonth); List profitAnalysisDto1 = insPlyIncomeMapper.changeAmount(profitAnalysisQueryDto); for (ProfitAnalysisDto analysisDto : profitAnalysisDto1) { String outCardNum = analysisDto.getOutCardNum(); String enterCardNum = analysisDto.getEnterCardNum(); InvAccountCardVo outAccount = invAccountMapper.getByCarNumber(outCardNum); InvAccountCardVo enterAccount = invAccountMapper.getByCarNumber(enterCardNum); if(ObjectUtils.isNotEmpty(outAccount) && ObjectUtils.isNotEmpty(enterAccount) ){ if( (StringUtils.isNotEmpty(outAccount.getOuterFlag()) && StringUtils.isNotEmpty(enterAccount.getOuterFlag()))){ if(!enterAccount.getOuterFlag().equals(outAccount.getOuterFlag())){ variableCost=variableCost.add(analysisDto.getApplyAmount()); } } } } profitAnalysisDto.setVariableCost(variableCost); } } return profitAnalysisQueryList; } @Override public List getProfitAnalysisQueryDetailsList(ProfitAnalysisQueryDto profitAnalysisQueryDto) { List resultList =new ArrayList<>(); // 总支出=人员成本+固定成本+变动成本+税费 BigDecimal allExpenditure =this.getAllExpenditure(profitAnalysisQueryDto); if (StringUtils.isNotEmpty(profitAnalysisQueryDto.getExpensesType()) && "3".equals(profitAnalysisQueryDto.getExpensesType())) { List profitAnalysisDtos = profitAnalysisMapper.selectAccountExpenses(profitAnalysisQueryDto); Map map = new HashMap<>(); for (ProfitAnalysisDto dto : profitAnalysisDtos) { map.put(dto.getExpensesId(), dto); } ArrayList parentExpenIdList = new ArrayList<>(); // 如果没有parentId为0 的子级 则构建 for (ProfitAnalysisDto profitAnalysisDto : profitAnalysisDtos) { if(ObjectUtils.isEmpty(map.get(profitAnalysisDto.getParentId())) && !profitAnalysisDto.getParentId() .equals("0")){ QueryWrapper queryWrapper = new QueryWrapper<>(); queryWrapper.eq("expenses_id", profitAnalysisDto.getParentId()); InvAccountExpenses invAccountExpenses = invAccountExpensesMapper.selectOne(queryWrapper); ProfitAnalysisDto profitAnalysisDto1 = new ProfitAnalysisDto(); profitAnalysisDto1.setExpensesId(invAccountExpenses.getExpensesId()); profitAnalysisDto1.setParentId(invAccountExpenses.getParentId()); profitAnalysisDto1.setCategory(invAccountExpenses.getCategory()); parentExpenIdList.add(profitAnalysisDto1); map.put(profitAnalysisDto1.getExpensesId(),profitAnalysisDto1); } } profitAnalysisDtos.addAll(parentExpenIdList); List addVariableCost = new ArrayList<>(); //变动成本金额 List profitAnalysisDto1 = insPlyIncomeMapper.changeAmount(profitAnalysisQueryDto); for (ProfitAnalysisDto analysisDto : profitAnalysisDto1) { String outCardNum = analysisDto.getOutCardNum(); String enterCardNum = analysisDto.getEnterCardNum(); InvAccountCardVo outAccount = invAccountMapper.getByCarNumber(outCardNum); InvAccountCardVo enterAccount = invAccountMapper.getByCarNumber(enterCardNum); if (StringUtils.isNotEmpty(outAccount.getOuterFlag()) && StringUtils.isNotEmpty(enterAccount.getOuterFlag())) { if (!enterAccount.getOuterFlag().equals(outAccount.getOuterFlag())) { addVariableCost.add(analysisDto); } } } Map profitAnalysisDtoMap = addVariableCost.stream() .collect(Collectors.toMap( ProfitAnalysisDto::getExpensesId, // keyMapper,用于提取键(expensesId) ProfitAnalysisDto::getApplyAmount, // valueMapper,用于提取初始值(applyAmount) BigDecimal::add // mergeFunction,用于处理键冲突(相加 applyAmount) )); for (ProfitAnalysisDto profitAnalysisDto : profitAnalysisDtos) { String expensesId = profitAnalysisDto.getExpensesId(); if (profitAnalysisDtoMap.containsKey(expensesId)) { BigDecimal bigDecimal = profitAnalysisDtoMap.get(expensesId); profitAnalysisDto.setApplyAmount(bigDecimal); } } for (ProfitAnalysisDto dto : profitAnalysisDtos) { if (dto.getParentId().equals("0")) { BigDecimal totalAmount = aggregateChildAmounts(dto.getExpensesId(), map); dto.setApplyAmount(totalAmount); } } for (ProfitAnalysisDto allAccountExpens : profitAnalysisDtos) { BigDecimal applyAmount = allAccountExpens.getApplyAmount() != null ? allAccountExpens.getApplyAmount() : BigDecimal.ZERO; if(applyAmount.compareTo(BigDecimal.ZERO)>0){ allAccountExpens.setRadio(applyAmount.divide(allExpenditure,4,RoundingMode.HALF_UP).multiply(new BigDecimal("100")).setScale(2,RoundingMode.HALF_UP).toString()); } } resultList.addAll(profitAnalysisDtos) ; } else { /** * 子类目金额 */ List allAccountExpenses = profitAnalysisMapper.getAllAccountExpenses(profitAnalysisQueryDto); //二级类目 List collect = allAccountExpenses.stream().filter(item -> !item.getParentId().equals("0")).map(ProfitAnalysisDto::getExpensesId).collect(Collectors.toList()); profitAnalysisQueryDto.setIds(collect); List pidAmountList = profitAnalysisMapper.getSumCategory(profitAnalysisQueryDto); Map amountMap = pidAmountList.stream().collect(Collectors.toMap(ProfitAnalysisDto::getParentId, ProfitAnalysisDto::getApplyAmount)); Map> stringListMap = buildTreeMap(allAccountExpenses); stringListMap.forEach((id ,children) ->{ profitAnalysisQueryDto.setExpensesIds(children); ProfitAnalysisDto sumCategory = profitAnalysisMapper.getSumByparentAmount(profitAnalysisQueryDto); if(!amountMap.containsKey(id) && ObjectUtils.isNotEmpty(sumCategory)){ amountMap.put(id,sumCategory.getApplyAmount()); } }); for (ProfitAnalysisDto allAccountExpens : allAccountExpenses) { if (amountMap.containsKey(allAccountExpens.getExpensesId())) { allAccountExpens.setApplyAmount(amountMap.get(allAccountExpens.getExpensesId())); } } for (ProfitAnalysisDto allAccountExpens : allAccountExpenses) { BigDecimal applyAmount = allAccountExpens.getApplyAmount() != null ? allAccountExpens.getApplyAmount() : BigDecimal.ZERO; if(applyAmount.compareTo(BigDecimal.ZERO)>0){ allAccountExpens.setRadio(applyAmount.divide(allExpenditure,4,RoundingMode.HALF_UP).multiply(new BigDecimal("100")).setScale(2,RoundingMode.HALF_UP).toString()); } } resultList.addAll(allAccountExpenses); } List tree = getTree(resultList); String orderBy = profitAnalysisQueryDto.getOrderBy(); return sortListByField(tree, orderBy); } /** * * @param tree * @param orderBy * @return 排序 */ private List sortListByField(List tree, String orderBy) { if (tree == null || tree.isEmpty()) { return tree; } if(StringUtils.isEmpty(orderBy)){ return tree; } // 初始化比较器 Comparator comparator = (dto1, dto2) -> { BigDecimal applyAmount = dto1.getApplyAmount();// 假设字段名为applyAmount,根据实际情况调整 BigDecimal applyAmount1 = dto2.getApplyAmount(); return applyAmount.compareTo(applyAmount1); }; // 根据排序方向调整比较器 if ("desc".equalsIgnoreCase(orderBy)) { comparator = comparator.reversed(); } // 对列表进行排序 List sortedList = new ArrayList<>(tree); Collections.sort(sortedList, comparator); return sortedList; } private BigDecimal aggregateChildAmounts(String expensesId, Map map) { BigDecimal totalAmount = BigDecimal.ZERO; for (ProfitAnalysisDto dto : map.values()) { if (dto.getParentId() .equals(expensesId) ) { totalAmount = totalAmount.add(dto.getApplyAmount() != null ? dto.getApplyAmount() : BigDecimal.ZERO); totalAmount = totalAmount.add(aggregateChildAmounts(dto.getExpensesId(), map)); // 递归查找子对象 } } return totalAmount; } private BigDecimal getAllExpenditure(ProfitAnalysisQueryDto profitAnalysisQueryDto) { HashMap sumExpenditure = profitAnalysisMapper.getTotalExpenditure(profitAnalysisQueryDto); // 查询变动成本 BigDecimal variableCost = BigDecimal.ZERO; BigDecimal allExpenditure = BigDecimal.ZERO; String yearAndMonth = profitAnalysisQueryDto.getYearAndMonth(); profitAnalysisQueryDto.setYearAndMonth(yearAndMonth); List profitAnalysisDto1 = insPlyIncomeMapper.changeAmount(profitAnalysisQueryDto); for (ProfitAnalysisDto analysisDto : profitAnalysisDto1) { String outCardNum = analysisDto.getOutCardNum(); String enterCardNum = analysisDto.getEnterCardNum(); InvAccountCardVo outAccount = invAccountMapper.getByCarNumber(outCardNum); InvAccountCardVo enterAccount = invAccountMapper.getByCarNumber(enterCardNum); if(StringUtils.isNotEmpty(outAccount.getOuterFlag()) && StringUtils.isNotEmpty(enterAccount.getOuterFlag())){ if(!enterAccount.getOuterFlag().equals(outAccount.getOuterFlag())){ variableCost=variableCost.add(analysisDto.getApplyAmount()); } } } if(!sumExpenditure.isEmpty()){ BigDecimal fixedCost = sumExpenditure.get("fixedCost") != null ? sumExpenditure.get("fixedCost") : BigDecimal.ZERO; BigDecimal laborCost = sumExpenditure.get("laborCost") != null ? sumExpenditure.get("laborCost") : BigDecimal.ZERO; BigDecimal taxation = sumExpenditure.get("taxation") != null ? sumExpenditure.get("taxation") : BigDecimal.ZERO; allExpenditure =allExpenditure.add(fixedCost).add(laborCost).add(taxation).add(variableCost); } return allExpenditure; } public static Map> buildTreeMap(List nodes) { Map nodeMap = new HashMap<>(); for (ProfitAnalysisDto node : nodes) { nodeMap.put(node.getExpensesId(), node); } Map> parentChildrenMap = new HashMap<>(); for (ProfitAnalysisDto node : nodes) { if (node.getParentId().equals("0")) { // Root node, start recursion here List allIds = getAllIds(node, nodeMap, new ArrayList<>()); parentChildrenMap.put(String.valueOf(node.getExpensesId()), allIds); } } return parentChildrenMap; } private static List getAllIds(ProfitAnalysisDto node, Map nodeMap, List ids) { ids.add(String.valueOf(node.getExpensesId())); for (ProfitAnalysisDto potentialChild : nodeMap.values()) { if (potentialChild.getParentId() .equals(node.getExpensesId())) { getAllIds(potentialChild, nodeMap, ids); } } return ids; } /** * 组装树形结构结果集方法 */ public List getTree(List list){ return list.stream().filter(accountExpenses -> accountExpenses.getParentId().equals("0")) .peek(accountExpenses -> accountExpenses.setChildren(getChildren(accountExpenses,list))).collect(Collectors.toList()); } public List getChildren(ProfitAnalysisDto user,List userList){ return userList.stream().filter(u -> Objects.equals(u.getParentId(),user.getExpensesId())).map( u -> { u.setChildren(getChildren(u,userList)); return u; } ).collect(Collectors.toList()); } /** * @version * @author: hxl * @Date: 2024/6/19 11:57 * @Description: 通过时间类型判断 */ private static HashMap getDateMapByType(String type, String year) { HashMap map =new HashMap<>(); String startDateStr=""; String endDateStr=""; if(StringUtils.isBlank(year) && StringUtils.isBlank(type)){ Calendar cale = Calendar.getInstance(); int yearNow = cale.get(Calendar.YEAR); startDateStr= SliceUpDateUtil.getYearBeginDateStr(yearNow)+" 00:00:00"; endDateStr= SliceUpDateUtil.getYearEndDateStr(yearNow)+" 23:59:59"; }else{ if(StringUtils.isNotBlank(year)){ startDateStr= SliceUpDateUtil.getYearBeginDateStr(Integer.parseInt(year))+" 00:00:00"; endDateStr= SliceUpDateUtil.getYearEndDateStr(Integer.parseInt(year))+" 23:59:59"; }else{ if(StringUtils.isNotBlank(type)){ if("1".equals(type)){ // 一月内 startDateStr=SliceUpDateUtil.getBeforeDay(new Date(),2)+" 00:00:00"; endDateStr=SliceUpDateUtil.getBeforeDay(new Date(),0)+" 23:59:59"; }else if("2".equals(type)){ // 三月内 startDateStr=SliceUpDateUtil.getBeforeDay(new Date(),3)+" 00:00:00"; endDateStr=SliceUpDateUtil.getBeforeDay(new Date(),0)+" 23:59:59"; }else if("3".equals(type)){ // 近半年 startDateStr=SliceUpDateUtil.getBeforeDay(new Date(),4)+" 00:00:00"; endDateStr=SliceUpDateUtil.getBeforeDay(new Date(),0)+" 23:59:59"; } } } } map.put("startDate",startDateStr); map.put("endDate",endDateStr); return map; } /** * @description: 控制台-利润分析应收金额导出明细 * @author: whp **/ @Override public HttpResult receivableExcel(ProfitAnalysisQueryDto profitAnalysisQueryDto) { List list = profitAnalysisMapper.receivableExcel(profitAnalysisQueryDto); String uploadPath = this.uploadPath + "/excel/"; Path path = Paths.get(uploadPath); if (!Files.exists(path)) { try { Files.createDirectories(path); } catch (IOException e) { e.printStackTrace(); } } String fileName = EasyExcelUtils.downExcel(uploadPath, "应收明细", ReceivableExcel.class, list); return HttpResult.ok("", uploadUrl + "excel/" + fileName); } /** * @description: 控制台-利润分析实付金额导出明细 * @author: whp **/ @Override public HttpResult payAmountExcel(ProfitAnalysisQueryDto profitAnalysisQueryDto) { List list = profitAnalysisMapper.payAmountExcel(profitAnalysisQueryDto); String uploadPath = this.uploadPath + "/excel/"; Path path = Paths.get(uploadPath); if (!Files.exists(path)) { try { Files.createDirectories(path); } catch (IOException e) { e.printStackTrace(); } } String fileName = EasyExcelUtils.downExcel(uploadPath, "实付明细", PayAmountExcel.class, list); return HttpResult.ok("", uploadUrl + "excel/" + fileName); } }