Commit 45629ec6 authored by fangxinjiang's avatar fangxinjiang

合同续签劳务派遣起止日期与合同起止日期一致性校验+批量派遣年限>2-fxj

parent 27a9e17a
package com.yifu.cloud.plus.v1.csp.utils;
import com.yifu.cloud.plus.v1.yifu.insurances.util.LocalDateUtil;
import org.springframework.stereotype.Service;
import java.time.LocalDate;
/**
* @Author fxj
* @Date 2026/2/24
* @Description
* @Version 1.0
*/
@Service
public class ContractTermCalculator {
/**
* 合同期限计算结果
*/
public static class ContractTerm {
private final int years;
private final int months;
public ContractTerm(int years, int months) {
this.years = years;
this.months = months;
}
public int getYears() { return years; }
public int getMonths() { return months; }
}
/**
* 计算合同期限(年数和月数)
* @param startDate 合同开始日期
* @param endDate 合同截止日期
* @return ContractTerm 包含年数和月数
*/
public static ContractTerm calculateTerm(String startDate, String endDate) {
// 验证日期
if (startDate == null || endDate == null) {
throw new IllegalArgumentException("开始日期和截止日期不能为空");
}
// 计算相差的年数
int years = 0;
int months = (int) LocalDateUtil.betweenMonth(startDate, endDate);
// 处理月份进位
if (months >= 12) {
years = (months / 12);
months = months % 12;
}
return new ContractTerm(years, months);
}
/**
* 解析日期字符串(支持yyyy-MM-dd和yyyy年MM月dd日格式)
*/
private static LocalDate parseDate(String dateStr) {
if (dateStr == null || dateStr.trim().isEmpty()) {
throw new IllegalArgumentException("日期不能为空");
}
dateStr = dateStr.trim();
try {
// 处理 yyyy-MM-dd 格式
if (dateStr.contains("-")) {
String[] parts = dateStr.split("-");
if (parts.length == 3) {
return LocalDate.of(
Integer.parseInt(parts[0]),
Integer.parseInt(parts[1]),
Integer.parseInt(parts[2])
);
}
}
// 处理 yyyy年MM月dd日 格式
if (dateStr.contains("年")) {
String yearPart = dateStr.substring(0, dateStr.indexOf("年"));
String monthPart = dateStr.substring(dateStr.indexOf("年") + 1, dateStr.indexOf("月"));
String dayPart = dateStr.substring(dateStr.indexOf("月") + 1, dateStr.indexOf("日"));
return LocalDate.of(
Integer.parseInt(yearPart),
Integer.parseInt(monthPart),
Integer.parseInt(dayPart)
);
}
throw new IllegalArgumentException("不支持的日期格式: " + dateStr);
} catch (Exception e) {
throw new IllegalArgumentException("日期解析失败: " + dateStr, e);
}
}
/**
* 测试方法
*/
public static void main(String[] args) {
System.out.println("=== 合同期限计算测试 ===");
// 测试示例1:2026年2月3日到2027年2月2日(正好一年)
testCase("2026-02-03", "2027-02-02", "正好一年");
// 测试示例2:2026年2月3日到2027年2月3日(一年零一天,应算一年一个月)
testCase("2026-02-03", "2027-02-03", "一年零一天");
// 测试示例3:2026年2月3日到2027年2月28日(一年零25天,应算一年一个月)
testCase("2026-02-03", "2027-02-28", "一年零25天");
// 测试示例3:2026年2月3日到2027年3月3日(应算一年2个月)
testCase("2026-02-03", "2027-03-02", "一年1月零1天");
// 测试示例4:2026年2月3日到2027年3月1日(一年零26天,应算一年一个月)
testCase("2026-02-03", "2027-03-03", "跨月一天");
// 测试示例5:2026年2月3日到2028年2月2日(正好两年)
testCase("2026-02-03", "2028-03-04", "正好两年");
// 测试示例6:2026年2月3日到2028年3月1日(两年多,应算两年一个月)
testCase("2026-02-03", "2028-03-01", "两年多一天");
// 测试示例7:2026年1月31日到2026年2月28日(一个月差几天)
testCase("2026-01-31", "2026-02-28", "跨月边界");
}
private static void testCase(String start, String end, String description) {
try {
ContractTerm term = calculateTerm(start, end);
LocalDate startDate = parseDate(start);
LocalDate endDate = parseDate(end);
System.out.printf("开始:%-12s | 截止:%-12s | 结果:(%d年%d个月)%n",
start, end, term.getYears(), term.getMonths());
} catch (Exception e) {
System.out.println("错误:" + e.getMessage());
}
}
}
...@@ -24,12 +24,12 @@ import com.yifu.cloud.plus.v1.csp.service.EmployeeRegistrationLeaveService; ...@@ -24,12 +24,12 @@ import com.yifu.cloud.plus.v1.csp.service.EmployeeRegistrationLeaveService;
import com.yifu.cloud.plus.v1.csp.service.EmployeeRegistrationService; import com.yifu.cloud.plus.v1.csp.service.EmployeeRegistrationService;
import com.yifu.cloud.plus.v1.csp.service.TAttaInfoService; import com.yifu.cloud.plus.v1.csp.service.TAttaInfoService;
import com.yifu.cloud.plus.v1.csp.service.TOperationLogService; import com.yifu.cloud.plus.v1.csp.service.TOperationLogService;
import com.yifu.cloud.plus.v1.csp.utils.ContractTermCalculator;
import com.yifu.cloud.plus.v1.csp.vo.*; import com.yifu.cloud.plus.v1.csp.vo.*;
import com.yifu.cloud.plus.v1.ekp.vo.EkpDeptContractInfoVo; import com.yifu.cloud.plus.v1.ekp.vo.EkpDeptContractInfoVo;
import com.yifu.cloud.plus.v1.yifu.admin.api.entity.SysUser; import com.yifu.cloud.plus.v1.yifu.admin.api.entity.SysUser;
import com.yifu.cloud.plus.v1.yifu.admin.api.vo.SysCspDeptVo; import com.yifu.cloud.plus.v1.yifu.admin.api.vo.SysCspDeptVo;
import com.yifu.cloud.plus.v1.yifu.archives.entity.SysAutoDictItem; import com.yifu.cloud.plus.v1.yifu.archives.entity.*;
import com.yifu.cloud.plus.v1.yifu.archives.entity.TEmployeeProjectBelongDept;
import com.yifu.cloud.plus.v1.yifu.archives.vo.*; import com.yifu.cloud.plus.v1.yifu.archives.vo.*;
import com.yifu.cloud.plus.v1.yifu.common.core.constant.ClientNameConstants; import com.yifu.cloud.plus.v1.yifu.common.core.constant.ClientNameConstants;
import com.yifu.cloud.plus.v1.yifu.common.core.constant.CommonConstants; import com.yifu.cloud.plus.v1.yifu.common.core.constant.CommonConstants;
...@@ -117,6 +117,9 @@ public class EmployeeRegistrationServiceImpl extends ServiceImpl<EmployeeRegistr ...@@ -117,6 +117,9 @@ public class EmployeeRegistrationServiceImpl extends ServiceImpl<EmployeeRegistr
private final TOperationLogService logService; private final TOperationLogService logService;
private final EmployeeRegistrationLeaveService employeeRegistrationLeaveService; private final EmployeeRegistrationLeaveService employeeRegistrationLeaveService;
@Autowired
private ContractTermCalculator calculator = new ContractTermCalculator();
/** /**
* 入离职登记表简单分页查询 * 入离职登记表简单分页查询
* *
...@@ -730,6 +733,20 @@ public class EmployeeRegistrationServiceImpl extends ServiceImpl<EmployeeRegistr ...@@ -730,6 +733,20 @@ public class EmployeeRegistrationServiceImpl extends ServiceImpl<EmployeeRegistr
} }
} }
if (preVo.getServerItem().contains("合同") && null != preVo.getEmployeeContractPreVos() &&
Common.isNotNull(preVo.getEmployeeContractPreVos().getContractFlag()) &&
CommonConstants.ONE_STRING.equals(preVo.getEmployeeContractPreVos().getContractFlag())) {
//生成合同待购买数据
String error = null;
try {
error = initContractPreInfo(registration, preVo.getEmployeeContractPreVos(), user);
} catch (ParseException e) {
errorTemp.append("初始化合同待购买数据异常:"+error);
}
if (error != null){
errorTemp.append(error);
}
}
//错误信息全量返回 //错误信息全量返回
if (errorTemp.length() > 0) { if (errorTemp.length() > 0) {
return R.other(CommonConstants.TWO_INT,null,errorTemp.toString()); return R.other(CommonConstants.TWO_INT,null,errorTemp.toString());
...@@ -780,7 +797,10 @@ public class EmployeeRegistrationServiceImpl extends ServiceImpl<EmployeeRegistr ...@@ -780,7 +797,10 @@ public class EmployeeRegistrationServiceImpl extends ServiceImpl<EmployeeRegistr
Common.isNotNull(preVo.getEmployeeContractPreVos().getContractFlag()) && Common.isNotNull(preVo.getEmployeeContractPreVos().getContractFlag()) &&
CommonConstants.ONE_STRING.equals(preVo.getEmployeeContractPreVos().getContractFlag())) { CommonConstants.ONE_STRING.equals(preVo.getEmployeeContractPreVos().getContractFlag())) {
//生成合同待购买数据 //生成合同待购买数据
initContractPreInfo(registration, preVo.getEmployeeContractPreVos(), user, domainR.getData()); //initContractPreInfo(registration, preVo.getEmployeeContractPreVos(), user, domainR.getData());
// 设置员工注册ID
preVo.getEmployeeContractPreVos().setRegisterId(domainR.getData());
archivesDaprUtil.saveContractPreInfo(preVo.getEmployeeContractPreVos());
} }
//服务类型包含社保购买时 //服务类型包含社保购买时
if (preVo.getServerItem().contains("社保") && (null != preVo.getExitSocialInfoList() if (preVo.getServerItem().contains("社保") && (null != preVo.getExitSocialInfoList()
...@@ -969,15 +989,12 @@ public class EmployeeRegistrationServiceImpl extends ServiceImpl<EmployeeRegistr ...@@ -969,15 +989,12 @@ public class EmployeeRegistrationServiceImpl extends ServiceImpl<EmployeeRegistr
* @param registration 员工注册信息对象,包含员工的基本注册信息 * @param registration 员工注册信息对象,包含员工的基本注册信息
* @param employeeContractPreVo 员工合同预信息对象,将被填充数据以用于合同签订流程 * @param employeeContractPreVo 员工合同预信息对象,将被填充数据以用于合同签订流程
* @param user 当前用户信息,用于记录合同预信息的创建和更新者 * @param user 当前用户信息,用于记录合同预信息的创建和更新者
* @param id 员工注册ID,用于关联合同预信息和员工注册信息
* @throws ParseException 日期解析异常,当日期格式不符合预期时抛出 * @throws ParseException 日期解析异常,当日期格式不符合预期时抛出
*/ */
private void initContractPreInfo(EmployeeRegistration registration, TEmployeeContractPreVo employeeContractPreVo, private String initContractPreInfo(EmployeeRegistration registration, TEmployeeContractPreVo employeeContractPreVo,
YifuUser user, String id) throws ParseException { YifuUser user) throws ParseException {
employeeContractPreVo.setProcessStatus(CommonConstants.ZERO_STRING); employeeContractPreVo.setProcessStatus(CommonConstants.ZERO_STRING);
employeeContractPreVo.setSituation("正常签订"); employeeContractPreVo.setSituation("正常签订");
// 设置员工注册ID
employeeContractPreVo.setRegisterId(id);
// 设置客户用户名 // 设置客户用户名
employeeContractPreVo.setCustomerUsername(registration.getCustomerUsernameNew()); employeeContractPreVo.setCustomerUsername(registration.getCustomerUsernameNew());
// 设置客户用户登录名 // 设置客户用户登录名
...@@ -1119,9 +1136,64 @@ public class EmployeeRegistrationServiceImpl extends ServiceImpl<EmployeeRegistr ...@@ -1119,9 +1136,64 @@ public class EmployeeRegistrationServiceImpl extends ServiceImpl<EmployeeRegistr
employeeContractPreVo.setExpectedConfirmTime(DateUtil.parseDate(DateUtil.dateToString( employeeContractPreVo.setExpectedConfirmTime(DateUtil.parseDate(DateUtil.dateToString(
employeeContractPreVo.getExpectedConfirmTime(), DateUtil.ISO_EXPANDED_DATE_FORMAT) + " 9:00", DateUtil.DATETIME_PATTERN_MINUTE)); employeeContractPreVo.getExpectedConfirmTime(), DateUtil.ISO_EXPANDED_DATE_FORMAT) + " 9:00", DateUtil.DATETIME_PATTERN_MINUTE));
} }
archivesDaprUtil.saveContractPreInfo(employeeContractPreVo); //指定日期 或 与商务合同一致 计算合同年限
if (CommonConstants.THREE_STRING.equals(employeeContractPreVo.getContractEndType())
||CommonConstants.ONE_STRING.equals(employeeContractPreVo.getContractEndType())){
//处理合同年限
ContractTermCalculator.ContractTerm term = calculator.calculateTerm(
DateUtil.formatDatePatten(employeeContractPreVo.getContractStart(),DateUtil.ISO_EXPANDED_DATE_FORMAT),
DateUtil.formatDatePatten(employeeContractPreVo.getContractEnd(),DateUtil.ISO_EXPANDED_DATE_FORMAT));
if (term != null){
employeeContractPreVo.setContractDurationYear(Integer.toString(term.getYears()));
employeeContractPreVo.setContractDurationMonth(Integer.toString(term.getMonths()));
}else {
employeeContractPreVo.setContractDurationYear(CommonConstants.ZERO_STRING);
employeeContractPreVo.setContractDurationMonth(CommonConstants.ZERO_STRING);
}
} }
if (CommonConstants.TWENTY_STRING.equals(employeeContractPreVo.getContractType())){
if (Common.isNotNull(employeeContractPreVo.getDispatchPeriodYear()) && Common.isNotNull(employeeContractPreVo.getDispatchPeriodMonth())){
//校验劳务派遣的派遣年限必须为两年
final int REQUIRED_SERVICE_YEARS = 2;
int year = 0;
try {
year = Integer.parseInt(Common.isEmpty(employeeContractPreVo.getDispatchPeriodYear()) ? "0" : employeeContractPreVo.getDispatchPeriodYear().trim());
} catch (NumberFormatException e) {
return "劳务派遣的派遣年限格式不正确";
}
String dispatchMonth = employeeContractPreVo.getDispatchPeriodMonth();
if ("12".equals(dispatchMonth)) {
year = year + 1;
}
if (year < REQUIRED_SERVICE_YEARS) {
return "劳务派遣合同的合同年限不能小于2年,请检查";
}
}
if (Common.isNotNull(employeeContractPreVo.getDispatchPeriodStart()) && Common.isNotNull(employeeContractPreVo.getDispatchPeriodEnd())){
if (employeeContractPreVo.getDispatchPeriodEnd().before(employeeContractPreVo.getDispatchPeriodStart())){
return "派遣结束日期需大于等于派遣开始日期";
}
}
//合同开始时间、合同截止时间 与派遣的合同开始时间、合同截止时间一致
if (Common.isNotNull(employeeContractPreVo.getContractStart()) && Common.isNotNull(employeeContractPreVo.getDispatchPeriodStart())
&& !employeeContractPreVo.getContractStart().equals(employeeContractPreVo.getDispatchPeriodStart())){
return "合同开始日期与派遣开始日期不一致";
}
if (Common.isNotNull(employeeContractPreVo.getContractEnd()) && Common.isNotNull(employeeContractPreVo.getDispatchPeriodEnd())
&& !employeeContractPreVo.getContractEnd().equals(employeeContractPreVo.getDispatchPeriodEnd())){
return "合同截止日期与派遣截止日期不一致";
}
}
//同商务合同一直 要 验证时间 截止时间大于等于开始时间、时间交叉
if (Common.isNotNull(employeeContractPreVo.getContractStart()) && Common.isNotNull(employeeContractPreVo.getContractEnd())){
if (employeeContractPreVo.getContractEnd().before(employeeContractPreVo.getContractStart())){
return "合同截止日期需大于等于合同开始日期";
}
}
return null;
}
/** /**
* 入职待确认表确认接收 * 入职待确认表确认接收
...@@ -1354,7 +1426,15 @@ public class EmployeeRegistrationServiceImpl extends ServiceImpl<EmployeeRegistr ...@@ -1354,7 +1426,15 @@ public class EmployeeRegistrationServiceImpl extends ServiceImpl<EmployeeRegistr
if (preVo.getServerItem().contains("合同") && Common.isNotNull(preVo.getEmployeeContractPreVos())) { if (preVo.getServerItem().contains("合同") && Common.isNotNull(preVo.getEmployeeContractPreVos())) {
BeanUtils.copyProperties(preVo.getEmployeeContractPreVos(),employeeContractPreVo); BeanUtils.copyProperties(preVo.getEmployeeContractPreVos(),employeeContractPreVo);
//生成合同待购买数据 //生成合同待购买数据
initContractPreInfo(registration, employeeContractPreVo, user, domainR.getData()); String errorStr = initContractPreInfo(registration, employeeContractPreVo, user);
if (null != errorStr){
exitCheckVo.setType("公积金");
exitCheckVo.setErrorMsg("该人员存在在途/有效的公积金数据");
errorList.add(exitCheckVo);
continue;
}
employeeContractPreVo.setRegisterId(domainR.getData());
archivesDaprUtil.saveContractPreInfo(employeeContractPreVo);
} }
//服务类型包含社保购买时 //服务类型包含社保购买时
if (preVo.getServerItem().contains("社保") && (null != preVo.getExitSocialInfoList() if (preVo.getServerItem().contains("社保") && (null != preVo.getExitSocialInfoList()
...@@ -1579,7 +1659,12 @@ public class EmployeeRegistrationServiceImpl extends ServiceImpl<EmployeeRegistr ...@@ -1579,7 +1659,12 @@ public class EmployeeRegistrationServiceImpl extends ServiceImpl<EmployeeRegistr
CommonConstants.ONE_STRING.equals(preVo.getEmployeeContractPreVos().getContractFlag())) || CommonConstants.ONE_STRING.equals(preVo.getEmployeeContractPreVos().getContractFlag())) ||
Common.isEmpty(preVo.getEmployeeContractPreVos().getContractFlag()))) { Common.isEmpty(preVo.getEmployeeContractPreVos().getContractFlag()))) {
//生成合同待购买数据 //生成合同待购买数据
initContractPreInfo(registrationNow, employeeContractPreVo, user, domainR.getData()); String errorStr = initContractPreInfo(registrationNow, employeeContractPreVo, user);
if (null != errorStr){
throw new RuntimeException(errorStr);
}
employeeContractPreVo.setRegisterId(domainR.getData());
archivesDaprUtil.saveContractPreInfo(employeeContractPreVo);
} }
//服务类型包含社保购买时 //服务类型包含社保购买时
if (preVo.getServerItem().contains("社保") && (null != preVo.getExitSocialInfoList() if (preVo.getServerItem().contains("社保") && (null != preVo.getExitSocialInfoList()
...@@ -2634,7 +2719,7 @@ public class EmployeeRegistrationServiceImpl extends ServiceImpl<EmployeeRegistr ...@@ -2634,7 +2719,7 @@ public class EmployeeRegistrationServiceImpl extends ServiceImpl<EmployeeRegistr
EmployeeRegistration insert = new EmployeeRegistration(); EmployeeRegistration insert = new EmployeeRegistration();
BeanUtil.copyProperties(excel, insert); BeanUtil.copyProperties(excel, insert);
//表数据验重 //表数据验重
//表内数据重复 员工姓名、员工身份证号码、反馈类型 //表内数据重复 员工姓名、员工身份证号码、反馈类型、项目编码
StringBuilder errorTempBuilder = new StringBuilder(); StringBuilder errorTempBuilder = new StringBuilder();
errorTempBuilder.append(Common.isNullToString(excel.getDeptNo())) errorTempBuilder.append(Common.isNullToString(excel.getDeptNo()))
.append("_") .append("_")
......
...@@ -675,7 +675,7 @@ ...@@ -675,7 +675,7 @@
FROM t_dispatch_info_pre a FROM t_dispatch_info_pre a
left join view_contract b on a.EMP_IDCARD = b.EMP_IDCARD and a.DEPT_NO = b.DEPT_NO left join view_contract b on a.EMP_IDCARD = b.EMP_IDCARD and a.DEPT_NO = b.DEPT_NO
LEFT JOIN (select t.DEPART_NAME,t.LOWER_LIMIT,t.UPPER_LIMIT from sys_base_set_info t where t.BASE_TYPE = '0' and t.STATUS = 0 and t.DELETE_FLAG = '0' and LEFT JOIN (select t.DEPART_NAME,t.LOWER_LIMIT,t.UPPER_LIMIT from sys_base_set_info t where t.BASE_TYPE = '0' and t.STATUS = 0 and t.DELETE_FLAG = '0' and
DATE_FORMAT(t.APPLY_START_DATE,'%Y%m%d') <![CDATA[ <= ]]> DATE_FORMAT(CURDATE(),'%Y%m%d') and DATE_FORMAT(CURDATE(),'%Y%m%d') <![CDATA[ <= ]]> IFNULL(t.APPLY_END_DATE,DATE_FORMAT(CURDATE(),'%Y%m%d')) DATE_FORMAT(t.APPLY_START_DATE,'%Y-%m-%d') <![CDATA[ <= ]]> DATE_FORMAT(CURDATE(),'%Y-%m-%d') and DATE_FORMAT(CURDATE(),'%Y-%m-%d') <![CDATA[ <= ]]> IFNULL(t.APPLY_END_DATE,DATE_FORMAT(CURDATE(),'%Y-%m-%d'))
) c on c.DEPART_NAME = a.SOCIAL_HOUSEHOLD_NAME ) c on c.DEPART_NAME = a.SOCIAL_HOUSEHOLD_NAME
<where> <where>
a.DELETE_FLAG = '0' and a.IS_REFUSE ='1' a.DELETE_FLAG = '0' and a.IS_REFUSE ='1'
...@@ -761,7 +761,7 @@ ...@@ -761,7 +761,7 @@
if(#{type} = '1',concat('自动化手动-',a.customer_username),concat('自动化自动-',a.customer_username)) preName if(#{type} = '1',concat('自动化手动-',a.customer_username),concat('自动化自动-',a.customer_username)) preName
FROM t_dispatch_info_pre a FROM t_dispatch_info_pre a
LEFT JOIN (select t.DEPART_NAME,t.LOWER_LIMIT,t.UPPER_LIMIT from sys_base_set_info t where t.BASE_TYPE = '1' and t.STATUS = 0 and t.DELETE_FLAG = '0' and LEFT JOIN (select t.DEPART_NAME,t.LOWER_LIMIT,t.UPPER_LIMIT from sys_base_set_info t where t.BASE_TYPE = '1' and t.STATUS = 0 and t.DELETE_FLAG = '0' and
DATE_FORMAT(t.APPLY_START_DATE,'%Y%m%d') <![CDATA[ <= ]]> DATE_FORMAT(CURDATE(),'%Y%m%d') and DATE_FORMAT(CURDATE(),'%Y%m%d') <![CDATA[ <= ]]> IFNULL(t.APPLY_END_DATE,DATE_FORMAT(CURDATE(),'%Y%m%d')) DATE_FORMAT(t.APPLY_START_DATE,'%Y-%m-%d') <![CDATA[ <= ]]> DATE_FORMAT(CURDATE(),'%Y-%m-%d') and DATE_FORMAT(CURDATE(),'%Y-%m-%d') <![CDATA[ <= ]]> IFNULL(t.APPLY_END_DATE,DATE_FORMAT(CURDATE(),'%Y-%m-%d'))
) c on c.DEPART_NAME = a.PROVIDENT_HOUSEHOLD_NAME ) c on c.DEPART_NAME = a.PROVIDENT_HOUSEHOLD_NAME
,(select @i:=0) as itable ,(select @i:=0) as itable
<where> <where>
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment