|
@@ -13,25 +13,20 @@ import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
|
import com.google.common.collect.ImmutableMap;
|
|
import com.google.common.collect.ImmutableMap;
|
|
import com.kcim.common.constants.Constant;
|
|
import com.kcim.common.constants.Constant;
|
|
import com.kcim.common.constants.NumberConstant;
|
|
import com.kcim.common.constants.NumberConstant;
|
|
|
|
+import com.kcim.common.constants.ParameterConstant;
|
|
import com.kcim.common.constants.SQLParameter;
|
|
import com.kcim.common.constants.SQLParameter;
|
|
import com.kcim.common.enums.*;
|
|
import com.kcim.common.enums.*;
|
|
import com.kcim.common.exception.CostException;
|
|
import com.kcim.common.exception.CostException;
|
|
import com.kcim.common.file.MinioConfig;
|
|
import com.kcim.common.file.MinioConfig;
|
|
import com.kcim.common.file.MinioFileUtil;
|
|
import com.kcim.common.file.MinioFileUtil;
|
|
-import com.kcim.common.util.BeanUtil;
|
|
|
|
-import com.kcim.common.util.DateUtils;
|
|
|
|
-import com.kcim.common.util.PageUtils;
|
|
|
|
-import com.kcim.common.util.UserContext;
|
|
|
|
|
|
+import com.kcim.common.util.*;
|
|
import com.kcim.common.util.excel.ExcelPoiUtil;
|
|
import com.kcim.common.util.excel.ExcelPoiUtil;
|
|
import com.kcim.common.util.excel.entity.ColEntity;
|
|
import com.kcim.common.util.excel.entity.ColEntity;
|
|
import com.kcim.common.util.excel.entity.TitleEntity;
|
|
import com.kcim.common.util.excel.entity.TitleEntity;
|
|
import com.kcim.dao.mapper.HospProfitAndLossMapper;
|
|
import com.kcim.dao.mapper.HospProfitAndLossMapper;
|
|
import com.kcim.dao.model.*;
|
|
import com.kcim.dao.model.*;
|
|
import com.kcim.service.*;
|
|
import com.kcim.service.*;
|
|
-import com.kcim.vo.AllocationQueryReportVO;
|
|
|
|
-import com.kcim.vo.HospProfitAndLossVo;
|
|
|
|
-import com.kcim.vo.HospProfitVO;
|
|
|
|
-import com.kcim.vo.RelationVO;
|
|
|
|
|
|
+import com.kcim.vo.*;
|
|
import lombok.extern.slf4j.Slf4j;
|
|
import lombok.extern.slf4j.Slf4j;
|
|
import org.apache.commons.fileupload.FileItem;
|
|
import org.apache.commons.fileupload.FileItem;
|
|
import org.apache.commons.fileupload.FileItemFactory;
|
|
import org.apache.commons.fileupload.FileItemFactory;
|
|
@@ -79,6 +74,8 @@ public class HospProfitAndLossServiceImpl extends ServiceImpl<HospProfitAndLossM
|
|
private final FileRecordService fileRecordService;
|
|
private final FileRecordService fileRecordService;
|
|
private final SqlService sqlService;
|
|
private final SqlService sqlService;
|
|
|
|
|
|
|
|
+ private final CenterService centerService;
|
|
|
|
+
|
|
private final MinioConfig minioConfig;
|
|
private final MinioConfig minioConfig;
|
|
|
|
|
|
private final MinioFileUtil minioFileUtil;
|
|
private final MinioFileUtil minioFileUtil;
|
|
@@ -91,7 +88,13 @@ public class HospProfitAndLossServiceImpl extends ServiceImpl<HospProfitAndLossM
|
|
CostShareLevelService shareLevelService,
|
|
CostShareLevelService shareLevelService,
|
|
CostOtherPaymentsDataService otherPaymentsDataService,
|
|
CostOtherPaymentsDataService otherPaymentsDataService,
|
|
ResponsibilityService responsibilityService,
|
|
ResponsibilityService responsibilityService,
|
|
- CostAccountShareService accountShareService, FileRecordService fileRecordService, MinioConfig minioConfig, MinioFileUtil minioFileUtil,SqlService sqlService) {
|
|
|
|
|
|
+ CostAccountShareService accountShareService,
|
|
|
|
+ FileRecordService fileRecordService,
|
|
|
|
+ MinioConfig minioConfig,
|
|
|
|
+ MinioFileUtil minioFileUtil,
|
|
|
|
+ SqlService sqlService,
|
|
|
|
+ CenterService centerService
|
|
|
|
+ ) {
|
|
this.reportFormService = reportFormService;
|
|
this.reportFormService = reportFormService;
|
|
this.collectionService = collectionService;
|
|
this.collectionService = collectionService;
|
|
this.allocationQueryService = allocationQueryService;
|
|
this.allocationQueryService = allocationQueryService;
|
|
@@ -105,6 +108,7 @@ public class HospProfitAndLossServiceImpl extends ServiceImpl<HospProfitAndLossM
|
|
this.minioConfig = minioConfig;
|
|
this.minioConfig = minioConfig;
|
|
this.minioFileUtil = minioFileUtil;
|
|
this.minioFileUtil = minioFileUtil;
|
|
this.sqlService=sqlService;
|
|
this.sqlService=sqlService;
|
|
|
|
+ this.centerService=centerService;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
@@ -196,6 +200,10 @@ public class HospProfitAndLossServiceImpl extends ServiceImpl<HospProfitAndLossM
|
|
@Override
|
|
@Override
|
|
public void calcHospProfit(String date, Long hospId, Integer reportType){
|
|
public void calcHospProfit(String date, Long hospId, Integer reportType){
|
|
calcHospProfitAction(date,hospId,reportType);
|
|
calcHospProfitAction(date,hospId,reportType);
|
|
|
|
+ //需要用代码计算同环比时
|
|
|
|
+ if(IsNeedCalcYM()){
|
|
|
|
+ handleSpecificMonthsCalculation(hospId, date, reportType);
|
|
|
|
+ }
|
|
execHospProfitSql(date,date);
|
|
execHospProfitSql(date,date);
|
|
}
|
|
}
|
|
@Transactional(rollbackFor = Throwable.class, propagation = Propagation.REQUIRED)
|
|
@Transactional(rollbackFor = Throwable.class, propagation = Propagation.REQUIRED)
|
|
@@ -399,6 +407,228 @@ public class HospProfitAndLossServiceImpl extends ServiceImpl<HospProfitAndLossM
|
|
|
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ /**
|
|
|
|
+ * 是否需要计算同环比
|
|
|
|
+ * @return
|
|
|
|
+ */
|
|
|
|
+ public boolean IsNeedCalcYM() {
|
|
|
|
+ String parameterValue = centerService.getParameterValue(ParameterConstant.HOSP_YM_CALC_TYPE);
|
|
|
|
+ return NumberConstant.ONE_S.equals(parameterValue);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /**
|
|
|
|
+ * 处理指定月份及关联月份的计算(当前月、下个月、明年同月)
|
|
|
|
+ *
|
|
|
|
+ * @param hospId 院区ID
|
|
|
|
+ * @param computeDate 日期字符串,格式:YYYY-MM
|
|
|
|
+ * @param shareType 报表类型
|
|
|
|
+ */
|
|
|
|
+ public void handleSpecificMonthsCalculation(Long hospId, String computeDate, Integer shareType) {
|
|
|
|
+ // 解析输入的年月
|
|
|
|
+ Integer currentYear = ComputeDateUtils.getComputeYear(computeDate);
|
|
|
|
+ Integer currentMonth = ComputeDateUtils.getComputeMonth(computeDate);
|
|
|
|
+ // 计算需要处理的期间信息
|
|
|
|
+ List<PeriodInfoVO> periods = calculateAllRelatedPeriods(currentYear, currentMonth);
|
|
|
|
+
|
|
|
|
+ // 获取所有相关的期间数据
|
|
|
|
+ Map<String, List<HospProfitAndLoss>> 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<HospProfitAndLoss> currentRecords = allDataMap.get(currentKey);
|
|
|
|
+ List<HospProfitAndLoss> prevRecords = getPeriodData(allDataMap, period.getPrevYear(), period.getPrevMonth());
|
|
|
|
+ List<HospProfitAndLoss> lastYearRecords = getPeriodData(allDataMap, period.getLastYear(), period.getLastMonth());
|
|
|
|
+
|
|
|
|
+ // 执行批量计算
|
|
|
|
+ calculatePeriodComparisonWithPreloadedData(currentRecords, prevRecords, lastYearRecords);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /**
|
|
|
|
+ * 构建所有需要处理的期间信息
|
|
|
|
+ */
|
|
|
|
+ private List<PeriodInfoVO> calculateAllRelatedPeriods(int baseYear, int baseMonth) {
|
|
|
|
+ List<PeriodInfoVO> result = new ArrayList<>();
|
|
|
|
+
|
|
|
|
+ // 添加当前期间
|
|
|
|
+ result.add(calculatePeriodInfo(baseYear, baseMonth));
|
|
|
|
+
|
|
|
|
+ // 下个月
|
|
|
|
+ int nextMonth = baseMonth + 1;
|
|
|
|
+ int nextMonthYear = baseYear;
|
|
|
|
+ if (baseMonth == 12) {
|
|
|
|
+ nextMonth = 1;
|
|
|
|
+ nextMonthYear += 1;
|
|
|
|
+ }
|
|
|
|
+ result.add(calculatePeriodInfo(nextMonthYear, nextMonth));
|
|
|
|
+
|
|
|
|
+ // 明年同月
|
|
|
|
+ result.add(calculatePeriodInfo(baseYear + 1, baseMonth));
|
|
|
|
+
|
|
|
|
+ return result;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /**
|
|
|
|
+ * 构建单个期间的信息(当前月、上月、去年同期)
|
|
|
|
+ */
|
|
|
|
+ private PeriodInfoVO calculatePeriodInfo(int year, int month) {
|
|
|
|
+ PeriodInfoVO info = new PeriodInfoVO();
|
|
|
|
+
|
|
|
|
+ info.setYear( year);
|
|
|
|
+ info.setMonth( month);
|
|
|
|
+
|
|
|
|
+ // 上期
|
|
|
|
+ if (month == 1) {
|
|
|
|
+ info.setPrevYear(year - 1);
|
|
|
|
+ info.setPrevMonth(12);
|
|
|
|
+ } else {
|
|
|
|
+ info.setPrevYear( year);
|
|
|
|
+ info.setPrevMonth(month - 1);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ // 同期
|
|
|
|
+ info.setLastYear(year - 1);
|
|
|
|
+ info.setLastMonth( month);
|
|
|
|
+
|
|
|
|
+ return info;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /**
|
|
|
|
+ * 加载所有相关期间的数据(去重处理)
|
|
|
|
+ */
|
|
|
|
+ private Map<String, List<HospProfitAndLoss>> loadAllPeriodData(Long hospId, Integer 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()));
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ // 去重后查询
|
|
|
|
+ Map<String, List<HospProfitAndLoss>> result = new HashMap<>();
|
|
|
|
+ Set<String> processedKeys = new HashSet<>(); // 已处理的键集合
|
|
|
|
+
|
|
|
|
+ for (String key : allPeriodKeys) {
|
|
|
|
+ if (!processedKeys.contains(key)) {
|
|
|
|
+ int[] ym = parsePeriodKey(key);
|
|
|
|
+ List<HospProfitAndLoss> 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 符合条件的数据列表
|
|
|
|
+ */
|
|
|
|
+ private List<HospProfitAndLoss> getPeriodRecords(Long hospId, Integer shareType, int year, int month) {
|
|
|
|
+ return this.list(new QueryWrapper<HospProfitAndLoss>().lambda()
|
|
|
|
+ .eq(HospProfitAndLoss::getHospId, hospId)
|
|
|
|
+ .eq(HospProfitAndLoss::getReportType, shareType)
|
|
|
|
+ .eq(HospProfitAndLoss::getDateYear, year)
|
|
|
|
+ .eq(HospProfitAndLoss::getDateMonth, month)
|
|
|
|
+ .eq(HospProfitAndLoss::getDeleteTime, 0));
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /**
|
|
|
|
+ * 根据年月获取对应的数据(从内存中查找)
|
|
|
|
+ */
|
|
|
|
+ private List<HospProfitAndLoss> getPeriodData(Map<String, List<HospProfitAndLoss>> dataMap, int year, int month) {
|
|
|
|
+ String key = buildPeriodKey(year, month);
|
|
|
|
+ return dataMap.getOrDefault(key, Collections.emptyList());
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /**
|
|
|
|
+ * 批量计算同环比及同期金额(使用预加载数据)
|
|
|
|
+ */
|
|
|
|
+ public void calculatePeriodComparisonWithPreloadedData(
|
|
|
|
+ List<HospProfitAndLoss> currentRecords,
|
|
|
|
+ List<HospProfitAndLoss> prevRecords,
|
|
|
|
+ List<HospProfitAndLoss> lastYearRecords) {
|
|
|
|
+
|
|
|
|
+ if (CollectionUtils.isEmpty(currentRecords)) {
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ // 创建报表编号到记录的映射
|
|
|
|
+ Map<String, HospProfitAndLoss> prevMap = new HashMap<>();
|
|
|
|
+ for (HospProfitAndLoss record : prevRecords) {
|
|
|
|
+ String key = buildRecordKey(record);
|
|
|
|
+ prevMap.put(key, record);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ Map<String, HospProfitAndLoss> lastYearMap = new HashMap<>();
|
|
|
|
+ for (HospProfitAndLoss record : lastYearRecords) {
|
|
|
|
+ String key = buildRecordKey(record);
|
|
|
|
+ lastYearMap.put(key, record);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ // 批量更新数据
|
|
|
|
+ for (HospProfitAndLoss record : currentRecords) {
|
|
|
|
+ String key = buildRecordKey(record);
|
|
|
|
+ HospProfitAndLoss prevRecord = prevMap.get(key);
|
|
|
|
+ HospProfitAndLoss 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().subtract(record.getSamePeriodAmount()), record.getPrevPeriodAmount()));
|
|
|
|
+ record.setYoyRate(calculateProfitRate(record.getAmount().subtract(record.getSamePeriodAmount()), record.getSamePeriodAmount()));
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ // 批量更新数据库
|
|
|
|
+ this.updateBatchById(currentRecords);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /**
|
|
|
|
+ * 构建期间键(用于存储和检索数据)
|
|
|
|
+ */
|
|
|
|
+ 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])};
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /**
|
|
|
|
+ * 构建记录的唯一标识键(责任码 + 报表编号)
|
|
|
|
+ */
|
|
|
|
+ private String buildRecordKey(HospProfitAndLoss record) {
|
|
|
|
+ return String.valueOf(record.getReportNum());
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /**
|
|
|
|
+ * 安全地计算百分比:避免除零错误
|
|
|
|
+ */
|
|
|
|
+ private BigDecimal calculateProfitRate(BigDecimal current, BigDecimal base) {
|
|
|
|
+ if (base == null || base.compareTo(BigDecimal.ZERO) == 0) {
|
|
|
|
+ return BigDecimal.ZERO;
|
|
|
|
+ }
|
|
|
|
+ BigDecimal bigDecimal = current.divide(base, 4, RoundingMode.HALF_UP).setScale(4, RoundingMode.HALF_UP);
|
|
|
|
+ return bigDecimal;
|
|
|
|
+ }
|
|
|
|
+
|
|
/**
|
|
/**
|
|
* 执行全院损益后续脚本
|
|
* 执行全院损益后续脚本
|
|
* @param date
|
|
* @param date
|