소스 검색

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

JammeyJiang 1 개월 전
부모
커밋
689703e16c
1개의 변경된 파일187개의 추가작업 그리고 0개의 파일을 삭제
  1. 187 0
      src/main/java/com/kcim/service/impl/CostDepartmentProfitServiceImpl.java

+ 187 - 0
src/main/java/com/kcim/service/impl/CostDepartmentProfitServiceImpl.java

@@ -52,6 +52,7 @@ 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;
@@ -1208,6 +1209,192 @@ public class CostDepartmentProfitServiceImpl extends ServiceImpl<CostDepartmentP
         //记录最后一次 损益计算日期
         computeLastProfitDateRepository.saveLastComputeDate(hospId, computeDate);
     }
+    /**
+     * 处理指定月份及关联月份的计算(当前月、下个月、明年同月)
+     *
+     * @param hospId      院区ID
+     * @param computeDate 日期字符串,格式:YYYY-MM
+     * @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));
+
+        // 计算下个月
+        int nextMonth = currentMonth + 1;
+        int nextMonthYear = currentYear;
+
+        if (nextMonth > 12) {
+            nextMonth = 1;
+            nextMonthYear = currentYear + 1;
+        }
+
+        // 计算明年同月
+        int nextYearMonth = currentMonth;
+        int nextYearMonthYear = currentYear + 1;
+
+        // 检查各月份是否有数据
+        boolean currentExists = checkDataExistence(hospId, shareType, currentYear, currentMonth);
+        boolean nextMonthExists = checkDataExistence(hospId, shareType, nextMonthYear, nextMonth);
+        boolean nextYearMonthExists = checkDataExistence(hospId, shareType, nextYearMonthYear, nextYearMonth);
+
+        // 执行当前月份计算
+        if (currentExists) {
+            calculatePeriodComparisonOptimized(hospId, shareType, currentYear, currentMonth);
+        }
+        // 执行下个月计算
+        if (nextMonthExists) {
+            calculatePeriodComparisonOptimized(hospId, shareType, nextMonthYear, nextMonth);
+        }
+        // 执行明年同月计算
+        if (nextYearMonthExists) {
+            calculatePeriodComparisonOptimized(hospId, shareType, nextYearMonthYear, nextYearMonth);
+        }
+    }
+
+    /**
+     * 检查指定条件的数据是否存在
+     *
+     * @param hospId    院区ID
+     * @param shareType 报表类型
+     * @param year      年份
+     * @param month     月份
+     * @return 是否存在数据
+     */
+    private boolean checkDataExistence(Long hospId, String shareType, int year, int month) {
+        LambdaQueryWrapper<CostDepartmentProfit> last = 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);
+    }
+
+
+    /**
+     * 批量计算同环比及同期金额
+     *
+     * @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;
+        }
+
+        // 构建上期和同期的时间参数
+        int prevPeriodYear = year;
+        int prevPeriodMonth = month - 1;
+        if (month == 1) {
+            prevPeriodYear = year - 1;
+            prevPeriodMonth = 12;
+        }
+
+        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) {
+            String key = buildRecordKey(record);
+            prevPeriodMap.put(key, record);
+        }
+
+        // 将同期数据转换为映射
+        Map<String, CostDepartmentProfit> lastYearMap = new HashMap<>();
+        for (CostDepartmentProfit record : lastYearRecords) {
+            String key = buildRecordKey(record);
+            lastYearMap.put(key, record);
+        }
+
+        // 批量更新数据
+        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);
+
+            // 设置上期和同期金额
+            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);
+    }
+
+
+    /**
+     * 获取指定期间的数据
+     *
+     * @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));
+    }
+
+
+    /**
+     * 构建记录的唯一标识键
+     *
+     * @param record 记录对象
+     * @return 唯一标识键
+     */
+    private String buildRecordKey(CostDepartmentProfit record) {
+        return String.format("%d_%d_%s_%d",
+                record.getYear(), record.getMonth(), 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);
+    }
+
 
     /**
      * 执行科室损益后续脚本