|
|
@@ -4,24 +4,30 @@ import cn.hutool.core.date.DateTime;
|
|
|
import cn.hutool.core.date.DateUtil;
|
|
|
import com.kcim.common.constants.Constant;
|
|
|
import com.kcim.common.constants.NumberConstant;
|
|
|
+import com.kcim.common.constants.ParameterConstant;
|
|
|
+import com.kcim.common.constants.SplitConstant;
|
|
|
+import com.kcim.common.exception.CostException;
|
|
|
import com.kcim.common.util.BeanUtil;
|
|
|
import com.kcim.common.util.UserContext;
|
|
|
-import com.kcim.dao.model.Accounting;
|
|
|
-import com.kcim.dao.model.AllocationQuery;
|
|
|
-import com.kcim.dao.model.Responsibility;
|
|
|
+import com.kcim.dao.model.*;
|
|
|
import com.kcim.dao.repository.AccountingRepository;
|
|
|
import com.kcim.dao.repository.ResponsibilityRepository;
|
|
|
+import com.kcim.dao.repository.ShareParamValueRepository;
|
|
|
import com.kcim.service.AllocationQueryService;
|
|
|
import com.kcim.service.CenterService;
|
|
|
+import com.kcim.service.IncomeCollectionService;
|
|
|
import com.kcim.service.StandardReportService;
|
|
|
import com.kcim.vo.*;
|
|
|
+import com.kcim.web.reponse.ComputeProfitCollectResponse;
|
|
|
import lombok.AllArgsConstructor;
|
|
|
import lombok.extern.slf4j.Slf4j;
|
|
|
import org.springframework.stereotype.Service;
|
|
|
import org.springframework.util.CollectionUtils;
|
|
|
+import org.springframework.util.StringUtils;
|
|
|
|
|
|
import java.lang.reflect.Field;
|
|
|
import java.math.BigDecimal;
|
|
|
+import java.math.RoundingMode;
|
|
|
import java.util.*;
|
|
|
import java.util.stream.Collectors;
|
|
|
|
|
|
@@ -35,6 +41,9 @@ import java.util.stream.Collectors;
|
|
|
@Slf4j
|
|
|
@AllArgsConstructor
|
|
|
public class StandardReportServiceImpl implements StandardReportService {
|
|
|
+ private static final String AMOUNT_FIELD = "amount";
|
|
|
+ private static final String PERCENT_FIELD = "percent" ;
|
|
|
+
|
|
|
ResponsibilityRepository responsibilityRepository;
|
|
|
|
|
|
AllocationQueryService allocationQueryService;
|
|
|
@@ -42,6 +51,10 @@ public class StandardReportServiceImpl implements StandardReportService {
|
|
|
CenterService centerService;
|
|
|
|
|
|
AccountingRepository accountingRepository;
|
|
|
+
|
|
|
+ IncomeCollectionService incomeCollectionService;
|
|
|
+
|
|
|
+ ShareParamValueRepository shareParamValueRepository;
|
|
|
|
|
|
/**
|
|
|
* 科室直接成本表(医疗成本)
|
|
|
@@ -256,6 +269,265 @@ public class StandardReportServiceImpl implements StandardReportService {
|
|
|
return reportList;
|
|
|
}
|
|
|
|
|
|
+ /**
|
|
|
+ * 获取医院临床服务类科室全成本构成分析表数据
|
|
|
+ * @param computeDate 核算年月
|
|
|
+ * @return 报表数据
|
|
|
+ */
|
|
|
+ @Override
|
|
|
+ public ComputeProfitCollectResponse getClinicalDeptFullCostAnalysis(String computeDate) {
|
|
|
+ DateTime parse = DateUtil.parse(computeDate);
|
|
|
+ int year = DateUtil.year(parse);
|
|
|
+ int month = DateUtil.month(parse) + 1;
|
|
|
+
|
|
|
+ // 获取科室成本
|
|
|
+ List<AllocationQuery> allocationQueryList = allocationQueryService.getAllByDate(UserContext.getCurrentLoginHospId(), year, month);
|
|
|
+ if (CollectionUtils.isEmpty(allocationQueryList)) {
|
|
|
+ throw new CostException("医院未分摊本月数据");
|
|
|
+ }
|
|
|
+ //获取科室收入
|
|
|
+ List<IncomeCollection> responsibilityIncomeList = incomeCollectionService.getResponsibilitiesAccounts(year, month, UserContext.getCurrentLoginHospId());
|
|
|
+ if (CollectionUtils.isEmpty(responsibilityIncomeList)) {
|
|
|
+ throw new CostException("医院未归集本月收入数据");
|
|
|
+ }
|
|
|
+ Map<String, BigDecimal> responsibilityIncomeMap = responsibilityIncomeList.stream().collect(Collectors.toMap(IncomeCollection::getResponsibilityCode, IncomeCollection::getAmount));
|
|
|
+ //获取分摊参数
|
|
|
+ List<ShareParamValue> shareParamValueList = shareParamValueRepository.getList(computeDate);
|
|
|
+ if (CollectionUtils.isEmpty(shareParamValueList)) {
|
|
|
+ throw new CostException("未获取医院本月分摊参数数据");
|
|
|
+ }
|
|
|
+ Map<String, List<ShareParamValue>> responsibilityParamValueMap = shareParamValueList.stream().collect(Collectors.groupingBy(ShareParamValue::getResponsibilityCode));
|
|
|
+ //获取诊次床日分摊参数代码
|
|
|
+ String[] visitsBedDaysParamCode = getVisitsBedDaysParamCode();
|
|
|
+ // 获取所有的标准字典数据
|
|
|
+ StandCostDictMapVO standCostDictMaps = getStandCostDictMaps();
|
|
|
+
|
|
|
+ // 处理 allocationQueryList 数据
|
|
|
+ Map<String ,DeptDirectMedicalCostVO> deptDirectMedicalCostMap = new HashMap<>();
|
|
|
+ //转换为DeptDirectMedicalCostVO(一个责任中心只一条记录)
|
|
|
+ for (AllocationQuery allocationQuery : allocationQueryList) {
|
|
|
+ addDeptDirectMedicalCostVO(deptDirectMedicalCostMap,allocationQuery, standCostDictMaps);
|
|
|
+ }
|
|
|
+
|
|
|
+ // 转成List便于处理
|
|
|
+ List<DeptDirectMedicalCostVO> reportList = deptDirectMedicalCostMap.values().stream().collect(Collectors.toList());
|
|
|
+ // 创建合计对象
|
|
|
+ DeptDirectMedicalCostVO subtotalVo = createSubtotalVo(reportList.get(NumberConstant.ZERO), "科室合计", DeptDirectMedicalCostVO.class);
|
|
|
+ subtotalVo.setResponsibilityCode("deptSubtotal");
|
|
|
+ for (DeptDirectMedicalCostVO item : reportList) {
|
|
|
+ //计算科室的收入及损益+床日成本及诊次成本
|
|
|
+ calcDeptExpandCost(item, responsibilityIncomeMap, responsibilityParamValueMap, visitsBedDaysParamCode);
|
|
|
+ // 将科室的金额加到合计对象中
|
|
|
+ addBigDecimalFields(item, subtotalVo);
|
|
|
+ }
|
|
|
+ // 合计加到列表最后面
|
|
|
+ reportList.add(subtotalVo);
|
|
|
+
|
|
|
+ // 创建成本项目列表
|
|
|
+ List<String> costItems = Arrays.asList(
|
|
|
+ "人员经费", "卫生材料费", "药品费", "固定资产折旧费", "无形资产摊销费",
|
|
|
+ "提取医疗风险基金", "其他医疗费用", "科室全成本合计","科室收入","收入-成本","床日成本","诊次成本"
|
|
|
+ );
|
|
|
+ //不要计算占比的项目列表
|
|
|
+ List<String> noPercentCostItems = Arrays.asList(
|
|
|
+ "科室收入","收入-成本","床日成本","诊次成本"
|
|
|
+ );
|
|
|
+
|
|
|
+ // 创建结果列表
|
|
|
+ List<ReportFormCustomVo> resultData = new ArrayList<>();
|
|
|
+ List<CommonResponsibilityReportVo> titleList = new ArrayList<>();
|
|
|
+
|
|
|
+ // 提取科室名称作为列标题
|
|
|
+ for (DeptDirectMedicalCostVO dept : reportList) {
|
|
|
+ CommonResponsibilityReportVo title = new CommonResponsibilityReportVo();
|
|
|
+ title.setResponsibilityName(dept.getResponsibilityName());
|
|
|
+ title.setResponsibilityCode(dept.getResponsibilityCode());
|
|
|
+ title.setSort(dept.getResponsibilitySort());
|
|
|
+ //添加子级标题
|
|
|
+ addCommonResponsibilityChild(title);
|
|
|
+ titleList.add(title);
|
|
|
+ }
|
|
|
+
|
|
|
+ // 遍历每个成本项目(列转行)
|
|
|
+ for (String costItem : costItems) {
|
|
|
+ ReportFormCustomVo itemVo = new ReportFormCustomVo();
|
|
|
+ itemVo.setReportName(costItem);
|
|
|
+ itemVo.setData(new ArrayList<>());
|
|
|
+ // 遍历每个科室
|
|
|
+ for (DeptDirectMedicalCostVO dept : reportList) {
|
|
|
+ //金额对象
|
|
|
+ ReportVo amountReportVo = new ReportVo();
|
|
|
+ amountReportVo.setCode(getResponsibilityAmountCode(dept.getResponsibilityCode()));
|
|
|
+ //占比对象
|
|
|
+ ReportVo percentReportVo = new ReportVo();
|
|
|
+ percentReportVo.setCode(getResponsibilityPercentCode(dept.getResponsibilityCode()));
|
|
|
+ //获取金额
|
|
|
+ BigDecimal deptAmount = getDeptAmount(dept, costItem);
|
|
|
+ // 设置金额和百分比
|
|
|
+ amountReportVo.setValue(deptAmount);
|
|
|
+ //要显示占比的字段才计算占比
|
|
|
+ if(!noPercentCostItems.contains(costItem)){
|
|
|
+ //计算百分比
|
|
|
+ BigDecimal percent = getPercent(deptAmount, dept.getTotal());
|
|
|
+ percentReportVo.setValue(percent);
|
|
|
+ }
|
|
|
+ // 添加金额和百分比
|
|
|
+ itemVo.getData().add(amountReportVo);
|
|
|
+ itemVo.getData().add(percentReportVo);
|
|
|
+ }
|
|
|
+ resultData.add(itemVo);
|
|
|
+ }
|
|
|
+
|
|
|
+ ComputeProfitCollectResponse response = new ComputeProfitCollectResponse();
|
|
|
+ response.setTitle(titleList);
|
|
|
+ response.setData(resultData);
|
|
|
+
|
|
|
+ return response;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 获取可是指定项目的金额
|
|
|
+ * @param dept
|
|
|
+ * @param costItem
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ public BigDecimal getDeptAmount(DeptDirectMedicalCostVO dept,String costItem) {
|
|
|
+ BigDecimal amount = BigDecimal.ZERO;
|
|
|
+ switch (costItem) {
|
|
|
+ case "人员经费":
|
|
|
+ amount = dept.getPersonnelExpense();
|
|
|
+ break;
|
|
|
+ case "卫生材料费":
|
|
|
+ amount = dept.getHealthMaterialFee();
|
|
|
+ break;
|
|
|
+ case "药品费":
|
|
|
+ amount = dept.getDrugFee();
|
|
|
+ break;
|
|
|
+ case "固定资产折旧费":
|
|
|
+ amount =dept.getFixedAssetDepreciation();
|
|
|
+ break;
|
|
|
+ case "无形资产摊销费":
|
|
|
+ amount = dept.getIntangibleAssetAmortization();
|
|
|
+ break;
|
|
|
+ case "提取医疗风险基金":
|
|
|
+ amount = dept.getMedicalRiskFundExtraction();
|
|
|
+ break;
|
|
|
+ case "其他医疗费用":
|
|
|
+ amount = dept.getOtherMedicalExpenses();
|
|
|
+ break;
|
|
|
+ case "科室全成本合计":
|
|
|
+ amount = dept.getTotal();
|
|
|
+ break;
|
|
|
+ case "科室收入":
|
|
|
+ amount = dept.getIncome();
|
|
|
+ break;
|
|
|
+ case "收入-成本":
|
|
|
+ amount = dept.getProfit();
|
|
|
+ break;
|
|
|
+ case "诊次成本":
|
|
|
+ amount = dept.getVisitsCost();
|
|
|
+ break;
|
|
|
+ case "床日成本":
|
|
|
+ amount = dept.getBedDaysCost();
|
|
|
+ break;
|
|
|
+ default:
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ return amount;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 计算科室的收入及损益+床日成本及诊次成本
|
|
|
+ * @param item
|
|
|
+ * @param responsibilityIncomeMap
|
|
|
+ * @param responsibilityParamValueMap
|
|
|
+ * @param visitsBedDaysParamCode
|
|
|
+ */
|
|
|
+ private void calcDeptExpandCost(DeptDirectMedicalCostVO item,
|
|
|
+ Map<String, BigDecimal> responsibilityIncomeMap,
|
|
|
+ Map<String, List<ShareParamValue>> responsibilityParamValueMap,
|
|
|
+ String[] visitsBedDaysParamCode) {
|
|
|
+ //计算科室的收入及损益
|
|
|
+ if(responsibilityIncomeMap.containsKey(item.getResponsibilityCode())){
|
|
|
+ item.setIncome(responsibilityIncomeMap.get(item.getResponsibilityCode()));
|
|
|
+ item.setProfit(item.getIncome().subtract(item.getTotal()));
|
|
|
+ }else{
|
|
|
+ item.setIncome(BigDecimal.ZERO);
|
|
|
+ item.setProfit(BigDecimal.ZERO);
|
|
|
+ }
|
|
|
+ //计算科室的床日成本及诊次成本
|
|
|
+ if(responsibilityParamValueMap.containsKey(item.getResponsibilityCode())){
|
|
|
+ List<ShareParamValue> shareParamValues = responsibilityParamValueMap.get(item.getResponsibilityCode());
|
|
|
+ //获取诊次参数
|
|
|
+ Optional<ShareParamValue> firstVisitParam = shareParamValues.stream().filter(shareParamValue -> shareParamValue.getShareParamCode().equals(visitsBedDaysParamCode[0])).findFirst();
|
|
|
+ if(firstVisitParam.isPresent()){
|
|
|
+ // 计算诊次成本=总成本/诊次数
|
|
|
+ item.setVisitsCost(getPercent(item.getTotal(),firstVisitParam.get().getValueNum()));
|
|
|
+ }else{
|
|
|
+ item.setVisitsCost(BigDecimal.ZERO);
|
|
|
+ }
|
|
|
+ Optional<ShareParamValue> firstBedDayParam = shareParamValues.stream().filter(shareParamValue -> shareParamValue.getShareParamCode().equals(visitsBedDaysParamCode[1])).findFirst();
|
|
|
+ if(firstBedDayParam.isPresent()){
|
|
|
+ // 床日成本=总成本/床日数
|
|
|
+ item.setBedDaysCost(getPercent(item.getTotal(),firstBedDayParam.get().getValueNum()));
|
|
|
+ }else{
|
|
|
+ item.setBedDaysCost(BigDecimal.ZERO);
|
|
|
+ }
|
|
|
+ }else{
|
|
|
+ item.setBedDaysCost(BigDecimal.ZERO);
|
|
|
+ item.setVisitsCost(BigDecimal.ZERO);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 获取百分比
|
|
|
+ * @param amount
|
|
|
+ * @param total
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ public BigDecimal getPercent(BigDecimal amount,BigDecimal total){
|
|
|
+ if(total.compareTo(BigDecimal.ZERO.setScale(4, RoundingMode.HALF_UP)) == 0){
|
|
|
+ return BigDecimal.ZERO;
|
|
|
+ }
|
|
|
+ return amount.divide(total,4, RoundingMode.HALF_UP);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 获取责任中心金额字段
|
|
|
+ * @param responsibilityCode
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ public String getResponsibilityAmountCode(String responsibilityCode){
|
|
|
+ return String.format("%s_%s", responsibilityCode, AMOUNT_FIELD);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 获取责任中心占比字段
|
|
|
+ * @param responsibilityCode
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ public String getResponsibilityPercentCode(String responsibilityCode){
|
|
|
+ return String.format("%s_%s", responsibilityCode, PERCENT_FIELD);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 添加全成本构成表标题的子级标题
|
|
|
+ * @param commonResponsibility
|
|
|
+ */
|
|
|
+ public void addCommonResponsibilityChild(CommonResponsibilityReportVo commonResponsibility) {
|
|
|
+ commonResponsibility.setChild(new ArrayList<>());
|
|
|
+ CommonResponsibilityReportVo amount=new CommonResponsibilityReportVo();
|
|
|
+ amount.setResponsibilityCode(getResponsibilityAmountCode(commonResponsibility.getResponsibilityCode() ));
|
|
|
+ amount.setResponsibilityName("金额");
|
|
|
+ amount.setSort(NumberConstant.ZERO);
|
|
|
+ commonResponsibility.getChild().add( amount);
|
|
|
+ CommonResponsibilityReportVo percent=new CommonResponsibilityReportVo();
|
|
|
+ percent.setResponsibilityCode(getResponsibilityPercentCode(commonResponsibility.getResponsibilityCode()));
|
|
|
+ percent.setResponsibilityName("占比");
|
|
|
+ percent.setSort(NumberConstant.ONE);
|
|
|
+ commonResponsibility.getChild().add( percent);
|
|
|
+ }
|
|
|
+
|
|
|
/**
|
|
|
* 添加临床服务类科室全成本明细
|
|
|
* @param reportMap
|
|
|
@@ -751,6 +1023,31 @@ public class StandardReportServiceImpl implements StandardReportService {
|
|
|
return target;
|
|
|
}
|
|
|
|
|
|
+ // 新增方法,用于设置科室金额
|
|
|
+ private void putDepartmentAmount(ClinicalDeptFullCostVO vo, String deptName, BigDecimal amount) {
|
|
|
+ try {
|
|
|
+ Field field = vo.getClass().getDeclaredField(deptName);
|
|
|
+ field.setAccessible(true);
|
|
|
+ field.set(vo, amount);
|
|
|
+ } catch (NoSuchFieldException | IllegalAccessException e) {
|
|
|
+ log.error("设置科室金额时发生错误", e);
|
|
|
+ }
|
|
|
+ }
|
|
|
|
|
|
+ /**
|
|
|
+ * 获取诊次床日分摊参数代码
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ public String[] getVisitsBedDaysParamCode(){
|
|
|
+ String parameterValue = centerService.getParameterValue(ParameterConstant.VISITS_BED_DAYS_PARAM_CODE);
|
|
|
+ if(StringUtils.isEmpty(parameterValue)||Constant.EMPTY_STR.equals(parameterValue)){
|
|
|
+ throw new CostException("请配置诊次床日分摊参数代码");
|
|
|
+ }
|
|
|
+ String[] split = parameterValue.split(SplitConstant.SEPARATOR_VERTICALLINE);
|
|
|
+ if(!NumberConstant.TWO.equals(split.length)){
|
|
|
+ throw new CostException("配置的诊次床日分摊参数代码不正确");
|
|
|
+ }
|
|
|
+ return split;
|
|
|
+ }
|
|
|
|
|
|
}
|