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.imed.costaccount.common.enums.CalcTypeEnum; import com.imed.costaccount.common.enums.ReportTypeEnum; import com.imed.costaccount.common.exception.CostException; import com.imed.costaccount.model.*; 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.ArrayList; import java.util.List; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.atomic.AtomicReference; import java.util.stream.Collectors; @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; public HospProfitAndLossServiceImpl(ReportFormService reportFormService, IncomeCollectionService collectionService, AllocationQueryService allocationQueryService, AllocationService allocationService, ReportRelationService reportRelationService, CostShareLevelService shareLevelService) { this.reportFormService = reportFormService; this.collectionService = collectionService; this.allocationQueryService = allocationQueryService; this.allocationService = allocationService; this.reportRelationService = reportRelationService; this.shareLevelService = shareLevelService; } /** * 计算全院损益 * * @param date yyyy-MM-dd 时间 * @param hospId 医院id */ @Override @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Throwable.class) public void calc(String date, Long hospId) { // 得到全院损益计算报表 List reportForms = reportFormService.getListByReportType(hospId, ReportTypeEnum.HOSP_PROFIT_LOSS.getType()); if (CollUtil.isEmpty(reportForms)) { throw new CostException("医院未设置全院损益计算报表"); } DateTime parse = DateUtil.parse(date); int year = DateUtil.year(parse); int month = DateUtil.month(parse) + 1; // 得到这个月所有收入数据 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<>(); reportForms.forEach(i -> { Integer calcType = i.getCalcType(); if (calcType == CalcTypeEnum.BY_ACCOUNT.getType()) { // 按会计科目计算 HospProfitAndLoss loss = new HospProfitAndLoss(); calcByAccount(hospId, i, loss, incomes, allocationQueries); loss.setDateMonth(month); loss.setDateYear(year); list.add(loss); return; } else if (calcType == CalcTypeEnum.BY_SHARE_LEVEL.getType()) { // 分摊层级计算 HospProfitAndLoss loss = new HospProfitAndLoss(); calcByShareLevel(hospId, i, loss, year, month); loss.setDateMonth(month); loss.setDateYear(year); list.add(loss); return; } else if (calcType == CalcTypeEnum.LITTER_COUNT.getType()) { // todo 留在最后直接加 减 // HospProfitAndLoss loss = new HospProfitAndLoss(); // loss.setDateYear(year).setDateMonth(month).setAmount(BigDecimal.ZERO) // .setReportName(i.getReportName()).setReportNum(i.getNum()) // .setCreateTime(System.currentTimeMillis()); // list.add(loss); return; } else if (calcType == CalcTypeEnum.CALC_FORMULA.getType()) { // todo 留在最后加减 // HospProfitAndLoss loss = new HospProfitAndLoss(); // loss.setDateYear(year).setDateMonth(month).setAmount(BigDecimal.ZERO) // .setReportName(i.getReportName()).setReportNum(i.getNum()) // .setCreateTime(System.currentTimeMillis()); // list.add(loss); return; } else if (calcType == CalcTypeEnum.BY_RESPONSIBILITY.getType()) { // 责任中心 HospProfitAndLoss loss = new HospProfitAndLoss(); calcByResponsibility(hospId, i, loss, incomes, allocationQueries); loss.setDateMonth(month); loss.setDateYear(year); list.add(loss); } else { // 不设置不计算 return; } }); // 先处理按公式 List 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() + "计算公式不正确"); } String replace = calcFormula.replace("[", "").replace("]", "").replace("-", ",").replace("+", ","); // ArrayList strings = CollUtil.newArrayList(replace.split(StrUtil.COMMA)); ArrayList strings = CollUtil.newArrayList(replace.split(",")); Map map = new ConcurrentHashMap<>(); for (int j = 0; j < strings.size(); j++) { map.put(j, strings.get(j)); } // ReUtil.contains(, "+" + calcFormula); }); // 处理小计 this.saveBatch(list); } /** * 按责任中心计算 * * @param hospId 医院id * @param reportForm 报表 * @param loss 创建的对象 * @param incomes 归集收入数据 * @param allocationQueries 分摊成本数据 */ private void calcByResponsibility(Long hospId, ReportForm reportForm, HospProfitAndLoss loss, List incomes, List allocationQueries) { List responsibilities = reportRelationService.getAccountRelation(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 incomeAmount = incomes.stream().filter(j -> i.equals(j.getResponsibilityCode())).map(IncomeCollection::getAmount) // .reduce(BigDecimal.ZERO, BigDecimal::add); BigDecimal costAmount = allocationQueries.stream().filter(j -> i.equals(j.getResponsibilityCode())).map(AllocationQuery::getAmount) .reduce(BigDecimal.ZERO, BigDecimal::add); // BigDecimal total = incomeAmount.subtract(costAmount); calcTotal.set(calcTotal.get().add(costAmount)); }); loss.setReportName(reportForm.getReportName()).setReportNum(reportForm.getNum()) .setAmount(calcTotal.get()).setCreateTime(System.currentTimeMillis()); } /** * 按计算公式计算 * * @param hospId 医院id * @param reportForm 报表 * @param loss 创建的对象 * @param incomes 归集收入数据 * @param allocationQueries 分摊成本数据 */ private void calcByFormula(Long hospId, ReportForm reportForm, HospProfitAndLoss loss, List incomes, List allocationQueries) { String calcFormula = reportForm.getCalcFormula(); // TODO: 2021/8/27 校验公式合法性 if (StrUtil.isBlank(calcFormula)) { throw new CostException("reportForm名称为" + reportForm.getReportName() + "计算公式不正确"); } // 得到11 + 12 - 1 String sub = StrUtil.removeAny(calcFormula, "[", "]"); // TODO: 2021/8/27 } /** * 按小计计算 * * @param hospId 医院id * @param reportForm 报表 * @param loss 创建的对象 * @param incomes 归集收入数据 * @param allocationQueries 分摊成本数据 */ private void calcByLitterCount(Long hospId, ReportForm reportForm, HospProfitAndLoss loss, List incomes, List allocationQueries) { Long parentId = reportForm.getParentId(); List forms = reportFormService.getByParentId(hospId, parentId); forms.forEach(i -> { // 排除自己 if (i.getId().equals(reportForm.getId())) { return; } // 计算其他几项之和 // TODO: 2021/8/27 }); } /** * 按分摊层级计算 * * @param hospId 医院id * @param reportForm 报表 * @param loss 创建的对象 * @param year * @param month */ private void calcByShareLevel(Long hospId, ReportForm reportForm, HospProfitAndLoss loss, int year, int month) { List shareLevels = reportRelationService.getAccountRelation(reportForm.getId(), hospId); List shareLevelId = shareLevels.stream().map(RelationVO::getCode).map(Long::valueOf).collect(Collectors.toList()); 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 = allocationService.getByDate(year, month, hospId, levelSorts); if (allocations.isEmpty()) { throw new CostException("医院未分摊本月数据"); } BigDecimal reduce = allocations.stream().map(Allocation::getAmount).reduce(BigDecimal.ZERO, BigDecimal::subtract); loss.setReportName(reportForm.getReportName()).setReportNum(reportForm.getNum()) .setAmount(reduce).setCreateTime(System.currentTimeMillis()).setDateYear(year).setDateMonth(month); } /** * 计算按会计科目下的科目名称 * * @param hospId 医院id * @param reportForm 报表 * @param loss 创建的对象 * @param incomes 归集收入数据 * @param allocationQueries 分摊成本数据 */ private void calcByAccount(Long hospId, ReportForm reportForm, HospProfitAndLoss loss, List incomes, List allocationQueries) { 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.subtract(costAmount); calcTotal.set(calcTotal.get().add(total)); }); loss.setReportName(reportForm.getReportName()).setReportNum(reportForm.getNum()) .setAmount(calcTotal.get()).setCreateTime(System.currentTimeMillis()); } }