Эх сурвалжийг харах

科室损益计算添加同环比计算逻辑

JammeyJiang 1 сар өмнө
parent
commit
43f77f8eb0

+ 4 - 1
src/main/java/com/kcim/common/constants/ParameterConstant.java

@@ -57,5 +57,8 @@ public interface ParameterConstant {
      */
     Long SHOW_PERCENT=1851077044079824896L;
 
-
+    /**
+     * 同环比计算方式 1代码计算 2脚本计算
+     */
+    Long YM_CALC_TYPE=1943243153054240768L;
 }

+ 147 - 106
src/main/java/com/kcim/service/impl/CostDepartmentProfitServiceImpl.java

@@ -52,7 +52,6 @@ import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Propagation;
 import org.springframework.transaction.annotation.Transactional;
 import org.springframework.util.CollectionUtils;
-import org.springframework.util.ObjectUtils;
 import org.springframework.util.StringUtils;
 import org.springframework.web.multipart.MultipartFile;
 import org.springframework.web.multipart.commons.CommonsMultipartFile;
@@ -1116,6 +1115,10 @@ public class CostDepartmentProfitServiceImpl extends ServiceImpl<CostDepartmentP
     @Override
     public void computeProfit(String computeDate, Long hospId, String reportType) {
         computeProfitAction(computeDate, hospId, reportType);
+        //需要用代码计算同环比时
+        if(IsNeedCalcYM()){
+            handleSpecificMonthsCalculation(hospId, computeDate, reportType);
+        }
         execDeptProfitSql(computeDate, reportType);
     }
 
@@ -1209,6 +1212,7 @@ public class CostDepartmentProfitServiceImpl extends ServiceImpl<CostDepartmentP
         //记录最后一次 损益计算日期
         computeLastProfitDateRepository.saveLastComputeDate(hospId, computeDate);
     }
