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.Constant; import com.kcim.common.constants.NumberConstant; import com.kcim.common.enums.CalcTypeEnum; import com.kcim.common.enums.ErrorCodeEnum; import com.kcim.common.enums.ReportTypeEnum; import com.kcim.common.exception.CostException; import com.kcim.common.file.MinioConfig; import com.kcim.common.file.MinioFileUtil; import com.kcim.common.util.BeanUtil; import com.kcim.common.util.PageUtils; import com.kcim.common.util.UserContext; 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.AllocationQueryReportVO; import com.kcim.vo.HospProfitAndLossVo; import com.kcim.vo.RelationVO; 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.springframework.stereotype.Service; import org.springframework.transaction.annotation.Propagation; import org.springframework.transaction.annotation.Transactional; import org.springframework.util.CollectionUtils; 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.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 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) { 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; } /** * 计算全院损益 * * @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); } // 计算公式中钱 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); 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("全院损益"); 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); } private List getAllDataByDate(int year, int month, Long hospId) { return this.list( new LambdaQueryWrapper() .eq(HospProfitAndLoss::getHospId, hospId) .eq(HospProfitAndLoss::getDateMonth, month) .eq(HospProfitAndLoss::getDateYear, year) ); } /** * @param date * @param hospId */ @Override @Transactional(rollbackFor = Throwable.class, propagation = Propagation.REQUIRED) public void calcByResponsibility(String date, Long hospId) { 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) ); // 得到全院损益计算报表 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("医院未归集本月收入数据"); } 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.0000")); } }); // // // // listVo.forEach(i -> { // Integer calcType = i.getCalcType(); // if (calcType == CalcTypeEnum.BY_ACCOUNT.getType()) { // // 按会计科目计算单的话 // calcByAccountByResp(hospId, i); // } else if (calcType == CalcTypeEnum.BY_SHARE_LEVEL.getType()) { // // 分摊层级计算 // calcByShareLevelResp(hospId, i); // } else if (calcType == CalcTypeEnum.LITTER_COUNT.getType()) { // // 处理小计 todo 默认认为 小计都是在同一个下面最后一个 // calcByLitterCountResp(i,listParentMap, listVo,hospId); // } else if (calcType == CalcTypeEnum.CALC_FORMULA.getType()) { // // 按公式 (要保证总合计放到最后呀) // calcByFormulaResp(i,listVo); // } else if (calcType == CalcTypeEnum.BY_RESPONSIBILITY.getType()) { // // 责任中心 // calcByResponsibilityResp(hospId, i); // } else if (calcType == CalcTypeEnum.NO_CONFIG.getType()) { // // 不设置不计算 // i.setAmount(new BigDecimal("0.0000")); // } else { // i.setAmount(new BigDecimal("0.0000")); // } // }); // for (Responsibility responsibility : leafResp) { // for (ReportForm parentForm : reportForms) { // 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()) { // // 按会计科目计算单的话 // calcByAccountByResp(hospId, child, list, month, year, responsibility); // } else if (calcType == CalcTypeEnum.BY_SHARE_LEVEL.getType()) { // // 分摊层级计算 // calcByShareLevelResp(hospId, child, list, year, month, responsibility); // } else if (calcType == CalcTypeEnum.LITTER_COUNT.getType()) { // // 处理小计 todo 默认认为 小计都是在同一个下面最后一个 // calcByLitterCountResp(year, month, child, children, list, hospId, responsibility); // } else if (calcType == CalcTypeEnum.CALC_FORMULA.getType()) { // // 按公式 (要保证总合计放到最后呀) // calcByFormulaResp(year, month, child, list, responsibility); // } else if (calcType == CalcTypeEnum.BY_RESPONSIBILITY.getType()) { // // 责任中心 // calcByResponsibilityResp(hospId, child, list, year, month, responsibility); // } else if (calcType == CalcTypeEnum.NO_CONFIG.getType()) { // // 不设置不计算 // } else { // // } // } // } // } //计算占比 if (CollectionUtils.isEmpty(listVo)) { return; } //收入 List profitIncomeList = listVo.stream().filter(f -> f.getType().equals(NumberConstant.ONE)).collect(Collectors.toList()); List profitIncome = costPercent(profitIncomeList); //成本 List profitCostList = listVo.stream().filter(f -> f.getType().equals(NumberConstant.TWO)).collect(Collectors.toList()); List profitCost = costPercent(profitCostList); //不计算项目 List noCompute = listVo.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()) { otherPaymentsDatas.forEach(ele -> { 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) ; list.add(loss); }); } long l = System.currentTimeMillis(); list.forEach(i -> { i.setCreateTime(l); }); this.saveBatch(list); } /** * 按照责任中心进行计算 * 原始责任中心是设置的责任中心 目标责任中心是报表的责任中心 * 查询分摊报表里面目标责任中心是当前责任中心 报表责任中心是当前设置的责任中心 */ 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> responsibilityGroup = profitIncomeList.stream().collect(Collectors.groupingBy(HospProfitAndLossVo::getResponsibilityCode)); for (String s : responsibilityGroup.keySet()) { List costDepartmentProfitVOS = responsibilityGroup.get(s); Map> collect = costDepartmentProfitVOS.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); } }