|
@@ -0,0 +1,283 @@
|
|
|
+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<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;
|
|
|
+
|
|
|
+ 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<ReportForm> 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<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 = 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<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() + "计算公式不正确");
|
|
|
+ }
|
|
|
+ String replace = calcFormula.replace("[", "").replace("]", "").replace("-", ",").replace("+", ",");
|
|
|
+// ArrayList<String> strings = CollUtil.newArrayList(replace.split(StrUtil.COMMA));
|
|
|
+ ArrayList<String> strings = CollUtil.newArrayList(replace.split(","));
|
|
|
+ Map<Integer, Object> 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<IncomeCollection> incomes, List<AllocationQuery> allocationQueries) {
|
|
|
+ List<RelationVO> responsibilities = reportRelationService.getAccountRelation(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 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<IncomeCollection> incomes, List<AllocationQuery> 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<IncomeCollection> incomes, List<AllocationQuery> allocationQueries) {
|
|
|
+ Long parentId = reportForm.getParentId();
|
|
|
+ List<ReportForm> 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<RelationVO> shareLevels = reportRelationService.getAccountRelation(reportForm.getId(), hospId);
|
|
|
+ List<Long> shareLevelId = shareLevels.stream().map(RelationVO::getCode).map(Long::valueOf).collect(Collectors.toList());
|
|
|
+ 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::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<IncomeCollection> incomes, List<AllocationQuery> allocationQueries) {
|
|
|
+ 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.subtract(costAmount);
|
|
|
+ calcTotal.set(calcTotal.get().add(total));
|
|
|
+ });
|
|
|
+ loss.setReportName(reportForm.getReportName()).setReportNum(reportForm.getNum())
|
|
|
+ .setAmount(calcTotal.get()).setCreateTime(System.currentTimeMillis());
|
|
|
+
|
|
|
+ }
|
|
|
+}
|