薪资接口的新要求
This commit is contained in:
@@ -117,10 +117,18 @@ public class OaEmployeeTemplateBindingController extends BaseController {
|
|||||||
if (bo.getPayYear() == null || bo.getPayMonth() == null) {
|
if (bo.getPayYear() == null || bo.getPayMonth() == null) {
|
||||||
return R.fail("请选择发薪年月");
|
return R.fail("请选择发薪年月");
|
||||||
}
|
}
|
||||||
if (bo.getDefaultInsuranceTemplateId() == null || bo.getDefaultSalaryTemplateId() == null) {
|
if (bo.getDefaultPersonalInsuranceTemplateId() == null || bo.getDefaultSalaryTemplateId() == null || bo.getDefaultCompanyInsuranceTemplateId() == null) {
|
||||||
return R.fail("请选择默认模板");
|
return R.fail("请选择默认模板");
|
||||||
}
|
}
|
||||||
return toAjax(iOaEmployeeTemplateBindingService.calculateSalary(bo.getEmployeeIds(), bo.getPayYear(), bo.getPayMonth(), bo.getDefaultInsuranceTemplateId(), bo.getDefaultSalaryTemplateId()));
|
|
||||||
|
return toAjax(iOaEmployeeTemplateBindingService.calculateSalary(
|
||||||
|
bo.getEmployeeIds(),
|
||||||
|
bo.getPayYear(),
|
||||||
|
bo.getPayMonth(),
|
||||||
|
bo.getDefaultPersonalInsuranceTemplateId(), // 个人
|
||||||
|
bo.getDefaultCompanyInsuranceTemplateId(), // 企业
|
||||||
|
bo.getDefaultSalaryTemplateId()
|
||||||
|
));
|
||||||
}
|
}
|
||||||
// 7. 批量确认发放
|
// 7. 批量确认发放
|
||||||
@PostMapping("/finalize")
|
@PostMapping("/finalize")
|
||||||
|
|||||||
@@ -1,14 +1,13 @@
|
|||||||
package com.ruoyi.oa.domain;
|
package com.ruoyi.oa.domain;
|
||||||
|
|
||||||
import com.baomidou.mybatisplus.annotation.*;
|
import com.baomidou.mybatisplus.annotation.TableId;
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableLogic;
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableName;
|
||||||
|
import com.ruoyi.common.core.domain.BaseEntity;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
import lombok.EqualsAndHashCode;
|
import lombok.EqualsAndHashCode;
|
||||||
import java.io.Serializable;
|
|
||||||
import java.util.Date;
|
|
||||||
import java.math.BigDecimal;
|
|
||||||
|
|
||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
import com.ruoyi.common.core.domain.BaseEntity;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 员工模板绑定及月度发放记录对象 oa_employee_template_binding
|
* 员工模板绑定及月度发放记录对象 oa_employee_template_binding
|
||||||
@@ -32,10 +31,12 @@ public class OaEmployeeTemplateBinding extends BaseEntity {
|
|||||||
* 员工ID → oa_employee.employee_id
|
* 员工ID → oa_employee.employee_id
|
||||||
*/
|
*/
|
||||||
private Long employeeId;
|
private Long employeeId;
|
||||||
/**
|
// /**
|
||||||
* 保险模板ID → oa_insurance_template.insurance_template_id
|
// * 保险模板ID → oa_insurance_template.insurance_template_id
|
||||||
*/
|
// */
|
||||||
private Long insuranceTemplateId;
|
// private Long insuranceTemplateId;
|
||||||
|
private Long personalInsuranceTemplateId;
|
||||||
|
private Long companyInsuranceTemplateId;
|
||||||
/**
|
/**
|
||||||
* 薪资模板ID → oa_salary_template.salary_template_id
|
* 薪资模板ID → oa_salary_template.salary_template_id
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -31,6 +31,10 @@ public class OaInsuranceTemplate extends BaseEntity {
|
|||||||
* 模板名称
|
* 模板名称
|
||||||
*/
|
*/
|
||||||
private String templateName;
|
private String templateName;
|
||||||
|
/**
|
||||||
|
* 模板类型'0个税1企业'
|
||||||
|
*/
|
||||||
|
private int type;
|
||||||
/**
|
/**
|
||||||
* 删除标志 0=未删,1=已删
|
* 删除标志 0=未删,1=已删
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -89,6 +89,7 @@ public class SysOaFinance extends BaseEntity {
|
|||||||
/**
|
/**
|
||||||
* 一对一关联项目表
|
* 一对一关联项目表
|
||||||
*/
|
*/
|
||||||
|
@TableField(exist = false)
|
||||||
private SysOaProject project;
|
private SysOaProject project;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -35,11 +35,20 @@ public class OaEmployeeTemplateBindingBo extends BaseEntity {
|
|||||||
*/
|
*/
|
||||||
private Long employeeId;
|
private Long employeeId;
|
||||||
private List<Long> employeeIds;
|
private List<Long> employeeIds;
|
||||||
|
//
|
||||||
|
// /**
|
||||||
|
// * 保险模板ID → oa_insurance_template.insurance_template_id
|
||||||
|
// */
|
||||||
|
// private Long insuranceTemplateId;
|
||||||
/**
|
/**
|
||||||
* 保险模板ID → oa_insurance_template.insurance_template_id
|
* personal_insurance_template_id bigint not null comment '个人保险模板ID → oa_insurance_template.insurance_template_id',
|
||||||
*/
|
*/
|
||||||
private Long insuranceTemplateId;
|
private Long personalInsuranceTemplateId;
|
||||||
|
/*
|
||||||
|
* company_insurance_template_id bigint not null comment '企业保险模板ID → oa_insurance_temp
|
||||||
|
* */
|
||||||
|
private Long companyInsuranceTemplateId;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 薪资模板ID → oa_salary_template.salary_template_id
|
* 薪资模板ID → oa_salary_template.salary_template_id
|
||||||
@@ -75,7 +84,9 @@ public class OaEmployeeTemplateBindingBo extends BaseEntity {
|
|||||||
* 备注
|
* 备注
|
||||||
*/
|
*/
|
||||||
private String remark;
|
private String remark;
|
||||||
private Long defaultInsuranceTemplateId; // 新增:默认社保模板ID
|
// private Long defaultInsuranceTemplateId; // 新增:默认社保模板ID
|
||||||
|
private Long defaultPersonalInsuranceTemplateId;
|
||||||
|
private Long defaultCompanyInsuranceTemplateId;
|
||||||
private Long defaultSalaryTemplateId; // 新增:默认薪资模板ID
|
private Long defaultSalaryTemplateId; // 新增:默认薪资模板ID
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -35,6 +35,10 @@ public class OaInsuranceTemplateBo extends BaseEntity {
|
|||||||
* 备注
|
* 备注
|
||||||
*/
|
*/
|
||||||
private String remark;
|
private String remark;
|
||||||
|
/**
|
||||||
|
* 模板类型type'0个税1企业',
|
||||||
|
*/
|
||||||
|
private int type;
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -34,11 +34,15 @@ public class OaEmployeeTemplateBindingVo {
|
|||||||
@ExcelProperty(value = "员工ID → oa_employee.employee_id")
|
@ExcelProperty(value = "员工ID → oa_employee.employee_id")
|
||||||
private Long employeeId;
|
private Long employeeId;
|
||||||
|
|
||||||
/**
|
// /**
|
||||||
* 保险模板ID → oa_insurance_template.insurance_template_id
|
// * 保险模板ID → oa_insurance_template.insurance_template_id
|
||||||
*/
|
// */
|
||||||
@ExcelProperty(value = "保险模板ID → oa_insurance_template.insurance_template_id")
|
// @ExcelProperty(value = "保险模板ID → oa_insurance_template.insurance_template_id")
|
||||||
private Long insuranceTemplateId;
|
// private Long insuranceTemplateId;
|
||||||
|
@ExcelProperty(value = "个人保险模板ID")
|
||||||
|
private Long personalInsuranceTemplateId;
|
||||||
|
@ExcelProperty(value = "企业保险模板ID")
|
||||||
|
private Long companyInsuranceTemplateId;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 薪资模板ID → oa_salary_template.salary_template_id
|
* 薪资模板ID → oa_salary_template.salary_template_id
|
||||||
@@ -61,7 +65,7 @@ public class OaEmployeeTemplateBindingVo {
|
|||||||
/**
|
/**
|
||||||
* 实发工资
|
* 实发工资
|
||||||
*/
|
*/
|
||||||
@ExcelProperty(value = "实发工资")
|
@ExcelProperty(value = "预计发放工资")
|
||||||
private BigDecimal netSalary;
|
private BigDecimal netSalary;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -85,5 +89,9 @@ public class OaEmployeeTemplateBindingVo {
|
|||||||
|
|
||||||
@ExcelProperty(value = "实发工资")
|
@ExcelProperty(value = "实发工资")
|
||||||
private BigDecimal totalSalary;
|
private BigDecimal totalSalary;
|
||||||
|
private BigDecimal totalPersonalInsurance;
|
||||||
|
private BigDecimal totalCompanyInsurance;
|
||||||
|
private String company; // 所属公司
|
||||||
|
private String deptName; // 所属部门名称
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -38,6 +38,11 @@ public class OaInsuranceTemplateVo {
|
|||||||
*/
|
*/
|
||||||
@ExcelProperty(value = "备注")
|
@ExcelProperty(value = "备注")
|
||||||
private String remark;
|
private String remark;
|
||||||
|
/**
|
||||||
|
* 模板类型type'0个税1企业',
|
||||||
|
*/
|
||||||
|
@ExcelProperty(value = "模板类型'0个税1企业'")
|
||||||
|
private int type;
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package com.ruoyi.oa.domain.vo;
|
|||||||
|
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableField;
|
||||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||||
import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
|
import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
|
||||||
import com.alibaba.excel.annotation.ExcelProperty;
|
import com.alibaba.excel.annotation.ExcelProperty;
|
||||||
@@ -118,6 +119,7 @@ public class SysOaFinanceVo extends SysOaFinance {
|
|||||||
/**
|
/**
|
||||||
* 一对一关联项目表
|
* 一对一关联项目表
|
||||||
*/
|
*/
|
||||||
|
@TableField(exist = false)
|
||||||
private SysOaProject project;
|
private SysOaProject project;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -48,7 +48,7 @@ public interface IOaEmployeeTemplateBindingService {
|
|||||||
*/
|
*/
|
||||||
Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid);
|
Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid);
|
||||||
|
|
||||||
Boolean calculateSalary(List<Long> employeeIds, Long payYear, Long payMonth,Long defaultInsuranceTemplateId, Long defaultSalaryTemplateId);
|
Boolean calculateSalary(List<Long> employeeIds, Long payYear, Long payMonth, Long defaultPersonalInsuranceTemplateId, Long defaultCompanyInsuranceTemplateId, Long defaultSalaryTemplateId);
|
||||||
Boolean finalizeSalary(List<String> bindingIds);
|
Boolean finalizeSalary(List<String> bindingIds);
|
||||||
List<EmployeeSalaryRecordVo> querySalaryHistory(Long employeeId);
|
List<EmployeeSalaryRecordVo> querySalaryHistory(Long employeeId);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package com.ruoyi.oa.service.impl;
|
|||||||
|
|
||||||
import cn.hutool.core.bean.BeanUtil;
|
import cn.hutool.core.bean.BeanUtil;
|
||||||
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
|
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
|
||||||
|
import com.ruoyi.common.core.domain.entity.SysDept;
|
||||||
import com.ruoyi.common.utils.StringUtils;
|
import com.ruoyi.common.utils.StringUtils;
|
||||||
import com.ruoyi.common.core.page.TableDataInfo;
|
import com.ruoyi.common.core.page.TableDataInfo;
|
||||||
import com.ruoyi.common.core.domain.PageQuery;
|
import com.ruoyi.common.core.domain.PageQuery;
|
||||||
@@ -12,6 +13,7 @@ import com.ruoyi.oa.domain.*;
|
|||||||
import com.ruoyi.oa.domain.vo.EmployeeSalaryRecordVo;
|
import com.ruoyi.oa.domain.vo.EmployeeSalaryRecordVo;
|
||||||
import com.ruoyi.oa.domain.vo.OaBindingItemDetailVo;
|
import com.ruoyi.oa.domain.vo.OaBindingItemDetailVo;
|
||||||
import com.ruoyi.oa.mapper.*;
|
import com.ruoyi.oa.mapper.*;
|
||||||
|
import com.ruoyi.system.mapper.SysDeptMapper;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import org.springframework.beans.BeanUtils;
|
import org.springframework.beans.BeanUtils;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
@@ -21,10 +23,7 @@ import com.ruoyi.oa.domain.vo.OaEmployeeTemplateBindingVo;
|
|||||||
import com.ruoyi.oa.service.IOaEmployeeTemplateBindingService;
|
import com.ruoyi.oa.service.IOaEmployeeTemplateBindingService;
|
||||||
|
|
||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
import java.util.Collections;
|
import java.util.*;
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -45,7 +44,11 @@ public class OaEmployeeTemplateBindingServiceImpl implements IOaEmployeeTemplate
|
|||||||
@Autowired
|
@Autowired
|
||||||
private final OaSalaryTemplateDetailMapper salaryDetailMapper;
|
private final OaSalaryTemplateDetailMapper salaryDetailMapper;
|
||||||
@Autowired
|
@Autowired
|
||||||
|
private final OaInsuranceTemplateMapper insuranceTemplateMapper;
|
||||||
|
@Autowired
|
||||||
private final OaInsuranceTemplateDetailMapper insuranceDetailMapper;
|
private final OaInsuranceTemplateDetailMapper insuranceDetailMapper;
|
||||||
|
@Autowired
|
||||||
|
private final SysDeptMapper deptMapper;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -63,24 +66,150 @@ public class OaEmployeeTemplateBindingServiceImpl implements IOaEmployeeTemplate
|
|||||||
public TableDataInfo<OaEmployeeTemplateBindingVo> queryPageList(OaEmployeeTemplateBindingBo bo, PageQuery pageQuery) {
|
public TableDataInfo<OaEmployeeTemplateBindingVo> queryPageList(OaEmployeeTemplateBindingBo bo, PageQuery pageQuery) {
|
||||||
LambdaQueryWrapper<OaEmployeeTemplateBinding> lqw = buildQueryWrapper(bo);
|
LambdaQueryWrapper<OaEmployeeTemplateBinding> lqw = buildQueryWrapper(bo);
|
||||||
Page<OaEmployeeTemplateBindingVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
|
Page<OaEmployeeTemplateBindingVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
|
||||||
// 根据bindingid和template_type(salary)去求和paid_amount字段
|
|
||||||
if (CollectionUtils.isNotEmpty(result.getRecords())) {
|
if (CollectionUtils.isNotEmpty(result.getRecords())) {
|
||||||
|
// 1. 批量查员工
|
||||||
|
List<Long> employeeIds = result.getRecords().stream()
|
||||||
|
.map(OaEmployeeTemplateBindingVo::getEmployeeId)
|
||||||
|
.filter(Objects::nonNull)
|
||||||
|
.distinct()
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
Map<Long, OaEmployee> employeeMap = new HashMap<>();
|
||||||
|
if (!employeeIds.isEmpty()) {
|
||||||
|
List<OaEmployee> employees = employeeMapper.selectBatchIds(employeeIds);
|
||||||
|
employeeMap = employees.stream().collect(Collectors.toMap(OaEmployee::getEmployeeId, e -> e));
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. 批量查部门
|
||||||
|
Set<Long> deptIds = employeeMap.values().stream()
|
||||||
|
.map(OaEmployee::getDeptId)
|
||||||
|
.filter(Objects::nonNull)
|
||||||
|
.collect(Collectors.toSet());
|
||||||
|
Map<Long, SysDept> deptMap = new HashMap<>();
|
||||||
|
if (!deptIds.isEmpty()) {
|
||||||
|
List<SysDept> depts = deptMapper.selectBatchIds(deptIds);
|
||||||
|
deptMap = depts.stream().collect(Collectors.toMap(SysDept::getDeptId, d -> d));
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3. 封装到VO
|
||||||
|
for (OaEmployeeTemplateBindingVo vo : result.getRecords()) {
|
||||||
|
OaEmployee emp = employeeMap.get(vo.getEmployeeId());
|
||||||
|
if (emp != null) {
|
||||||
|
vo.setCompany(emp.getCompany());
|
||||||
|
SysDept dept = deptMap.get(emp.getDeptId());
|
||||||
|
vo.setDeptName(dept != null ? dept.getDeptName() : null);
|
||||||
|
}
|
||||||
|
}
|
||||||
// 提取所有bindingId
|
// 提取所有bindingId
|
||||||
List<Long> bindingIds = result.getRecords().stream()
|
List<Long> bindingIds = result.getRecords().stream()
|
||||||
.map(OaEmployeeTemplateBindingVo::getBindingId)
|
.map(OaEmployeeTemplateBindingVo::getBindingId)
|
||||||
.collect(Collectors.toList());
|
.collect(Collectors.toList());
|
||||||
|
|
||||||
// 批量查询每个bindingId对应的薪资总额
|
// 批量查询每个bindingId对应的各项金额
|
||||||
Map<Long, BigDecimal> salaryTotalMap = calculateSalaryTotalByBindingIds(bindingIds);
|
Map<Long, SalaryCalculationResult> calculationMap = calculateSalaryDetailsByBindingIds(bindingIds);
|
||||||
|
|
||||||
// 将计算结果设置到对应的VO对象中
|
// 将计算结果设置到对应的VO对象中
|
||||||
for (OaEmployeeTemplateBindingVo vo : result.getRecords()) {
|
for (OaEmployeeTemplateBindingVo vo : result.getRecords()) {
|
||||||
vo.setTotalSalary(salaryTotalMap.getOrDefault(vo.getBindingId(), BigDecimal.ZERO));
|
SalaryCalculationResult calc = calculationMap.getOrDefault(vo.getBindingId(), new SalaryCalculationResult());
|
||||||
|
vo.setNetSalary(calc.getTotalSalary()); // 薪资总额
|
||||||
|
vo.setTotalPersonalInsurance(calc.getTotalPersonalInsurance()); // 个人社保总额
|
||||||
|
vo.setTotalCompanyInsurance(calc.getTotalCompanyInsurance()); // 企业社保总额
|
||||||
|
vo.setTotalSalary(calc.getNetSalary()); // 实发工资
|
||||||
|
vo.setTotalCompanyCost(calc.getTotalCompanyCost()); // 公司总成本
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return TableDataInfo.build(result);
|
return TableDataInfo.build(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 薪资计算结果内部类
|
||||||
|
*/
|
||||||
|
private static class SalaryCalculationResult {
|
||||||
|
private BigDecimal totalSalary = BigDecimal.ZERO; // 薪资总额
|
||||||
|
private BigDecimal totalPersonalInsurance = BigDecimal.ZERO; // 个人社保总额
|
||||||
|
private BigDecimal totalCompanyInsurance = BigDecimal.ZERO; // 企业社保总额
|
||||||
|
private BigDecimal netSalary = BigDecimal.ZERO; // 实发工资
|
||||||
|
private BigDecimal totalCompanyCost = BigDecimal.ZERO; // 公司总成本
|
||||||
|
|
||||||
|
// getters and setters
|
||||||
|
public BigDecimal getTotalSalary() { return totalSalary; }
|
||||||
|
public void setTotalSalary(BigDecimal totalSalary) { this.totalSalary = totalSalary; }
|
||||||
|
|
||||||
|
public BigDecimal getTotalPersonalInsurance() { return totalPersonalInsurance; }
|
||||||
|
public void setTotalPersonalInsurance(BigDecimal totalPersonalInsurance) { this.totalPersonalInsurance = totalPersonalInsurance; }
|
||||||
|
|
||||||
|
public BigDecimal getTotalCompanyInsurance() { return totalCompanyInsurance; }
|
||||||
|
public void setTotalCompanyInsurance(BigDecimal totalCompanyInsurance) { this.totalCompanyInsurance = totalCompanyInsurance; }
|
||||||
|
|
||||||
|
public BigDecimal getNetSalary() { return netSalary; }
|
||||||
|
public void setNetSalary(BigDecimal netSalary) { this.netSalary = netSalary; }
|
||||||
|
|
||||||
|
public BigDecimal getTotalCompanyCost() { return totalCompanyCost; }
|
||||||
|
public void setTotalCompanyCost(BigDecimal totalCompanyCost) { this.totalCompanyCost = totalCompanyCost; }
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据绑定记录ID集合批量计算薪资明细
|
||||||
|
*/
|
||||||
|
private Map<Long, SalaryCalculationResult> calculateSalaryDetailsByBindingIds(List<Long> bindingIds) {
|
||||||
|
if (CollectionUtils.isEmpty(bindingIds)) {
|
||||||
|
return Collections.emptyMap();
|
||||||
|
}
|
||||||
|
|
||||||
|
Map<Long, SalaryCalculationResult> resultMap = new HashMap<>();
|
||||||
|
|
||||||
|
// 查询所有明细记录
|
||||||
|
LambdaQueryWrapper<OaBindingItemDetail> queryWrapper = new LambdaQueryWrapper<>();
|
||||||
|
queryWrapper.in(OaBindingItemDetail::getBindingId, bindingIds)
|
||||||
|
.eq(OaBindingItemDetail::getDelFlag, 0);
|
||||||
|
|
||||||
|
List<OaBindingItemDetail> allDetails = bindingItemDetailMapper.selectList(queryWrapper);
|
||||||
|
|
||||||
|
// 按bindingId分组处理
|
||||||
|
Map<Long, List<OaBindingItemDetail>> detailsByBindingId = allDetails.stream()
|
||||||
|
.collect(Collectors.groupingBy(OaBindingItemDetail::getBindingId));
|
||||||
|
|
||||||
|
for (Long bindingId : bindingIds) {
|
||||||
|
SalaryCalculationResult calc = new SalaryCalculationResult();
|
||||||
|
List<OaBindingItemDetail> details = detailsByBindingId.getOrDefault(bindingId, Collections.emptyList());
|
||||||
|
|
||||||
|
for (OaBindingItemDetail detail : details) {
|
||||||
|
if (detail.getPaidAmount() != null) {
|
||||||
|
if ("salary".equals(detail.getTemplateType())) {
|
||||||
|
// 薪资项目
|
||||||
|
calc.setTotalSalary(calc.getTotalSalary().add(detail.getPaidAmount()));
|
||||||
|
} else if ("insurance".equals(detail.getTemplateType())) {
|
||||||
|
// 社保项目 - 需要区分个人还是企业
|
||||||
|
OaInsuranceTemplateDetail insuranceDetail = insuranceDetailMapper.selectById(detail.getItemDetailId());
|
||||||
|
if (insuranceDetail != null) {
|
||||||
|
OaInsuranceTemplate template = insuranceTemplateMapper.selectById(insuranceDetail.getInsuranceTemplateId());
|
||||||
|
if (template != null) {
|
||||||
|
if (template.getType() == 0) {
|
||||||
|
// 个人社保
|
||||||
|
calc.setTotalPersonalInsurance(calc.getTotalPersonalInsurance().add(detail.getPaidAmount()));
|
||||||
|
} else if (template.getType() == 1) {
|
||||||
|
// 企业社保
|
||||||
|
calc.setTotalCompanyInsurance(calc.getTotalCompanyInsurance().add(detail.getPaidAmount()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
// 计算实发工资和公司总成本
|
||||||
|
BigDecimal personalInsurance = calc.getTotalPersonalInsurance();
|
||||||
|
if (personalInsurance.compareTo(BigDecimal.ZERO) < 0) {
|
||||||
|
personalInsurance = personalInsurance.abs(); // 或直接设为0
|
||||||
|
}
|
||||||
|
calc.setNetSalary(calc.getTotalSalary().subtract(personalInsurance));
|
||||||
|
calc.setTotalCompanyCost(calc.getTotalSalary().add(calc.getTotalCompanyInsurance()));
|
||||||
|
resultMap.put(bindingId, calc);
|
||||||
|
}
|
||||||
|
|
||||||
|
return resultMap;
|
||||||
|
}
|
||||||
/**
|
/**
|
||||||
* 根据绑定记录ID集合批量计算薪资总额
|
* 根据绑定记录ID集合批量计算薪资总额
|
||||||
* @param bindingIds 绑定记录ID集合
|
* @param bindingIds 绑定记录ID集合
|
||||||
@@ -124,7 +253,8 @@ public class OaEmployeeTemplateBindingServiceImpl implements IOaEmployeeTemplate
|
|||||||
Map<String, Object> params = bo.getParams();
|
Map<String, Object> params = bo.getParams();
|
||||||
LambdaQueryWrapper<OaEmployeeTemplateBinding> lqw = Wrappers.lambdaQuery();
|
LambdaQueryWrapper<OaEmployeeTemplateBinding> lqw = Wrappers.lambdaQuery();
|
||||||
lqw.eq(bo.getEmployeeId() != null, OaEmployeeTemplateBinding::getEmployeeId, bo.getEmployeeId());
|
lqw.eq(bo.getEmployeeId() != null, OaEmployeeTemplateBinding::getEmployeeId, bo.getEmployeeId());
|
||||||
lqw.eq(bo.getInsuranceTemplateId() != null, OaEmployeeTemplateBinding::getInsuranceTemplateId, bo.getInsuranceTemplateId());
|
lqw.eq(bo.getPersonalInsuranceTemplateId() != null, OaEmployeeTemplateBinding::getPersonalInsuranceTemplateId, bo.getPersonalInsuranceTemplateId());
|
||||||
|
lqw.eq(bo.getCompanyInsuranceTemplateId() != null, OaEmployeeTemplateBinding::getCompanyInsuranceTemplateId, bo.getCompanyInsuranceTemplateId());
|
||||||
lqw.eq(bo.getSalaryTemplateId() != null, OaEmployeeTemplateBinding::getSalaryTemplateId, bo.getSalaryTemplateId());
|
lqw.eq(bo.getSalaryTemplateId() != null, OaEmployeeTemplateBinding::getSalaryTemplateId, bo.getSalaryTemplateId());
|
||||||
lqw.eq(bo.getPayYear() != null, OaEmployeeTemplateBinding::getPayYear, bo.getPayYear());
|
lqw.eq(bo.getPayYear() != null, OaEmployeeTemplateBinding::getPayYear, bo.getPayYear());
|
||||||
lqw.eq(bo.getPayMonth() != null, OaEmployeeTemplateBinding::getPayMonth, bo.getPayMonth());
|
lqw.eq(bo.getPayMonth() != null, OaEmployeeTemplateBinding::getPayMonth, bo.getPayMonth());
|
||||||
@@ -178,9 +308,9 @@ public class OaEmployeeTemplateBindingServiceImpl implements IOaEmployeeTemplate
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Boolean calculateSalary(List<Long> employeeIds, Long payYear, Long payMonth,
|
public Boolean calculateSalary(List<Long> employeeIds, Long payYear, Long payMonth,
|
||||||
Long defaultInsuranceTemplateId, Long defaultSalaryTemplateId) {
|
Long defaultPersonalInsuranceTemplateId, Long defaultCompanyInsuranceTemplateId, Long defaultSalaryTemplateId) {
|
||||||
// 参数校验
|
// 参数校验
|
||||||
if (defaultInsuranceTemplateId == null || defaultSalaryTemplateId == null) {
|
if (defaultPersonalInsuranceTemplateId == null || defaultCompanyInsuranceTemplateId == null || defaultSalaryTemplateId == null) {
|
||||||
throw new RuntimeException("请选择默认的薪资模板和社保模板");
|
throw new RuntimeException("请选择默认的薪资模板和社保模板");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -206,11 +336,13 @@ public class OaEmployeeTemplateBindingServiceImpl implements IOaEmployeeTemplate
|
|||||||
|
|
||||||
if (lastBinding != null) {
|
if (lastBinding != null) {
|
||||||
// 存在上月记录,复制上月的模板ID
|
// 存在上月记录,复制上月的模板ID
|
||||||
binding.setInsuranceTemplateId(lastBinding.getInsuranceTemplateId());
|
binding.setPersonalInsuranceTemplateId(lastBinding.getPersonalInsuranceTemplateId());
|
||||||
|
binding.setCompanyInsuranceTemplateId(lastBinding.getCompanyInsuranceTemplateId());
|
||||||
binding.setSalaryTemplateId(lastBinding.getSalaryTemplateId());
|
binding.setSalaryTemplateId(lastBinding.getSalaryTemplateId());
|
||||||
} else {
|
} else {
|
||||||
// 首次配置,使用默认模板
|
// 首次配置,使用默认模板
|
||||||
binding.setInsuranceTemplateId(defaultInsuranceTemplateId);
|
binding.setPersonalInsuranceTemplateId(defaultPersonalInsuranceTemplateId);
|
||||||
|
binding.setCompanyInsuranceTemplateId(defaultCompanyInsuranceTemplateId);
|
||||||
binding.setSalaryTemplateId(defaultSalaryTemplateId);
|
binding.setSalaryTemplateId(defaultSalaryTemplateId);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -224,7 +356,7 @@ public class OaEmployeeTemplateBindingServiceImpl implements IOaEmployeeTemplate
|
|||||||
} else {
|
} else {
|
||||||
// 首次配置,使用模板默认金额
|
// 首次配置,使用模板默认金额
|
||||||
createNewDetails(binding.getBindingId(), binding.getSalaryTemplateId(),
|
createNewDetails(binding.getBindingId(), binding.getSalaryTemplateId(),
|
||||||
binding.getInsuranceTemplateId());
|
binding.getPersonalInsuranceTemplateId(), binding.getCompanyInsuranceTemplateId());
|
||||||
}
|
}
|
||||||
|
|
||||||
// 5. 更新主表的汇总金额
|
// 5. 更新主表的汇总金额
|
||||||
@@ -253,7 +385,7 @@ public class OaEmployeeTemplateBindingServiceImpl implements IOaEmployeeTemplate
|
|||||||
/**
|
/**
|
||||||
* 创建新的明细记录(使用模板默认值)
|
* 创建新的明细记录(使用模板默认值)
|
||||||
*/
|
*/
|
||||||
private void createNewDetails(Long bindingId, Long salaryTemplateId, Long insuranceTemplateId) {
|
private void createNewDetails(Long bindingId, Long salaryTemplateId, Long personalInsuranceTemplateId, Long companyInsuranceTemplateId) {
|
||||||
// 薪资明细
|
// 薪资明细
|
||||||
List<OaSalaryTemplateDetail> salaryDetails = salaryDetailMapper.findByTemplateId(salaryTemplateId);
|
List<OaSalaryTemplateDetail> salaryDetails = salaryDetailMapper.findByTemplateId(salaryTemplateId);
|
||||||
for (OaSalaryTemplateDetail detail : salaryDetails) {
|
for (OaSalaryTemplateDetail detail : salaryDetails) {
|
||||||
@@ -265,9 +397,12 @@ public class OaEmployeeTemplateBindingServiceImpl implements IOaEmployeeTemplate
|
|||||||
bindingItemDetailMapper.insert(item);
|
bindingItemDetailMapper.insert(item);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 社保明细
|
// 个人社保明细
|
||||||
List<OaInsuranceTemplateDetail> insuranceDetails = insuranceDetailMapper.findByTemplateId(insuranceTemplateId);
|
List<OaInsuranceTemplateDetail> personalDetails = insuranceDetailMapper.findByTemplateId(personalInsuranceTemplateId);
|
||||||
for (OaInsuranceTemplateDetail detail : insuranceDetails) {
|
for (OaInsuranceTemplateDetail detail : personalDetails) {
|
||||||
|
// 只处理主表type=0的模板
|
||||||
|
OaInsuranceTemplate template = insuranceTemplateMapper.selectById(detail.getInsuranceTemplateId());
|
||||||
|
if (template != null && template.getType() == 0) {
|
||||||
OaBindingItemDetail item = new OaBindingItemDetail();
|
OaBindingItemDetail item = new OaBindingItemDetail();
|
||||||
item.setBindingId(bindingId);
|
item.setBindingId(bindingId);
|
||||||
item.setTemplateType("insurance");
|
item.setTemplateType("insurance");
|
||||||
@@ -277,30 +412,61 @@ public class OaEmployeeTemplateBindingServiceImpl implements IOaEmployeeTemplate
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
// 企业社保明细
|
||||||
* 更新主表的汇总金额
|
List<OaInsuranceTemplateDetail> companyDetails = insuranceDetailMapper.findByTemplateId(companyInsuranceTemplateId);
|
||||||
*/
|
for (OaInsuranceTemplateDetail detail : companyDetails) {
|
||||||
|
// 只处理主表type=1的模板
|
||||||
|
OaInsuranceTemplate template = insuranceTemplateMapper.selectById(detail.getInsuranceTemplateId());
|
||||||
|
if (template != null && template.getType() == 1) {
|
||||||
|
OaBindingItemDetail item = new OaBindingItemDetail();
|
||||||
|
item.setBindingId(bindingId);
|
||||||
|
item.setTemplateType("insurance");
|
||||||
|
item.setItemDetailId(detail.getInsuranceDetailId());
|
||||||
|
item.setPaidAmount(detail.getAmount() != null ? detail.getAmount() : BigDecimal.ZERO);
|
||||||
|
bindingItemDetailMapper.insert(item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void updateBindingTotals(Long bindingId) {
|
private void updateBindingTotals(Long bindingId) {
|
||||||
// 查询该binding下所有明细
|
|
||||||
List<OaBindingItemDetail> details = bindingItemDetailMapper.findByBindingId(bindingId);
|
List<OaBindingItemDetail> details = bindingItemDetailMapper.findByBindingId(bindingId);
|
||||||
|
|
||||||
BigDecimal totalSalary = BigDecimal.ZERO;
|
BigDecimal totalSalary = BigDecimal.ZERO;
|
||||||
BigDecimal totalCost = BigDecimal.ZERO;
|
BigDecimal totalPersonalInsurance = BigDecimal.ZERO;
|
||||||
|
BigDecimal totalCompanyInsurance = BigDecimal.ZERO;
|
||||||
|
|
||||||
for (OaBindingItemDetail detail : details) {
|
for (OaBindingItemDetail detail : details) {
|
||||||
if (detail.getPaidAmount() != null) {
|
if (detail.getPaidAmount() != null) {
|
||||||
if ("salary".equals(detail.getTemplateType())) {
|
if ("salary".equals(detail.getTemplateType())) {
|
||||||
totalSalary = totalSalary.add(detail.getPaidAmount());
|
totalSalary = totalSalary.add(detail.getPaidAmount());
|
||||||
|
} else if ("insurance".equals(detail.getTemplateType())) {
|
||||||
|
// 通过明细的 insuranceTemplateId 查主表 type
|
||||||
|
OaInsuranceTemplateDetail insuranceDetail = insuranceDetailMapper.selectById(detail.getItemDetailId());
|
||||||
|
if (insuranceDetail != null) {
|
||||||
|
OaInsuranceTemplate template = insuranceTemplateMapper.selectById(insuranceDetail.getInsuranceTemplateId());
|
||||||
|
if (template != null) {
|
||||||
|
// 强制社保金额为正数
|
||||||
|
BigDecimal paid = detail.getPaidAmount().abs();
|
||||||
|
if (template.getType() == 0) {
|
||||||
|
totalPersonalInsurance = totalPersonalInsurance.add(paid);
|
||||||
|
} else if (template.getType() == 1) {
|
||||||
|
totalCompanyInsurance = totalCompanyInsurance.add(paid);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
totalCost = totalCost.add(detail.getPaidAmount());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 更新主表
|
// 实发工资 = 薪资合计 - 个人社保
|
||||||
|
BigDecimal netSalary = totalSalary.subtract(totalPersonalInsurance);
|
||||||
|
// 单位总支出 = 薪资合计 + 企业社保
|
||||||
|
BigDecimal totalCompanyCost = totalSalary.add(totalCompanyInsurance);
|
||||||
|
|
||||||
OaEmployeeTemplateBinding binding = new OaEmployeeTemplateBinding();
|
OaEmployeeTemplateBinding binding = new OaEmployeeTemplateBinding();
|
||||||
binding.setBindingId(bindingId);
|
binding.setBindingId(bindingId);
|
||||||
binding.setNetSalary(totalSalary);
|
binding.setNetSalary(netSalary);
|
||||||
binding.setTotalCompanyCost(totalCost);
|
binding.setTotalCompanyCost(totalCompanyCost);
|
||||||
baseMapper.updateById(binding);
|
baseMapper.updateById(binding);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -7,7 +7,8 @@
|
|||||||
<resultMap type="com.ruoyi.oa.domain.OaEmployeeTemplateBinding" id="OaEmployeeTemplateBindingResult">
|
<resultMap type="com.ruoyi.oa.domain.OaEmployeeTemplateBinding" id="OaEmployeeTemplateBindingResult">
|
||||||
<result property="bindingId" column="binding_id"/>
|
<result property="bindingId" column="binding_id"/>
|
||||||
<result property="employeeId" column="employee_id"/>
|
<result property="employeeId" column="employee_id"/>
|
||||||
<result property="insuranceTemplateId" column="insurance_template_id"/>
|
<result property="personalInsuranceTemplateId" column="personal_insurance_template_id"/>
|
||||||
|
<result property="companyInsuranceTemplateId" column="company_insurance_template_id"/>
|
||||||
<result property="salaryTemplateId" column="salary_template_id"/>
|
<result property="salaryTemplateId" column="salary_template_id"/>
|
||||||
<result property="payYear" column="pay_year"/>
|
<result property="payYear" column="pay_year"/>
|
||||||
<result property="payMonth" column="pay_month"/>
|
<result property="payMonth" column="pay_month"/>
|
||||||
@@ -23,14 +24,15 @@
|
|||||||
</resultMap>
|
</resultMap>
|
||||||
<insert id="insertBinding">
|
<insert id="insertBinding">
|
||||||
INSERT INTO oa_employee_template_binding
|
INSERT INTO oa_employee_template_binding
|
||||||
(employee_id, insurance_template_id, salary_template_id, pay_year, pay_month, net_salary, total_company_cost, status)
|
(employee_id,personal_insurance_template_id,company_insurance_template_id, salary_template_id, pay_year, pay_month, net_salary, total_company_cost, status)
|
||||||
VALUES (#{employeeId}, #{insuranceTemplateId}, #{salaryTemplateId}, #{payYear}, #{payMonth}, #{netSalary}, #{totalCompanyCost}, #{status})
|
VALUES (#{employeeId}, #{personalInsuranceTemplateId},#{companyInsuranceTemplateId}, #{salaryTemplateId}, #{payYear}, #{payMonth}, #{netSalary}, #{totalCompanyCost}, #{status})
|
||||||
</insert>
|
</insert>
|
||||||
<select id="findByEmployeeAndMonth" resultType="com.ruoyi.oa.domain.OaEmployeeTemplateBinding">
|
<select id="findByEmployeeAndMonth" resultType="com.ruoyi.oa.domain.OaEmployeeTemplateBinding">
|
||||||
SELECT * FROM oa_employee_template_binding
|
SELECT * FROM oa_employee_template_binding
|
||||||
WHERE employee_id = #{employeeId}
|
WHERE employee_id = #{employeeId}
|
||||||
AND pay_year = #{payYear}
|
AND pay_year = #{payYear}
|
||||||
AND pay_month = #{payMonth}
|
AND pay_month = #{payMonth}
|
||||||
|
AND del_flag = '0'
|
||||||
LIMIT 1
|
LIMIT 1
|
||||||
</select>
|
</select>
|
||||||
|
|
||||||
|
|||||||
@@ -7,6 +7,7 @@
|
|||||||
<resultMap type="com.ruoyi.oa.domain.OaInsuranceTemplate" id="OaInsuranceTemplateResult">
|
<resultMap type="com.ruoyi.oa.domain.OaInsuranceTemplate" id="OaInsuranceTemplateResult">
|
||||||
<result property="insuranceTemplateId" column="insurance_template_id"/>
|
<result property="insuranceTemplateId" column="insurance_template_id"/>
|
||||||
<result property="templateName" column="template_name"/>
|
<result property="templateName" column="template_name"/>
|
||||||
|
<result property="type" column="type"/>
|
||||||
<result property="delFlag" column="del_flag"/>
|
<result property="delFlag" column="del_flag"/>
|
||||||
<result property="remark" column="remark"/>
|
<result property="remark" column="remark"/>
|
||||||
<result property="createBy" column="create_by"/>
|
<result property="createBy" column="create_by"/>
|
||||||
|
|||||||
Reference in New Issue
Block a user