package com.ruoyi.staff.service.impl;
|
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
import com.ruoyi.common.utils.StringUtils;
|
import com.ruoyi.framework.web.domain.AjaxResult;
|
import com.ruoyi.production.bean.dto.UserAccountDto;
|
import com.ruoyi.production.bean.dto.UserProductionAccountingDto;
|
import com.ruoyi.production.service.SalesLedgerProductionAccountingService;
|
import com.ruoyi.project.system.domain.SysDept;
|
import com.ruoyi.project.system.domain.SysUser;
|
import com.ruoyi.project.system.mapper.SysDeptMapper;
|
import com.ruoyi.project.system.mapper.SysUserMapper;
|
import com.ruoyi.staff.controller.TaxCalculator;
|
import com.ruoyi.staff.mapper.*;
|
import com.ruoyi.staff.pojo.*;
|
import com.ruoyi.staff.service.SchemeApplicableStaffService;
|
import lombok.RequiredArgsConstructor;
|
import org.springframework.stereotype.Service;
|
import org.springframework.util.CollectionUtils;
|
|
import java.math.BigDecimal;
|
import java.math.RoundingMode;
|
import java.time.YearMonth;
|
import java.time.format.DateTimeFormatter;
|
import java.time.format.DateTimeParseException;
|
import java.util.Arrays;
|
import java.util.Collections;
|
import java.util.List;
|
import java.util.Map;
|
import java.util.Objects;
|
import java.util.stream.Collectors;
|
|
/**
|
* <p>
|
* 社保方案适用人员表 服务实现类
|
* </p>
|
*
|
* @author 芯导软件(江苏)有限公司
|
* @since 2026-03-05 11:50:17
|
*/
|
@Service
|
@RequiredArgsConstructor
|
public class SchemeApplicableStaffServiceImpl extends ServiceImpl<SchemeApplicableStaffMapper, SchemeApplicableStaff> implements SchemeApplicableStaffService {
|
|
private final SchemeApplicableStaffMapper schemeApplicableStaffMapper;
|
private final SchemeInsuranceDetailMapper schemeInsuranceDetailMapper;
|
private final SysUserMapper sysUserMapper;
|
private final SysDeptMapper sysDeptMapper;
|
private final StaffOnJobMapper staffOnJobMapper;
|
private final PersonalShiftMapper personalShiftMapper;
|
private final PersonalAttendanceLocationConfigMapper personalAttendanceLocationConfigMapper;
|
private final SalesLedgerProductionAccountingService salesLedgerProductionAccountingService;
|
private final SubsidyConfigurationMapper subsidyConfigurationMapper;
|
private final StaffSalaryMainMapper staffSalaryMainMapper;
|
private final StaffSalaryDetailMapper staffSalaryDetailMapper;
|
|
|
@Override
|
public AjaxResult listPage(Page page, SchemeApplicableStaff schemeApplicableStaff) {
|
LambdaQueryWrapper<SchemeApplicableStaff> schemeApplicableStaffLambdaQueryWrapper = new LambdaQueryWrapper<>();
|
if(schemeApplicableStaff != null){
|
if(StringUtils.isNotEmpty(schemeApplicableStaff.getTitle())){
|
schemeApplicableStaffLambdaQueryWrapper.like(SchemeApplicableStaff::getTitle, schemeApplicableStaff.getTitle());
|
}
|
}
|
schemeApplicableStaffLambdaQueryWrapper.orderByDesc(SchemeApplicableStaff::getId);
|
Page<SchemeApplicableStaff> page1 = schemeApplicableStaffMapper.selectPage(page, schemeApplicableStaffLambdaQueryWrapper);
|
List<Long> collect = page1.getRecords().stream().map(SchemeApplicableStaff::getId).collect(Collectors.toList());
|
if(CollectionUtils.isEmpty(collect)){
|
return AjaxResult.success(page1);
|
}
|
List<SchemeInsuranceDetail> schemeInsuranceDetails = schemeInsuranceDetailMapper
|
.selectList(new LambdaQueryWrapper<SchemeInsuranceDetail>()
|
.in(SchemeInsuranceDetail::getSchemeId, collect));
|
page1.getRecords().forEach(item -> {
|
item.setSchemeInsuranceDetailList(schemeInsuranceDetails
|
.stream()
|
.filter(detail -> detail.getSchemeId().equals(item.getId()))
|
.collect(Collectors.toList()));
|
SysUser sysUser = sysUserMapper.selectUserById(item.getCreateUser().longValue());
|
item.setCreateUserName(sysUser == null ? "未知" : sysUser.getNickName());
|
// 获取部门信息
|
String[] split = item.getDeptIds().split(",");
|
List<SysDept> sysDepts = sysDeptMapper.selectList(new LambdaQueryWrapper<SysDept>()
|
.in(SysDept::getDeptId, Arrays.stream(split).map(Long::valueOf).collect(Collectors.toList())));
|
if(!CollectionUtils.isEmpty(sysDepts)){
|
item.setDeptNames(sysDepts.stream().map(SysDept::getDeptName).collect(Collectors.joining(",")));
|
}
|
});
|
return AjaxResult.success(page1);
|
}
|
|
public void setSchemeApplicableStaffUserInfo(SchemeApplicableStaff schemeApplicableStaff) {
|
// 通过部门获取人员id
|
String[] split = schemeApplicableStaff.getDeptIds().split(",");
|
List<StaffOnJob> staffOnJobs = staffOnJobMapper.selectList(new LambdaQueryWrapper<StaffOnJob>()
|
.in(StaffOnJob::getSysDeptId, Arrays.stream(split).map(Long::valueOf).collect(Collectors.toList())));
|
if(CollectionUtils.isEmpty(staffOnJobs)){
|
throw new IllegalArgumentException("部门下无员工");
|
}
|
schemeApplicableStaff.setStaffIds(staffOnJobs
|
.stream()
|
.map(StaffOnJob::getId)
|
.filter(Objects::nonNull) // 过滤掉 null 值
|
.map(String::valueOf)
|
.collect(Collectors.joining( ",")));
|
schemeApplicableStaff.setStaffNames(staffOnJobs.stream().map(StaffOnJob::getStaffName).collect(Collectors.joining(",")));
|
}
|
|
@Override
|
public AjaxResult add(SchemeApplicableStaff schemeApplicableStaff) {
|
if(schemeApplicableStaff == null){
|
return AjaxResult.error("参数错误");
|
}
|
if(CollectionUtils.isEmpty(schemeApplicableStaff.getSchemeInsuranceDetailList())){
|
return AjaxResult.error("请选择方案明细");
|
}
|
setSchemeApplicableStaffUserInfo(schemeApplicableStaff); //根据部门设置用户信息
|
int insert = schemeApplicableStaffMapper.insert(schemeApplicableStaff);
|
schemeApplicableStaff.getSchemeInsuranceDetailList().forEach(item -> {
|
item.setSchemeId(schemeApplicableStaff.getId());
|
schemeInsuranceDetailMapper.insert(item);
|
});
|
return AjaxResult.success(insert);
|
}
|
|
@Override
|
public AjaxResult updateSchemeApplicableStaff(SchemeApplicableStaff schemeApplicableStaff) {
|
if(schemeApplicableStaff == null){
|
return AjaxResult.error("参数错误");
|
}
|
setSchemeApplicableStaffUserInfo(schemeApplicableStaff); //根据部门设置用户信息
|
int update = schemeApplicableStaffMapper.updateById(schemeApplicableStaff);
|
// 先删,重新绑定
|
schemeInsuranceDetailMapper.delete(new LambdaQueryWrapper<SchemeInsuranceDetail>()
|
.eq(SchemeInsuranceDetail::getSchemeId, schemeApplicableStaff.getId()));
|
schemeApplicableStaff.getSchemeInsuranceDetailList().forEach(item -> {
|
item.setSchemeId(schemeApplicableStaff.getId());
|
schemeInsuranceDetailMapper.insert(item);
|
});
|
return AjaxResult.success(update);
|
}
|
|
@Override
|
public AjaxResult delete(List<Long> ids) {
|
if (CollectionUtils.isEmpty(ids)) {
|
return AjaxResult.error("参数错误");
|
}
|
int delete = schemeApplicableStaffMapper.deleteBatchIds(ids);
|
schemeInsuranceDetailMapper.delete(new LambdaQueryWrapper<SchemeInsuranceDetail>()
|
.in(SchemeInsuranceDetail::getSchemeId, ids));
|
return AjaxResult.success(delete);
|
}
|
|
/**
|
* 通过员工id计算社保方案
|
* @param id
|
*/
|
public void calculateByEmployeeId(Integer id,Map<String, Object> map,String date) {
|
// 1. 入参校验
|
if (id == null) {
|
return; // 或返回空列表,根据业务需求调整
|
}
|
Long staffId = id.longValue();
|
// 社保金额
|
BigDecimal socialPersonal = new BigDecimal("0.00");
|
// 公积金金额
|
BigDecimal fundPersonal = new BigDecimal("0.00");
|
// 基本工资
|
BigDecimal basicSalary = new BigDecimal("0.00");
|
map.put("fundPersonal", fundPersonal); // 公积金
|
map.put("socialPersonal", socialPersonal); // 社保金额
|
map.put("socialSupplementAmount", BigDecimal.ZERO); // 社保补缴金额
|
map.put("basicSalary", basicSalary); // 基本工资
|
// 个税金额
|
BigDecimal salaryTax = new BigDecimal("0.00");
|
map.put("salaryTax", salaryTax);
|
// 计件工资
|
BigDecimal pieceSalary = new BigDecimal("0.00");
|
map.put("pieceSalary", pieceSalary);
|
// 计时工资
|
BigDecimal hourlySalary = new BigDecimal("0.00");
|
map.put("hourlySalary", hourlySalary);
|
// 其他收入
|
BigDecimal otherIncome = new BigDecimal("0.00");
|
map.put("otherIncome", otherIncome);
|
// 其他支出
|
BigDecimal otherDeduct = new BigDecimal("0.00");
|
map.put("otherDeduct", otherDeduct);
|
// 应发工资
|
BigDecimal grossSalary = new BigDecimal("0.00");
|
map.put("grossSalary", grossSalary);
|
// 应扣工资
|
BigDecimal deductSalary = new BigDecimal("0.00");
|
map.put("deductSalary", deductSalary);
|
// 实发工资
|
BigDecimal netSalary = new BigDecimal("0.00");
|
map.put("netSalary", netSalary);
|
// 根据排班数据计算白班天数和夜班天数
|
BigDecimal dayDays = new BigDecimal("0.00");
|
BigDecimal nightDays = new BigDecimal("0.00");
|
|
// 查询当月排班记录
|
List<PersonalShift> shiftList = personalShiftMapper.selectList(new LambdaQueryWrapper<PersonalShift>()
|
.eq(PersonalShift::getStaffOnJobId, staffId)
|
.like(PersonalShift::getWorkTime, date));
|
|
if(!CollectionUtils.isEmpty(shiftList)){
|
// 收集所有班次配置ID
|
List<Integer> configIds = shiftList.stream()
|
.map(PersonalShift::getPersonalAttendanceLocationConfigId)
|
.filter(Objects::nonNull)
|
.collect(Collectors.toList());
|
|
if(!CollectionUtils.isEmpty(configIds)){
|
// 查询班次配置信息
|
List<PersonalAttendanceLocationConfig> configList = personalAttendanceLocationConfigMapper.selectList(
|
new LambdaQueryWrapper<PersonalAttendanceLocationConfig>()
|
.in(PersonalAttendanceLocationConfig::getId, configIds));
|
|
// 构建班次配置映射
|
Map<Integer, String> configMap = configList.stream()
|
.collect(Collectors.toMap(
|
PersonalAttendanceLocationConfig::getId,
|
PersonalAttendanceLocationConfig::getShift,
|
(a, b) -> a));
|
|
// 统计白班和夜班天数
|
for (PersonalShift shift : shiftList) {
|
Integer configId = shift.getPersonalAttendanceLocationConfigId();
|
String shiftName = configMap.get(configId);
|
if(shiftName != null){
|
// 根据班次名称判断:包含"白"或"日"为白班,包含"夜"为夜班
|
if(shiftName.contains("白") || shiftName.contains("日")){
|
dayDays = dayDays.add(BigDecimal.ONE);
|
} else if(shiftName.contains("夜")){
|
nightDays = nightDays.add(BigDecimal.ONE);
|
}
|
}
|
}
|
}
|
}
|
map.put("dayDays", dayDays); // 白班天数
|
map.put("nightDays", nightDays); // 夜班天数
|
|
// 查询餐补和夜班补贴
|
// 计算餐补(回族特有)和夜班补助
|
BigDecimal mealAmount = new BigDecimal("0.00"); // 餐补
|
BigDecimal nightAmount = new BigDecimal("0.00"); // 夜班补助
|
|
// 获取餐补和夜班补贴标准(从补贴配置中获取)
|
SubsidyConfiguration subsidyConfig = subsidyConfigurationMapper.selectOne(null);
|
BigDecimal mealStandard = new BigDecimal("0.00"); // 餐补标准
|
BigDecimal nightStandard = new BigDecimal("0.00"); // 夜班补贴标准
|
if(subsidyConfig != null){
|
mealStandard = subsidyConfig.getMealAmount() != null ? subsidyConfig.getMealAmount() : new BigDecimal("0.00");
|
nightStandard = subsidyConfig.getNightAmount() != null ? subsidyConfig.getNightAmount() : new BigDecimal("0.00");
|
}
|
|
// 餐补:民族为回族特有,计算方式为(白班天数+夜班天数)*餐补标准
|
StaffOnJob staffOnJobDto = staffOnJobMapper.selectById(staffId);
|
if(staffOnJobDto == null){
|
return;
|
}
|
|
String nation = staffOnJobDto.getNation();
|
if("回族".equals(nation)){
|
mealAmount = dayDays.add(nightDays).multiply(mealStandard);
|
}
|
|
// 夜班补助:夜班天数*夜班补贴标准
|
nightAmount = nightDays.multiply(nightStandard);
|
|
map.put("mealAmount", mealAmount); // 餐补
|
map.put("nightAmount", nightAmount); // 夜班补助
|
|
// 调用基本工资
|
basicSalary = staffOnJobDto.getBasicSalary();
|
map.put("basicSalary", basicSalary);
|
// 应发工资(基本工资+餐补+夜班补助+其他收入)
|
grossSalary = basicSalary.add(mealAmount).add(nightAmount).add(otherIncome);
|
map.put("grossSalary", grossSalary);
|
// 实发工资初始值
|
netSalary = grossSalary;
|
map.put("netSalary", netSalary);
|
// 个税金额(无社保版)
|
BigDecimal bigDecimal = TaxCalculator.calculateMonthlyTax(basicSalary, socialPersonal, fundPersonal);
|
map.put("salaryTax", bigDecimal);
|
// 计时工资 计件工资
|
UserProductionAccountingDto userProductionAccountingDto = new UserProductionAccountingDto();
|
userProductionAccountingDto.setUserId(getUidByStaffId(staffId));
|
userProductionAccountingDto.setDate(date);
|
UserAccountDto byUserId = salesLedgerProductionAccountingService.getByUserId(userProductionAccountingDto);
|
if(byUserId != null){
|
map.put("pieceSalary", byUserId.getAccountBalance());
|
map.put("hourlySalary", byUserId.getAccount());
|
// 应发 实发增加
|
grossSalary = grossSalary.add(byUserId.getAccountBalance()).add(byUserId.getAccount());
|
map.put("grossSalary", grossSalary);
|
netSalary = netSalary.add(byUserId.getAccountBalance()).add(byUserId.getAccount());
|
map.put("netSalary", netSalary);
|
}
|
// 2. 查询该人员对应的社保方案
|
List<SchemeApplicableStaff> schemeList = schemeApplicableStaffMapper.selectSchemeByStaffId(staffId);
|
if (CollectionUtils.isEmpty(schemeList)) {
|
return; // 无匹配方案,返回空列表
|
}
|
YearMonth targetMonth = parseTargetMonth(date);
|
SchemeApplicableStaff currentScheme = resolveCurrentScheme(schemeList, targetMonth);
|
if (currentScheme == null) {
|
return;
|
}
|
List<SchemeInsuranceDetail> currentDetailList = defaultIfNull(
|
schemeApplicableStaffMapper.selectDetailBySchemeId(currentScheme.getId())
|
);
|
for (SchemeInsuranceDetail detail : currentDetailList) {
|
BigDecimal amount = calculateInsuranceAmount(staffOnJobDto, detail);
|
if ("公积金".equals(detail.getInsuranceType())) {
|
fundPersonal = fundPersonal.add(amount);
|
} else {
|
socialPersonal = socialPersonal.add(amount);
|
}
|
}
|
BigDecimal socialSupplementAmount = calculateSocialSupplementAmount(
|
staffId,
|
staffOnJobDto,
|
targetMonth,
|
currentScheme,
|
currentDetailList,
|
socialPersonal
|
);
|
if (socialSupplementAmount.compareTo(BigDecimal.ZERO) > 0) {
|
socialPersonal = socialPersonal.add(socialSupplementAmount);
|
}
|
map.put("socialPersonal", socialPersonal);
|
map.put("fundPersonal", fundPersonal);
|
map.put("socialSupplementAmount", socialSupplementAmount);
|
// 个税金额(社保版)
|
bigDecimal = TaxCalculator.calculateMonthlyTax(basicSalary, socialPersonal, fundPersonal);
|
map.put("salaryTax", bigDecimal);
|
|
// 应扣工资 = 个税 + 公积金个人 + 社保个人 + 其他支出
|
deductSalary = bigDecimal.add(fundPersonal).add(socialPersonal).add(otherDeduct);
|
map.put("deductSalary", deductSalary);
|
|
// 实发工资 = 应发工资 - 应扣工资
|
netSalary = grossSalary.subtract(deductSalary);
|
map.put("netSalary", netSalary);
|
|
}
|
|
/**
|
* 通过员工Id获取用户id
|
* @param staffId
|
* @return
|
*/
|
public Long getUidByStaffId(Long staffId){
|
StaffOnJob staffOnJob = staffOnJobMapper.selectById(staffId);
|
if(staffOnJob == null){
|
return -1L; // 返回不存在Id
|
}
|
SysUser sysUser = sysUserMapper.selectOne(new LambdaQueryWrapper<SysUser>()
|
.eq(SysUser::getUserName, staffOnJob.getStaffNo())
|
.eq(SysUser::getDelFlag, "0")
|
.last("limit 1"));
|
if(sysUser == null){
|
return -1L; // 返回不存在Id
|
}
|
return sysUser.getUserId();
|
}
|
|
/**
|
* 计算单项保险金额
|
*/
|
public BigDecimal calculateInsuranceAmount(StaffOnJob staffOnJobDto, SchemeInsuranceDetail detail) {
|
if (staffOnJobDto == null || detail == null) {
|
return BigDecimal.ZERO;
|
}
|
BigDecimal ratio = detail.getPersonalRatio() == null ? BigDecimal.ZERO : detail.getPersonalRatio();
|
BigDecimal fixed = detail.getPersonalFixed() == null ? BigDecimal.ZERO : detail.getPersonalFixed();
|
BigDecimal baseAmount;
|
if (detail.getUseBasicSalary() == 1) {
|
baseAmount = detail.getPaymentBase() == null ? BigDecimal.ZERO : detail.getPaymentBase();
|
} else {
|
baseAmount = staffOnJobDto.getBasicSalary() == null ? BigDecimal.ZERO : staffOnJobDto.getBasicSalary();
|
}
|
BigDecimal ratioAmount = baseAmount.multiply(ratio).divide(new BigDecimal("100"), 2, RoundingMode.HALF_UP);
|
return ratioAmount.add(fixed);
|
}
|
|
private SchemeApplicableStaff resolveCurrentScheme(List<SchemeApplicableStaff> schemeList, YearMonth targetMonth) {
|
if (CollectionUtils.isEmpty(schemeList)) {
|
return null;
|
}
|
if (targetMonth == null) {
|
return schemeList.get(0);
|
}
|
for (SchemeApplicableStaff scheme : schemeList) {
|
if (scheme.getCreateTime() == null) {
|
continue;
|
}
|
YearMonth schemeMonth = YearMonth.from(scheme.getCreateTime());
|
if (!schemeMonth.isAfter(targetMonth)) {
|
return scheme;
|
}
|
}
|
return schemeList.get(schemeList.size() - 1);
|
}
|
|
/**
|
* 计算社保补缴金额
|
*
|
* 业务逻辑:
|
* 1. 只有在社保方案设置新增的当月才计算补缴金额,其余月份返回0
|
* 2. 根据最新社保比例计算当月及以后应缴纳的金额标准
|
* 3. 统计当年1月到当前月已缴纳的社保总额
|
* 4. 用最新标准计算的期望总额与实际已缴纳金额的差额即为补缴金额
|
*
|
* @param staffId 员工ID
|
* @param staffOnJobDto 员工在职信息(用于计算社保金额)
|
* @param targetMonth 目标计算月份
|
* @param currentScheme 当前社保方案
|
* @param currentDetailList 当前社保方案明细列表
|
* @param currentMonthSocialPersonal 当前月个人社保金额
|
* @return 社保补缴金额(负数或0返回0)
|
*/
|
private BigDecimal calculateSocialSupplementAmount(Long staffId,
|
StaffOnJob staffOnJobDto,
|
YearMonth targetMonth,
|
SchemeApplicableStaff currentScheme,
|
List<SchemeInsuranceDetail> currentDetailList,
|
BigDecimal currentMonthSocialPersonal) {
|
// 1. 参数校验:任一必填参数为空,返回0
|
if (staffId == null || staffOnJobDto == null || targetMonth == null || currentScheme == null || currentScheme.getCreateTime() == null) {
|
return BigDecimal.ZERO;
|
}
|
|
// 2. 判断是否为社保方案新增当月
|
// 只有新增社保设置的当月才计算补缴,其余月份返回0
|
YearMonth schemeMonth = YearMonth.from(currentScheme.getCreateTime());
|
if (!schemeMonth.equals(targetMonth)) {
|
return BigDecimal.ZERO;
|
}
|
|
// 3. 计算最新月度社保个人金额(排除公积金)
|
BigDecimal latestMonthlySocial = defaultIfNull(currentDetailList).stream()
|
.filter(Objects::nonNull)
|
.filter(detail -> !"公积金".equals(detail.getInsuranceType())) // 排除公积金
|
.map(detail -> calculateInsuranceAmount(staffOnJobDto, detail)) // 计算每项社保金额
|
.reduce(BigDecimal.ZERO, BigDecimal::add); // 累加求和
|
|
// 如果最新月度社保金额为0或负数,无需补缴
|
if (latestMonthlySocial.compareTo(BigDecimal.ZERO) <= 0) {
|
return BigDecimal.ZERO;
|
}
|
|
// 4. 统计当年1月到当前月之前已缴纳的社保总额
|
BigDecimal paidYtdSocial = sumPaidSocialPersonalBeforeMonth(staffId, targetMonth);
|
|
// 5. 计算按最新标准应缴纳的年度总额
|
// 期望总额 = 最新月度社保 × 当前月份(1-12)
|
BigDecimal expectedYtdSocial = latestMonthlySocial.multiply(BigDecimal.valueOf(targetMonth.getMonthValue()));
|
|
// 6. 计算补缴金额
|
// 补缴金额 = 期望总额 - 已缴纳总额 - 当前月已计算的社保
|
BigDecimal supplement = expectedYtdSocial.subtract(paidYtdSocial).subtract(defaultZero(currentMonthSocialPersonal));
|
|
// 7. 返回结果:负数或0返回0,正数保留两位小数
|
return supplement.compareTo(BigDecimal.ZERO) > 0 ? supplement.setScale(2, RoundingMode.HALF_UP) : BigDecimal.ZERO;
|
}
|
|
/**
|
* 统计员工当年1月到目标月份之前已缴纳的社保个人部分总额
|
*
|
* 查询逻辑:
|
* 1. 根据目标月份获取当年年份前缀(如 "2024-")
|
* 2. 查询该年份下所有早于目标月份的薪资主表记录
|
* 3. 根据薪资主表ID查询对应的薪资明细表
|
* 4. 按员工ID筛选并累加社保个人部分金额
|
*
|
* @param staffId 员工ID
|
* @param targetMonth 目标月份(统计截止到该月份之前)
|
* @return 已缴纳的社保个人部分总额
|
*/
|
private BigDecimal sumPaidSocialPersonalBeforeMonth(Long staffId, YearMonth targetMonth) {
|
// 1. 参数校验
|
if (staffId == null || targetMonth == null) {
|
return BigDecimal.ZERO;
|
}
|
|
// 2. 构建查询条件
|
String yearPrefix = targetMonth.getYear() + "-"; // 年份前缀,如 "2024-"
|
String currentMonthStr = targetMonth.format(DateTimeFormatter.ofPattern("yyyy-MM")); // 目标月份字符串,如 "2024-03"
|
|
// 3. 查询当年1月到目标月份之前的薪资主表
|
List<StaffSalaryMain> salaryMainList = staffSalaryMainMapper.selectList(
|
new LambdaQueryWrapper<StaffSalaryMain>()
|
.likeRight(StaffSalaryMain::getSalaryMonth, yearPrefix) // 匹配当年所有月份
|
.lt(StaffSalaryMain::getSalaryMonth, currentMonthStr) // 小于目标月份
|
);
|
if (CollectionUtils.isEmpty(salaryMainList)) {
|
return BigDecimal.ZERO;
|
}
|
|
// 4. 提取薪资主表ID列表
|
List<Long> mainIds = salaryMainList.stream()
|
.map(StaffSalaryMain::getId)
|
.filter(Objects::nonNull)
|
.collect(Collectors.toList());
|
if (CollectionUtils.isEmpty(mainIds)) {
|
return BigDecimal.ZERO;
|
}
|
|
// 5. 查询对应的薪资明细表
|
List<StaffSalaryDetail> detailList = staffSalaryDetailMapper.selectList(
|
new LambdaQueryWrapper<StaffSalaryDetail>()
|
.in(StaffSalaryDetail::getMainId, mainIds) // 根据主表ID查询
|
.eq(StaffSalaryDetail::getStaffOnJobId, staffId) // 按员工ID筛选
|
);
|
if (CollectionUtils.isEmpty(detailList)) {
|
return BigDecimal.ZERO;
|
}
|
|
// 6. 累加社保个人部分金额
|
return detailList.stream()
|
.map(StaffSalaryDetail::getSocialPersonal) // 获取社保个人部分
|
.filter(Objects::nonNull)
|
.reduce(BigDecimal.ZERO, BigDecimal::add); // 累加求和
|
}
|
|
private YearMonth parseTargetMonth(String date) {
|
if (StringUtils.isEmpty(date)) {
|
return null;
|
}
|
String normalized = date.length() >= 7 ? date.substring(0, 7) : date;
|
try {
|
return YearMonth.parse(normalized, DateTimeFormatter.ofPattern("yyyy-MM"));
|
} catch (DateTimeParseException ex) {
|
return null;
|
}
|
}
|
|
private <T> List<T> defaultIfNull(List<T> list) {
|
return list == null ? Collections.emptyList() : list;
|
}
|
|
private BigDecimal defaultZero(BigDecimal value) {
|
return value == null ? BigDecimal.ZERO : value;
|
}
|
}
|