package com.kcim.service.impl; import cn.hutool.core.collection.CollUtil; import cn.hutool.core.date.DatePattern; import cn.hutool.core.date.DateTime; import cn.hutool.core.date.DateUtil; import cn.hutool.core.util.ReUtil; import cn.hutool.core.util.StrUtil; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; 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.google.common.collect.ImmutableMap; import com.kcim.common.constants.*; import com.kcim.common.enums.*; import com.kcim.common.exception.CostException; import com.kcim.common.file.MinioConfig; import com.kcim.common.file.MinioFileUtil; import com.kcim.common.util.*; import com.kcim.common.util.excel.ExcelPoiUtil; import com.kcim.common.util.excel.entity.ColEntity; import com.kcim.common.util.excel.entity.TitleEntity; import com.kcim.dao.mapper.HospProfitAndLossMapper; import com.kcim.dao.model.*; import com.kcim.service.*; import com.kcim.vo.*; import com.kcim.web.reponse.BatchCostProfitResponse; import lombok.extern.slf4j.Slf4j; import org.apache.commons.fileupload.FileItem; import org.apache.commons.fileupload.FileItemFactory; import org.apache.commons.fileupload.disk.DiskFileItemFactory; import org.apache.poi.hssf.usermodel.HSSFWorkbook; import org.jetbrains.annotations.NotNull; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Propagation; import org.springframework.transaction.annotation.Transactional; import org.springframework.util.CollectionUtils; import org.springframework.util.ObjectUtils; import org.springframework.util.StringUtils; import org.springframework.web.multipart.MultipartFile; import org.springframework.web.multipart.commons.CommonsMultipartFile; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.math.BigDecimal; import java.math.RoundingMode; import java.text.DecimalFormat; import java.util.*; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.atomic.AtomicReference; import java.util.function.UnaryOperator; import java.util.stream.Collectors; @Slf4j @Service("hospProfitAndLossService") public class HospProfitAndLossServiceImpl extends ServiceImpl implements HospProfitAndLossService { // @Value("${file.filelocal}") // private String hospProfitReportUrl; // // @Value("${file.serverUrl}") // private String serverUrl; private final ReportFormService reportFormService; private final IncomeCollectionService collectionService; private final AllocationQueryService allocationQueryService; private final AllocationService allocationService; private final ReportRelationService reportRelationService; private final CostShareLevelService shareLevelService; private final CostOtherPaymentsDataService otherPaymentsDataService; private final ResponsibilityService responsibilityService; private final CostAccountShareService accountShareService; private final FileRecordService fileRecordService; private final SqlService sqlService; private final CenterService centerService; private final MinioConfig minioConfig; private final MinioFileUtil minioFileUtil; public HospProfitAndLossServiceImpl(ReportFormService reportFormService, IncomeCollectionService collectionService, AllocationQueryService allocationQueryService, AllocationService allocationService, ReportRelationService reportRelationService, CostShareLevelService shareLevelService, CostOtherPaymentsDataService otherPaymentsDataService, ResponsibilityService responsibilityService, CostAccountShareService accountShareService, FileRecordService fileRecordService, MinioConfig minioConfig, MinioFileUtil minioFileUtil, SqlService sqlService, CenterService centerService ) { this.reportFormService = reportFormService; this.collectionService = collectionService; this.allocationQueryService = allocationQueryService; this.allocationService = allocationService; this.reportRelationService = reportRelationService; this.shareLevelService = shareLevelService; this.otherPaymentsDataService = otherPaymentsDataService; this.responsibilityService = responsibilityService; this.accountShareService = accountShareService; this.fileRecordService = fileRecordService; this.minioConfig = minioConfig; this.minioFileUtil = minioFileUtil; this.sqlService=sqlService; this.centerService=centerService; } /** * 计算全院损益 * * @param date yyyy-MM-dd 时间 * @param hospId 医院id */ @Override @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Throwable.class) public void calc(String date, Long hospId) { reportFormService.checkExistLoss(hospId); DateTime parse = DateUtil.parse(date); int year = DateUtil.year(parse); int month = DateUtil.month(parse) + 1; this.remove(new LambdaQueryWrapper().eq(HospProfitAndLoss::getDateYear, year).eq(HospProfitAndLoss::getDateMonth, month).eq(HospProfitAndLoss::getHospId, hospId)); // 得到全院损益计算报表 List reportForms = reportFormService.getListByReportType(hospId, ReportTypeEnum.HOSP_PROFIT_LOSS.getType()); if (CollUtil.isEmpty(reportForms)) { throw new CostException("医院未设置全院损益计算报表"); } // 得到这个月所有收入数据 List incomes = collectionService.getCollectionsByDate(year, month, hospId); if (incomes.isEmpty()) { throw new CostException("医院未归集本月收入数据"); } // 得到这个月的所有成本数据 List allocationQueries = allocationQueryService.getAllByDate(hospId, year, month); if (allocationQueries.isEmpty()) { throw new CostException("医院未分摊本月数据"); } List list = new ArrayList<>(); List parentForms = reportForms.stream().filter(i -> i.getParentId().equals(0L)).collect(Collectors.toList()); for (ReportForm parentForm : parentForms) { Long parentId = parentForm.getId(); List children = reportForms.stream().filter(i -> i.getParentId().equals(parentId)).collect(Collectors.toList()); for (ReportForm child : children) { Integer calcType = child.getCalcType(); if (calcType == CalcTypeEnum.BY_ACCOUNT.getType()) { // 按会计科目计算单的话 calcByAccount(hospId, child, incomes, list, allocationQueries, month, year); } else if (calcType == CalcTypeEnum.BY_SHARE_LEVEL.getType()) { // 分摊层级计算 calcByShareLevel(hospId, child, list, year, month); } else if (calcType == CalcTypeEnum.LITTER_COUNT.getType()) { // 处理小计 todo 默认认为 小计都是在同一个下面最后一个 calcByLitterCount(year, month, child, children, list, hospId); } else if (calcType == CalcTypeEnum.CALC_FORMULA.getType()) { // 按公式 (要保证总合计放到最后呀) calcByFormula(year, month, child, children, list); } else if (calcType == CalcTypeEnum.BY_RESPONSIBILITY.getType()) { // 责任中心 calcByResponsibility(hospId, child, allocationQueries, list, year, month); } else if (calcType == CalcTypeEnum.NO_CONFIG.getType()) { // 不设置不计算 } else { } } } // 处理医院其他收支 List otherPaymentsDatas = otherPaymentsDataService.getByMonth(year, month, hospId); if (!otherPaymentsDatas.isEmpty()) { otherPaymentsDatas.forEach(ele -> { HospProfitAndLoss loss = new HospProfitAndLoss(); loss.setDateYear(year).setDateMonth(month).setReportName(ele.getPaymentsName()).setReportNum(ele.getId().intValue()) .setCreateTime(System.currentTimeMillis()).setAmount(ele.getTotalAmount()).setHospId(hospId); // if (ele.getPaymentsType() == 2) { // loss.setAmount(BigDecimal.ZERO.subtract(ele.getTotalAmount())); // } list.add(loss); }); } this.saveBatch(list); } /** * 计算全院损益 * @param date yyyy-MM-dd 时间 * @param hospId 医院id * @param reportType 报表类型 */ @Override public void calcHospProfit(String date, Long hospId, Integer reportType){ //需要用代码计算全院损益时 if(IsNeedCalc(reportType)){ //计算全院损益 calcHospProfitAction(date,hospId,reportType); //计算同环比 handleSpecificMonthsCalculation(hospId, date, reportType); } execHospProfitSql(date,reportType); } @Transactional(rollbackFor = Throwable.class, propagation = Propagation.REQUIRED) public void calcHospProfitAction(String date, Long hospId, Integer reportType) { List leafResp = responsibilityService.getLeafResp(hospId); DateTime parse = DateUtil.parse(date); int year = DateUtil.year(parse); int month = DateUtil.month(parse) + 1; this.remove( new LambdaQueryWrapper() .eq(HospProfitAndLoss::getDateYear, year) .eq(HospProfitAndLoss::getDateMonth, month) .eq(HospProfitAndLoss::getHospId, hospId) .eq(HospProfitAndLoss::getReportType, reportType) ); // 得到全院损益计算报表 List reportForms = reportFormService.getListByReportType(hospId, reportType); if (CollUtil.isEmpty(reportForms)) { throw new CostException("医院未设置全院损益计算报表"); } reportFormService.checkExistLoss(hospId,reportType); // 得到这个月所有收入数据 List incomes = collectionService.getCollectionsByDate(year, month, hospId); if (incomes.isEmpty()) { throw new CostException("医院未归集本月收入数据"); } Map> reportRelationMap = reportRelationService.list(new QueryWrapper().lambda().eq(ReportRelation::getHospId, hospId)).stream().collect(Collectors.groupingBy(ReportRelation::getReportId)); // 得到这个月的所有成本数据 List allocationQueries = allocationQueryService.getAllByDate(hospId, year, month); if (allocationQueries.isEmpty()) { throw new CostException("医院未分摊本月数据"); } List allocationQueryReportVOList = BeanUtil.convertList(allocationQueries, 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 costShareLevelList = shareLevelService.list(new QueryWrapper().lambda() .eq(CostShareLevel::getHospId, hospId).orderByDesc(CostShareLevel::getLeverSort)); if (CollUtil.isEmpty(costShareLevelList)) { throw new CostException(500, "分摊层级未设置"); } List listVo = new ArrayList<>(); // List parentForms = reportForms.stream().filter(i -> i.getParentId().equals(0L)).collect(Collectors.toList()); int finalYear = year; int finalMonth = month; leafResp.forEach(i -> { reportForms.forEach(j -> { HospProfitAndLossVo hospProfitAndLossVo = new HospProfitAndLossVo(); hospProfitAndLossVo.setDateYear(finalYear); hospProfitAndLossVo.setDateMonth(finalMonth); hospProfitAndLossVo.setReportNum(j.getNum()); hospProfitAndLossVo.setReportName(j.getReportName()); hospProfitAndLossVo.setResponsibilityCode(i.getResponsibilityCode()); hospProfitAndLossVo.setResponsibilityName(i.getResponsibilityName()); hospProfitAndLossVo.setCostType(NumberConstant.ZERO); hospProfitAndLossVo.setIncomeType(NumberConstant.ZERO); hospProfitAndLossVo.setHospId(hospId); hospProfitAndLossVo.setType(j.getCostType()); hospProfitAndLossVo.setFraction(j.getFraction()); hospProfitAndLossVo.setReportId(j.getId()); hospProfitAndLossVo.setReportNum(j.getNum()); hospProfitAndLossVo.setCalcType(j.getCalcType()); hospProfitAndLossVo.setReportName(j.getReportName()); hospProfitAndLossVo.setCalcFormula(j.getCalcFormula()); hospProfitAndLossVo.setReportParentId(j.getParentId()); listVo.add(hospProfitAndLossVo); }); }); Map> listMap = listVo.stream().collect(Collectors.groupingBy(HospProfitAndLossVo::getReportId)); List allList = BeanUtil.convertList(listVo, HospProfitAndLossVo.class); // 记录每一次计算的钱 //所有小计 总计单独处理 listVo.forEach(i -> { Integer calcType = i.getCalcType(); if (NumberConstant.ONE.equals(calcType)) { // TODO 按照会计科目进行计算 i.setAmount(setAccountReportData(i, incomes, allocationQueryReportVOList, reportRelationMap)); } else if (NumberConstant.TWO.equals(calcType)) { // TODO 按照分摊层级进行计算 i.setAmount(setShareLevelReportData(i, reportRelationMap, allocationList)); } else if (NumberConstant.THREE.equals(calcType)) { // TODO 按照小计进行计算 i.setAmount(setSubtotal(i, costShareLevelList, listMap, listVo, incomes, allocationQueryReportVOList, reportRelationMap, allocationList, allList)); } else if (NumberConstant.FOUR.equals(calcType)) { // TODO 按照计算公式进行计算 // i.setAmount(setCalculation(i, listVo, costShareLevelList, listMap, incomes, allocationQueryReportVOList, reportRelationMap, allocationList, allList)); } else if (NumberConstant.FIVE.equals(calcType)) { // TODO 按照责任中心进行计算 i.setAmount(setResponsibilityCode(i, reportRelationMap, allocationList, allList)); } else { i.setAmount(new BigDecimal("0.000000")); } }); //计算占比 if (CollectionUtils.isEmpty(listVo)) { return; } List listSum = new ArrayList<>(); //把所有数据按报表项目汇总 for (ReportForm j : reportForms) { HospProfitAndLossVo hospProfitAndLossVo = new HospProfitAndLossVo(); hospProfitAndLossVo.setDateYear(finalYear); hospProfitAndLossVo.setDateMonth(finalMonth); hospProfitAndLossVo.setReportNum(j.getNum()); hospProfitAndLossVo.setReportName(j.getReportName()); hospProfitAndLossVo.setCostType(NumberConstant.ZERO); hospProfitAndLossVo.setIncomeType(NumberConstant.ZERO); hospProfitAndLossVo.setHospId(hospId); hospProfitAndLossVo.setType(j.getCostType()); hospProfitAndLossVo.setFraction(j.getFraction()); hospProfitAndLossVo.setReportId(j.getId()); hospProfitAndLossVo.setReportNum(j.getNum()); hospProfitAndLossVo.setCalcType(j.getCalcType()); hospProfitAndLossVo.setReportName(j.getReportName()); hospProfitAndLossVo.setCalcFormula(j.getCalcFormula()); hospProfitAndLossVo.setReportParentId(j.getParentId()); listSum.add(hospProfitAndLossVo); } Map> reportNumGroup = listVo.stream().collect(Collectors.groupingBy(HospProfitAndLossVo::getReportNum)); Map reportNumSumMap = new HashMap<>(); reportNumGroup.forEach((reportNum, hospProfitAndLossList) -> { AtomicReference sum = new AtomicReference<>(new BigDecimal("0.000000")); for (HospProfitAndLossVo hospProfitAndLoss : hospProfitAndLossList) { if (hospProfitAndLoss.getAmount() != null) { sum.updateAndGet(f -> f.add(hospProfitAndLoss.getAmount())); } } reportNumSumMap.put(reportNum, sum.get()); }); for (HospProfitAndLossVo costProfitVo : listSum) { BigDecimal bigDecimal = reportNumSumMap.get(costProfitVo.getReportNum()); if (bigDecimal != null) { costProfitVo.setAmount(bigDecimal); } else { costProfitVo.setAmount(BigDecimal.ZERO.setScale(6, RoundingMode.HALF_UP)); } } //单独计算计算公式数据 setCalculationAmount(listSum); //收入 List profitIncomeList = listSum.stream().filter(f -> f.getType().equals(NumberConstant.ONE)).collect(Collectors.toList()); List profitIncome = costPercent(profitIncomeList); //成本 List profitCostList = listSum.stream().filter(f -> f.getType().equals(NumberConstant.TWO)).collect(Collectors.toList()); List profitCost = costPercent(profitCostList); //不计算项目 List noCompute = listSum.stream().filter(f -> f.getFraction().equals(NumberConstant.THREE)).collect(Collectors.toList()); noCompute.forEach(profitVO -> profitVO.setPercent(null)); List listAllVo = new ArrayList<>(); if (!CollectionUtils.isEmpty(profitIncome) && !CollectionUtils.isEmpty(profitCost) && !CollectionUtils.isEmpty(noCompute)) { listAllVo.addAll(profitIncome); listAllVo.addAll(profitCost); listAllVo.addAll(noCompute); } else if (!CollectionUtils.isEmpty(profitIncome) && !CollectionUtils.isEmpty(noCompute)) { listAllVo.addAll(noCompute); listAllVo.addAll(profitIncome); } else if (!CollectionUtils.isEmpty(profitCost) && !CollectionUtils.isEmpty(noCompute)) { listAllVo.addAll(noCompute); listAllVo.addAll(profitCost); } else if (!CollectionUtils.isEmpty(noCompute)) { listAllVo.addAll(noCompute); } List list = BeanUtil.convertList(listAllVo, HospProfitAndLoss.class); // 处理医院其他收支 List otherPaymentsDatas = otherPaymentsDataService.getByMonth(year, month, hospId); if (!otherPaymentsDatas.isEmpty()) { Optional firstLossReport = reportForms.stream().filter(f -> NumberConstant.ONE.equals(f.getIsLoss())).findFirst(); if(!firstLossReport.isPresent()){ throw new CostException("全院损益报表配置有误,未设置损益项目"); } Optional firstHospProfitAndLoss = list.stream().filter(f -> firstLossReport.get().getNum().equals(f.getReportNum())).findFirst(); if(!firstHospProfitAndLoss.isPresent()){ throw new CostException("全院损益报表配置有误,未找到配置的损益项目"); } for (CostOtherPaymentsData ele : otherPaymentsDatas) { HospProfitAndLoss loss = new HospProfitAndLoss(); loss.setDateYear(year).setDateMonth(month).setReportName(ele.getPaymentsName()).setReportNum((int) (-ele.getId())) .setCreateTime(System.currentTimeMillis()).setAmount(ele.getTotalAmount()).setHospId(hospId) .setResponsibilityName("全院").setResponsibilityCode("-1").setPercent(null).setOriginType(NumberConstant.ONE); if( NumberConstant.ONE.equals(ele.getPaymentsType()) ) { //全院损益项目加上收入 firstHospProfitAndLoss.get().setAmount(firstHospProfitAndLoss.get().getAmount().add(ele.getTotalAmount())); }else{ //全院损益项目减去支出 firstHospProfitAndLoss.get().setAmount(firstHospProfitAndLoss.get().getAmount().subtract(ele.getTotalAmount())); } list.add(loss); } } long l = System.currentTimeMillis(); list.forEach(i -> { i.setCreateTime(l); i.setReportType(reportType); }); this.saveBatch(list); } /** * 是否需要代码计算 * @return */ public boolean IsNeedCalc(Integer reportType) { String parameterValue = centerService.getParameterValue(ParameterConstant.SQL_CALC_REPORT_TYPE); if(StringUtils.isEmpty(parameterValue)){ return true; } //不需计算的报表类型列表 List nonCalcReportTypeList = Arrays.stream(parameterValue.split(SplitConstant.SEPARATOR_VERTICALLINE)).collect(Collectors.toList()); return !nonCalcReportTypeList.contains(String.valueOf(reportType)); } /** * 处理指定月份及关联月份的计算(当前月、下个月、明年同月) * * @param hospId 院区ID * @param computeDate 日期字符串,格式:YYYY-MM * @param shareType 报表类型 */ public void handleSpecificMonthsCalculation(Long hospId, String computeDate, Integer shareType) { // 解析输入的年月 Integer currentYear = ComputeDateUtils.getComputeYear(computeDate); Integer currentMonth = ComputeDateUtils.getComputeMonth(computeDate); // 计算需要处理的期间信息 List periods = calculateAllRelatedPeriods(currentYear, currentMonth); // 获取所有相关的期间数据 Map> allDataMap = loadAllPeriodData(hospId, shareType, periods); // 对每个期间执行计算 for (PeriodInfoVO period : periods) { String currentKey = buildPeriodKey(period.getYear(), period.getMonth()); if (allDataMap.containsKey(currentKey) && !CollectionUtils.isEmpty(allDataMap.get(currentKey))) { List currentRecords = allDataMap.get(currentKey); List prevRecords = getPeriodData(allDataMap, period.getPrevYear(), period.getPrevMonth()); List lastYearRecords = getPeriodData(allDataMap, period.getLastYear(), period.getLastMonth()); // 执行批量计算 calculatePeriodComparisonWithPreloadedData(currentRecords, prevRecords, lastYearRecords); } } } /** * 构建所有需要处理的期间信息 */ private List calculateAllRelatedPeriods(int baseYear, int baseMonth) { List result = new ArrayList<>(); // 添加当前期间 result.add(calculatePeriodInfo(baseYear, baseMonth)); // 下个月 int nextMonth = baseMonth + 1; int nextMonthYear = baseYear; if (baseMonth == 12) { nextMonth = 1; nextMonthYear += 1; } result.add(calculatePeriodInfo(nextMonthYear, nextMonth)); // 明年同月 result.add(calculatePeriodInfo(baseYear + 1, baseMonth)); return result; } /** * 构建单个期间的信息(当前月、上月、去年同期) */ private PeriodInfoVO calculatePeriodInfo(int year, int month) { PeriodInfoVO info = new PeriodInfoVO(); info.setYear( year); info.setMonth( month); // 上期 if (month == 1) { info.setPrevYear(year - 1); info.setPrevMonth(12); } else { info.setPrevYear( year); info.setPrevMonth(month - 1); } // 同期 info.setLastYear(year - 1); info.setLastMonth( month); return info; } /** * 加载所有相关期间的数据(去重处理) */ private Map> loadAllPeriodData(Long hospId, Integer shareType, List periods) { Set allPeriodKeys = new HashSet<>(); // 收集所有需要查询的年月组合 for (PeriodInfoVO period : periods) { allPeriodKeys.add(buildPeriodKey(period.getYear(), period.getMonth())); allPeriodKeys.add(buildPeriodKey(period.getPrevYear(), period.getPrevMonth())); allPeriodKeys.add(buildPeriodKey(period.getLastYear(), period.getLastMonth())); } // 去重后查询 Map> result = new HashMap<>(); Set processedKeys = new HashSet<>(); // 已处理的键集合 for (String key : allPeriodKeys) { if (!processedKeys.contains(key)) { int[] ym = parsePeriodKey(key); List records = getPeriodRecords(hospId, shareType, ym[0], ym[1]); result.put(key, records); processedKeys.add(key); // 标记为已处理 } } return result; } /** * 获取指定期间的数据 * * @param hospId 院区ID * @param shareType 报表类型 * @param year 年份 * @param month 月份 * @return 符合条件的数据列表 */ private List getPeriodRecords(Long hospId, Integer shareType, int year, int month) { return this.list(new QueryWrapper().lambda() .eq(HospProfitAndLoss::getHospId, hospId) .eq(HospProfitAndLoss::getReportType, shareType) .eq(HospProfitAndLoss::getDateYear, year) .eq(HospProfitAndLoss::getDateMonth, month) .eq(HospProfitAndLoss::getDeleteTime, 0)); } /** * 根据年月获取对应的数据(从内存中查找) */ private List getPeriodData(Map> dataMap, int year, int month) { String key = buildPeriodKey(year, month); return dataMap.getOrDefault(key, Collections.emptyList()); } /** * 批量计算同环比及同期金额(使用预加载数据) */ public void calculatePeriodComparisonWithPreloadedData( List currentRecords, List prevRecords, List lastYearRecords) { if (CollectionUtils.isEmpty(currentRecords)) { return; } // 创建报表编号到记录的映射 Map prevMap = new HashMap<>(); for (HospProfitAndLoss record : prevRecords) { String key = buildRecordKey(record); prevMap.put(key, record); } Map lastYearMap = new HashMap<>(); for (HospProfitAndLoss record : lastYearRecords) { String key = buildRecordKey(record); lastYearMap.put(key, record); } // 批量更新数据 for (HospProfitAndLoss record : currentRecords) { String key = buildRecordKey(record); HospProfitAndLoss prevRecord = prevMap.get(key); HospProfitAndLoss lastYearRecord = lastYearMap.get(key); // 设置上期和同期金额 record.setPrevPeriodAmount(prevRecord != null ? prevRecord.getAmount() : BigDecimal.ZERO); record.setSamePeriodAmount(lastYearRecord != null ? lastYearRecord.getAmount() : BigDecimal.ZERO); // 计算环比和同比 record.setMomRate(calculateProfitRate(record.getAmount().subtract(record.getSamePeriodAmount()), record.getPrevPeriodAmount())); record.setYoyRate(calculateProfitRate(record.getAmount().subtract(record.getSamePeriodAmount()), record.getSamePeriodAmount())); } // 批量更新数据库 this.updateBatchById(currentRecords); } /** * 构建期间键(用于存储和检索数据) */ private String buildPeriodKey(int year, int month) { return year + "_" + month; } /** * 解析期间键为年月数组 */ private int[] parsePeriodKey(String key) { String[] parts = key.split("_"); return new int[]{Integer.parseInt(parts[0]), Integer.parseInt(parts[1])}; } /** * 构建记录的唯一标识键(责任码 + 报表编号) */ private String buildRecordKey(HospProfitAndLoss record) { return String.valueOf(record.getReportNum()); } /** * 安全地计算百分比:避免除零错误 */ private BigDecimal calculateProfitRate(BigDecimal current, BigDecimal base) { if (base == null || base.compareTo(BigDecimal.ZERO) == 0) { return BigDecimal.ZERO; } BigDecimal bigDecimal = current.divide(base, 4, RoundingMode.HALF_UP).setScale(4, RoundingMode.HALF_UP); return bigDecimal; } /** * 执行全院损益后续脚本 * @param date * @param reportType */ public void execHospProfitSql(String date,Integer reportType){ Map sqlParameter = new HashMap<>(); sqlParameter.put(SQLParameter.COMPUTE_DATE_CODE, DateUtils.StringToString(date, DateStyleEnum.YYYY_MM)); sqlParameter.put(SQLParameter.REPORT_TYPE_CODE,String.valueOf(reportType)); sqlService.autoExecuteSql(CustomSqlTypeEnum.HOSP_PROFIT_CALC.getCode(),sqlParameter); } // 计算公式中钱 private BigDecimal calcAmount(List list, String calcFormula, ReportForm reportForm) { // 得到所有的编号 String replace = calcFormula.replace("[", "").replace("]", "").replace("-", ",").replace("+", ","); ArrayList numList = CollUtil.newArrayList(replace.split(",")); // 得到编号的map Map numMap = new ConcurrentHashMap<>(); for (int j = 0; j < numList.size(); j++) { numMap.put(j, Integer.parseInt(numList.get(j))); } List expressions = ReUtil.findAll("[^0-9]", "+" + calcFormula.replace("[", "").replace("]", "").trim(), 0) .stream().filter(StrUtil::isNotBlank).collect(Collectors.toList()); // 得到预算表达式 得到所有表达式的Map + - 相关的 Map expressionMap = new ConcurrentHashMap<>(); for (int k = 0; k < expressions.size(); k++) { expressionMap.put(k, expressions.get(k)); } // 数字的索引和表达式的索引累加计算 Set numSet = numMap.keySet(); List nums = new ArrayList<>(numSet); AtomicReference totalAmount = new AtomicReference<>(); totalAmount.set(BigDecimal.ZERO); for (int i = 0; i < nums.size(); i++) { // 编号 Integer num = numMap.get(i); List losses = list.stream().filter(item -> item.getReportNum().equals(num)).collect(Collectors.toList()); if (CollUtil.isEmpty(losses)) { continue; } // log.info("data={}", reportForm); // if (losses.size() != 0 && losses.size() != 1) { // throw new CostException("数据异常"); // } HospProfitAndLoss loss = losses.get(0); BigDecimal amount = loss.getAmount(); String str = expressionMap.get(i); if (str.equals("+")) { totalAmount.set(totalAmount.get().add(amount)); } else { totalAmount.set(totalAmount.get().subtract(amount)); } } return totalAmount.get(); } /** * 按责任中心计算 * * @param hospId 医院id * @param reportForm 报表 * @param allocationQueries 分摊成本数据 * @param list * @param year * @param month */ private void calcByResponsibility(Long hospId, ReportForm reportForm, List allocationQueries, List list, int year, int month) { List responsibilities = reportRelationService.getResponsibilities(reportForm.getId(), hospId); if (responsibilities.isEmpty()) { return; } List accountCodes = responsibilities.stream().map(RelationVO::getCode).collect(Collectors.toList()); AtomicReference calcTotal = new AtomicReference<>(); calcTotal.set(BigDecimal.ZERO); accountCodes.forEach(i -> { BigDecimal costAmount = allocationQueries.stream().filter(j -> i.equals(j.getResponsibilityCode())).map(AllocationQuery::getAmount) .reduce(BigDecimal.ZERO, BigDecimal::add); calcTotal.set(calcTotal.get().add(costAmount)); }); HospProfitAndLoss loss = new HospProfitAndLoss(); loss.setReportName(reportForm.getReportName()).setReportNum(reportForm.getNum()) .setAmount(calcTotal.get()).setCreateTime(System.currentTimeMillis()).setHospId(hospId).setDateYear(year).setDateMonth(month); list.add(loss); } /** * 按计算公式计算 */ private void calcByFormula(Integer year, Integer month, ReportForm child, List reportForms, List list) { // 得到当前下按公式计算的 List calcFormulas = reportForms.stream().filter(i -> i.getCalcType() == CalcTypeEnum.CALC_FORMULA.getType()).collect(Collectors.toList()); calcFormulas = calcFormulas.stream().filter(i -> i.getNum().equals(child.getNum())).collect(Collectors.toList()); for (ReportForm i : calcFormulas) { String calcFormula = i.getCalcFormula(); // TODO: 2021/8/27 校验公式合法性 if (StrUtil.isBlank(calcFormula)) { throw new CostException("reportForm名称为" + i.getReportName() + "计算公式不正确"); } BigDecimal bigDecimal = calcAmount(list, calcFormula, i); HospProfitAndLoss loss = new HospProfitAndLoss(); loss.setDateYear(year).setDateMonth(month).setReportNum(i.getNum()).setReportName(i.getReportName()) .setAmount(bigDecimal).setCreateTime(System.currentTimeMillis()).setHospId(i.getHospId()); list.add(loss); } } /** * 按小计计算 */ private void calcByLitterCount(Integer year, Integer month, ReportForm child, List reportForms, List list, Long hospId) { // 其他的 List calcList = reportForms.stream().filter(i -> !i.getCalcType().equals(CalcTypeEnum.LITTER_COUNT.getType())).collect(Collectors.toList()); List thisList = new ArrayList<>(); list.forEach(i -> { calcList.forEach(j -> { if (i.getReportNum().equals(j.getNum())) { thisList.add(i); } }); }); if (thisList.isEmpty()) { return; } BigDecimal reduce = thisList.stream().map(HospProfitAndLoss::getAmount).reduce(BigDecimal.ZERO, BigDecimal::add); HospProfitAndLoss loss = new HospProfitAndLoss(); loss.setDateYear(year).setDateMonth(month).setAmount(reduce).setCreateTime(System.currentTimeMillis()).setHospId(hospId); // 小计只能有一个 loss.setReportNum(child.getNum()).setReportName(child.getReportName()); list.add(loss); } /** * 按分摊层级计算、 * * @param hospId 医院id * @param reportForm 报表 * @param list * @param year * @param month */ private void calcByShareLevel(Long hospId, ReportForm reportForm, List list, int year, int month) { List shareLevels = reportRelationService.getShareLevel(reportForm.getId(), hospId); List shareLevelId = shareLevels.stream().map(RelationVO::getCode).map(Long::valueOf).sorted(Long::compareTo).collect(Collectors.toList()); if (CollUtil.isEmpty(shareLevelId)) { return; } List costShareLevels = shareLevelService.listByIds(shareLevelId); if (costShareLevels.isEmpty()) { throw new CostException("医院分摊层级设置错误," + reportForm.getReportName()); } List levelSorts = costShareLevels.stream().map(CostShareLevel::getLeverSort).collect(Collectors.toList()); List allocations = allocationQueryService.getByDate(year, month, hospId, shareLevelId); if (allocations.isEmpty()) { throw new CostException("医院未分摊本月数据"); } List accountShares = accountShareService.getByShareLevelSort(levelSorts, hospId); if (accountShares.isEmpty()) { return; } // allocations = allocations.stream().filter(i -> levelSorts.contains(i.getLevelSort())).collect(Collectors.toList()); BigDecimal reduce = allocations.stream().map(AllocationQuery::getAmount).reduce(BigDecimal.ZERO, BigDecimal::add); HospProfitAndLoss loss = new HospProfitAndLoss(); loss.setReportName(reportForm.getReportName()).setReportNum(reportForm.getNum()) .setAmount(reduce).setCreateTime(System.currentTimeMillis()).setHospId(hospId).setDateYear(year).setDateMonth(month); list.add(loss); } /** * 计算按会计科目下的科目名称 * * @param hospId 医院id * @param reportForm 报表 * @param incomes 归集收入数据 * @param list * @param allocationQueries 分摊成本数据 * @param month * @param year */ private void calcByAccount(Long hospId, ReportForm reportForm, List incomes, List list, List allocationQueries, int month, int year) { // check 这个医院是否有对应的损益标识 reportFormService.checkExistLoss(hospId); // 报表项目关联的会计科目对象 List accountRelations = reportRelationService.getAccountRelation(reportForm.getId(), hospId); if (accountRelations.isEmpty()) { return; } List accountCodes = accountRelations.stream().map(RelationVO::getCode).collect(Collectors.toList()); AtomicReference calcTotal = new AtomicReference<>(); calcTotal.set(BigDecimal.ZERO); accountCodes.forEach(i -> { BigDecimal incomeAmount = incomes.stream().filter(j -> i.equals(j.getAccountingCode())).map(IncomeCollection::getAmount) .reduce(BigDecimal.ZERO, BigDecimal::add); BigDecimal costAmount = allocationQueries.stream().filter(j -> i.equals(j.getAccountingCode())).map(AllocationQuery::getAmount) .reduce(BigDecimal.ZERO, BigDecimal::add); BigDecimal total = incomeAmount.add(costAmount); calcTotal.set(calcTotal.get().add(total)); }); HospProfitAndLoss loss = new HospProfitAndLoss(); loss.setReportName(reportForm.getReportName()).setReportNum(reportForm.getNum()) .setAmount(calcTotal.get()).setCreateTime(System.currentTimeMillis()).setHospId(hospId).setDateYear(year).setDateMonth(month); list.add(loss); } /** * 全院损益列表 * * @param current 当前页 * @param pageSize 每页展示数据大小 * @param date 日期 * @param hospId 医院id * @return PageUtils */ @Override public PageUtils getHospProfits(Integer current, Integer pageSize, String date, Long hospId) { reportFormService.checkExistLoss(hospId); DateTime parse = DateUtil.parse(date); int year = DateUtil.year(parse); int month = DateUtil.month(parse) + 1; int startIndex = (current - 1) * pageSize; List list = baseMapper.getPageList(startIndex, pageSize, year, month, hospId); // 损益的时候计算下 list.forEach(i -> { ReportForm one = reportFormService.getOne( new LambdaQueryWrapper().select(ReportForm::getId) .eq(ReportForm::getNum, i.getReportNum()) .eq(ReportForm::getHospId, hospId) .eq(ReportForm::getReportType, 3) .eq(ReportForm::getIsLoss, 1) .last(Constant.LIMIT) ); if (Objects.nonNull(one)) { List byMonth = otherPaymentsDataService.getByMonth(year, month, hospId); AtomicReference total = new AtomicReference<>(); total.set(BigDecimal.ZERO); byMonth.forEach(j -> { if (j.getPaymentsType().equals(1)) { total.set(total.get().add(j.getTotalAmount())); } else { total.set(total.get().subtract(j.getTotalAmount())); } }); i.setAmount(i.getAmount().add(total.get())); } }); int totalCount = baseMapper.getPageCount(year, month, hospId); return new PageUtils(list, totalCount, pageSize, current); } /** * 导出全院损益计算 * * @param date yyyy-MM-dd * @param hospId */ @Override public void hospProfitReport(String date, Long hospId) { DateTime parse = DateUtil.parse(date); int year = DateUtil.year(parse); int month = DateUtil.month(parse) + 1; // 得到所有责任中心的子节点 List responsibilityList = responsibilityService.list(new QueryWrapper().lambda().eq(Responsibility::getHospId, hospId)); // List leafResp = responsibilityService.getLeafResp(hospId); List byMonth = otherPaymentsDataService.getByMonth(year, month, hospId); // if (!byMonth.isEmpty()) { // Responsibility responsibility = new Responsibility("-1", "全院", -1L); // responsibilityList.add(responsibility); // } Map responseCodeParentIdMap = responsibilityList.stream().collect(Collectors.toMap(Responsibility::getResponsibilityCode, Responsibility::getParentId, (a, b) -> b)); Map responsibilityIdMap = responsibilityList.stream().collect(Collectors.toMap(Responsibility::getId, responsibility -> responsibility, (a, b) -> b)); // 查询所有的全院损益数据 内存溢出问题 List hospProfitAndLosses = getAllDataByDate(year, month, hospId,NumberConstant.THREE); if (CollectionUtils.isEmpty(hospProfitAndLosses)) { throw new CostException(500, "未进行全院损益计算"); } //判断是否有全院的数据 有单独取出另算 List hospAllList = hospProfitAndLosses.stream().filter(f -> f.getResponsibilityCode().equals("-1")).collect(Collectors.toList()); if (!CollectionUtils.isEmpty(hospAllList)) { hospProfitAndLosses.removeAll(hospAllList); } //多层级责任 中心 添加父类责任中心 方便excel分组 for (HospProfitAndLoss hospProfitAndLoss : hospProfitAndLosses) { Long aLong = responseCodeParentIdMap.get(hospProfitAndLoss.getResponsibilityCode()); if (aLong != null) { if (aLong.equals(NumberConstant.ZERO_L)) { // Long aLong1 = responseCodeIdMap.get(departmentProfit.getResponsibilityCode()); hospProfitAndLoss.setParentResponsibilityCode(hospProfitAndLoss.getResponsibilityCode()); hospProfitAndLoss.setParentResponsibilityName(hospProfitAndLoss.getResponsibilityName()); } else if (aLong.equals(-1L)) { hospProfitAndLoss.setParentResponsibilityCode("-1"); hospProfitAndLoss.setParentResponsibilityName("全院"); } else { Responsibility responsibility = responsibilityIdMap.get(aLong); if (Objects.nonNull(responsibility)) { hospProfitAndLoss.setParentResponsibilityCode(responsibility.getResponsibilityCode()); hospProfitAndLoss.setParentResponsibilityName(responsibility.getResponsibilityName()); } } } } //损益表设置 List reportFormList = reportFormService.list(new QueryWrapper().lambda() .eq(ReportForm::getHospId, hospId) .eq(ReportForm::getReportType, NumberConstant.THREE)); if (CollUtil.isEmpty(reportFormList)) { throw new CostException(500, "损益表未找到"); } if (!byMonth.isEmpty()) { // 手动构造全院数据表头 生成全院其他收支 //添加全院其他报表项目 //最上层 ReportForm parentReport = new ReportForm(); parentReport.setId(-1L); parentReport.setReportType(NumberConstant.THREE); parentReport.setParentId(NumberConstant.ZERO_L); parentReport.setSort(0); parentReport.setReportName("全院其他收支"); parentReport.setNum(-1); reportFormList.add(parentReport); //第二层按全院收支数据自动生成 for (int i = 0; i < byMonth.size(); i++) { CostOtherPaymentsData data = byMonth.get(i); ReportForm reportForm = new ReportForm(); // reportForm.setId(-1L -i - byMonth.size()); reportForm.setId(-System.currentTimeMillis() - i); reportForm.setReportType(NumberConstant.THREE); reportForm.setParentId(-1L); reportForm.setSort(0); reportForm.setReportName(data.getPaymentsName()); reportForm.setNum((int) (-data.getId())); reportFormList.add(reportForm); } } Map> collect = reportFormList.stream().collect(Collectors.groupingBy(ReportForm::getParentId)); Map> heads = new HashMap<>();// 最终导出的多个sheet的表头 Map>> datas = new HashMap<>();// 最终导出的多个sheet的内容 Map types = new HashMap<>(); Map> mergeindexs = new HashMap<>();// 最终导出的每个sheet的需要纵向合并的单元格列号 //第一层 List firstTitle = collect.get(NumberConstant.ZERO_L); List titleList = new ArrayList<>(); titleList.add(new TitleEntity("0", null, "全院损益 \n" + "制表时间:" + DateUtil.now(), false, NumberConstant.ZERO)); //添加默认三列责任中心 父类责任中心 子类责任中心 项目名称 setDefaultColumn(titleList); for (ReportForm reportForm : firstTitle) { TitleEntity entity = new TitleEntity(); entity.setId(String.valueOf(reportForm.getId())); entity.setPid(String.valueOf(reportForm.getParentId())); entity.setContent(reportForm.getReportName()); entity.setFieldName(String.valueOf(reportForm.getNum())); entity.setWidth(20); entity.setSort(reportForm.getSort()); boolean child = getChild(titleList, reportForm, collect); entity.setLast(child); titleList.add(entity); } titleList.sort(Comparator.comparing(TitleEntity::getSort)); hospProfitAndLosses.sort(Comparator.comparing(HospProfitAndLoss::getParentResponsibilityCode)); //行 Map> lineMap = hospProfitAndLosses.stream().collect(Collectors.groupingBy(HospProfitAndLoss::getParentResponsibilityCode)); //列 List titleEntities = titleList.stream().filter(TitleEntity::isLast).collect(Collectors.toList()); List> rowList = new ArrayList<>(); //行数据 setRowList(lineMap, titleEntities, rowList); //添加 全院其他收支数据 setHospRowList(hospAllList, titleEntities, rowList); try { ExcelPoiUtil excelTool = new ExcelPoiUtil(); excelTool.setTitle("全院损益"); Map param = ImmutableMap.builder().put("id", "id").put("pid", "pid") .put("content", "content").put("fieldName", "fieldName").put("width", "width").build(); List titleData = excelTool.colEntityTransformer(titleList, param, "0"); Map> autoRowHeights = new HashMap<>(); heads.put("全院损益", titleData);// 每个sheet的表头,sheet名称为key datas.put("全院损益", rowList);// 每个sheet的内容,sheet名称为key types.put("全院损益", 0);// 每个sheet的样式类型,sheet名称为key mergeindexs.put("全院损益", Arrays.asList(0, 1));// 每个sheet的默认行高,sheet名称为key autoRowHeights.put("全院损益", Arrays.asList(1, 2, 3, 4, 5)); // 多个sheet导出 HSSFWorkbook workbook = excelTool.exportWorkbook(heads, datas, types, autoRowHeights, mergeindexs); // excelTool.save(workbook, "D:\\全院损益.xls"); // // 得到上一层的title子节点 //// ExcelWriter writer = ExcelUtil.getWriter(); // String time = DateUtil.format(DateUtil.date(), "yyyy年MM月dd日HH时mm分ss秒"); // //todo:后面调整为上传到文件服务器,先启动确认环境 // String fileName = "全院损益" + time + ".xlsx"; // ExcelWriter writer = ExcelUtil.getWriter(fileName); // // List secondTitleListCode = leafResp.stream().map(Responsibility::getResponsibilityCode).collect(Collectors.toList()); // writer.merge(leafResp.size() + 1, "全院损益计算导出 \n" + "制表时间:" + DateUtil.now()); // // 得到两层结构 // writer.setColumnWidth(-1, 20); // writer.passCurrentRow(); // writer.merge(2, 2, 0, 1, "项目", true); // int oldSize = 2; // Map map = new HashMap<>(); // for (int i = 0; i < leafResp.size(); i++) { // Responsibility responsibility = leafResp.get(i); // String str = responsibility.getResponsibilityName(); // writer.writeCellValue(i + 2, 2, str); // // 写父亲层级 // Long parentId = responsibility.getParentId(); // if (map.get(parentId) != null) { // // 如果parentId = 0 // if (parentId != 0L) { // continue; // } // } // Responsibility byId = responsibilityService.getById(parentId); // String name = ""; // if (byId != null) { // name = byId.getResponsibilityName(); // } // int count = (int) leafResp.stream().filter(o -> o.getParentId().equals(parentId)).count(); // // if (count == 1) { // writer.writeCellValue(oldSize, 1, name); // } else if (count == 0) { // writer.writeCellValue(oldSize, 1, "全院其他"); // } else { // writer.merge(1, 1, oldSize, oldSize + count - 1, name, false); // } // // oldSize = oldSize + count; // map.put(parentId, oldSize); // // } // // 得到全院损益报表处理 树状结构(only 2层) // List allHospList = reportFormService.getAllHospList(hospId); // if (allHospList.isEmpty()) { // throw new CostException("请先设置全院损益报表"); // } // // if (!byMonth.isEmpty()) { // // 构造假数据 生成全院其他收支 // ReportFormVO vo = new ReportFormVO(-1L, -1, "全院其他收支", 0L, new ArrayList<>()); // for (CostOtherPaymentsData data : byMonth) { // ReportFormVO reportFormVO = new ReportFormVO(-2L, (int) (-data.getId()), data.getPaymentsName(), -1L, null); // vo.getChildren().add(reportFormVO); // } // allHospList.add(allHospList.size() - 1, vo); // } // // 查询所有的全院损益数据 内存溢出问题 // List list = getAllDataByDate(year, month, hospId); // int lastRow = 3; // for (int i = 0; i < allHospList.size(); i++) { // ReportFormVO parentFormVO = allHospList.get(i); // List children = parentFormVO.getChildren(); // if (CollUtil.isEmpty(children)) { // continue; // } // int size = children.size(); // // 当最后一个的时候写上全院其他收支 // if (allHospList.size() == 1) { // writer.writeCellValue(0, lastRow, parentFormVO.getReportName()); // } else { // writer.merge(lastRow, lastRow + size - 1, 0, 0, parentFormVO.getReportName(), true); // } // // // 具体的报表项目 // for (int j = 0; j < size; j++) { // // todo 可以抽取出单独方法 // ReportFormVO childFormVO = children.get(j); // // 第二列的数据 // writer.writeCellValue(1, lastRow + j, childFormVO.getReportName()); // // 单独计每个数据的责任中心对应的金额 // for (int k = 0; k < secondTitleListCode.size(); k++) { // // String responsibilityCode = secondTitleListCode.get(k); // Integer num = childFormVO.getNum(); // HospProfitAndLoss loss = list.stream().filter(o -> o.getReportNum().equals(num) && o.getResponsibilityCode().equals(responsibilityCode)).findAny() // .orElse(null); // BigDecimal bigDecimal = Objects.isNull(loss) ? BigDecimal.ZERO : loss.getAmount(); // writer.writeCellValue(k + 2, lastRow + j, bigDecimal); // if (k == secondTitleListCode.size() - 1) { // bigDecimal = list.stream().filter(o -> o.getReportNum().equals(num)).map(HospProfitAndLoss::getAmount).reduce(BigDecimal.ZERO, BigDecimal::add); // writer.writeCellValue(k + 2, lastRow + j, bigDecimal); // // if (j == size - 1 && i == allHospList.size() - 1) { // // 计算 其他 // BigDecimal another = BigDecimal.ZERO; // for (CostOtherPaymentsData costOtherPaymentsData : byMonth) { // if (costOtherPaymentsData.getPaymentsType() == 1) { // another = another.add(costOtherPaymentsData.getTotalAmount()); // } else { // another = another.subtract(costOtherPaymentsData.getTotalAmount()); // } // } // bigDecimal = bigDecimal.add(another); // writer.writeCellValue(k + 2, lastRow + j, bigDecimal); // } // } // // // } // // } // lastRow = lastRow + size; // } String time = DateUtil.format(DateUtil.date(), "yyyy年MM月dd日HH时mm分ss秒"); FileItemFactory factory = new DiskFileItemFactory(5242880, null); FileItem fileItem = factory.createItem("file", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=utf-8", true, "全院损益" + time + ".xls"); String file = ""; OutputStream outputStream = fileItem.getOutputStream(); // writer.flush(outputStream,true); workbook.write(outputStream); MultipartFile multipartFile = new CommonsMultipartFile(fileItem); //上传 excel file = uploadFile(multipartFile); //保存文件记录 FileRecord fileRecord = new FileRecord(); fileRecord.setFileName("全院损益" + time + ".xls") .setFileSource(1) .setFileType("全院损益") .setFileUrl(file) .setHospId(hospId) .setDateYear(year).setDateMonth(month) .setCreateTime(System.currentTimeMillis()); fileRecordService.save(fileRecord); workbook.close(); } catch (Exception e) { throw new RuntimeException(e); } } private static void setHospRowList(List hospAllList, List titleEntities, List> rowList) { List> amountRowList = new ArrayList<>(); for (Map map : rowList) { String itemType = map.get("itemType"); if (itemType.equals("金额")) { amountRowList.add(map); } } //相 同key 的数值 进行汇总 // for (int i = 0; i < 2; i++) { Map hospMap = new HashMap<>(); for (TitleEntity titleEntity : titleEntities) { AtomicReference total = new AtomicReference<>(new BigDecimal("0.00")); for (Map map : amountRowList) { String s = map.get(titleEntity.getFieldName()); if (!titleEntity.getFieldName().equals("child") && !titleEntity.getFieldName().equals("parent") && !titleEntity.getFieldName().equals("itemType")) { // if(StringUtils.isEmpty(s)){ // total.updateAndGet(v -> v.add(BigDecimal.ZERO)); // }else { total.updateAndGet(v -> v.add(new BigDecimal(s))); // } } } if (titleEntity.getFieldName().equals("parent")) { hospMap.put("parent", "全院"); } else if (titleEntity.getFieldName().equals("child")) { hospMap.put("child", "全院"); } else if (titleEntity.getFieldName().equals("itemType")) { // if (i == 0) { hospMap.put("itemType", "金额"); // } else { // hospMap.put("itemType", "占比"); // } } else { // if (i == 0) { hospMap.put(titleEntity.getFieldName(), total.get().toString()); if (!CollectionUtils.isEmpty(hospAllList)) { for (HospProfitAndLoss data : hospAllList) { hospMap.put(data.getReportNum().toString(), data.getAmount().setScale(2, RoundingMode.HALF_UP).toString()); } } // } else { // hospMap.put(titleEntity.getFieldName(), ""); // } } } rowList.add(hospMap); // } } private static void setRowList(Map> lineMap, List titleEntities, List> rowList) { DecimalFormat df = new DecimalFormat("0.00%"); for (String parentCode : lineMap.keySet()) { List costDepartmentProfits1 = lineMap.get(parentCode); Map> listMap = costDepartmentProfits1.stream().collect(Collectors.groupingBy(HospProfitAndLoss::getResponsibilityCode)); for (String s : listMap.keySet()) { List costDepartmentProfits2 = listMap.get(s); Map map = costDepartmentProfits2.stream().collect(Collectors.toMap(profit -> String.valueOf(profit.getReportNum()), profit -> profit, (a, b) -> b)); for (int i = 0; i < 2; i++) { Map m = new HashMap(); for (TitleEntity titleEntity : titleEntities) { if (titleEntity.getId().equals("parentResponsibility")) { m.put("parent", costDepartmentProfits2.get(0).getParentResponsibilityName()); } else if (titleEntity.getId().equals("childResponsibility")) { m.put("child", costDepartmentProfits2.get(0).getResponsibilityName()); } else if (titleEntity.getId().equals("item")) { if (i == 0) { m.put("itemType", "金额"); } else { m.put("itemType", "占比"); } } else if (titleEntity.getId().contains("-")) { HospProfitAndLoss profit = map.get(titleEntity.getFieldName()); if (Objects.nonNull(profit)) { if (i == 0) { m.put(titleEntity.getFieldName(), profit.getAmount().setScale(2, RoundingMode.HALF_UP).toString()); } else { if (profit.getPercent() != null) { m.put(titleEntity.getFieldName(), df.format(profit.getPercent())); } else { m.put(titleEntity.getFieldName(), ""); } } } else { m.put(titleEntity.getFieldName(), "0.00"); } } else { HospProfitAndLoss profit = map.get(titleEntity.getFieldName()); if (Objects.nonNull(profit)) { if (i == 0) { m.put(titleEntity.getFieldName(), profit.getAmount().setScale(2, RoundingMode.HALF_UP).toString()); } else { if (profit.getPercent() != null) { m.put(titleEntity.getFieldName(), df.format(profit.getPercent())); } else { m.put(titleEntity.getFieldName(), ""); } } } } } rowList.add(m); } } } } private void setDefaultColumn(List titleList) { TitleEntity parentResponsibility = new TitleEntity(); parentResponsibility.setId("parentResponsibility"); parentResponsibility.setPid("0"); parentResponsibility.setContent(""); parentResponsibility.setFieldName("parent"); parentResponsibility.setWidth(15); parentResponsibility.setSort(NumberConstant.ZERO); parentResponsibility.setLast(true); titleList.add(parentResponsibility); TitleEntity childResponsibility = new TitleEntity(); childResponsibility.setId("childResponsibility"); childResponsibility.setPid("0"); childResponsibility.setContent(""); childResponsibility.setFieldName("child"); childResponsibility.setWidth(15); childResponsibility.setSort(NumberConstant.ZERO); childResponsibility.setLast(true); titleList.add(childResponsibility); TitleEntity item = new TitleEntity(); item.setId("item"); item.setPid("0"); item.setContent(""); item.setFieldName("itemType"); item.setWidth(10); item.setSort(NumberConstant.ZERO); item.setLast(true); titleList.add(item); } private boolean getChild(List titleList, ReportForm reportForm, Map> collect) { List forms = collect.get(reportForm.getId()); if (!CollectionUtils.isEmpty(forms)) { for (ReportForm form : forms) { TitleEntity entity = new TitleEntity(); entity.setId(String.valueOf(form.getId())); entity.setPid(String.valueOf(form.getParentId())); entity.setContent(form.getReportName()); entity.setFieldName(String.valueOf(form.getNum())); entity.setWidth(15); entity.setSort(form.getSort()); boolean last = getChild(titleList, form, collect); entity.setLast(last); titleList.add(entity); } return false; } else { return true; } } public String uploadFile(MultipartFile file) { Long hospId = UserContext.getCurrentLoginHospId(); String fileName = file.getOriginalFilename().substring(0, file.getOriginalFilename().lastIndexOf(".")) + System.currentTimeMillis() + ".xls"; DateTime date = DateUtil.date(); int month = DateUtil.month(date) + 1; int year = DateUtil.year(date); int day = DateUtil.dayOfMonth(date); String fileUrl = ""; try { // file.transferTo(new File(localFilePath)); String format = DateUtil.format(date, DatePattern.PURE_DATETIME_PATTERN); String originalFilename = format + fileName; String dataDirectory = minioConfig.getBucketName(); String uploadFileName = "hospReport" + "/" + hospId + "/" + year + "/" + month + "/" + day + "/" + originalFilename; InputStream inputStream = file.getInputStream(); minioFileUtil.putObject(dataDirectory, uploadFileName, inputStream); fileUrl = minioFileUtil.getObjectUrl(dataDirectory, uploadFileName); } catch (IOException e) { log.error("【文件上传至服务器】失败,绝对路径:{}", e.getMessage()); throw new CostException(ErrorCodeEnum.FILE_UPLOAD_ERROR); } return fileUrl; } @Override public PageUtils hospProfitReports(Integer current, Integer pageSize, Long hospId, String date) { DateTime parse = DateUtil.parse(date); int year = DateUtil.year(parse); int month = DateUtil.month(parse) + 1; Page page = new Page<>(current, pageSize); Page pageUtils = fileRecordService.page(page, new LambdaQueryWrapper() .eq(FileRecord::getHospId, hospId) .eq(FileRecord::getFileType, "全院损益") .eq(FileRecord::getDateYear, year) .eq(FileRecord::getDateMonth, month) .orderByDesc(FileRecord::getCreateTime) ); return new PageUtils(pageUtils); } @Override public Object getHospProfitResponsibilities(String responsibilityName) { List responsibilityList = responsibilityService.list(new QueryWrapper().lambda() .eq(Responsibility::getHospId, UserContext.getHospId()) .and(q -> q.eq(Responsibility::getStatus, NumberConstant.ONE).or().eq(Responsibility::getStatus, null)) .like(StrUtil.isNotBlank(responsibilityName), Responsibility::getResponsibilityName, responsibilityName)); List responsibilityAllList = responsibilityService.list(new QueryWrapper().lambda() .eq(Responsibility::getHospId, UserContext.getHospId())); Map map = responsibilityAllList.stream().collect(Collectors.toMap(Responsibility::getId, responsibility -> responsibility, (a, b) -> b)); List addList = new ArrayList<>(); for (Responsibility responsibility : responsibilityList) { Responsibility responsibility1 = map.get(responsibility.getParentId()); if (Objects.nonNull(responsibility1)) { addList.add(responsibility1); if (!responsibility1.getParentId().equals(NumberConstant.ZERO_L)) { getResponsibilityParent(responsibility1, map, addList); } } } if (!CollectionUtils.isEmpty(addList)) { //去重 List collect = addList.stream().distinct().collect(Collectors.toList()); responsibilityList.addAll(collect); } Map> collect = responsibilityList.stream().collect(Collectors.groupingBy(Responsibility::getParentId)); List responsibilities = collect.get(NumberConstant.ZERO_L); collect.remove(NumberConstant.ZERO_L); for (Responsibility responsibility : responsibilities) { List responsibilities1 = collect.get(responsibility.getId()); if (!CollectionUtils.isEmpty(responsibilities1)) { responsibility.setChildren(setResponsibilityChildren(responsibilities1, collect)); } } responsibilitySort(responsibilities); return responsibilities; } @Override public Object getHospProfitList(String computeDate, Long hospId, String reportType) { DateTime parse = DateUtil.parse(computeDate); int year = DateUtil.year(parse); int month = DateUtil.month(parse) + 1; //查询全院损益报表配置 Integer integerReportType = Integer.valueOf(reportType); // Integer year = ComputeDateUtils.getComputeYear(computeDate); // Integer month = ComputeDateUtils.getComputeMonth(computeDate); // 查询所有的全院损益数据 内存溢出问题 List hospProfitAndLosses = getAllDataByDate(year, month, hospId,integerReportType); if (CollectionUtils.isEmpty(hospProfitAndLosses)) { throw new CostException(500, "未进行全院损益计算"); } //判断是否有全院的数据 有单独取出另算 List hospAllList = hospProfitAndLosses.stream().filter(f -> f.getResponsibilityCode().equals("-1")).collect(Collectors.toList()); if (!CollectionUtils.isEmpty(hospAllList)) { hospProfitAndLosses.removeAll(hospAllList); } List reportFormList = reportFormService.list(new QueryWrapper().lambda() .eq(ReportForm::getHospId, hospId) .eq(ReportForm::getReportType, integerReportType).eq(ReportForm::getHide, NumberConstant.ONE)); if (CollUtil.isEmpty(reportFormList)) { throw new CostException(500, "未找到全院损益表配置"); } List costProfitVos = BeanUtil.convertList(reportFormList, HospProfitVO.class); //把所有数据按报表项目汇总 Map> reportNumGroup = hospProfitAndLosses.stream().collect(Collectors.groupingBy(HospProfitAndLoss::getReportNum)); Map reportNumSumMap = new HashMap<>(); reportNumGroup.forEach((reportNum, hospProfitAndLossList) -> { AtomicReference sum = new AtomicReference<>(new BigDecimal("0.000000")); hospProfitAndLossList.stream().>map(hospProfitAndLoss -> f -> f.add(hospProfitAndLoss.getAmount())).forEach(sum::updateAndGet); reportNumSumMap.put(reportNum, sum.get()); }); for (HospProfitVO costProfitVo : costProfitVos) { BigDecimal bigDecimal = reportNumSumMap.get(costProfitVo.getNum()); if (bigDecimal != null) { costProfitVo.setAmount(bigDecimal); } else { costProfitVo.setAmount(BigDecimal.ZERO.setScale(6, RoundingMode.HALF_UP)); } } //判断有无其他全院数据 有组装进去 if (!CollectionUtils.isEmpty(hospAllList)) { //全院其他收支 HospProfitVO hospProfitVO = new HospProfitVO(); hospProfitVO.setId(-1L); hospProfitVO.setNum(-1); hospProfitVO.setParentId(0L); hospProfitVO.setReportName("全院其他收支"); hospProfitVO.setSort(costProfitVos.size()); hospProfitVO.setReportType(integerReportType); hospProfitVO.setFraction(3); costProfitVos.add(hospProfitVO); for (int i = 0, hospAllListSize = hospAllList.size(); i < hospAllListSize; i++) { costProfitVos.add(getHospProfitVO(hospAllList, i,integerReportType)); } } //取出所有成本项目 List costFractionList = costProfitVos.stream().filter(f -> f.getCostType() != null && f.getCostType().equals(NumberConstant.TWO) && f.getFraction().equals(NumberConstant.TWO)).collect(Collectors.toList()); if (CollectionUtils.isEmpty(costFractionList)) { throw new CostException("全院损益未配置成本占比计算分母"); } else { if (costFractionList.size() > 1) { throw new CostException("全院损益成本占比计算分母有且只能有一个"); } } List inComeFractionList = costProfitVos.stream().filter(f -> f.getCostType() != null && f.getCostType().equals(NumberConstant.ONE) && f.getFraction().equals(NumberConstant.TWO)).collect(Collectors.toList()); if (CollectionUtils.isEmpty(inComeFractionList)) { throw new CostException("全院损益未配置收入占比计算分母"); } else { if (inComeFractionList.size() > 1) { throw new CostException("全院损益收入占比计算分母有且只能有一个"); } } HospProfitVO inComeFraction = inComeFractionList.get(0); HospProfitVO costFraction = costFractionList.get(0); for (HospProfitVO costProfitVo : costProfitVos) { if (costProfitVo.getCostType() != null) { if (costProfitVo.getCostType().equals(NumberConstant.ONE) && costProfitVo.getFraction().equals(NumberConstant.ONE)) { //收入 BigDecimal denominator = inComeFraction.getAmount(); //收入分子 if (denominator.compareTo(BigDecimal.ZERO) == 0) { costProfitVo.setPercent(BigDecimal.ZERO.setScale(4, RoundingMode.HALF_UP)); } else { costProfitVo.setPercent(costProfitVo.getAmount().divide(denominator, 4, RoundingMode.HALF_UP)); } } else if (costProfitVo.getCostType().equals(NumberConstant.TWO) && costProfitVo.getFraction().equals(NumberConstant.ONE)) { //成本 BigDecimal denominator = costFraction.getAmount(); if (denominator.compareTo(BigDecimal.ZERO) == 0) { costProfitVo.setPercent(BigDecimal.ZERO.setScale(4, RoundingMode.HALF_UP)); } else { costProfitVo.setPercent(costProfitVo.getAmount().divide(denominator, 4, RoundingMode.HALF_UP)); } } } } Map> collect = costProfitVos.stream().collect(Collectors.groupingBy(HospProfitVO::getParentId)); List costProfitParentVos = collect.get(NumberConstant.ZERO_L); collect.remove(NumberConstant.ZERO_L); for (HospProfitVO costProfitVo : costProfitParentVos) { List costProfitVo1 = collect.get(costProfitVo.getId()); if (!CollectionUtils.isEmpty(costProfitVo1)) { costProfitVo.setChild(setChildren(costProfitVo1, collect)); } } if (!CollectionUtils.isEmpty(costProfitParentVos)) { costProfitParentVos.sort(Comparator.comparing(HospProfitVO::getSort, Comparator.nullsLast(Integer::compareTo))); } return costProfitParentVos; } @Override public Object getBatchHospProfitList(String beginComputeDate, String endComputeDate, Long hospId, Integer reportType) { List hospProfitAndLossByDateRange = getHospProfitAndLossByDateRange(beginComputeDate, endComputeDate,reportType); if (CollectionUtils.isEmpty(hospProfitAndLossByDateRange)) { throw new CostException(500, "未进行全院损益计算"); } //获取全院损益表配置信息 List reportFormList=getReportFormList(hospId,reportType); if (CollectionUtils.isEmpty(reportFormList)) { throw new CostException(500, "未找到全院损益表配置"); } //按年-月进行分组 Map> groupedByYearMonth = hospProfitAndLossByDateRange.stream() .collect(Collectors.groupingBy( item -> item.getDateYear() + "-" + (item.getDateMonth() < 10 ? "0" + item.getDateMonth() : item.getDateMonth()) )); List responses = new ArrayList<>(); List allCostProfitVo=new ArrayList<>(); //按年-月处理科室损益数据 for (Map.Entry> entry : groupedByYearMonth.entrySet()){ List hospProfitAndLossList = entry.getValue(); //转换成成本损益数据 List costProfitVos = convertToCostProfitVoList(hospProfitAndLossList, reportFormList); //记录所有月份的损益数据 allCostProfitVo.addAll(costProfitVos); //生成出参样式 BatchCostProfitResponse response = new BatchCostProfitResponse(); //第13月为审计月份 if(hospProfitAndLossList.get(0).getDateMonth()==13){ response.setComputeDate(String.format("%s-%s", hospProfitAndLossList.get(0).getDateYear(), "12A")); response.setAuditMonth(true); response.setMonthlyAccumulation(false); }else { response.setComputeDate(entry.getKey()); response.setAuditMonth(false); response.setMonthlyAccumulation(false); } response.setProfitVoList(costProfitVos); response.setAllowDrillDown(false); responses.add(response); } responses.sort(Comparator.comparing(BatchCostProfitResponse::getComputeDate)); //起止年月不同时代表有多月份需要处理月累计 if(!beginComputeDate.equals(endComputeDate)){ //获取月度汇总数据 List costProfitVos = generateSummaryForMultipleMonths(allCostProfitVo); if(!CollectionUtils.isEmpty(costProfitVos)){ BatchCostProfitResponse response = new BatchCostProfitResponse(); response.setComputeDate(String.format("%s至%s", beginComputeDate, endComputeDate)); response.setProfitVoList(costProfitVos); response.setAllowDrillDown(false); response.setMonthlyAccumulation(true); response.setAuditMonth(false); responses.add(NumberConstant.ZERO,response); } } return responses; } /** * 生成多月份汇总的科室损益数据 * * @param allCostProfitVo 原始数据列表 * @return 汇总后的科室损益数据 */ private List generateSummaryForMultipleMonths(List allCostProfitVo){ // 参数校验 if (CollectionUtils.isEmpty(allCostProfitVo)) { return Collections.emptyList(); } //排除掉13月的数据 List activeCostProfitVo = allCostProfitVo.stream().filter(profitVo -> profitVo.getMonth() != 13).collect(Collectors.toList()); if (CollectionUtils.isEmpty(activeCostProfitVo)) { return Collections.emptyList(); } List profitVoList=new ArrayList<>() ; Map> reportGroup = allCostProfitVo.stream().collect(Collectors.groupingBy(CostProfitVo::getReportId)); reportGroup.forEach((reportId, profitVos) -> { CostProfitVo costProfitVo = BeanUtil.convertObj(profitVos.get(NumberConstant.ZERO), CostProfitVo.class); BigDecimal totalAmount = profitVos.stream().map(vo -> Optional.ofNullable(vo.getAmount()).orElse(BigDecimal.ZERO)) .reduce(BigDecimal.ZERO, BigDecimal::add); BigDecimal totalBudgetAmount = profitVos.stream().map(vo -> Optional.ofNullable(vo.getBudgetAmount()).orElse(BigDecimal.ZERO)) .reduce(BigDecimal.ZERO, BigDecimal::add); BigDecimal totalPrevPeriodAmount = profitVos.stream().map(vo -> Optional.ofNullable(vo.getPrevPeriodAmount()).orElse(BigDecimal.ZERO)) .reduce(BigDecimal.ZERO, BigDecimal::add); BigDecimal totalSamePeriodAmount = profitVos.stream().map(vo -> Optional.ofNullable(vo.getSamePeriodAmount()).orElse(BigDecimal.ZERO)) .reduce(BigDecimal.ZERO, BigDecimal::add); costProfitVo.setAmount(totalAmount); costProfitVo.setBudgetAmount(totalBudgetAmount); costProfitVo.setPrevPeriodAmount(totalPrevPeriodAmount); costProfitVo.setSamePeriodAmount(totalSamePeriodAmount); costProfitVo.setCompletionRate(calculateProfitRate(costProfitVo.getAmount(), costProfitVo.getBudgetAmount())); costProfitVo.setMomRate(calculateProfitRate(costProfitVo.getAmount().subtract(costProfitVo.getPrevPeriodAmount()), costProfitVo.getPrevPeriodAmount())); costProfitVo.setYoyRate(calculateProfitRate(costProfitVo.getAmount().subtract(costProfitVo.getSamePeriodAmount()), costProfitVo.getSamePeriodAmount())); profitVoList.add(costProfitVo); }); //转成树状结构 List costProfitVoTree = converToCostProfitVoTree(profitVoList); return costProfitVoTree; } /** * 转换为多层级样式全院损益数据 * @param hospProfitAndLossList * @param reportFormList * @return */ public List convertToCostProfitVoList(List hospProfitAndLossList,List reportFormList ){ //全院其他收支项目 List otherHospProfitAndLoss = hospProfitAndLossList.stream().filter(i -> NumberConstant.ONE.equals(i.getOriginType())).collect(Collectors.toList()); //按报表项目编号map Map hospProfitAndLossMap = hospProfitAndLossList.stream().collect(Collectors.toMap(HospProfitAndLoss::getReportNum, b -> b)); //报表项目转换成多层级损益对象 List costProfitVos =reportFormList.stream().map(reportForm -> reportFormToProfitVo(reportForm)).collect(Collectors.toList()); //组装全院损益及报表项目信息 for (CostProfitVo profitVo : costProfitVos) { //处理年月数据 profitVo.setYear(hospProfitAndLossList.get(0).getDateYear()); profitVo.setMonth(hospProfitAndLossList.get(0).getDateMonth()); //添加损益数据 HospProfitAndLoss hospProfitAndLoss = hospProfitAndLossMap.get(profitVo.getReportNum()); //组装全院损益及报表项目金额信息 combineReportAndProfitAmount(profitVo,hospProfitAndLoss); } //有全院其他收支时添加全院其他收支 if(!CollectionUtils.isEmpty(otherHospProfitAndLoss)){ //找到配置的损益项目 Optional firstLossReport = reportFormList.stream().filter(i -> NumberConstant.ONE.equals(i.getIsLoss())).findFirst(); if(!firstLossReport.isPresent()){ throw new CostException(500, "全院损益报表配置有误,未设置损益项目"); } //生成一个虚拟的全院其他收支 CostProfitVo otherProfit = getOtherProfit(reportFormList); //处理年月数据 otherProfit.setYear(otherHospProfitAndLoss.get(NumberConstant.ZERO).getDateYear()); otherProfit.setMonth(otherHospProfitAndLoss.get(NumberConstant.ZERO).getDateMonth()); costProfitVos.add(otherProfit); ReportForm reportForm = firstLossReport.get(); for (int i = 0; i < otherHospProfitAndLoss.size(); i++) { HospProfitAndLoss hospProfitAndLoss = otherHospProfitAndLoss.get(i); CostProfitVo costProfitVo =reportFormToProfitVo(reportForm); //组装全院损益及报表项目金额信息 combineReportAndProfitAmount(costProfitVo,hospProfitAndLoss); //处理年月数据 costProfitVo.setYear(hospProfitAndLoss.getDateYear()); costProfitVo.setMonth(hospProfitAndLoss.getDateMonth()); //全院其他收支项目放在虚拟的全院其他收支下 costProfitVo.setSort(i); costProfitVo.setReportNum(hospProfitAndLoss.getReportNum()); costProfitVo.setReportId(hospProfitAndLoss.getReportNum().longValue()); costProfitVo.setReportParentId(otherProfit.getReportId()); costProfitVos.add(costProfitVo); } } //转成树状结构的损益数据 List costProfitVoTree = converToCostProfitVoTree(costProfitVos); return costProfitVoTree; } /** * 生成一个虚拟的全院其他收支 * @param reportFormList * @return */ public CostProfitVo getOtherProfit(List reportFormList) { //全院其他收支 CostProfitVo hospProfitVO = reportFormToProfitVo(reportFormList.get(NumberConstant.ZERO)); hospProfitVO.setId(-1L); hospProfitVO.setReportId(-1L); hospProfitVO.setReportNum(-1); hospProfitVO.setReportParentId(0L); hospProfitVO.setReportName("全院其他收支"); hospProfitVO.setSort(reportFormList.size()); return hospProfitVO; } /** * 报表项目转换成多层级损益对象 * @param reportForm * @return */ public CostProfitVo reportFormToProfitVo(ReportForm reportForm){ CostProfitVo profitVo = new CostProfitVo(); profitVo.setReportId(reportForm.getId()); profitVo.setReportName(reportForm.getReportName()); profitVo.setReportParentId(reportForm.getParentId()); profitVo.setReportNum(reportForm.getNum()); profitVo.setCalcType(reportForm.getCalcType()); profitVo.setCalcFormula(reportForm.getCalcFormula()); profitVo.setCostType(reportForm.getCostType()); profitVo.setShareType(reportForm.getReportType()); profitVo.setSort(reportForm.getSort()); profitVo.setDescription(reportForm.getDescription()); profitVo.setDataType(reportForm.getDataType()); profitVo.setDecimalPlace(reportForm.getDecimalPlace()); profitVo.setPermil(reportForm.getPermil()); return profitVo; } /** * 组装全院损益及报表项目的金额信息 * @param profitVo * @param hospProfitAndLoss */ public void combineReportAndProfitAmount(CostProfitVo profitVo, HospProfitAndLoss hospProfitAndLoss) { if (ObjectUtils.isEmpty(hospProfitAndLoss)) { profitVo.setAmount(BigDecimal.ZERO); profitVo.setSamePeriodAmount(BigDecimal.ZERO); profitVo.setPrevPeriodAmount(BigDecimal.ZERO); profitVo.setBudgetAmount(BigDecimal.ZERO); profitVo.setYoyRate(BigDecimal.ZERO); profitVo.setMomRate(BigDecimal.ZERO); profitVo.setCompletionRate(BigDecimal.ZERO); } else { profitVo.setAmount(hospProfitAndLoss.getAmount()); profitVo.setSamePeriodAmount(hospProfitAndLoss.getSamePeriodAmount()); profitVo.setPrevPeriodAmount(hospProfitAndLoss.getPrevPeriodAmount()); profitVo.setBudgetAmount(hospProfitAndLoss.getBudgetAmount()); profitVo.setYoyRate(hospProfitAndLoss.getYoyRate()); profitVo.setMomRate(hospProfitAndLoss.getMomRate()); profitVo.setCompletionRate(hospProfitAndLoss.getCompletionRate()); } } /** * 转成树状结构的损益数据 * @param costProfitVos * @return */ public List converToCostProfitVoTree(List costProfitVos){ // 参数校验 if (CollectionUtils.isEmpty(costProfitVos)) { return Collections.emptyList(); } Map> collect = costProfitVos.stream().collect(Collectors.groupingBy(CostProfitVo::getReportParentId)); List costProfitParentVos = collect.get(NumberConstant.ZERO_L); collect.remove(NumberConstant.ZERO_L); for (CostProfitVo costProfitVo : costProfitParentVos) { List costProfitVo1 = collect.get(costProfitVo.getReportId()); if (!CollectionUtils.isEmpty(costProfitVo1)) { costProfitVo.setChildren(setChildrenProfitVo(costProfitVo1, collect)); } } if (!CollectionUtils.isEmpty(costProfitParentVos)) { costProfitParentVos.sort(Comparator.comparing(CostProfitVo::getSort, Comparator.nullsLast(Integer::compareTo))); } return costProfitParentVos; } private List setChildrenProfitVo(List child, Map> collect) { for (CostProfitVo costProfitVo : child) { if (!CollectionUtils.isEmpty(collect.get(costProfitVo.getReportId()))) { costProfitVo.setChildren(setChildrenProfitVo(collect.get(costProfitVo.getReportId()), collect)); } } if (!CollectionUtils.isEmpty(child)) { child.sort(Comparator.comparing(CostProfitVo::getSort, Comparator.nullsLast(Integer::compareTo))); } return child; } /** * 获取全院损益表配置信息 * @param hospId * @param reportType * @return */ public List getReportFormList(Long hospId,Integer reportType ) { List reportFormList = reportFormService.list(new QueryWrapper().lambda() .eq(ReportForm::getHospId, hospId) .eq(ReportForm::getReportType, reportType) .eq(ReportForm::getDeleteTime , NumberConstant.ZERO) .eq(ReportForm::getHide, NumberConstant.ONE)); return reportFormList; } /** * 获取指定年月区间的全院损益数据 * @param beginComputeDate * @param endComputeDate * @return */ public List getHospProfitAndLossByDateRange(String beginComputeDate, String endComputeDate, Integer reportType) { // 解析开始和结束时间 int startYear = Integer.parseInt(beginComputeDate.split("-")[0]); int startMonth = Integer.parseInt(beginComputeDate.split("-")[1]); int endYear = Integer.parseInt(endComputeDate.split("-")[0]); int endMonth = Integer.parseInt(endComputeDate.split("-")[1]); if( startYear * 100 + startMonth> endYear * 100 + endMonth){ throw new CostException("开始时间不能大于结束时间"); } //如果截止月份是12月要自动添加第13月的数据 if(endMonth==12) { endMonth=13; } List list = this.list(new QueryWrapper().lambda() .eq(HospProfitAndLoss::getDeleteTime, NumberConstant.ZERO) .eq(HospProfitAndLoss::getHospId, UserContext.getHospId()) .eq(HospProfitAndLoss::getReportType, reportType) .apply("(date_year * 100 + date_month) >= {0}", startYear * 100 + startMonth) .apply("(date_year * 100 + date_month) <= {0}", endYear * 100 + endMonth)); return list; } private static @NotNull HospProfitVO getHospProfitVO(List hospAllList, int i,int reportType) { HospProfitAndLoss hospProfitAndLoss = hospAllList.get(i); HospProfitVO hospProfitVO1 = new HospProfitVO(); hospProfitVO1.setId(Long.valueOf(hospProfitAndLoss.getReportNum())); hospProfitVO1.setNum(hospProfitAndLoss.getReportNum()); hospProfitVO1.setParentId(-1L); hospProfitVO1.setReportName(hospProfitAndLoss.getReportName()); hospProfitVO1.setSort(i); hospProfitVO1.setReportType(reportType); hospProfitVO1.setAmount(hospProfitAndLoss.getAmount()); hospProfitVO1.setFraction(3); return hospProfitVO1; } private List getAllDataByDate(int year, int month, Long hospId,int reportType) { return this.list( new LambdaQueryWrapper() .eq(HospProfitAndLoss::getHospId, hospId) .eq(HospProfitAndLoss::getDateMonth, month) .eq(HospProfitAndLoss::getDateYear, year) .eq(HospProfitAndLoss::getReportType, reportType) ); } /** * @param date * @param hospId */ @Override public void calcByResponsibility(String date, Long hospId) { calcHospProfit(date,hospId,ReportTypeEnum.HOSP_PROFIT_LOSS.getType()); } private void setCalculationAmount(List listVo) { Map> collect = listVo.stream().collect(Collectors.groupingBy(HospProfitAndLossVo::getCalcType)); //取出所有计算公式数据 List costDepartmentProfitVOS = collect.get(NumberConstant.FOUR); costDepartmentProfitVOS.sort(Comparator.comparing(HospProfitAndLossVo::getReportNum, Comparator.nullsLast(Integer::compareTo))); for (HospProfitAndLossVo profitVO : costDepartmentProfitVOS) { // 获取当前报表的计算方式 [1]+[2]类型/ [1]-[2] [1]*[2] [1]/[2] String formula = profitVO.getCalcFormula(); //找出公式当中所有代码 String replace = formula.replace("[", "") .replace("]", "") .replace("-", ",") .replace("+", ",") .replace("*", ",") .replace("/", ","); ArrayList codeList = CollUtil.newArrayList(replace.split(",")); Map codeMap = new ConcurrentHashMap<>(); for (int j = 0; j < codeList.size(); j++) { codeMap.put(j, codeList.get(j)); } List expressions = ReUtil.findAll("[^0-9]", "+" + formula.replace("[", "") .replace("]", "").trim(), 0) .stream().filter(StrUtil::isNotBlank).collect(Collectors.toList()); // 得到预算表达式 得到所有表达式的Map + - 相关的 Map expressionMap = new ConcurrentHashMap<>(); for (int k = 0; k < expressions.size(); k++) { expressionMap.put(k, expressions.get(k)); } // 数字的索引和表达式的索引累加计算 Set codeSet = codeMap.keySet(); List codes = new ArrayList<>(codeSet); AtomicReference totalAmount = new AtomicReference<>(new BigDecimal("0.000000")); for (int i = 0; i < codes.size(); i++) { // 编号 String code = codeMap.get(i); BigDecimal amount = null; for (HospProfitAndLossVo costDepartmentProfitVO : listVo) { if (costDepartmentProfitVO.getReportNum().equals(Integer.valueOf(code))) { amount = costDepartmentProfitVO.getAmount(); } } if (amount == null) { continue; } // BigDecimal amount = new BigDecimal(o.toString()); String str = expressionMap.get(i); if (str.equals("+")) { totalAmount.set(totalAmount.get().add(amount)); } else if (str.contains("-")) { totalAmount.set(totalAmount.get().subtract(amount)); } else if (str.contains("*")) { totalAmount.set(totalAmount.get().multiply(amount)); } else if (str.contains("/")) { if (amount.compareTo(BigDecimal.ZERO.setScale(6, RoundingMode.HALF_UP)) == 0) { totalAmount.set(BigDecimal.ZERO); break; } else { totalAmount.set(totalAmount.get().divide(amount, 6, RoundingMode.HALF_UP)); } } } profitVO.setAmount(totalAmount.get()); } } /** * 按照责任中心进行计算 * 原始责任中心是设置的责任中心 目标责任中心是报表的责任中心 * 查询分摊报表里面目标责任中心是当前责任中心 报表责任中心是当前设置的责任中心 */ public BigDecimal setResponsibilityCode(HospProfitAndLossVo 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 setCalculation(HospProfitAndLossVo 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(HospProfitAndLossVo::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 setSubtotal(HospProfitAndLossVo 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 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()); // 都一个就是 HospProfitAndLossVo costDepartmentProfitVO = costDepartmentProfitVOS.get(0); Integer calcType = costDepartmentProfitVO.getCalcType(); if (NumberConstant.ONE.equals(calcType)) { // 调用计算的方法 按照会计科目 bigDecimal = setAccountReportData(costDepartmentProfitVO, list, allocationQueryReportVOList, reportRelationMap); } else if (NumberConstant.TWO.equals(calcType)) { // 按照分摊层级 bigDecimal = setShareLevelReportData(costDepartmentProfitVO, reportRelationMap, allocationList); } 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; } private BigDecimal setAccountReportData(HospProfitAndLossVo i, List list, List allocationQueryReportVOList, Map> reportRelationMap) { // 在报表关联里面查询当前报表关联的 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 reportVOList = allocationQueryReportVOList.stream().filter(m -> m.getTargetResponsibilityCode().equals(i.getResponsibilityCode()) && accountList.contains(m.getAccountingCode())).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(HospProfitAndLossVo i, 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(shareLevelIds)) { // 查询报表里面是当前分摊层级的数据 List allocations = allocationList.stream().filter(m -> shareLevelIds.contains(m.getShareLevelId()) && 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(); } private void calcByLitterCountResp(HospProfitAndLossVo lossVo, Map> listParentMap, List listVo, Long hospId) { //lossVo 当前 小计对象 //listParentMap 与小计同级别的对象 //listVo 存储计算过的对象 // 通地当前小计 找出 同级别需要合计的对象 再从计算过的对象取出数值合计 Long reportParentId = lossVo.getReportParentId(); List hospProfitAndLossVos = listParentMap.get(reportParentId); //去除小计本身 hospProfitAndLossVos.remove(lossVo); List reportNums = hospProfitAndLossVos.stream().map(HospProfitAndLossVo::getReportNum).collect(Collectors.toList()); List collect = listVo.stream().filter(i -> reportNums.contains(i.getReportNum()) && i.getResponsibilityCode().equals(lossVo.getResponsibilityCode())).collect(Collectors.toList()); if (collect.isEmpty()) { return; } BigDecimal reduce = collect.stream().map(HospProfitAndLossVo::getAmount).reduce(BigDecimal.ZERO, BigDecimal::add); lossVo.setAmount(reduce); } private List costPercent(List profitIncomeList) { List list = new ArrayList<>(); Map> collect = profitIncomeList.stream().collect(Collectors.groupingBy(HospProfitAndLossVo::getFraction)); //分母只有一个 List denominatorList = collect.get(NumberConstant.TWO); if (denominatorList.size() > 1) { throw new CostException("收入项目分母大于一个,请查证后再计算科室损益"); } BigDecimal denominator = denominatorList.get(0).getAmount(); //收入分子 List numeratorList = collect.get(NumberConstant.ONE); if (denominator.compareTo(BigDecimal.ZERO) == 0) { for (HospProfitAndLossVo profitVO : numeratorList) { profitVO.setPercent(BigDecimal.ZERO.setScale(4, RoundingMode.HALF_UP)); } denominatorList.get(0).setPercent(BigDecimal.ZERO.setScale(4, RoundingMode.HALF_UP)); } else { for (HospProfitAndLossVo profitVO : numeratorList) { profitVO.setPercent(profitVO.getAmount().divide(denominator, 4, RoundingMode.HALF_UP)); } denominatorList.get(0).setPercent(BigDecimal.ONE.setScale(4, RoundingMode.HALF_UP)); } list.add(denominatorList.get(0)); list.addAll(numeratorList); return list; } private void calcByResponsibilityResp(Long hospId, HospProfitAndLossVo lossVo) { List responsibilities = reportRelationService.getResponsibilities(lossVo.getReportId(), hospId); if (responsibilities.isEmpty()) { return; } List responsibilityCodes = responsibilities.stream().map(RelationVO::getCode).collect(Collectors.toList()); AtomicReference calcTotal = new AtomicReference<>(); calcTotal.set(BigDecimal.ZERO); List allocationQueries = allocationQueryService.getByDateAndResp(lossVo.getDateYear(), lossVo.getDateMonth(), hospId, lossVo.getResponsibilityCode()); responsibilityCodes.forEach(i -> { BigDecimal costAmount = allocationQueries.stream().filter(j -> i.equals(j.getResponsibilityCode())).map(AllocationQuery::getAmount) .reduce(BigDecimal.ZERO, BigDecimal::add); calcTotal.set(calcTotal.get().add(costAmount)); }); lossVo.setAmount(calcTotal.get()); } private void calcByResponsibilityResp(Long hospId, ReportForm child, List list, int year, int month, Responsibility responsibility) { List responsibilities = reportRelationService.getResponsibilities(child.getId(), hospId); if (responsibilities.isEmpty()) { return; } List responsibilityCodes = responsibilities.stream().map(RelationVO::getCode).collect(Collectors.toList()); AtomicReference calcTotal = new AtomicReference<>(); calcTotal.set(BigDecimal.ZERO); List allocationQueries = allocationQueryService.getByDateAndResp(year, month, hospId, responsibility.getResponsibilityCode()); responsibilityCodes.forEach(i -> { BigDecimal costAmount = allocationQueries.stream().filter(j -> i.equals(j.getResponsibilityCode())).map(AllocationQuery::getAmount) .reduce(BigDecimal.ZERO, BigDecimal::add); calcTotal.set(calcTotal.get().add(costAmount)); }); HospProfitAndLoss loss = new HospProfitAndLoss(); loss.setReportName(child.getReportName()).setReportNum(child.getNum()).setResponsibilityCode(responsibility.getResponsibilityCode()).setResponsibilityName(responsibility.getResponsibilityName()) .setAmount(calcTotal.get()).setCreateTime(System.currentTimeMillis()).setHospId(hospId).setDateYear(year).setDateMonth(month); list.add(loss); } private void calcByFormulaResp(HospProfitAndLossVo lossVo, List list) { // 得到这个责任中心下所有的已经收集的数据 List hadCalcLosses = list.stream().filter(i -> i.getResponsibilityCode().equals(lossVo.getResponsibilityCode())).collect(Collectors.toList()); String calcFormula = lossVo.getCalcFormula(); // TODO: 2021/8/27 校验公式合法性 if (StrUtil.isBlank(calcFormula)) { throw new CostException("reportForm名称为" + lossVo.getReportName() + "计算公式不正确"); } BigDecimal bigDecimal = calcAmountRes(hadCalcLosses, calcFormula); lossVo.setAmount(bigDecimal); } private void calcByFormulaResp(int year, int month, ReportForm child, List list, Responsibility responsibility) { // 得到这个责任中心下所有的已经收集的数据 List hadCalcLosses = list.stream().filter(i -> i.getResponsibilityCode().equals(responsibility.getResponsibilityCode())).collect(Collectors.toList()); String calcFormula = child.getCalcFormula(); // TODO: 2021/8/27 校验公式合法性 if (StrUtil.isBlank(calcFormula)) { throw new CostException("reportForm名称为" + child.getReportName() + "计算公式不正确"); } BigDecimal bigDecimal = calcAmountResp(hadCalcLosses, calcFormula); HospProfitAndLoss loss = new HospProfitAndLoss(); loss.setDateYear(year).setDateMonth(month).setReportNum(child.getNum()).setReportName(child.getReportName()) .setAmount(bigDecimal).setCreateTime(System.currentTimeMillis()).setHospId(child.getHospId()).setResponsibilityCode(responsibility.getResponsibilityCode()).setResponsibilityName(responsibility.getResponsibilityName()); list.add(loss); } private BigDecimal calcAmountRes(List hadCalcLosses, String calcFormula) { // 得到所有的编号 String replace = calcFormula.replace("[", "").replace("]", "").replace("-", ",").replace("+", ","); ArrayList numList = CollUtil.newArrayList(replace.split(",")); // 得到编号的map Map numMap = new ConcurrentHashMap<>(); for (int j = 0; j < numList.size(); j++) { numMap.put(j, Integer.parseInt(numList.get(j))); } List expressions = ReUtil.findAll("[^0-9]", "+" + calcFormula.replace("[", "").replace("]", "").trim(), 0) .stream().filter(StrUtil::isNotBlank).collect(Collectors.toList()); // 得到预算表达式 得到所有表达式的Map + - 相关的 Map expressionMap = new ConcurrentHashMap<>(); for (int k = 0; k < expressions.size(); k++) { expressionMap.put(k, expressions.get(k)); } // 数字的索引和表达式的索引累加计算 Set numSet = numMap.keySet(); List nums = new ArrayList<>(numSet); AtomicReference totalAmount = new AtomicReference<>(); totalAmount.set(BigDecimal.ZERO); for (int i = 0; i < nums.size(); i++) { // 编号 Integer num = numMap.get(i); List losses = hadCalcLosses.stream().filter(item -> item.getReportNum().equals(num)).collect(Collectors.toList()); if (CollUtil.isEmpty(losses)) { continue; } HospProfitAndLossVo loss = losses.get(0); BigDecimal amount = loss.getAmount(); String str = expressionMap.get(i); if (str.equals("+")) { totalAmount.set(totalAmount.get().add(amount)); } else { totalAmount.set(totalAmount.get().subtract(amount)); } } return totalAmount.get(); } private BigDecimal calcAmountResp(List hadCalcLosses, String calcFormula) { // 得到所有的编号 String replace = calcFormula.replace("[", "").replace("]", "").replace("-", ",").replace("+", ","); ArrayList numList = CollUtil.newArrayList(replace.split(",")); // 得到编号的map Map numMap = new ConcurrentHashMap<>(); for (int j = 0; j < numList.size(); j++) { numMap.put(j, Integer.parseInt(numList.get(j))); } List expressions = ReUtil.findAll("[^0-9]", "+" + calcFormula.replace("[", "").replace("]", "").trim(), 0) .stream().filter(StrUtil::isNotBlank).collect(Collectors.toList()); // 得到预算表达式 得到所有表达式的Map + - 相关的 Map expressionMap = new ConcurrentHashMap<>(); for (int k = 0; k < expressions.size(); k++) { expressionMap.put(k, expressions.get(k)); } // 数字的索引和表达式的索引累加计算 Set numSet = numMap.keySet(); List nums = new ArrayList<>(numSet); AtomicReference totalAmount = new AtomicReference<>(); totalAmount.set(BigDecimal.ZERO); for (int i = 0; i < nums.size(); i++) { // 编号 Integer num = numMap.get(i); List losses = hadCalcLosses.stream().filter(item -> item.getReportNum().equals(num)).collect(Collectors.toList()); if (CollUtil.isEmpty(losses)) { continue; } HospProfitAndLoss loss = losses.get(0); BigDecimal amount = loss.getAmount(); String str = expressionMap.get(i); if (str.equals("+")) { totalAmount.set(totalAmount.get().add(amount)); } else { totalAmount.set(totalAmount.get().subtract(amount)); } } return totalAmount.get(); } private void calcByLitterCountResp(int year, int month, ReportForm child, List children, List list, Long hospId, Responsibility responsibility) { List thisRespCodeList = list.stream().filter(i -> i.getResponsibilityCode().equals(responsibility.getResponsibilityCode())).collect(Collectors.toList()); List thisForEachList = children.stream().filter(i -> !i.getCalcType().equals(CalcTypeEnum.LITTER_COUNT.getType())).collect(Collectors.toList()); List collect = thisRespCodeList.stream().filter(i -> thisForEachList.stream().map(ReportForm::getNum).collect(Collectors.toList()).contains(i.getReportNum())).collect(Collectors.toList()); if (collect.isEmpty()) { return; } BigDecimal reduce = collect.stream().map(HospProfitAndLoss::getAmount).reduce(BigDecimal.ZERO, BigDecimal::add); HospProfitAndLoss loss = new HospProfitAndLoss(); loss.setDateYear(year).setDateMonth(month) .setAmount(reduce).setCreateTime(System.currentTimeMillis()).setHospId(hospId); // 小计只能有一个 loss.setReportNum(child.getNum()).setReportName(child.getReportName()) .setResponsibilityCode(responsibility.getResponsibilityCode()) .setResponsibilityName(responsibility.getResponsibilityName()); list.add(loss); } private void calcByShareLevelResp(Long hospId, ReportForm child, List list, int year, int month, Responsibility responsibility) { List shareLevels = reportRelationService.getShareLevel(child.getId(), hospId); List shareLevelId = shareLevels.stream().map(RelationVO::getCode).map(Long::valueOf).sorted(Long::compareTo).collect(Collectors.toList()); if (CollUtil.isEmpty(shareLevelId)) { return; } List costShareLevels = shareLevelService.listByIds(shareLevelId); if (costShareLevels.isEmpty()) { throw new CostException("医院分摊层级设置错误," + child.getReportName()); } List levelSorts = costShareLevels.stream().map(CostShareLevel::getLeverSort).collect(Collectors.toList()); List allocations = allocationQueryService.getByDateRespn(year, month, hospId, shareLevelId, responsibility.getResponsibilityCode()); if (allocations.isEmpty()) { throw new CostException("医院未分摊本月数据"); } List accountShares = accountShareService.getByShareLevelSort(levelSorts, hospId); if (accountShares.isEmpty()) { return; } BigDecimal reduce = allocations.stream().map(AllocationQuery::getAmount).reduce(BigDecimal.ZERO, BigDecimal::add); HospProfitAndLoss loss = new HospProfitAndLoss(); loss.setReportName(child.getReportName()).setReportNum(child.getNum()) .setAmount(reduce).setCreateTime(System.currentTimeMillis()).setHospId(hospId).setDateYear(year).setDateMonth(month) .setResponsibilityCode(responsibility.getResponsibilityCode()).setResponsibilityName(responsibility.getResponsibilityName()) ; list.add(loss); } private void calcByShareLevelResp(Long hospId, HospProfitAndLossVo lossVo) { List shareLevels = reportRelationService.getShareLevel(lossVo.getReportId(), hospId); List shareLevelId = shareLevels.stream().map(RelationVO::getCode).map(Long::valueOf).sorted(Long::compareTo).collect(Collectors.toList()); if (CollUtil.isEmpty(shareLevelId)) { return; } List costShareLevels = shareLevelService.listByIds(shareLevelId); if (costShareLevels.isEmpty()) { throw new CostException("医院分摊层级设置错误," + lossVo.getReportName()); } List levelSorts = costShareLevels.stream().map(CostShareLevel::getLeverSort).collect(Collectors.toList()); List allocations = allocationQueryService.getByDateRespn(lossVo.getDateYear(), lossVo.getDateMonth(), hospId, shareLevelId, lossVo.getResponsibilityCode()); if (allocations.isEmpty()) { throw new CostException("医院未分摊本月数据"); } List accountShares = accountShareService.getByShareLevelSort(levelSorts, hospId); if (accountShares.isEmpty()) { return; } BigDecimal reduce = allocations.stream().map(AllocationQuery::getAmount).reduce(BigDecimal.ZERO, BigDecimal::add); lossVo.setAmount(reduce); // HospProfitAndLoss loss = new HospProfitAndLoss(); // loss.setReportName(child.getReportName()).setReportNum(child.getNum()) // .setAmount(reduce).setCreateTime(System.currentTimeMillis()).setHospId(hospId).setDateYear(year).setDateMonth(month) // .setResponsibilityCode(responsibility.getResponsibilityCode()).setResponsibilityName(responsibility.getResponsibilityName()) // ; // list.add(loss); } private void calcByAccountByResp(Long hospId, HospProfitAndLossVo lossVo) { // 报表项目关联的会计科目对象 List accountRelations = reportRelationService.getAccountRelation(lossVo.getReportId(), hospId); if (accountRelations.isEmpty()) { return; } List accountCodes = accountRelations.stream().map(RelationVO::getCode).collect(Collectors.toList()); AtomicReference calcTotal = new AtomicReference<>(); calcTotal.set(BigDecimal.ZERO); List incomes = collectionService.getCollectionsByDateAndResp(lossVo.getDateYear(), lossVo.getDateMonth(), hospId, lossVo.getResponsibilityCode()); List allocationQueries = allocationQueryService.getByDateAndResp(lossVo.getDateYear(), lossVo.getDateMonth(), hospId, lossVo.getResponsibilityCode()); accountCodes.forEach(i -> { BigDecimal incomeAmount = incomes.stream().filter(j -> i.equals(j.getAccountingCode())).map(IncomeCollection::getAmount) .reduce(BigDecimal.ZERO, BigDecimal::add); BigDecimal costAmount = allocationQueries.stream().filter(j -> i.equals(j.getAccountingCode())).map(AllocationQuery::getAmount) .reduce(BigDecimal.ZERO, BigDecimal::add); BigDecimal total = incomeAmount.add(costAmount); calcTotal.set(calcTotal.get().add(total)); }); // HospProfitAndLoss loss = new HospProfitAndLoss(); lossVo.setAmount(calcTotal.get()); // loss.setReportName(child.getReportName()).setReportNum(child.getNum()) // .setAmount(calcTotal.get()).setCreateTime(System.currentTimeMillis()).setHospId(hospId).setDateYear(year).setDateMonth(month) // .setResponsibilityCode(responsibility.getResponsibilityCode()).setResponsibilityName(responsibility.getResponsibilityName()); // list.add(loss); } private void calcByAccountByResp(Long hospId, ReportForm child, List list, int month, int year, Responsibility responsibility) { // 报表项目关联的会计科目对象 List accountRelations = reportRelationService.getAccountRelation(child.getId(), hospId); if (accountRelations.isEmpty()) { return; } List accountCodes = accountRelations.stream().map(RelationVO::getCode).collect(Collectors.toList()); AtomicReference calcTotal = new AtomicReference<>(); calcTotal.set(BigDecimal.ZERO); List incomes = collectionService.getCollectionsByDateAndResp(year, month, hospId, responsibility.getResponsibilityCode()); List allocationQueries = allocationQueryService.getByDateAndResp(year, month, hospId, responsibility.getResponsibilityCode()); accountCodes.forEach(i -> { BigDecimal incomeAmount = incomes.stream().filter(j -> i.equals(j.getAccountingCode())).map(IncomeCollection::getAmount) .reduce(BigDecimal.ZERO, BigDecimal::add); BigDecimal costAmount = allocationQueries.stream().filter(j -> i.equals(j.getAccountingCode())).map(AllocationQuery::getAmount) .reduce(BigDecimal.ZERO, BigDecimal::add); BigDecimal total = incomeAmount.add(costAmount); calcTotal.set(calcTotal.get().add(total)); }); HospProfitAndLoss loss = new HospProfitAndLoss(); loss.setReportName(child.getReportName()).setReportNum(child.getNum()) .setAmount(calcTotal.get()).setCreateTime(System.currentTimeMillis()).setHospId(hospId).setDateYear(year).setDateMonth(month) .setResponsibilityCode(responsibility.getResponsibilityCode()).setResponsibilityName(responsibility.getResponsibilityName()) ; list.add(loss); } private void responsibilitySort(List responsibilityList) { for (Responsibility responsibility : responsibilityList) { if (!CollectionUtils.isEmpty(responsibility.getChildren())) { responsibilitySort(responsibility.getChildren()); } } responsibilityList.sort(Comparator.comparing(Responsibility::getSort, Comparator.nullsLast(Integer::compareTo))); } private List setResponsibilityChildren(List child, Map> collect) { for (Responsibility responsibility : child) { if (!CollectionUtils.isEmpty(collect.get(responsibility.getId()))) { responsibility.setChildren(setResponsibilityChildren(collect.get(responsibility.getId()), collect)); } } return child; } private void getResponsibilityParent(Responsibility responsibility, Map collect, List addList) { Responsibility responsibility1 = collect.get(responsibility.getParentId()); if (Objects.nonNull(responsibility1)) { addList.add(responsibility1); if (!responsibility1.getParentId().equals(NumberConstant.ZERO_L)) { getResponsibilityParent(responsibility1, collect, addList); } } } private List setChildren(List child, Map> collect) { for (HospProfitVO costProfitVo : child) { if (!CollectionUtils.isEmpty(collect.get(costProfitVo.getId()))) { costProfitVo.setChild(setChildren(collect.get(costProfitVo.getId()), collect)); } } if (!CollectionUtils.isEmpty(child)) { child.sort(Comparator.comparing(HospProfitVO::getSort, Comparator.nullsLast(Integer::compareTo))); } return child; } }