123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367 |
- package com.imed.costaccount.service.impl;
- import cn.hutool.core.collection.CollUtil;
- import cn.hutool.core.date.DateTime;
- import cn.hutool.core.date.DateUtil;
- import cn.hutool.core.util.ReUtil;
- import cn.hutool.core.util.StrUtil;
- 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.service.*;
- 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 java.math.BigDecimal;
- import java.util.*;
- import java.util.concurrent.ConcurrentHashMap;
- import java.util.concurrent.atomic.AtomicReference;
- import java.util.stream.Collectors;
- @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;
- public HospProfitAndLossServiceImpl(ReportFormService reportFormService,
- IncomeCollectionService collectionService,
- AllocationQueryService allocationQueryService,
- AllocationService allocationService,
- ReportRelationService reportRelationService,
- CostShareLevelService shareLevelService,
- CostOtherPaymentsDataService otherPaymentsDataService) {
- this.reportFormService = reportFormService;
- this.collectionService = collectionService;
- this.allocationQueryService = allocationQueryService;
- this.allocationService = allocationService;
- this.reportRelationService = reportRelationService;
- this.shareLevelService = shareLevelService;
- this.otherPaymentsDataService = otherPaymentsDataService;
- }
- /**
- * 计算全院损益
- *
- * @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<>();
- reportForms.forEach(i -> {
- Integer calcType = i.getCalcType();
- if (calcType == CalcTypeEnum.BY_ACCOUNT.getType()) {
- // 按会计科目计算
- HospProfitAndLoss loss = calcByAccount(hospId, i, incomes, allocationQueries);
- if (Objects.isNull(loss)) {
- return;
- }
- loss.setDateMonth(month);
- loss.setDateYear(year);
- list.add(loss);
- return;
- } else if (calcType == CalcTypeEnum.BY_SHARE_LEVEL.getType()) {
- // 分摊层级计算
- HospProfitAndLoss loss = calcByShareLevel(hospId, i, year, month);
- if (Objects.isNull(loss)) {
- return;
- }
- loss.setDateMonth(month);
- loss.setDateYear(year);
- list.add(loss);
- return;
- } else if (calcType == CalcTypeEnum.LITTER_COUNT.getType()) {
- return;
- } else if (calcType == CalcTypeEnum.CALC_FORMULA.getType()) {
- // todo 留在最后加减
- return;
- } else if (calcType == CalcTypeEnum.BY_RESPONSIBILITY.getType()) {
- // 责任中心
- HospProfitAndLoss loss = calcByResponsibility(hospId, i, incomes, allocationQueries);
- if (loss == null) {
- return;
- }
- loss.setDateMonth(month);
- loss.setDateYear(year);
- list.add(loss);
- } else {
- // 不设置不计算
- return;
- }
- });
- // 先处理按公式
- calcByFormula(year, month, reportForms, list);
- // 处理小计
- calcByLitterCount(year, month, reportForms, list, hospId);
- // 处理医院其他收支
- 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) {
- String replace = calcFormula.replace("[", "").replace("]", "").replace("-", ",").replace("+", ",");
- ArrayList<String> numList = CollUtil.newArrayList(replace.split(","));
- // 得到数字
- Map<Integer, Object> numMap = new ConcurrentHashMap<>();
- for (int j = 0; j < numList.size(); j++) {
- numMap.put(j, numList.get(j));
- }
- List<String> expressions = ReUtil.findAll("[^0-9]", "+" + calcFormula.replace("[", "").replace("]", "").trim(), 0)
- .stream().filter(StrUtil::isNotBlank).collect(Collectors.toList());
- // 得到预算表达式
- 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);
- Map<Integer, BigDecimal> map = new HashMap<>();
- for (int l = 0; l < nums.size(); l++) {
- for (HospProfitAndLoss z : list) {
- if (z.getReportNum().equals(nums.get(l))) {
- map.put(l, z.getAmount());
- }
- }
- }
- Set<Integer> integers = map.keySet();
- List<Integer> mapList = new ArrayList<>(integers);
- AtomicReference<BigDecimal> total = new AtomicReference<>();
- total.set(BigDecimal.ZERO);
- for (int x = 0; x < mapList.size(); x++) {
- BigDecimal bigDecimal = map.get(x);
- if (expressionMap.get(x).equals("+")) {
- total.set(total.get().add(bigDecimal));
- } else {
- total.set(total.get().subtract(bigDecimal));
- }
- }
- return total.get();
- }
- /**
- * 按责任中心计算
- *
- * @param hospId 医院id
- * @param reportForm 报表
- * @param incomes 归集收入数据
- * @param allocationQueries 分摊成本数据
- */
- private HospProfitAndLoss calcByResponsibility(Long hospId, ReportForm reportForm, List<IncomeCollection> incomes, List<AllocationQuery> allocationQueries) {
- List<RelationVO> responsibilities = reportRelationService.getAccountRelation(reportForm.getId(), hospId);
- if (responsibilities.isEmpty()) {
- return null;
- }
- 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();
- return loss.setReportName(reportForm.getReportName()).setReportNum(reportForm.getNum())
- .setAmount(calcTotal.get()).setCreateTime(System.currentTimeMillis()).setHospId(hospId);
- }
- /**
- * 按计算公式计算
- */
- private void calcByFormula(Integer year, Integer month, List<ReportForm> reportForms, List<HospProfitAndLoss> list) {
- List<ReportForm> calcFormulas = reportForms.stream().filter(i -> i.getCalcType() == CalcTypeEnum.CALC_FORMULA.getType()).collect(Collectors.toList());
- calcFormulas.forEach(i -> {
- String calcFormula = i.getCalcFormula();
- // TODO: 2021/8/27 校验公式合法性
- if (StrUtil.isBlank(calcFormula)) {
- throw new CostException("reportForm名称为" + i.getReportName() + "计算公式不正确");
- }
- BigDecimal bigDecimal = calcAmount(list, calcFormula);
- 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, List<ReportForm> reportForms, List<HospProfitAndLoss> list, Long hospId) {
- List<ReportForm> litterCounts = reportForms.stream().filter(i -> i.getCalcType() == CalcTypeEnum.LITTER_COUNT.getType()).collect(Collectors.toList());
- litterCounts.forEach(reportForm -> {
- Long parentId = reportForm.getParentId();
- List<ReportForm> reportFormByParents = reportFormService.getByParentId(hospId, parentId);
- List<Integer> reportNums = new ArrayList<>();
- reportFormByParents.forEach(form -> {
- // 去掉自己
- if (form.getId().equals(reportForm.getId())) {
- return;
- }
- reportNums.add(form.getNum());
- });
- AtomicReference<BigDecimal> total = new AtomicReference<>();
- total.set(BigDecimal.ZERO);
- reportNums.forEach(num -> {
- list.forEach(item -> {
- if (num.equals(item.getReportNum())) {
- total.set(total.get().add(item.getAmount()));
- }
- });
- });
- HospProfitAndLoss loss = new HospProfitAndLoss();
- loss.setDateYear(year).setDateMonth(month).setReportNum(reportForm.getNum())
- .setReportName(reportForm.getReportName()).setAmount(total.get()).setCreateTime(System.currentTimeMillis()).setHospId(hospId);
- list.add(loss);
- });
- }
- /**
- * 按分摊层级计算
- *
- * @param hospId 医院id
- * @param reportForm 报表
- * @param year
- * @param month
- */
- private HospProfitAndLoss calcByShareLevel(Long hospId, ReportForm reportForm, int year, int month) {
- List<RelationVO> shareLevels = reportRelationService.getAccountRelation(reportForm.getId(), hospId);
- List<Long> shareLevelId = shareLevels.stream().map(RelationVO::getCode).map(Long::valueOf).collect(Collectors.toList());
- if (CollUtil.isEmpty(shareLevelId)) {
- return null;
- }
- 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<Allocation> allocations = allocationService.getByDate(year, month, hospId, levelSorts);
- if (allocations.isEmpty()) {
- throw new CostException("医院未分摊本月数据");
- }
- BigDecimal reduce = allocations.stream().map(Allocation::getAmount).reduce(BigDecimal.ZERO, BigDecimal::add);
- HospProfitAndLoss loss = new HospProfitAndLoss();
- return loss.setReportName(reportForm.getReportName()).setReportNum(reportForm.getNum())
- .setAmount(reduce).setCreateTime(System.currentTimeMillis()).setHospId(hospId);
- }
- /**
- * 计算按会计科目下的科目名称
- *
- * @param hospId 医院id
- * @param reportForm 报表
- * @param incomes 归集收入数据
- * @param allocationQueries 分摊成本数据
- */
- private HospProfitAndLoss calcByAccount(Long hospId, ReportForm reportForm, List<IncomeCollection> incomes, List<AllocationQuery> allocationQueries) {
- List<RelationVO> accountRelations = reportRelationService.getAccountRelation(reportForm.getId(), hospId);
- if (accountRelations.isEmpty()) {
- return null;
- }
- 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();
- return loss.setReportName(reportForm.getReportName()).setReportNum(reportForm.getNum())
- .setAmount(calcTotal.get()).setCreateTime(System.currentTimeMillis()).setHospId(hospId);
- }
- /**
- * 全院损益列表
- *
- * @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;
- }
- }
|