123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348 |
- package com.kcim.service.impl;
- import com.kcim.common.constants.Constant;
- import com.kcim.common.constants.NumberConstant;
- import com.kcim.common.constants.ParameterConstant;
- import com.kcim.common.enums.EmpCostComputeTypeEnum;
- import com.kcim.common.exception.CostException;
- import com.kcim.common.util.BeanUtil;
- import com.kcim.common.util.UserContext;
- import com.kcim.dao.model.ComputeEmpCost;
- import com.kcim.dao.model.EmpCostMap;
- import com.kcim.dao.model.EmpCostType;
- import com.kcim.dao.model.ImportEmpCost;
- import com.kcim.dao.repository.ComputeEmpCostRepository;
- import com.kcim.dao.repository.EmpCostMapRepository;
- import com.kcim.dao.repository.EmpCostTypeRepository;
- import com.kcim.dao.repository.ImportEmpCostRepository;
- import com.kcim.service.CenterService;
- import com.kcim.service.EmpCostCalculateService;
- import com.kcim.vo.CommonParameterVo;
- import com.kcim.vo.DictDataVo;
- 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.math.BigDecimal;
- import java.math.RoundingMode;
- import java.util.*;
- import java.util.stream.Collectors;
- import static com.kcim.common.enums.EmpCostComputeTypeEnum.POSITION;
- /**
- * @program: CostAccount
- * @description: 单位人事成本计算实现类
- * @author: Wang.YS
- * @create: 2023-10-23 16:11
- **/
- @Service("EmpCostCalculateService")
- @Slf4j
- @AllArgsConstructor
- public class EmpCostCalculateServiceImpl implements EmpCostCalculateService {
- /**
- * 月度人事成本计算
- */
- ComputeEmpCostRepository repository;
- /**
- * 人事分类字典
- */
- EmpCostTypeRepository empCostTypeRepository;
- /**
- * 人事分类与人员对照
- */
- EmpCostMapRepository empCostMapRepository;
- /**
- * 人事成本导入数据
- */
- ImportEmpCostRepository importEmpCostRepository;
- CenterService centerService;
- /**
- * 成本核算-单位人事成本计算-获取计算列表
- *
- * @param computeDate 核算年月
- * @param filter 过滤 人事分类名称
- * @return 列表
- */
- @Override
- public Object getEmpCostCalculateList(String computeDate, String filter) {
- if(!StringUtils.isEmpty(filter)){
- List<ComputeEmpCost> filterList = repository.getByComputeDate(computeDate, filter);
- if(!CollectionUtils.isEmpty(filterList)){
- List<ComputeEmpCost> parentList = repository.getByParentComputeDate(computeDate);
- Map<String,ComputeEmpCost> parentMap = parentList.stream().collect(Collectors.toMap(ComputeEmpCost::getCode, computeEmpCost -> computeEmpCost, (a, b) -> b));
- //先取出过滤条件中的 上层数据
- List<ComputeEmpCost> collect = filterList.stream().filter(f -> f.getParentCode().equals(NumberConstant.ZERO_S)).collect(Collectors.toList());
- if(!CollectionUtils.isEmpty(collect)){
- filterList.removeAll(collect);
- }
- //子集去除上层数据 是否还有数据
- if(!CollectionUtils.isEmpty(filterList)){
- //找出符合条件的 子集 没有上层的数据 在所有上层数据中找到父类用于显示
- for (ComputeEmpCost computeEmpCost : filterList) {
- //组装成符合条件的上层数据中
- collect.add(parentMap.get(computeEmpCost.getParentCode()));
- }
- //可能存在重复 去重 用于显示的最外层
- List<ComputeEmpCost> collectParent = collect.stream().distinct().collect(Collectors.toList());
- Map<String, List<ComputeEmpCost>> map = filterList.stream().collect(Collectors.groupingBy(ComputeEmpCost::getParentCode));
- for (ComputeEmpCost empCost : collectParent) {
- List<ComputeEmpCost> childList = map.get(empCost.getCode());
- if(!CollectionUtils.isEmpty(childList)){
- empCost.setChildList(childList);
- }
- }
- return collectParent;
- }else {
- return collect;
- }
- }else {
- return new ArrayList<>();
- }
- }else {
- List<ComputeEmpCost> list = repository.getByComputeDate(computeDate);
- if(!CollectionUtils.isEmpty(list)){
- Map<String, List<ComputeEmpCost>> map = list.stream().collect(Collectors.groupingBy(ComputeEmpCost::getParentCode));
- List<ComputeEmpCost> parent = map.get(NumberConstant.ZERO_S);
- for (ComputeEmpCost empCost : parent) {
- List<ComputeEmpCost> childList = map.get(empCost.getCode());
- if(!CollectionUtils.isEmpty(childList)){
- empCost.setChildList(childList);
- }
- }
- return parent;
- }else {
- return new ArrayList<>();
- }
- }
- }
- /**
- * 成本核算-单位人事成本计算-计算
- *
- * @param computeDate 核算年月
- */
- @Override
- public void empCostCalculate(String computeDate) {
- List<EmpCostType> list = empCostTypeRepository.getList();
- if(CollectionUtils.isEmpty(list)){
- log.error("当前院区未维护人事分类,计算中止");
- throw new CostException("当前院区未维护人事分类,计算中止");
- }
- List<EmpCostMap> empCostMapList = empCostMapRepository.getList();
- if(CollectionUtils.isEmpty(empCostMapList)){
- log.info("当前院区人事分类未对照人员信息,计算中止");
- throw new CostException("当前院区人事分类未对照人员信息,计算中止");
- }
- List<ImportEmpCost> importEmpCosts = importEmpCostRepository.getByComputeDate(computeDate);
- if(CollectionUtils.isEmpty(importEmpCosts)){
- log.info("当前核算年月【"+computeDate+"】未导入人事成本数据");
- throw new CostException("当前核算年月【"+computeDate+"】未导入人事成本数据,计算中止");
- }
- //获取中台科室字典
- Map<String, String> department = centerService.getDepartment();
- if(CollectionUtils.isEmpty(department)){
- throw new CostException("未获取到当前院区科室信息,计算中止");
- }
- //获取中台岗位字典
- DictDataVo dict = centerService.getCenterDict(Constant.POSITION);
- List<DictDataVo> dataVoList = dict.getDataVoList();
- Map<String,String> positionMap = dataVoList.stream().collect(Collectors.toMap(DictDataVo::getCode, DictDataVo::getName, (a, b) -> b));
- //获取中台应工作天数字典
- DictDataVo monthWorkdays = centerService.getCenterDict(Constant.MONTH_WORKDAYS);
- Map<String, String> monthWorkdayMap = monthWorkdays.getDataVoList().stream().collect(Collectors.toMap(DictDataVo::getCode, DictDataVo::getExpandOne, (a, b) -> b));
- String currentWorkDay = monthWorkdayMap.get(computeDate);
- //获取每日工时参数
- CommonParameterVo parameter = centerService.getParameter(ParameterConstant.DAY_HOUR);
- String dayHour = parameter.getValue();
- if(StringUtils.isEmpty(dayHour)){
- throw new CostException("中台未找到每日工时参数, 请确认参数数据是否正确");
- }
- Map<String,ImportEmpCost> importEmpCostMap = importEmpCosts.stream().collect(Collectors.toMap(ImportEmpCost::getEmpCode, importEmpCost -> importEmpCost, (a, b) -> b));
- Map<String, List<EmpCostMap>> costTypeGroup = empCostMapList.stream().collect(Collectors.groupingBy(EmpCostMap::getCostTypeCode));
- ComputeEmpCost computeEmpCost = new ComputeEmpCost();
- computeEmpCost.setHospId(UserContext.getHospId());
- computeEmpCost.setComputeDate(computeDate);
- computeEmpCost.setCreateUser(String.valueOf(UserContext.getCurrentUser().getId()));
- computeEmpCost.setCreateTime(new Date());
- List<ComputeEmpCost> saveList = new ArrayList<>();
- for (EmpCostType empCostType : list) {
- ComputeEmpCost empCost = BeanUtil.convertObj(computeEmpCost, ComputeEmpCost.class);
- String code = empCostType.getCostTypeCode();
- empCost.setCode(code);
- empCost.setName(empCostType.getCostTypeName());
- empCost.setParentCode(NumberConstant.ZERO_S);
- empCost.setEmpType(code);
- String computeType = empCostType.getComputeType();
- if(!CollectionUtils.isEmpty(costTypeGroup)){
- //有子类 计算子类项目
- List<EmpCostMap> empCostMaps = costTypeGroup.get(code);
- if(!CollectionUtils.isEmpty(empCostMaps)){
- List<String> collect = empCostMaps.stream().map(EmpCostMap::getAccount).collect(Collectors.toList());
- List<ImportEmpCost> costTypeEmpCost = collect.stream().map(importEmpCostMap::get).filter(Objects::nonNull).collect(Collectors.toList());
- log.info("----for-8----"+costTypeEmpCost.toString());
- if(!CollectionUtils.isEmpty(costTypeEmpCost)){
- // 实际编制人数
- int empNum = costTypeEmpCost.size();
- empCost.setEmpNum(empNum);
- setSaveCost(currentWorkDay, dayHour, empCost, empNum, costTypeEmpCost);
- if(computeType.equals(EmpCostComputeTypeEnum.DEPARTMENT.getCode())){
- //按科室计算子类
- Map<String,ImportEmpCost> empCostMap = costTypeEmpCost.stream().collect(Collectors.toMap(ImportEmpCost::getEmpCode, importEmpCost -> importEmpCost, (a, b) -> b));
- Map<String, List<EmpCostMap>> departGroup = empCostMaps.stream().collect(Collectors.groupingBy(EmpCostMap::getDepartmentCode));
- for (String s : departGroup.keySet()) {
- ComputeEmpCost empChildCost = BeanUtil.convertObj(computeEmpCost, ComputeEmpCost.class);
- //单个科室所有人员
- List<EmpCostMap> empCostMaps1 = departGroup.get(s);
- //人员工号
- List<String> collect1 = empCostMaps1.stream().map(EmpCostMap::getAccount).collect(Collectors.toList());
- //获取实院导入数据
- List<ImportEmpCost> costTypeChildEmpCost = collect1.stream().map(empCostMap::get).filter(Objects::nonNull).collect(Collectors.toList());
- empChildCost.setCode(s);
- empChildCost.setParentCode(code);
- empChildCost.setEmpType(code);
- empChildCost.setName(department.get(s));
- if(!CollectionUtils.isEmpty(costTypeChildEmpCost)){
- empChildCost.setEmpNum(costTypeChildEmpCost.size());// 人数
- setSaveCost(currentWorkDay, dayHour, empChildCost, costTypeChildEmpCost.size(), costTypeChildEmpCost);
- saveList.add(empChildCost);
- }
- }
- } else if (computeType.equals(POSITION.getCode())) {
- //按岗位计算子类
- Map<String,ImportEmpCost> empCostMap = costTypeEmpCost.stream().collect(Collectors.toMap(ImportEmpCost::getEmpCode, importEmpCost -> importEmpCost, (a, b) -> b));
- Map<String, List<EmpCostMap>> positionGroup = empCostMaps.stream().collect(Collectors.groupingBy(EmpCostMap::getPosition));
- for (String s : positionGroup.keySet()) {
- ComputeEmpCost empChildCost = BeanUtil.convertObj(computeEmpCost, ComputeEmpCost.class);
- //单个科室所有人员
- List<EmpCostMap> empCostMaps1 = positionGroup.get(s);
- //人员工号
- List<String> collect1 = empCostMaps1.stream().map(EmpCostMap::getAccount).collect(Collectors.toList());
- //获取实院导入数据
- List<ImportEmpCost> costTypeChildEmpCost = collect1.stream().map(empCostMap::get).filter(Objects::nonNull).collect(Collectors.toList());
- empChildCost.setCode(s);
- empChildCost.setParentCode(code);
- empChildCost.setEmpType(code);
- empChildCost.setName(positionMap.get(s));
- if(!CollectionUtils.isEmpty(costTypeChildEmpCost)){
- empChildCost.setEmpNum(costTypeChildEmpCost.size());// 实际总工时
- setSaveCost(currentWorkDay, dayHour, empChildCost, costTypeChildEmpCost.size(), costTypeChildEmpCost);
- saveList.add(empChildCost);
- }
- }
- }
- }
- }
- }else {
- //子类人员为空 无子集
- empCost.setEmpNum(NumberConstant.ZERO);
- // 实际总工时
- empCost.setActualHour(BigDecimal.ZERO);
- // 预计总工时 预计总工时=应上班天数*实际编制人数*每日工时
- empCost.setExpectHour(BigDecimal.ZERO);
- // 总成本
- empCost.setTotalCost(BigDecimal.ZERO);
- // 人均成本
- empCost.setAvgCost(BigDecimal.ZERO);
- // 每分钟成本
- empCost.setMinuteCost(BigDecimal.ZERO);
- }
- saveList.add(empCost);
- }
- if(!CollectionUtils.isEmpty(saveList)){
- //判断当前核算年月是否有数据 有 作废 无保存
- repository.removeByComputeDate(computeDate);
- repository.saveBatch(saveList);
- }
- }
- private void setSaveCost(String currentWorkDay, String dayHour, ComputeEmpCost empCost, int empNum, List<ImportEmpCost> costTypeEmpCost) {
- // 实际总工时
- BigDecimal totalHour = computeTotalHour(costTypeEmpCost);
- empCost.setActualHour(totalHour);
- // 预计总工时 预计总工时=应上班天数*实际编制人数*每日工时
- BigDecimal expectHour = computeExpectHour(empNum, currentWorkDay, dayHour);
- empCost.setExpectHour(expectHour);
- // 总成本
- BigDecimal totalCost = computeTotalCost(costTypeEmpCost);
- empCost.setTotalCost(totalCost);
- // 人均成本
- BigDecimal avgCost = computeAvgCost(totalCost, empNum);
- empCost.setAvgCost(avgCost);
- // 每分钟成本
- BigDecimal minuteCost = computeMinuteCost(totalCost, totalHour);
- empCost.setMinuteCost(minuteCost);
- }
- private BigDecimal computeExpectHour(int size, String i, String v) {
- double hour = size * Double.parseDouble(i) * Double.parseDouble(v);
- return BigDecimal.valueOf(hour);
- }
- /**
- * 计算每分钟成本 总成本/实际工时/60
- * @param total 总成本
- * @param totalHour 总工时
- * @return 每分钟成本
- */
- private BigDecimal computeMinuteCost(BigDecimal total, BigDecimal totalHour) {
- return total.divide(totalHour,4,RoundingMode.HALF_UP).divide(BigDecimal.valueOf(60),4,RoundingMode.HALF_UP).setScale(4,RoundingMode.HALF_UP);
- }
- /**
- * 计算总工时
- * @param costTypeEmpCost 导入数据
- * @return 总工时
- */
- private BigDecimal computeTotalHour(List<ImportEmpCost> costTypeEmpCost) {
- BigDecimal total = new BigDecimal("0.0000");
- for (ImportEmpCost importEmpCost : costTypeEmpCost) {
- total = total.add(importEmpCost.getHour());
- }
- return total;
- }
- /**
- * 计算人均成本 总成本/实际编制人数
- * @param total 总成本
- * @param size 实际编制人数
- * @return 人均成本
- */
- private BigDecimal computeAvgCost(BigDecimal total, int size) {
- return total.divide(BigDecimal.valueOf(size),4,RoundingMode.HALF_UP);
- }
- /**
- * 计算总成本
- * @param costTypeEmpCost 列表数据
- * @return 总成本
- */
- private BigDecimal computeTotalCost(List<ImportEmpCost> costTypeEmpCost) {
- BigDecimal total = new BigDecimal("0.0000");
- for (ImportEmpCost importEmpCost : costTypeEmpCost) {
- total = total.add(importEmpCost.getCost());
- }
- return total;
- }
- }
|