123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744 |
- 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<HospProfitAndLossMapper, HospProfitAndLoss> 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<HospProfitAndLoss>().eq(HospProfitAndLoss::getDateYear, year).eq(HospProfitAndLoss::getDateMonth, month).eq(HospProfitAndLoss::getHospId, hospId));
- // 得到全院损益计算报表
- List<ReportForm> reportForms = reportFormService.getListByReportType(hospId, ReportTypeEnum.HOSP_PROFIT_LOSS.getType());
- if (CollUtil.isEmpty(reportForms)) {
- throw new CostException("医院未设置全院损益计算报表");
- }
- // 得到这个月所有收入数据
- List<IncomeCollection> incomes = collectionService.getCollectionsByDate(year, month, hospId);
- if (incomes.isEmpty()) {
- throw new CostException("医院未归集本月收入数据");
- }
- // 得到这个月的所有成本数据
- List<AllocationQuery> allocationQueries = allocationQueryService.getAllByDate(hospId, year, month);
- if (allocationQueries.isEmpty()) {
- throw new CostException("医院未分摊本月数据");
- }
- List<HospProfitAndLoss> list = new ArrayList<>();
- List<ReportForm> parentForms = reportForms.stream().filter(i -> i.getParentId().equals(0L)).collect(Collectors.toList());
- for (ReportForm parentForm : parentForms) {
- Long parentId = parentForm.getId();
- List<ReportForm> 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<CostOtherPaymentsData> 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<HospProfitAndLoss> list, String calcFormula, ReportForm reportForm) {
- // 得到所有的编号
- String replace = calcFormula.replace("[", "").replace("]", "").replace("-", ",").replace("+", ",");
- ArrayList<String> numList = CollUtil.newArrayList(replace.split(","));
- // 得到编号的map
- Map<Integer, Integer> numMap = new ConcurrentHashMap<>();
- for (int j = 0; j < numList.size(); j++) {
- numMap.put(j, Integer.parseInt(numList.get(j)));
- }
- List<String> expressions = ReUtil.findAll("[^0-9]", "+" + calcFormula.replace("[", "").replace("]", "").trim(), 0)
- .stream().filter(StrUtil::isNotBlank).collect(Collectors.toList());
- // 得到预算表达式 得到所有表达式的Map + - 相关的
- Map<Integer, String> expressionMap = new ConcurrentHashMap<>();
- for (int k = 0; k < expressions.size(); k++) {
- expressionMap.put(k, expressions.get(k));
- }
- // 数字的索引和表达式的索引累加计算
- Set<Integer> numSet = numMap.keySet();
- List<Integer> nums = new ArrayList<>(numSet);
- AtomicReference<BigDecimal> totalAmount = new AtomicReference<>();
- totalAmount.set(BigDecimal.ZERO);
- for (int i = 0; i < nums.size(); i++) {
- // 编号
- Integer num = numMap.get(i);
- List<HospProfitAndLoss> 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<AllocationQuery> allocationQueries, List<HospProfitAndLoss> list, int year, int month) {
- List<RelationVO> responsibilities = reportRelationService.getResponsibilities(reportForm.getId(), hospId);
- if (responsibilities.isEmpty()) {
- return;
- }
- List<String> accountCodes = responsibilities.stream().map(RelationVO::getCode).collect(Collectors.toList());
- AtomicReference<BigDecimal> 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<ReportForm> reportForms, List<HospProfitAndLoss> list) {
- // 得到当前下按公式计算的
- List<ReportForm> 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<ReportForm> reportForms, List<HospProfitAndLoss> list, Long hospId) {
- // 其他的
- List<ReportForm> calcList = reportForms.stream().filter(i -> !i.getCalcType().equals(CalcTypeEnum.LITTER_COUNT.getType())).collect(Collectors.toList());
- List<HospProfitAndLoss> 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<HospProfitAndLoss> list, int year, int month) {
- List<RelationVO> shareLevels = reportRelationService.getShareLevel(reportForm.getId(), hospId);
- List<Long> shareLevelId = shareLevels.stream().map(RelationVO::getCode).map(Long::valueOf).sorted(Long::compareTo).collect(Collectors.toList());
- if (CollUtil.isEmpty(shareLevelId)) {
- return;
- }
- List<CostShareLevel> costShareLevels = shareLevelService.listByIds(shareLevelId);
- if (costShareLevels.isEmpty()) {
- throw new CostException("医院分摊层级设置错误," + reportForm.getReportName());
- }
- List<Integer> levelSorts = costShareLevels.stream().map(CostShareLevel::getLeverSort).collect(Collectors.toList());
- List<AllocationQuery> allocations = allocationQueryService.getByDate(year, month, hospId, shareLevelId);
- if (allocations.isEmpty()) {
- throw new CostException("医院未分摊本月数据");
- }
- List<CostAccountShare> 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<IncomeCollection> incomes, List<HospProfitAndLoss> list, List<AllocationQuery> allocationQueries, int month, int year) {
- // 报表项目关联的会计科目对象
- List<RelationVO> accountRelations = reportRelationService.getAccountRelation(reportForm.getId(), hospId);
- if (accountRelations.isEmpty()) {
- return;
- }
- List<String> accountCodes = accountRelations.stream().map(RelationVO::getCode).collect(Collectors.toList());
- AtomicReference<BigDecimal> 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<HospProfitAndLoss> page = new Page<>(current, pageSize);
- Page<HospProfitAndLoss> pages = this.page(
- page,
- new LambdaQueryWrapper<HospProfitAndLoss>()
- .eq(HospProfitAndLoss::getHospId, hospId)
- .eq(HospProfitAndLoss::getDateMonth, month)
- .eq(HospProfitAndLoss::getDateYear, year)
- );
- List<HospProfitAndLoss> records = pages.getRecords();
- List<HospProfitVO> 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<Responsibility> leafResp = responsibilityService.getLeafResp(hospId);
- // 得到上一层的title子节点
- ExcelWriter writer = ExcelUtil.getWriter();
- List<String> 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<Long, Object> 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<ReportFormVO> allHospList = reportFormService.getAllHospList(hospId);
- if (allHospList.isEmpty()) {
- throw new CostException("请先设置全院损益报表");
- }
- // 查询所有的全院损益数据 内存溢出问题
- List<HospProfitAndLoss> 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<ReportFormVO> 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<String> getLeafRespOnlyOne(Long hospId, List<Responsibility> leafResp) {
- // List<Long> parentIds = leafResp.stream().map(Responsibility::getParentId).collect(Collectors.toList());
- // responsibilityService.getById(pare)
- //
- // }
- private List<HospProfitAndLoss> getAllDataByDate(int year, int month, Long hospId) {
- return this.list(
- new LambdaQueryWrapper<HospProfitAndLoss>()
- .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<Responsibility> leafResp = responsibilityService.getLeafResp(hospId);
- DateTime parse = DateUtil.parse(date);
- int year = DateUtil.year(parse);
- int month = DateUtil.month(parse) + 1;
- this.remove(new LambdaQueryWrapper<HospProfitAndLoss>().eq(HospProfitAndLoss::getDateYear, year).eq(HospProfitAndLoss::getDateMonth, month).eq(HospProfitAndLoss::getHospId, hospId));
- // 得到全院损益计算报表
- List<ReportForm> reportForms = reportFormService.getListByReportType(hospId, ReportTypeEnum.HOSP_PROFIT_LOSS.getType());
- if (CollUtil.isEmpty(reportForms)) {
- throw new CostException("医院未设置全院损益计算报表");
- }
- // 得到这个月所有收入数据
- List<IncomeCollection> incomes = collectionService.getCollectionsByDate(year, month, hospId);
- if (incomes.isEmpty()) {
- throw new CostException("医院未归集本月收入数据");
- }
- // 得到这个月的所有成本数据
- List<AllocationQuery> allocationQueries = allocationQueryService.getAllByDate(hospId, year, month);
- if (allocationQueries.isEmpty()) {
- throw new CostException("医院未分摊本月数据");
- }
- List<HospProfitAndLoss> list = new ArrayList<>();
- List<ReportForm> 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<ReportForm> 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<CostOtherPaymentsData> 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<HospProfitAndLoss> list, int year, int month, Responsibility responsibility) {
- List<RelationVO> responsibilities = reportRelationService.getResponsibilities(child.getId(), hospId);
- if (responsibilities.isEmpty()) {
- return;
- }
- List<String> responsibilityCodes = responsibilities.stream().map(RelationVO::getCode).collect(Collectors.toList());
- AtomicReference<BigDecimal> calcTotal = new AtomicReference<>();
- calcTotal.set(BigDecimal.ZERO);
- List<AllocationQuery> 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<HospProfitAndLoss> list, Responsibility responsibility) {
- // 得到这个责任中心下所有的已经收集的数据
- List<HospProfitAndLoss> 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<HospProfitAndLoss> hadCalcLosses, String calcFormula) {
- // 得到所有的编号
- String replace = calcFormula.replace("[", "").replace("]", "").replace("-", ",").replace("+", ",");
- ArrayList<String> numList = CollUtil.newArrayList(replace.split(","));
- // 得到编号的map
- Map<Integer, Integer> numMap = new ConcurrentHashMap<>();
- for (int j = 0; j < numList.size(); j++) {
- numMap.put(j, Integer.parseInt(numList.get(j)));
- }
- List<String> expressions = ReUtil.findAll("[^0-9]", "+" + calcFormula.replace("[", "").replace("]", "").trim(), 0)
- .stream().filter(StrUtil::isNotBlank).collect(Collectors.toList());
- // 得到预算表达式 得到所有表达式的Map + - 相关的
- Map<Integer, String> expressionMap = new ConcurrentHashMap<>();
- for (int k = 0; k < expressions.size(); k++) {
- expressionMap.put(k, expressions.get(k));
- }
- // 数字的索引和表达式的索引累加计算
- Set<Integer> numSet = numMap.keySet();
- List<Integer> nums = new ArrayList<>(numSet);
- AtomicReference<BigDecimal> totalAmount = new AtomicReference<>();
- totalAmount.set(BigDecimal.ZERO);
- for (int i = 0; i < nums.size(); i++) {
- // 编号
- Integer num = numMap.get(i);
- List<HospProfitAndLoss> 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<ReportForm> children,
- List<HospProfitAndLoss> list, Long hospId, Responsibility responsibility) {
- List<HospProfitAndLoss> thisRespCodeList = list.stream().filter(i -> i.getResponsibilityCode().equals(responsibility.getResponsibilityCode())).collect(Collectors.toList());
- List<ReportForm> thisForEachList = children.stream().filter(i -> !i.getCalcType().equals(CalcTypeEnum.LITTER_COUNT.getType())).collect(Collectors.toList());
- List<HospProfitAndLoss> 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<HospProfitAndLoss> list, int year, int month, Responsibility responsibility) {
- List<RelationVO> shareLevels = reportRelationService.getShareLevel(child.getId(), hospId);
- List<Long> shareLevelId = shareLevels.stream().map(RelationVO::getCode).map(Long::valueOf).sorted(Long::compareTo).collect(Collectors.toList());
- if (CollUtil.isEmpty(shareLevelId)) {
- return;
- }
- List<CostShareLevel> costShareLevels = shareLevelService.listByIds(shareLevelId);
- if (costShareLevels.isEmpty()) {
- throw new CostException("医院分摊层级设置错误," + child.getReportName());
- }
- List<Integer> levelSorts = costShareLevels.stream().map(CostShareLevel::getLeverSort).collect(Collectors.toList());
- List<AllocationQuery> allocations = allocationQueryService.getByDateRespn(year, month, hospId, shareLevelId, responsibility.getResponsibilityCode());
- if (allocations.isEmpty()) {
- throw new CostException("医院未分摊本月数据");
- }
- List<CostAccountShare> 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<HospProfitAndLoss> list, int month, int year, Responsibility responsibility) {
- // 报表项目关联的会计科目对象
- List<RelationVO> accountRelations = reportRelationService.getAccountRelation(child.getId(), hospId);
- if (accountRelations.isEmpty()) {
- return;
- }
- List<String> accountCodes = accountRelations.stream().map(RelationVO::getCode).collect(Collectors.toList());
- AtomicReference<BigDecimal> calcTotal = new AtomicReference<>();
- calcTotal.set(BigDecimal.ZERO);
- List<IncomeCollection> incomes = collectionService.getCollectionsByDateAndResp(year, month, hospId, responsibility.getResponsibilityCode());
- List<AllocationQuery> 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);
- }
- }
|