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, "分摊层级未设置"); } 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)); // 分摊后的数据getOriginType等于2说明是分摊后的数据 List allocationQueryList = allocationQueryService.list(new QueryWrapper().lambda().eq(AllocationQuery::getHospId, hospId) .eq(year > 0, AllocationQuery::getDateYear, year) .eq(month > 0, AllocationQuery::getDateMonth, month) .eq(AllocationQuery::getOriginType, NumberConstant.TWO)); 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.forEach(i -> { Integer calcType = i.getCalcType(); if (NumberConstant.ONE.equals(calcType)){ // TODO 按照会计科目进行计算 i.setAmount(setAccountReportData(i, incomeList, allocationQueryReportVOList, reportRelationMap)); }else if (NumberConstant.TWO.equals(calcType)){ // TODO 按照分摊层级进行计算 i.setAmount(setShareLevelReportData(i, costShareLevelList, reportRelationMap, allocationList)); }else if (NumberConstant.THREE.equals(calcType)){ // TODO 按照小计进行计算 i.setAmount(setSubtotal(i, costShareLevelList, listMap, list, incomeList, allocationQueryReportVOList, reportRelationMap, allocationList)); }else if (NumberConstant.FOUR.equals(calcType)){ // TODO 按照计算公式进行计算 i.setAmount(setCalculation(i, list, costShareLevelList, listMap, incomeList, allocationQueryReportVOList, reportRelationMap, allocationList)); }else if (NumberConstant.FIVE.equals(calcType)){ // TODO 按照责任中心进行计算 i.setAmount(setResponsibilityCode(i, reportRelationMap, allocationList)); }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) { 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; } Long hospId = UserContext.getHospId(); List costDepartmentProfitList = this.list(new QueryWrapper().lambda().eq(CostDepartmentProfit::getHospId, hospId).eq(StrUtil.isNotBlank(date), CostDepartmentProfit::getYear, year).eq(StrUtil.isNotBlank(date), CostDepartmentProfit::getMonth, month)); // 16个责任中心名称 List responsibilityNameList = costDepartmentProfitList.stream().map(CostDepartmentProfit::getResponsibilityName).distinct().sorted().collect(Collectors.toList()); Map> responsibilityNameMap = costDepartmentProfitList.stream().collect(Collectors.groupingBy(CostDepartmentProfit::getResponsibilityName)); for (int i = 0; i < responsibilityNameList.size(); i++) { String responsibilityName = responsibilityNameList.get(i); List departmentProfits = responsibilityNameMap.get(responsibilityName); writer.merge(0, 2, 0, departmentProfits.size() + 2, responsibilityName, false); } System.out.println(responsibilityNameList); } /** * 按照会计科目进行计算 * * @param i */ private BigDecimal setAccountReportData(CostDepartmentProfitVO i, List list, List allocationQueryReportVOList, Map> reportRelationMap) { // 在报表关联里面查询当前报表关联的 Long reportId = i.getReportId(); List reportRelationList = reportRelationMap.get(i.getReportId()); 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 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 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())); }); } } } i.setAmount(new BigDecimal(sum.toString())); return sum.get(); } /** * 按照责任中心进行计算 * 原始责任中心是设置的责任中心 目标责任中心是报表的责任中心 * 查询分摊报表里面目标责任中心是当前责任中心 报表责任中心是当前设置的责任中心 */ public BigDecimal setResponsibilityCode(CostDepartmentProfitVO costDepartmentProfitVO, Map> reportRelationMap, List allocationList) { // 获取当前报表对应的责任中心 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)) { 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) { // 因为报表是按照报表项目的升序进行排序的 前面的报表是已经进行计算了的 // 查询当前报表的父层级id Long reportParentId = costDepartmentProfitVO.getReportParentId(); String responsibilityCode = costDepartmentProfitVO.getResponsibilityCode(); // 查询报表里面在当前父层级下的并且不是自己的报表项目 List costDepartmentProfitVOS = profitVOS.stream().filter(i -> i.getReportParentId().equals(reportParentId) && i.getResponsibilityCode().equals(responsibilityCode) && !NumberConstant.THREE.equals(i.getCostType())).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(profitVOS, costShareLevelList, responsibilityCode, list, allocationQueryReportVOList, reportRelationMap, allocationList, listMap); sum.updateAndGet(v -> v.add(amount)); }); 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) { // 获取当前报表的计算方式 [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 = costDepartmentProfitVOList.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); 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) { 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 costType = costDepartmentProfitVO.getCostType(); if (NumberConstant.ONE.equals(costType)) { // 调用计算的方法 按照会计科目 bigDecimal = setAccountReportData(costDepartmentProfitVO, list, allocationQueryReportVOList, reportRelationMap); } else if (NumberConstant.TWO.equals(costType)) { // 按照分摊层级 bigDecimal = setShareLevelReportData(costDepartmentProfitVO, costShareLevelList, reportRelationMap, allocationList); } else if (NumberConstant.THREE.equals(costType)) { // 小计 bigDecimal = setSubtotal(costDepartmentProfitVO, costShareLevelList, listMap, profitVOS, list, allocationQueryReportVOList, reportRelationMap, allocationList); } else if (NumberConstant.FIVE.equals(costType)) { // 按照责任中心 bigDecimal = setResponsibilityCode(costDepartmentProfitVO, reportRelationMap, allocationList); } return bigDecimal; } }