+
     /**
      * 处理指定月份及关联月份的计算(当前月、下个月、明年同月)
      *
@@ -1217,105 +1221,153 @@ public class CostDepartmentProfitServiceImpl extends ServiceImpl<CostDepartmentP
      * @param shareType   报表类型
      */
     public void handleSpecificMonthsCalculation(Long hospId, String computeDate, String shareType) {
-
         // 解析输入的年月
-        int currentYear = Integer.parseInt(computeDate.substring(0, 4));
-        int currentMonth = Integer.parseInt(computeDate.substring(5, 7));
+        Integer currentYear = ComputeDateUtils.getComputeYear(computeDate);
+        Integer currentMonth = ComputeDateUtils.getComputeMonth(computeDate);
+        // 计算需要处理的期间信息
+        List<PeriodInfoVO> periods = calculateAllRelatedPeriods(currentYear, currentMonth);
 
-        // 计算下个月
-        int nextMonth = currentMonth + 1;
-        int nextMonthYear = currentYear;
+        // 获取所有相关的期间数据
+        Map<String, List<CostDepartmentProfit>> allDataMap = loadAllPeriodData(hospId, shareType, periods);
+
+        // 对每个期间执行计算
+        for (PeriodInfoVO period : periods) {
+            String currentKey = buildPeriodKey(period.getYear(), period.getMonth());
+            if (allDataMap.containsKey(currentKey) && !CollectionUtils.isEmpty(allDataMap.get(currentKey))) {
+                List<CostDepartmentProfit> currentRecords = allDataMap.get(currentKey);
+                List<CostDepartmentProfit> prevRecords = getPeriodData(allDataMap, period.getPrevYear(), period.getPrevMonth());
+                List<CostDepartmentProfit> lastYearRecords = getPeriodData(allDataMap, period.getLastYear(), period.getLastMonth());
+
+                // 执行批量计算
+                calculatePeriodComparisonWithPreloadedData(currentRecords, prevRecords, lastYearRecords);
+            }
+        }
+    }
+
+    /**
+     * 构建所有需要处理的期间信息
+     */
+    private List<PeriodInfoVO> calculateAllRelatedPeriods(int baseYear, int baseMonth) {
+        List<PeriodInfoVO> result = new ArrayList<>();
 
-        if (nextMonth > 12) {
+        // 添加当前期间
+        result.add(calculatePeriodInfo(baseYear, baseMonth));
+
+        // 下个月
+        int nextMonth = baseMonth + 1;
+        int nextMonthYear = baseYear;
+        if (baseMonth == 12) {
             nextMonth = 1;
-            nextMonthYear = currentYear + 1;
+            nextMonthYear += 1;
         }
+        result.add(calculatePeriodInfo(nextMonthYear, nextMonth));
+
+        // 明年同月
+        result.add(calculatePeriodInfo(baseYear + 1, baseMonth));
 
-        // 计算明年同月
-        int nextYearMonth = currentMonth;
-        int nextYearMonthYear = currentYear + 1;
+        return result;
+    }
+
+    /**
+     * 构建单个期间的信息(当前月、上月、去年同期)
+     */
+    private PeriodInfoVO calculatePeriodInfo(int year, int month) {
+        PeriodInfoVO info = new PeriodInfoVO();
 
-        // 检查各月份是否有数据
-        boolean currentExists = checkDataExistence(hospId, shareType, currentYear, currentMonth);
-        boolean nextMonthExists = checkDataExistence(hospId, shareType, nextMonthYear, nextMonth);
-        boolean nextYearMonthExists = checkDataExistence(hospId, shareType, nextYearMonthYear, nextYearMonth);
+        info.setYear( year);
+        info.setMonth( month);
 
-        // 执行当前月份计算
-        if (currentExists) {
-            calculatePeriodComparisonOptimized(hospId, shareType, currentYear, currentMonth);
+        // 上期
+        if (month == 1) {
+            info.setPrevYear(year - 1);
+            info.setPrevMonth(12);
+        } else {
+            info.setPrevYear( year);
+            info.setPrevMonth(month - 1);
         }
-        // 执行下个月计算
-        if (nextMonthExists) {
-            calculatePeriodComparisonOptimized(hospId, shareType, nextMonthYear, nextMonth);
+
+        // 同期
+        info.setLastYear(year - 1);
+        info.setLastMonth( month);
+
+        return info;
+    }
+
+    /**
+     * 加载所有相关期间的数据(去重处理)
+     */
+    private Map<String, List<CostDepartmentProfit>> loadAllPeriodData(Long hospId, String shareType, List<PeriodInfoVO> periods) {
+        Set<String> allPeriodKeys = new HashSet<>();
+
+        // 收集所有需要查询的年月组合
+        for (PeriodInfoVO period : periods) {
+            allPeriodKeys.add(buildPeriodKey(period.getYear(), period.getMonth()));
+            allPeriodKeys.add(buildPeriodKey(period.getPrevYear(), period.getPrevMonth()));
+            allPeriodKeys.add(buildPeriodKey(period.getLastYear(), period.getLastMonth()));
         }
-        // 执行明年同月计算
-        if (nextYearMonthExists) {
-            calculatePeriodComparisonOptimized(hospId, shareType, nextYearMonthYear, nextYearMonth);
+
+        // 去重后查询
+        Map<String, List<CostDepartmentProfit>> result = new HashMap<>();
+        Set<String> processedKeys = new HashSet<>(); // 已处理的键集合
+
+        for (String key : allPeriodKeys) {
+            if (!processedKeys.contains(key)) {
+                int[] ym = parsePeriodKey(key);
+                List<CostDepartmentProfit> records = getPeriodRecords(hospId, shareType, ym[0], ym[1]);
+                result.put(key, records);
+                processedKeys.add(key); // 标记为已处理
+            }
         }
+
+        return result;
     }
 
+
     /**
-     * 检查指定条件的数据是否存在
+     * 获取指定期间的数据
      *
      * @param hospId    院区ID
      * @param shareType 报表类型
      * @param year      年份
      * @param month     月份
-     * @return 是否存在数据
+     * @return 符合条件的数据列表
      */
-    private boolean checkDataExistence(Long hospId, String shareType, int year, int month) {
-        LambdaQueryWrapper<CostDepartmentProfit> last = new QueryWrapper<CostDepartmentProfit>().lambda()
+    private List<CostDepartmentProfit> getPeriodRecords(Long hospId, String shareType, int year, int month) {
+        return this.list(new QueryWrapper<CostDepartmentProfit>().lambda()
                 .eq(CostDepartmentProfit::getHospId, hospId)
                 .eq(CostDepartmentProfit::getShareType, shareType)
                 .eq(CostDepartmentProfit::getYear, year)
                 .eq(CostDepartmentProfit::getMonth, month)
-                .eq(CostDepartmentProfit::getDeleteTime, 0)
-                .last("LIMIT 1");
-        CostDepartmentProfit one = this.getOne(last);
-        return !ObjectUtils.isEmpty(one);
+                .eq(CostDepartmentProfit::getDeleteTime, 0));
     }
 
+    /**
+     * 根据年月获取对应的数据(从内存中查找)
+     */
+    private List<CostDepartmentProfit> getPeriodData(Map<String, List<CostDepartmentProfit>> dataMap, int year, int month) {
+        String key = buildPeriodKey(year, month);
+        return dataMap.getOrDefault(key, Collections.emptyList());
+    }
 
     /**
-     * 批量计算同环比及同期金额
-     *
-     * @param hospId    院区ID
-     * @param shareType 报表类型
-     * @param year      年份
-     * @param month     月份
+     * 批量计算同环比及同期金额(使用预加载数据)
      */
-    public void calculatePeriodComparisonOptimized(Long hospId, String shareType, Integer year, Integer month) {
-        // 查询符合条件的数据
-        List<CostDepartmentProfit> records = getPeriodRecords(hospId, shareType, year, month);
-        // 如果没有记录,直接返回
-        if (CollectionUtils.isEmpty(records)) {
-            return;
-        }
+    public void calculatePeriodComparisonWithPreloadedData(
+            List<CostDepartmentProfit> currentRecords,
+            List<CostDepartmentProfit> prevRecords,
+            List<CostDepartmentProfit> lastYearRecords) {
 
-        // 构建上期和同期的时间参数
-        int prevPeriodYear = year;
-        int prevPeriodMonth = month - 1;
-        if (month == 1) {
-            prevPeriodYear = year - 1;
-            prevPeriodMonth = 12;
+        if (CollectionUtils.isEmpty(currentRecords)) {
+            return;
         }
 
-        int lastYearYear = year - 1;
-
-        // 批量查询上期数据
-        List<CostDepartmentProfit> prevPeriodRecords = getPeriodRecords(hospId, shareType, prevPeriodYear, prevPeriodMonth);
-
-        // 批量查询同期数据
-        List<CostDepartmentProfit> lastYearRecords = getPeriodRecords(hospId, shareType, lastYearYear, month);
-
-        // 将上期数据转换为映射
-        Map<String, CostDepartmentProfit> prevPeriodMap = new HashMap<>();
-        for (CostDepartmentProfit record : prevPeriodRecords) {
+        // 创建责任码+报表编号到记录的映射
+        Map<String, CostDepartmentProfit> prevMap = new HashMap<>();
+        for (CostDepartmentProfit record : prevRecords) {
             String key = buildRecordKey(record);
-            prevPeriodMap.put(key, record);
+            prevMap.put(key, record);
         }
 
-        // 将同期数据转换为映射
         Map<String, CostDepartmentProfit> lastYearMap = new HashMap<>();
         for (CostDepartmentProfit record : lastYearRecords) {
             String key = buildRecordKey(record);
@@ -1323,79 +1375,59 @@ public class CostDepartmentProfitServiceImpl extends ServiceImpl<CostDepartmentP
         }
 
         // 批量更新数据
-        for (CostDepartmentProfit record : records) {
-            // 构建上期和同期的键
-            String prevKey = String.format("%d_%d_%s_%d",
-                    prevPeriodYear, prevPeriodMonth, record.getResponsibilityCode(), record.getReportNum());
-            String lastYearKey = String.format("%d_%d_%s_%d",
-                    lastYearYear, month, record.getResponsibilityCode(), record.getReportNum());
-
-            // 获取上期和同期记录
-            CostDepartmentProfit prevRecord = prevPeriodMap.get(prevKey);
-            CostDepartmentProfit lastYearRecord = lastYearMap.get(lastYearKey);
+        for (CostDepartmentProfit record : currentRecords) {
+            String key = buildRecordKey(record);
+            CostDepartmentProfit prevRecord = prevMap.get(key);
+            CostDepartmentProfit lastYearRecord = lastYearMap.get(key);
 
             // 设置上期和同期金额
             record.setPrevPeriodAmount(prevRecord != null ? prevRecord.getAmount() : BigDecimal.ZERO);
             record.setSamePeriodAmount(lastYearRecord != null ? lastYearRecord.getAmount() : BigDecimal.ZERO);
 
-            // 计算环比
+            // 计算环比和同比
             record.setMomRate(calculateProfitRate(record.getAmount(), record.getPrevPeriodAmount()));
-            // 计算同比
             record.setYoyRate(calculateProfitRate(record.getAmount(), record.getSamePeriodAmount()));
         }
 
         // 批量更新数据库
-        this.updateBatchById(records);
+        this.updateBatchById(currentRecords);
     }
 
-
     /**
-     * 获取指定期间的数据
-     *
-     * @param hospId    院区ID
-     * @param shareType 报表类型
-     * @param year      年份
-     * @param month     月份
-     * @return 符合条件的数据列表
+     * 构建期间键(用于存储和检索数据)
      */
-    private List<CostDepartmentProfit> getPeriodRecords(Long hospId, String shareType, int year, int month) {
-        return this.baseMapper.selectList(new QueryWrapper<CostDepartmentProfit>().lambda()
-                .eq(CostDepartmentProfit::getHospId, hospId)
-                .eq(CostDepartmentProfit::getShareType, shareType)
-                .eq(CostDepartmentProfit::getYear, year)
-                .eq(CostDepartmentProfit::getMonth, month)
-                .eq(CostDepartmentProfit::getDeleteTime, 0));
+    private String buildPeriodKey(int year, int month) {
+        return year + "_" + month;
     }
 
+    /**
+     * 解析期间键为年月数组
+     */
+    private int[] parsePeriodKey(String key) {
+        String[] parts = key.split("_");
+        return new int[]{Integer.parseInt(parts[0]), Integer.parseInt(parts[1])};
+    }
 
     /**
-     * 构建记录的唯一标识键
-     *
-     * @param record 记录对象
-     * @return 唯一标识键
+     * 构建记录的唯一标识键(责任码 + 报表编号)
      */
     private String buildRecordKey(CostDepartmentProfit record) {
-        return String.format("%d_%d_%s_%d",
-                record.getYear(), record.getMonth(), record.getResponsibilityCode(), record.getReportNum());
+        return record.getResponsibilityCode() + "_" + record.getReportNum();
     }
 
     /**
      * 安全地计算百分比:避免除零错误
-     *
-     * @param current 当前值
-     * @param base    基准值
-     * @return 计算结果,保留4位小数
      */
     private BigDecimal calculateProfitRate(BigDecimal current, BigDecimal base) {
         if (base == null || base.compareTo(BigDecimal.ZERO) == 0) {
             return BigDecimal.ZERO;
         }
-        // 先计算到4位小数,再四舍五入到4位
-        BigDecimal rate = current.divide(base, 4, RoundingMode.HALF_UP);
-        return rate.setScale(4, RoundingMode.HALF_UP);
+        BigDecimal bigDecimal = current.divide(base, 4, RoundingMode.HALF_UP).setScale(4, RoundingMode.HALF_UP);
+        return bigDecimal;
     }
 
 
+
     /**
      * 执行科室损益后续脚本
      *
@@ -2789,6 +2821,15 @@ public class CostDepartmentProfitServiceImpl extends ServiceImpl<CostDepartmentP
         return NumberConstant.ONE_S.equals(parameterValue);
     }
 
+    /**
+     * 是否需要计算同环比
+     * @return
+     */
+    public boolean IsNeedCalcYM() {
+        String parameterValue = centerService.getParameterValue(ParameterConstant.YM_CALC_TYPE);
+        return NumberConstant.ONE_S.equals(parameterValue);
+    }
+
     private List<CommonResponsibilityReportVo> getChildTitle(List<Responsibility> responsibilities, Map<Long, List<Responsibility>> responsibilityGroup) {
         List<CommonResponsibilityReportVo> list = new ArrayList<>();
         for (Responsibility responsibility : responsibilities) {

+ 39 - 0
src/main/java/com/kcim/vo/PeriodInfoVO.java

@@ -0,0 +1,39 @@
+package com.kcim.vo;
+
+import lombok.Data;
+
+/**
+ *
+ */
+@Data
+public class PeriodInfoVO {
+    /**
+     * 当前记录的年份
+     */
+    private Integer year;
+
+    /**
+     * 当前记录的月份
+     */
+    private Integer month;
+
+    /**
+     * 上期记录的年份
+     */
+    private Integer prevYear;
+
+    /**
+     * 上期记录的月份
+     */
+    private Integer prevMonth;
+
+    /**
+     * 同期记录的年份(去年)
+     */
+    private Integer lastYear;
+
+    /**
+     * 同期记录的月份(去年同期)
+     */
+    private Integer lastMonth;
+}