package com.imed.costaccount.service.impl; import cn.hutool.core.collection.CollUtil; import cn.hutool.core.date.DateTime; import cn.hutool.core.date.DateUtil; import cn.hutool.core.io.IoUtil; import cn.hutool.core.util.ReUtil; import cn.hutool.core.util.StrUtil; import cn.hutool.poi.excel.ExcelUtil; import cn.hutool.poi.excel.ExcelWriter; import cn.hutool.poi.excel.StyleSet; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.imed.costaccount.common.enums.CalcTypeEnum; import com.imed.costaccount.common.enums.ReportTypeEnum; import com.imed.costaccount.common.exception.CostException; import com.imed.costaccount.common.util.BeanUtil; import com.imed.costaccount.common.util.PageUtils; import com.imed.costaccount.model.*; import com.imed.costaccount.model.vo.HospProfitVO; import com.imed.costaccount.model.vo.RelationVO; import com.imed.costaccount.model.vo.ReportFormVO; import com.imed.costaccount.service.*; import lombok.extern.slf4j.Slf4j; import org.apache.poi.hssf.usermodel.HSSFCellStyle; import org.apache.poi.ss.usermodel.*; import org.apache.poi.xssf.usermodel.XSSFCellStyle; import org.springframework.stereotype.Service; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.imed.costaccount.mapper.HospProfitAndLossMapper; import org.springframework.transaction.annotation.Propagation; import org.springframework.transaction.annotation.Transactional; import javax.servlet.ServletOutputStream; import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.math.BigDecimal; 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 { 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; public HospProfitAndLossServiceImpl(ReportFormService reportFormService, IncomeCollectionService collectionService, AllocationQueryService allocationQueryService, AllocationService allocationService, ReportRelationService reportRelationService, CostShareLevelService shareLevelService, CostOtherPaymentsDataService otherPaymentsDataService, ResponsibilityService responsibilityService, CostAccountShareService accountShareService) { 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; } /** * 计算全院损益 * * @param date yyyy-MM-dd 时间 * @param hospId 医院id */ @Override @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Throwable.class) public void calc(String date, Long 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) { // 报表项目关联的会计科目对象 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) { DateTime parse = DateUtil.parse(date); int year = DateUtil.year(parse); int month = DateUtil.month(parse) + 1; Page page = new Page<>(current, pageSize); Page pages = this.page( page, new LambdaQueryWrapper() .eq(HospProfitAndLoss::getHospId, hospId) .eq(HospProfitAndLoss::getDateMonth, month) .eq(HospProfitAndLoss::getDateYear, year) ); List records = pages.getRecords(); List hospProfitVOS = BeanUtil.convertList(records, HospProfitVO.class); PageUtils pageUtils = new PageUtils(pages); pageUtils.setList(hospProfitVOS); return pageUtils; } /** * 导出全院损益计算 * * @param date yyyy-MM-dd * @param hospId * @param response */ @Override public void hospProfitReport(String date, Long hospId, HttpServletResponse response) { DateTime parse = DateUtil.parse(date); int year = DateUtil.year(parse); int month = DateUtil.month(parse) + 1; // 得到所有责任中心的子节点 List leafResp = responsibilityService.getLeafResp(hospId); // 得到上一层的title子节点 ExcelWriter writer = ExcelUtil.getWriter(); 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 { 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("请先设置全院损益报表"); } // 查询所有的全院损益数据 内存溢出问题 List list = getAllDataByDate(year, month, hospId); int lastRow = 3; Sheet sheet = writer.getSheet(); 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(); 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); } } lastRow = lastRow + size; } response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=utf-8"); response.setHeader("Content-Disposition", "attachment;filename=" + "全院损益列表" + ".xls"); ServletOutputStream out = null; try { out = response.getOutputStream(); } catch (IOException e) { e.printStackTrace(); } writer.flush(out, true); writer.close(); IoUtil.close(out); } // private List getLeafRespOnlyOne(Long hospId, List leafResp) { // List parentIds = leafResp.stream().map(Responsibility::getParentId).collect(Collectors.toList()); // responsibilityService.getById(pare) // // } 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 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("医院未归集本月收入数据"); } // 得到这个月的所有成本数据 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 (Responsibility responsibility : leafResp) { 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()) { // 按会计科目计算单的话 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 { } } } } // 处理医院其他收支 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 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(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 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 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); } }