package com.imed.costaccount.service.impl; import cn.hutool.core.collection.CollUtil; import cn.hutool.core.date.DateTime; import cn.hutool.core.date.DateUtil; import cn.hutool.core.util.StrUtil; import cn.hutool.poi.excel.ExcelWriter; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.imed.costaccount.common.enums.DateStyleEnum; import com.imed.costaccount.common.exception.CostException; import com.imed.costaccount.common.util.BeanUtil; import com.imed.costaccount.common.util.DateUtils; import com.imed.costaccount.common.util.PageUtils; import com.imed.costaccount.common.util.UserContext; import com.imed.costaccount.constants.NumberConstant; import com.imed.costaccount.mapper.CostDepartmentProfitMapper; import com.imed.costaccount.model.*; import com.imed.costaccount.model.vo.AllocationQueryReportVO; import com.imed.costaccount.model.vo.CostDepartmentProfitVO; import com.imed.costaccount.service.*; import org.apache.poi.ss.usermodel.Sheet; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Propagation; import org.springframework.transaction.annotation.Transactional; import java.math.BigDecimal; import java.util.*; import java.util.concurrent.atomic.AtomicReference; import java.util.stream.Collectors; @Service("costDepartmentProfitService") public class CostDepartmentProfitServiceImpl extends ServiceImpl implements CostDepartmentProfitService { private final ReportFormService reportFormService; private final IncomeCollectionService incomeCollectionService; private final CostShareLevelService costShareLevelService; private final ResponsibilityService responsibilityService; private final ReportRelationService reportRelationService; private final AllocationService allocationService; private final AllocationQueryService allocationQueryService; public CostDepartmentProfitServiceImpl(ReportFormService reportFormService, IncomeCollectionService incomeCollectionService, CostShareLevelService costShareLevelService, ResponsibilityService responsibilityService, ReportRelationService reportRelationService, AllocationService allocationService, AllocationQueryService allocationQueryService) { this.reportFormService = reportFormService; this.incomeCollectionService = incomeCollectionService; this.costShareLevelService = costShareLevelService; this.responsibilityService = responsibilityService; this.reportRelationService = reportRelationService; this.allocationService = allocationService; this.allocationQueryService = allocationQueryService; } /** * 查询科室损益数据 * * @param current * @param pageSize * @param responsibilityCode * @param date * @param hospId * @return */ @Override public PageUtils queryList(Integer current, Integer pageSize, String responsibilityCode, String date, Long hospId) { int year = 0; int month = 0; if (StrUtil.isNotBlank(date)) { Date dateTime = DateUtils.StringToDate(date, DateStyleEnum.YYYY_MM_DD); year = DateUtil.year(dateTime); month = DateUtil.month(dateTime) + 1; } Page departmentProfitPage = new Page<>(current, pageSize); // 查询的时候过过滤那些计算方式是不设置的数据 Page pages = this.page(departmentProfitPage, new QueryWrapper().lambda() .eq(CostDepartmentProfit::getHospId, hospId) .eq(StrUtil.isNotBlank(responsibilityCode), CostDepartmentProfit::getResponsibilityCode, responsibilityCode) .eq(StrUtil.isNotBlank(date), CostDepartmentProfit::getYear, year) .eq(StrUtil.isNotBlank(date), CostDepartmentProfit::getMonth, month) .ne(CostDepartmentProfit::getCalcType, NumberConstant.ZERO).orderByDesc(CostDepartmentProfit::getAmount)); List records = pages.getRecords(); List costDepartmentProfitVOList = BeanUtil.convertList(records, CostDepartmentProfitVO.class); PageUtils pageUtils = new PageUtils(pages); pageUtils.setList(costDepartmentProfitVOList); return pageUtils; } /** * 科室损益计算 * * @param date * @param hospId */ @Override @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Throwable.class) public void setDepartmentProfit(String date, Long hospId) { DateTime parse = DateUtil.parse(date); int year = DateUtil.year(parse); int month = DateUtil.month(parse) + 1; // 先查询指定条件的报表数据 查询损益表的数据 List reportFormList = reportFormService.list(new QueryWrapper().lambda() .eq(ReportForm::getHospId, hospId) .eq(ReportForm::getReportType, NumberConstant.ZERO)); if (CollUtil.isEmpty(reportFormList)) { throw new CostException(500, "损益表未找到"); } // 遍历报表数据根据报表数据计算方式进行计算 // 查询最后一个层级的责任中心 List costShareLevelList = costShareLevelService.list(new QueryWrapper().lambda() .eq(CostShareLevel::getHospId, hospId).orderByDesc(CostShareLevel::getLeverSort)); if (CollUtil.isEmpty(costShareLevelList)) { throw new CostException(500, "分摊层级未设置"); } // TODO 可能多个 Long id = costShareLevelList.get(0).getId(); // 查询责任中心里面是这个层级的所有的收益中心 List responsibilityList = responsibilityService.list(new QueryWrapper().lambda() .eq(Responsibility::getHospId, hospId).eq(Responsibility::getResponsibilityType, NumberConstant.ONE).eq(Responsibility::getShareId, id)); // 归集后 List incomeList = incomeCollectionService.list(new QueryWrapper().lambda() .eq(IncomeCollection::getHospId, hospId) .eq(year > 0, IncomeCollection::getYear, year).eq(month > 0, IncomeCollection::getMonth, month)); if (CollUtil.isEmpty(incomeList)) { throw new CostException(500, "归集后数据不存在"); } Map> reportRelationMap = reportRelationService.list(new QueryWrapper().lambda().eq(ReportRelation::getHospId, hospId)).stream().collect(Collectors.groupingBy(ReportRelation::getReportId)); // 分摊后的数据说明是分摊后的数据 List allocationQueryList = allocationQueryService.list(new QueryWrapper().lambda().eq(AllocationQuery::getHospId, hospId) .eq(year > 0, AllocationQuery::getDateYear, year) .eq(month > 0, AllocationQuery::getDateMonth, month) ); if (CollUtil.isEmpty(allocationQueryList)) { throw new CostException(500, "分摊后数据不存在"); } // 封装数据 List allocationQueryReportVOList = BeanUtil.convertList(allocationQueryList, AllocationQueryReportVO.class); allocationQueryReportVOList.forEach(i -> { i.setAccountingCodes(Arrays.asList(i.getAccountingCode().split(StrUtil.COMMA))); i.setAccountingNames(Arrays.asList(i.getAccountingName().split(StrUtil.COMMA))); }); // 查询分摊的报表数据 后面的计算方式需要使用 小计等需要使用 List allocationList = allocationService.list(new QueryWrapper().lambda().eq(Allocation::getHospId, hospId) .eq(year > 0, Allocation::getDateYear, year).eq(month > 0, Allocation::getDateMonth, month)); if (CollUtil.isEmpty(allocationList)) { throw new CostException(500, "分摊报表数据不存在"); } // 查询所有指定类型的损益表 // 每个责任中心对应报表都要生成记录 // 封装需要设置的数据 List list = new ArrayList<>(); int finalYear = year; int finalMonth = month; responsibilityList.forEach(i -> { reportFormList.forEach(j -> { CostDepartmentProfitVO costDepartmentProfitVO = new CostDepartmentProfitVO(); costDepartmentProfitVO.setYear(finalYear); costDepartmentProfitVO.setMonth(finalMonth); costDepartmentProfitVO.setReportId(j.getId()); costDepartmentProfitVO.setReportNum(j.getNum()); costDepartmentProfitVO.setCalcType(j.getCalcType()); costDepartmentProfitVO.setReportName(j.getReportName()); costDepartmentProfitVO.setCalcFormula(j.getCalcFormula()); costDepartmentProfitVO.setReportParentId(j.getParentId()); costDepartmentProfitVO.setResponsibilityCode(i.getResponsibilityCode()); costDepartmentProfitVO.setResponsibilityName(i.getResponsibilityName()); costDepartmentProfitVO.setCostType(NumberConstant.ONE); costDepartmentProfitVO.setIncomeType(NumberConstant.ONE); costDepartmentProfitVO.setHospId(hospId); list.add(costDepartmentProfitVO); }); }); Map> listMap = list.stream().collect(Collectors.groupingBy(CostDepartmentProfitVO::getReportId)); List allList = BeanUtil.convertList(list, CostDepartmentProfitVO.class); // 记录每一次计算的钱 list.forEach(i -> { Long reportId = i.getReportId(); Integer calcType = i.getCalcType(); if (NumberConstant.ONE.equals(calcType)){ // TODO 按照会计科目进行计算 i.setAmount(setAccountReportData(i, incomeList, allocationQueryReportVOList, reportRelationMap,allList)); }else if (NumberConstant.TWO.equals(calcType)){ // TODO 按照分摊层级进行计算 i.setAmount(setShareLevelReportData(i, costShareLevelList, reportRelationMap, allocationList,allList)); }else if (NumberConstant.THREE.equals(calcType)){ // TODO 按照小计进行计算 i.setAmount(setSubtotal(i, costShareLevelList, listMap, list, incomeList, allocationQueryReportVOList, reportRelationMap, allocationList,allList)); }else if (NumberConstant.FOUR.equals(calcType)){ // TODO 按照计算公式进行计算 i.setAmount(setCalculation(i, list, costShareLevelList, listMap, incomeList, allocationQueryReportVOList, reportRelationMap, allocationList,allList)); }else if (NumberConstant.FIVE.equals(calcType)){ // TODO 按照责任中心进行计算 i.setAmount(setResponsibilityCode(i, reportRelationMap, allocationList,allList)); }else { i.setAmount(new BigDecimal("0.0000")); } // switch (calcType) { // case 1: // // break; // case 2: // // break; // case 3: // // break; // case 4: // // break; // case 5: // // break; // default: // break; // } }); // 删除这个年月的数据 this.remove(new QueryWrapper().lambda().eq(CostDepartmentProfit::getHospId, hospId) .eq(CostDepartmentProfit::getYear, year).eq(CostDepartmentProfit::getMonth, month)); // 添加数据 List costDepartmentProfits = BeanUtil.convertList(list, CostDepartmentProfit.class); long l = System.currentTimeMillis(); costDepartmentProfits.forEach(i -> { i.setCreateTime(l); }); this.saveBatch(costDepartmentProfits); } /** * 科室损益计算导出 * * @param writer * @param sheet * @param date */ @Override public void getDepartmentProfit(ExcelWriter writer, Sheet sheet, String date) { Long hospId = UserContext.getHospId(); UserContext.getHospId(); //先展示所有责任中心 非汇总中心 收益中心的责任中心 // 查询所有的节点 List responsibilityList = responsibilityService.list(new QueryWrapper().lambda().eq(Responsibility::getHospId, hospId)); if (CollUtil.isEmpty(responsibilityList)){ throw new CostException(500,"责任中心不存在"); } // 设置表头 Map> responsibilityMap = responsibilityList.stream().collect(Collectors.groupingBy(Responsibility::getId)); List responsibilities = responsibilityList.stream().filter(i -> NumberConstant.TWO.equals(i.getIsGatherCenter()) && NumberConstant.ONE.equals(i.getResponsibilityType())).collect(Collectors.toList()); Map> responsibilityParentMap = responsibilities.stream().collect(Collectors.groupingBy(Responsibility::getParentId)); Set keySet = responsibilityParentMap.keySet(); int column=2; for (Long parentId:keySet){ // 同一父节点的叶子节点数据 List list = responsibilityParentMap.get(parentId); for (int i=0;i responsibilityList1 = responsibilityMap.get(list.get(i).getParentId()); if (CollUtil.isEmpty(responsibilityList1)) { writer.writeCellValue(column, 0, null); } else { // 父层级责任中心名称 String responsibilityName = responsibilityList1.get(0).getResponsibilityName(); // 子层级责任中心名称 writer.writeCellValue(column, 0, responsibilityName); } writer.writeCellValue(column, 1, responsibilityName1); column++; } } writer.merge(1,1,0,1,"项目",false); DateTime dateTime = DateUtil.parse(date); int year = DateUtil.year(dateTime); int month = DateUtil.month(dateTime)+1; // 设置列 List departmentProfits = this.list(new QueryWrapper().lambda() .eq(CostDepartmentProfit::getHospId, hospId) .eq(CostDepartmentProfit::getYear, year).eq(CostDepartmentProfit::getMonth, month)); // 用来筛选金额 Map profitMap = departmentProfits.stream().filter(i->i.getReportParentId()!=0L).collect(Collectors.toMap(k -> k.getReportName() + "cost" + k.getResponsibilityName(), synOne -> synOne)); // 报表的父层级报表 Map> departmentParentReportMap = departmentProfits.stream().filter(i -> i.getReportParentId() == 0L) .collect(Collectors.groupingBy(CostDepartmentProfit::getReportId)).entrySet().stream() .sorted(Map.Entry.comparingByKey()).collect( Collectors.toMap( Map.Entry::getKey, Map.Entry::getValue, (oldVal, newVal) -> oldVal, LinkedHashMap::new ) ); // 不是父节点的所有叶子节点 Map> listParentMap = departmentProfits.stream().filter(i -> i.getReportParentId() != 0L).collect(Collectors.groupingBy(CostDepartmentProfit::getReportParentId)); Set ids = departmentParentReportMap.keySet(); // 默认是在第二行开始的 int row=2; int columnNum=0; for (Long id:ids){ String reportParentName = departmentParentReportMap.get(id).get(0).getReportName(); List profitList = listParentMap.get(id); Map> linkedHashMap = profitList.stream().collect(Collectors.groupingBy(CostDepartmentProfit::getReportNum)).entrySet().stream() .sorted(Map.Entry.comparingByKey()).collect( Collectors.toMap( Map.Entry::getKey, Map.Entry::getValue, (oldVal, newVal) -> oldVal, LinkedHashMap::new )); Set reportNums = linkedHashMap.keySet(); for (Integer reportNum:reportNums){ // 这一行要显示的记录 List costDepartmentProfits = linkedHashMap.get(reportNum); // 子层级扥报表名称 String reportName = costDepartmentProfits.get(0).getReportName(); for (int i=0;i list, List allocationQueryReportVOList, Map> reportRelationMap,List allList) { // 在报表关联里面查询当前报表关联的 Long reportId = i.getReportId(); List reportRelationList = reportRelationMap.get(reportId); AtomicReference sum = new AtomicReference<>(new BigDecimal("0.000")); if (CollUtil.isNotEmpty(reportRelationList)) { // 获取对应的会计科目信息 筛选会计科目的Code List accountList = reportRelationList.stream().map(ReportRelation::getRelationCode).collect(Collectors.toList()); // 查找在归集数据里面当前责任中心对应的这些会计科目的金额 List incomeCollectionList = list.stream().filter(income -> income.getResponsibilityCode().equals(i.getResponsibilityCode()) && accountList.contains(income.getAccountingCode())).collect(Collectors.toList()); // 需要查询分摊后的表 // List collect = allocationQueryReportVOList.stream().filter(m -> m.getResponsibilityCode().equals(i.getResponsibilityCode())).collect(Collectors.toList()); // List collect1 = collect.stream().filter(m -> !Collections.disjoint(accountList, m.getAccountingCodes())).collect(Collectors.toList()); List reportVOList = allocationQueryReportVOList.stream().filter(m -> m.getResponsibilityCode().equals(i.getResponsibilityCode()) && !Collections.disjoint(accountList, m.getAccountingCodes())).collect(Collectors.toList()); if (CollUtil.isNotEmpty(incomeCollectionList)) { incomeCollectionList.forEach(m -> { sum.updateAndGet(v -> v.add(m.getAmount())); }); } // 成本减 if (CollUtil.isNotEmpty(reportVOList)) { reportVOList.forEach(m -> { sum.updateAndGet(v -> v.add(m.getAmount())); }); } } // i.setAmount(new BigDecimal(sum.toString())); // numMap.put(i.getReportNum()+i.getResponsibilityCode(),new BigDecimal(sum.toString())); return sum.get(); } /** * 按照分摊层级进行计算 * 按照分摊层级计算 报表分摊层级是当前的层级 并且目标责任中心失败当前责任中心 */ private BigDecimal setShareLevelReportData(CostDepartmentProfitVO i, List costShareLevelList, Map> reportRelationMap, List allocationList,List allList) { List reportRelationList = reportRelationMap.get(i.getReportId()); AtomicReference sum = new AtomicReference<>(new BigDecimal("0.000")); if (CollUtil.isNotEmpty(reportRelationList)) { // 找到对应的分摊层级的Id 但是分摊报表里面存的是分摊层级的序号 List shareLevelIds = reportRelationList.stream().map(ReportRelation::getRelationCode).map(Long::valueOf).collect(Collectors.toList()); List levelShortList = costShareLevelList.stream().filter(m -> shareLevelIds.contains(m.getId())).map(CostShareLevel::getLeverSort).collect(Collectors.toList()); if (CollUtil.isNotEmpty(levelShortList)) { // 查询报表里面是当前分摊层级的数据 List allocations = allocationList.stream().filter(m -> levelShortList.contains(m.getLevelSort()) && m.getTargetResponsibilityCode().equals(i.getResponsibilityCode())).collect(Collectors.toList()); if (CollUtil.isNotEmpty(allocations)) { // allocations.forEach(m -> { // sum.updateAndGet(v -> v.add(m.getAmount())); // }); BigDecimal reduce = allocations.stream().map(Allocation::getAmount).reduce(BigDecimal.ZERO, BigDecimal::add); sum.set(reduce); } } } // i.setAmount(new BigDecimal(sum.toString())); return sum.get(); } /** * 按照责任中心进行计算 * 原始责任中心是设置的责任中心 目标责任中心是报表的责任中心 * 查询分摊报表里面目标责任中心是当前责任中心 报表责任中心是当前设置的责任中心 */ public BigDecimal setResponsibilityCode(CostDepartmentProfitVO costDepartmentProfitVO, Map> reportRelationMap, List allocationList,List allList) { // 获取当前报表对应的责任中心 List reportRelationList = reportRelationMap.get(costDepartmentProfitVO.getReportId()); AtomicReference sum = new AtomicReference<>(new BigDecimal("0.000")); if (CollUtil.isNotEmpty(reportRelationList)) { // 获取对应的责任中心的Code集合 这个是设置的责任中心 List responsibilityCodes = reportRelationList.stream().map(ReportRelation::getRelationCode).collect(Collectors.toList()); if (CollUtil.isNotEmpty(responsibilityCodes)) { // 查询报表里面是当前分摊层级的数据 List allocations = allocationList.stream().filter(i -> i.getTargetResponsibilityCode().equals(costDepartmentProfitVO.getResponsibilityCode()) && responsibilityCodes.contains(i.getResponsibilityCode())).collect(Collectors.toList()); if (CollUtil.isNotEmpty(allocations)) { BigDecimal reduce = allocations.stream().map(Allocation::getAmount).reduce(BigDecimal.ZERO, BigDecimal::add); sum.set(reduce); // allocations.forEach(m -> { // sum.updateAndGet(v -> v.add(m.getAmount())); // }); } } } // costDepartmentProfitVO.setAmount(new BigDecimal(sum.toString())); return sum.get(); } /** * 按照小计的计算方式 * 同一个目录下相同的其他金额的和 */ public BigDecimal setSubtotal(CostDepartmentProfitVO costDepartmentProfitVO, List costShareLevelList, Map> listMap, List profitVOS, List list, List allocationQueryReportVOList, Map> reportRelationMap, List allocationList,List allList) { // 因为报表是按照报表项目的升序进行排序的 前面的报表是已经进行计算了的 // 查询当前报表的父层级id Long reportParentId = costDepartmentProfitVO.getReportParentId(); String responsibilityCode = costDepartmentProfitVO.getResponsibilityCode(); // 查询报表里面在当前父层级下的并且不是自己的报表项目 List costDepartmentProfitVOS = allList.stream().filter(i -> i.getReportParentId().equals(reportParentId) && i.getResponsibilityCode().equals(responsibilityCode) && !NumberConstant.THREE.equals(i.getCalcType())).collect(Collectors.toList()); AtomicReference sum = new AtomicReference<>(new BigDecimal("0.0000")); // 遍历数据 之前的已经经过了计算 costDepartmentProfitVOS.forEach(i -> { Long reportId = i.getReportId(); List costDepartmentProfitVOS1 = listMap.get(reportId); if (CollUtil.isEmpty(costDepartmentProfitVOS1)) { throw new CostException(500, "报表未找到"); } BigDecimal amount = getAmount(costDepartmentProfitVOS1, costShareLevelList, responsibilityCode, list, allocationQueryReportVOList, reportRelationMap, allocationList, listMap,allList); sum.set(amount.add(sum.get()));; }); // costDepartmentProfitVO.setAmount(new BigDecimal(sum.toString())); return sum.get(); } /*** * 按照计算方式进行计算 */ public BigDecimal setCalculation(CostDepartmentProfitVO costDepartmentProfitVO, List costDepartmentProfitVOList, List costShareLevelList, Map> listMap, List list, List allocationQueryReportVOList, Map> reportRelationMap, List allocationList,List allList) { // 获取当前报表的计算方式 [1]+[2]类型/ [1]-[2] String calcFormula = costDepartmentProfitVO.getCalcFormula(); String responsibilityCode = costDepartmentProfitVO.getResponsibilityCode(); String replace = calcFormula.replace("[", "").replace("]", "").replace("+", ",").replace("-", ",-"); List calcFormulaList = Arrays.stream(replace.split(StrUtil.COMMA)).map(Integer::valueOf).collect(Collectors.toList()); // 查询这个编号集合的报表 AtomicReference bigDecimal = new AtomicReference<>(new BigDecimal("0.0000")); calcFormulaList.forEach(calc -> { Integer calcNum=Math.abs(calc); List reportIdList = allList.stream().filter(i -> i.getResponsibilityCode().equals(responsibilityCode) && calcNum.equals(i.getReportNum())).map(CostDepartmentProfitVO::getReportId).collect(Collectors.toList()); if (CollUtil.isNotEmpty(reportIdList)) { reportIdList.forEach(i -> { List profitVOS = listMap.get(i); if (CollUtil.isEmpty(profitVOS)) { throw new CostException(500, "报表未找到"); } BigDecimal amount = getAmount(profitVOS, costShareLevelList, responsibilityCode, list, allocationQueryReportVOList, reportRelationMap, allocationList, listMap,allList); if (calc>0){ bigDecimal.updateAndGet(v -> v.add(amount)); }else { bigDecimal.updateAndGet(v -> v.subtract(amount)); } }); } }); return bigDecimal.get(); } /** * 判断是那种计算方式 调用方法进行计算 */ public BigDecimal getAmount(List profitVOS, List costShareLevelList, String responsibilityCode, List list, List allocationQueryReportVOList, Map> reportRelationMap, List allocationList, Map> listMap,List allList) { BigDecimal bigDecimal = new BigDecimal("0.0000"); // 在对这个报表进行过滤 List costDepartmentProfitVOS = profitVOS.stream().filter(i -> i.getResponsibilityCode().equals(responsibilityCode)).collect(Collectors.toList()); // 都一个就是 CostDepartmentProfitVO costDepartmentProfitVO = costDepartmentProfitVOS.get(0); Integer calcType = costDepartmentProfitVO.getCalcType(); if (NumberConstant.ONE.equals(calcType)) { // 调用计算的方法 按照会计科目 bigDecimal = setAccountReportData(costDepartmentProfitVO, list, allocationQueryReportVOList, reportRelationMap,allList); } else if (NumberConstant.TWO.equals(calcType)) { // 按照分摊层级 bigDecimal = setShareLevelReportData(costDepartmentProfitVO, costShareLevelList, reportRelationMap, allocationList,allList); } else if (NumberConstant.THREE.equals(calcType)) { // 小计 bigDecimal = setSubtotal(costDepartmentProfitVO, costShareLevelList, listMap, profitVOS, list, allocationQueryReportVOList, reportRelationMap, allocationList,allList); } else if (NumberConstant.FIVE.equals(calcType)) { // 按照责任中心 bigDecimal = setResponsibilityCode(costDepartmentProfitVO, reportRelationMap, allocationList,allList); }else if (NumberConstant.FOUR.equals(calcType)){ bigDecimal=setCalculation(costDepartmentProfitVO,costDepartmentProfitVOS,costShareLevelList,listMap,list,allocationQueryReportVOList,reportRelationMap,allocationList,allList); } return bigDecimal; } }