| | |
| | | import java.time.LocalDateTime; |
| | | import java.time.YearMonth; |
| | | import java.util.Collections; |
| | | import java.util.HashMap; |
| | | import java.util.List; |
| | | import java.util.Map; |
| | | import java.util.Objects; |
| | |
| | | private HrmEmployeeSocialSecurityMapper employeeSocialSecurityMapper; |
| | | @Resource |
| | | private HrmSocialSecuritySchemeMapper socialSecuritySchemeMapper; |
| | | @Resource |
| | | private HrmSocialSecuritySchemeService socialSecuritySchemeService; |
| | | @Resource |
| | | private HrmNoRedisDAO noRedisDAO; |
| | | @Resource |
| | |
| | | .toList(); |
| | | |
| | | // 2. 遍历员工进行薪酬核算 |
| | | // 部门 -> 方案 的解析结果在本次核算内缓存,避免逐员工重复查库 |
| | | Map<Long, HrmSocialSecuritySchemeDO> deptSchemeCache = new HashMap<>(); |
| | | for (HrmEmployeeDO employee : employees) { |
| | | // employeeId 是员工ID,用于关联薪酬档案、社保档案、核算记录 |
| | | Long employeeId = employee.getId(); |
| | |
| | | |
| | | // 2.3 获取员工社保公积金档案(按员工ID查询,取最新生效的) |
| | | HrmEmployeeSocialSecurityDO socialSecurity = employeeSocialSecurityMapper.selectLatestByUserId(employeeId); |
| | | // 2.4 如果有社保档案,获取绑定的方案 |
| | | HrmSocialSecuritySchemeDO scheme = null; |
| | | if (socialSecurity != null && socialSecurity.getSocialSecuritySchemeId() != null) { |
| | | scheme = socialSecuritySchemeMapper.selectById(socialSecurity.getSocialSecuritySchemeId()); |
| | | } |
| | | // 2.4 获取方案:员工档案指定 > 所在部门绑定 > 全局默认 |
| | | HrmSocialSecuritySchemeDO scheme = resolveScheme(socialSecurity, employee, effectiveDate, deptSchemeCache); |
| | | |
| | | // 2.5 构建核算记录(包含扣除计算,通过方案获取比例) |
| | | HrmSalaryCalculationDO calculation = buildSalaryCalculation(period, employeeId, employee, employeeSalary, socialSecurity, scheme, effectiveDate); |
| | |
| | | BigDecimal totalIncome = baseSalary.add(performanceSalary).add(mealAllowance) |
| | | .add(transportAllowance).add(otherAllowance).add(overtimePay); |
| | | |
| | | // 获取社保基数:员工社保档案 > 员工基本工资 |
| | | // 获取社保基数:员工社保档案 > 方案默认缴费基数 > 员工基本工资 |
| | | BigDecimal socialSecurityBase = (socialSecurity != null && socialSecurity.getSocialSecurityBase() != null) |
| | | ? socialSecurity.getSocialSecurityBase() : baseSalary; |
| | | ? socialSecurity.getSocialSecurityBase() |
| | | : (scheme != null && scheme.getDefaultSocialSecurityBase() != null |
| | | ? scheme.getDefaultSocialSecurityBase() : baseSalary); |
| | | |
| | | // 获取公积金基数:员工社保档案 > 员工基本工资 |
| | | BigDecimal housingFundBase = (socialSecurity != null && socialSecurity.getHousingFundBase() != null) |
| | | ? socialSecurity.getHousingFundBase() : baseSalary; |
| | | // 获取公积金基数:员工社保档案 > 方案默认公积金基数(大于 0 时)> 社保基数 |
| | | BigDecimal housingFundBase; |
| | | if (socialSecurity != null && socialSecurity.getHousingFundBase() != null) { |
| | | housingFundBase = socialSecurity.getHousingFundBase(); |
| | | } else if (scheme != null && scheme.getDefaultHousingFundBase() != null |
| | | && scheme.getDefaultHousingFundBase().compareTo(BigDecimal.ZERO) > 0) { |
| | | housingFundBase = scheme.getDefaultHousingFundBase(); |
| | | } else { |
| | | housingFundBase = socialSecurityBase; |
| | | } |
| | | |
| | | // 从方案中获取缴纳比例(优先使用方案中的比例,否则使用默认比例) |
| | | BigDecimal pensionPersonalRatio = (scheme != null && scheme.getPensionPersonalRatio() != null) |
| | |
| | | .totalWorkHours(totalWorkHours) |
| | | .status(0) // 待确认 |
| | | .build(); |
| | | } |
| | | |
| | | /** |
| | | * 解析员工核算用的社保公积金方案 |
| | | * |
| | | * 优先级:员工社保档案指定的方案(个别覆盖)> 员工所在部门绑定的方案 > 全局默认方案。 |
| | | * 都取不到时返回 null,由 {@link #buildSalaryCalculation} 使用默认比例常量。 |
| | | * |
| | | * @param deptSchemeCache 本次核算内「部门 -> 方案」的缓存(允许 null 值,用于缓存"该部门无方案") |
| | | */ |
| | | private HrmSocialSecuritySchemeDO resolveScheme(HrmEmployeeSocialSecurityDO socialSecurity, HrmEmployeeDO employee, |
| | | LocalDate periodDate, |
| | | Map<Long, HrmSocialSecuritySchemeDO> deptSchemeCache) { |
| | | if (socialSecurity != null && socialSecurity.getSocialSecuritySchemeId() != null) { |
| | | HrmSocialSecuritySchemeDO scheme = socialSecuritySchemeMapper.selectById(socialSecurity.getSocialSecuritySchemeId()); |
| | | if (scheme != null) { |
| | | return scheme; |
| | | } |
| | | } |
| | | Long deptId = employee.getDeptId(); |
| | | if (!deptSchemeCache.containsKey(deptId)) { |
| | | deptSchemeCache.put(deptId, socialSecuritySchemeService.resolveSchemeByDeptId(deptId, periodDate)); |
| | | } |
| | | return deptSchemeCache.get(deptId); |
| | | } |
| | | |
| | | /** |
| | |
| | | |
| | | // 2. 遍历员工实时计算薪酬 |
| | | List<HrmSalaryCalculationDO> resultList = new java.util.ArrayList<>(); |
| | | // 部门 -> 方案 的解析结果在本次预览内缓存,避免逐员工重复查库 |
| | | Map<Long, HrmSocialSecuritySchemeDO> deptSchemeCache = new HashMap<>(); |
| | | for (HrmEmployeeDO employee : employees) { |
| | | Long employeeId = employee.getId(); |
| | | |
| | |
| | | |
| | | // 2.2 获取员工社保公积金档案(按员工ID查询,取最新生效的) |
| | | HrmEmployeeSocialSecurityDO socialSecurity = employeeSocialSecurityMapper.selectLatestByUserId(employeeId); |
| | | // 2.3 如果有社保档案,获取绑定的方案 |
| | | HrmSocialSecuritySchemeDO scheme = null; |
| | | if (socialSecurity != null && socialSecurity.getSocialSecuritySchemeId() != null) { |
| | | scheme = socialSecuritySchemeMapper.selectById(socialSecurity.getSocialSecuritySchemeId()); |
| | | } |
| | | // 2.3 获取方案:员工档案指定 > 所在部门绑定 > 全局默认 |
| | | HrmSocialSecuritySchemeDO scheme = resolveScheme(socialSecurity, employee, effectiveDate, deptSchemeCache); |
| | | |
| | | // 2.4 构建核算记录(实时计算,不存储) |
| | | HrmSalaryCalculationDO calculation = buildSalaryCalculation(period, employeeId, employee, employeeSalary, socialSecurity, scheme, effectiveDate); |