DynamicSalaryCalculator.java 6.24 KB
package cn.fw.morax.service.biz.calculator.salary;

import cn.fw.morax.common.utils.DateUtil;
import cn.fw.morax.domain.db.salary.*;
import cn.fw.morax.domain.enums.ExtraSalaryTypeEnum;
import cn.fw.morax.domain.enums.SalaryCalMethodEnum;
import cn.fw.morax.domain.enums.SalaryTypeEnum;
import cn.fw.morax.service.data.salary.SalaryExtraProjectService;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.lang.NonNull;
import org.springframework.stereotype.Component;

import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.YearMonth;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;

/**
 * @author : kurisu
 * @version : 1.0
 * @className : DynamicSalaryCalculator
 * @description : 动态薪资计算器
 * @date : 2022-04-27 10:37
 */
@Component
@Slf4j
public class DynamicSalaryCalculator extends SalaryBaseCalculator {

    private final SalaryExtraProjectService salaryExtraProjectService;

    @Autowired
    public DynamicSalaryCalculator(final SalaryExtraProjectService salaryExtraProjectService) {
        this.salaryExtraProjectService = salaryExtraProjectService;
    }

    @Override
    public BigDecimal calculate(SalaryGroupProject param1, SalaryGroupUser param2) {
        // 用不到这个计算器
        // 动态金额类不在此计算
        return null;
    }


    @Override
    public SalaryPoolDetail calcDynamicMoney(@NonNull SalaryPool pool, @NonNull LocalDate date, @NonNull ExtraSalaryTypeEnum extraSalaryTypeEnum) {
        SalaryPoolDetail poolDetail = createDetail(pool, date, extraSalaryTypeEnum);
        List<SalaryExtraProject> projectList = queryProjectList(pool, date, extraSalaryTypeEnum);
        calculate(poolDetail, projectList);
        return poolDetail;
    }

    @Override
    public SalaryCalMethodEnum getCalMethod() {
        return SalaryCalMethodEnum.DYNAMIC;
    }

    private void calculate(SalaryPoolDetail poolDetail, List<SalaryExtraProject> projectList) {
        BigDecimal actualSalaryAmount = projectList.stream()
                .filter(r -> !Boolean.TRUE.equals(r.getTimely()))
                .map(SalaryExtraProject::getMoney)
                .reduce(BigDecimal.ZERO, BigDecimal::add);
        BigDecimal processedAmount = projectList.stream()
                .filter(r -> Boolean.TRUE.equals(r.getTimely()))
                .map(SalaryExtraProject::getMoney)
                .reduce(BigDecimal.ZERO, BigDecimal::add);
        BigDecimal expectedAmount = actualSalaryAmount.add(processedAmount);

        poolDetail.setSalaryAmount(expectedAmount);
        poolDetail.setProcessedAmount(processedAmount);
        poolDetail.setActualSalaryAmount(actualSalaryAmount);
    }

    /**
     * 查询额外薪资记录
     *
     * @param pool
     * @param date
     * @param extraSalaryTypeEnum
     * @return
     */
    private List<SalaryExtraProject> queryProjectList(SalaryPool pool, LocalDate date, ExtraSalaryTypeEnum extraSalaryTypeEnum) {
        LocalDate startTime = YearMonth.from(date).minusMonths(1L).atEndOfMonth();
        LocalDateTime endTime = date.plusDays(1L).atStartOfDay();

        //调岗前后还是同一个薪酬组,不算调岗。搜索调岗之前的门店,获取薪酬额外数据
        List<SalaryGroupUser> groupUsers = salaryGroupUserService.list(Wrappers.<SalaryGroupUser>lambdaQuery()
                .eq(SalaryGroupUser::getSalaryGroupId, pool.getSalaryGroupId())
                .eq(SalaryGroupUser::getPostId, pool.getPostId())
                .eq(SalaryGroupUser::getUserId, pool.getUserId())
                .ge(SalaryGroupUser::getDataDate, startTime)
                .le(SalaryGroupUser::getDataDate, date)
                .eq(SalaryGroupUser::getYn, Boolean.TRUE)
        );
        List<Long> shopIds = groupUsers.stream().map(SalaryGroupUser::getShopId).distinct().collect(Collectors.toList());

        List<SalaryExtraProject> list = salaryExtraProjectService.list(Wrappers.<SalaryExtraProject>lambdaQuery()
                .eq(SalaryExtraProject::getPostId, pool.getPostId())
                .in(SalaryExtraProject::getShopId, shopIds)
                .eq(SalaryExtraProject::getUserId, pool.getUserId())
                .eq(SalaryExtraProject::getSalaryType, extraSalaryTypeEnum)
                .gt(SalaryExtraProject::getDataDate, startTime)
                .lt(SalaryExtraProject::getDataDate, endTime)
                .eq(SalaryExtraProject::getYn, Boolean.TRUE)
        );
        return Optional.ofNullable(list).orElse(new ArrayList<>());
    }

    /**
     * 创建实体
     *
     * @param pool
     * @param date
     * @param extraSalaryTypeEnum
     * @return
     */
    private SalaryPoolDetail createDetail(SalaryPool pool, LocalDate date, ExtraSalaryTypeEnum extraSalaryTypeEnum) {
        SalaryPoolDetail poolDetail = new SalaryPoolDetail();
        SalaryTypeEnum salaryTypeEnum = extraSalaryTypeTransform(extraSalaryTypeEnum);
        poolDetail.setSalaryPoolId(pool.getId());
        poolDetail.setType(salaryTypeEnum);
        poolDetail.setSalaryAmount(BigDecimal.ZERO);
        poolDetail.setProcessedAmount(BigDecimal.ZERO);
        poolDetail.setActualSalaryAmount(BigDecimal.ZERO);
        poolDetail.setSalaryDate(date);
        poolDetail.setGroupId(pool.getGroupId());
        poolDetail.setYn(Boolean.TRUE);
        return poolDetail;
    }

    /**
     * 枚举类型转换
     *
     * @param extraSalaryTypeEnum
     * @return
     */
    private SalaryTypeEnum extraSalaryTypeTransform(ExtraSalaryTypeEnum extraSalaryTypeEnum) {
        SalaryTypeEnum salaryTypeEnum = SalaryTypeEnum.AWARD;
        switch (extraSalaryTypeEnum) {
            case PENALTY:
                salaryTypeEnum = SalaryTypeEnum.PENALTY;
                break;
            case NECESSARY:
                salaryTypeEnum = SalaryTypeEnum.NECESSARY;
                break;
            case SUBSIDY:
                salaryTypeEnum = SalaryTypeEnum.SUBSIDY;
                break;
            case PERSON_TAX:
                salaryTypeEnum = SalaryTypeEnum.PERSON_TAX;
                break;
            default:
                break;
        }
        return salaryTypeEnum;
    }
}