refactor: WorkProcess 业务逻辑复用原有 service
- HIRE 调用 createEmployee(含社保/公积金/薪资/部门记录) - RENEW/CUSTOM_CONTRACT 调用 addContract(含重复检查、试用期验证、风险检测) - TERMINATE/RESCIND 调用 createTerminationDraft + executeTermination(含风险评级、合规清单、社保截止) - CONFIRM 增加 probationEndDate 更新和 runRiskDetection - FLEXIBLE 调用 createEmployee + addContract - 前端 TERMINATE/RESCIND 表单增加 reason 和 compensation 字段 - 原有 Roster 入口保持不变,两条路径共用同一套 service
This commit is contained in:
@@ -1,6 +1,9 @@
|
||||
import prisma from '../lib/prisma'
|
||||
import { encrypt } from '../lib/crypto'
|
||||
import crypto from 'crypto'
|
||||
import { createDraft as createTerminationDraft, executeTermination, createResignation } from './termination.service'
|
||||
import { createEmployee, addContract, batchRenew } from './contract.service'
|
||||
import { runRiskDetection } from './risk.service'
|
||||
|
||||
// 13类流程定义
|
||||
export const PROCESS_TYPES: Record<string, { label: string; description: string; icon: string }> = {
|
||||
@@ -33,38 +36,25 @@ export const PROCESS_STATUS: Record<string, { label: string; color: string }> =
|
||||
export async function executeWorkProcess(processId: string, type: string, formData: any, orgId: string, userId: string) {
|
||||
switch (type) {
|
||||
case 'HIRE': {
|
||||
// 创建员工 + 合同
|
||||
const { name, department, hireDate, monthlySalary, phone, idCardNumber, gender, contractStartDate, contractEndDate, contractType = 'FIXED' } = formData
|
||||
const idCardHash = idCardNumber ? crypto.createHash('sha256').update(idCardNumber).digest('hex') : null
|
||||
const employee = await prisma.employee.create({
|
||||
data: {
|
||||
orgId,
|
||||
name,
|
||||
department: department || '未分配',
|
||||
hireDate: new Date(hireDate),
|
||||
monthlySalary: encrypt(String(monthlySalary || 0)),
|
||||
phone: phone || null,
|
||||
idCardNumber: idCardNumber ? encrypt(idCardNumber) : null,
|
||||
idCardHash,
|
||||
gender: gender || null,
|
||||
createdBy: userId,
|
||||
},
|
||||
const result = await createEmployee(orgId, userId, {
|
||||
name,
|
||||
department: department || '未分配',
|
||||
hireDate,
|
||||
monthlySalary: monthlySalary || 0,
|
||||
phone,
|
||||
idCardNumber,
|
||||
gender,
|
||||
contract: contractStartDate ? {
|
||||
contractType,
|
||||
startDate: contractStartDate,
|
||||
endDate: contractEndDate || undefined,
|
||||
contractYears: 3,
|
||||
probationMonths: 0,
|
||||
probationSalary: 0,
|
||||
} : undefined,
|
||||
})
|
||||
if (contractStartDate) {
|
||||
await prisma.laborContract.create({
|
||||
data: {
|
||||
orgId,
|
||||
employeeId: employee.id,
|
||||
startDate: new Date(contractStartDate),
|
||||
endDate: contractEndDate ? new Date(contractEndDate) : null,
|
||||
contractType: contractType as any,
|
||||
signMethod: 'PAPER',
|
||||
contractYears: 3,
|
||||
createdBy: userId,
|
||||
},
|
||||
})
|
||||
}
|
||||
return { employeeId: employee.id }
|
||||
return { employeeId: result.id }
|
||||
}
|
||||
case 'ONBOARD': {
|
||||
const { employeeId, hireDate } = formData
|
||||
@@ -79,17 +69,26 @@ export async function executeWorkProcess(processId: string, type: string, formDa
|
||||
case 'CONFIRM': {
|
||||
const { employeeId, confirmDate, regularSalary } = formData
|
||||
if (employeeId) {
|
||||
const updateData: any = {}
|
||||
if (regularSalary) {
|
||||
updateData.monthlySalary = encrypt(String(regularSalary))
|
||||
}
|
||||
if (confirmDate) {
|
||||
updateData.probationEndDate = new Date(confirmDate)
|
||||
}
|
||||
if (Object.keys(updateData).length > 0) {
|
||||
await prisma.employee.update({
|
||||
where: { id: employeeId },
|
||||
data: { monthlySalary: encrypt(String(regularSalary)) },
|
||||
data: updateData,
|
||||
})
|
||||
await runRiskDetection(orgId)
|
||||
}
|
||||
}
|
||||
return { employeeId }
|
||||
}
|
||||
case 'RENEW': {
|
||||
const { employeeId, oldContractId, newStartDate, newEndDate, newSalary, contractType = 'FIXED', contractYears = 3 } = formData
|
||||
// 截止旧合同
|
||||
if (oldContractId) {
|
||||
const oldEndDate = new Date(newStartDate)
|
||||
oldEndDate.setDate(oldEndDate.getDate() - 1)
|
||||
@@ -98,21 +97,16 @@ export async function executeWorkProcess(processId: string, type: string, formDa
|
||||
data: { endDate: oldEndDate },
|
||||
})
|
||||
}
|
||||
// 创建新合同(复用 addContract 的验证逻辑)
|
||||
if (employeeId) {
|
||||
const oldContract = oldContractId ? await prisma.laborContract.findUnique({ where: { id: oldContractId } }) : null
|
||||
const contract = await prisma.laborContract.create({
|
||||
data: {
|
||||
orgId,
|
||||
employeeId,
|
||||
signDate: new Date(),
|
||||
startDate: new Date(newStartDate),
|
||||
endDate: newEndDate ? new Date(newEndDate) : null,
|
||||
contractType: contractType as any,
|
||||
signMethod: 'PAPER',
|
||||
contractYears: Number(contractYears) || 3,
|
||||
renewalCount: (oldContract?.renewalCount || 0) + 1,
|
||||
createdBy: userId,
|
||||
},
|
||||
const result = await addContract(orgId, userId, {
|
||||
employeeId,
|
||||
startDate: newStartDate,
|
||||
endDate: newEndDate || undefined,
|
||||
contractType,
|
||||
contractYears: Number(contractYears) || 3,
|
||||
probationMonths: 0,
|
||||
probationSalary: 0,
|
||||
})
|
||||
if (newSalary) {
|
||||
await prisma.employee.update({
|
||||
@@ -120,39 +114,54 @@ export async function executeWorkProcess(processId: string, type: string, formDa
|
||||
data: { monthlySalary: encrypt(String(newSalary)) },
|
||||
})
|
||||
}
|
||||
return { employeeId, newContractId: contract.id }
|
||||
return { employeeId, newContractId: result.id }
|
||||
}
|
||||
return { employeeId }
|
||||
}
|
||||
case 'TERMINATE': {
|
||||
const { employeeId, contractId, terminateDate } = formData
|
||||
const { employeeId, contractId, terminateDate, reason = 'EXPIRED', compensation = 0 } = formData
|
||||
// 截止合同
|
||||
if (contractId) {
|
||||
await prisma.laborContract.update({
|
||||
where: { id: contractId },
|
||||
data: { endDate: new Date(terminateDate) },
|
||||
})
|
||||
}
|
||||
// 通过 termination service 创建解聘记录(含风险评级、合规清单)
|
||||
if (employeeId) {
|
||||
await prisma.employee.update({
|
||||
where: { id: employeeId },
|
||||
data: { status: 'RESIGNED' },
|
||||
const draft = await createTerminationDraft(orgId, userId, {
|
||||
employeeId,
|
||||
type: 'TERMINATION',
|
||||
reason,
|
||||
terminationDate: terminateDate,
|
||||
compensation,
|
||||
})
|
||||
// 直接执行(WorkProcess 流程审批已通过)
|
||||
await executeTermination(orgId, draft.id, userId)
|
||||
return { employeeId, terminationRecordId: draft.id }
|
||||
}
|
||||
return { employeeId }
|
||||
}
|
||||
case 'RESCIND': {
|
||||
const { employeeId, contractId, rescindDate } = formData
|
||||
const { employeeId, contractId, rescindDate, reason = 'NEGOTIATED', compensation = 0 } = formData
|
||||
// 截止合同
|
||||
if (contractId) {
|
||||
await prisma.laborContract.update({
|
||||
where: { id: contractId },
|
||||
data: { endDate: new Date(rescindDate) },
|
||||
})
|
||||
}
|
||||
// 通过 termination service 创建解聘记录(含风险评级、合规清单)
|
||||
if (employeeId) {
|
||||
await prisma.employee.update({
|
||||
where: { id: employeeId },
|
||||
data: { status: 'RESIGNED' },
|
||||
const draft = await createTerminationDraft(orgId, userId, {
|
||||
employeeId,
|
||||
type: 'TERMINATION',
|
||||
reason,
|
||||
terminationDate: rescindDate,
|
||||
compensation,
|
||||
})
|
||||
await executeTermination(orgId, draft.id, userId)
|
||||
return { employeeId, terminationRecordId: draft.id }
|
||||
}
|
||||
return { employeeId }
|
||||
}
|
||||
@@ -179,53 +188,40 @@ export async function executeWorkProcess(processId: string, type: string, formDa
|
||||
case 'CUSTOM_CONTRACT': {
|
||||
const { employeeId, contractStartDate, contractEndDate, contractType = 'FIXED', signMethod = 'PAPER', contractYears = 3 } = formData
|
||||
if (employeeId) {
|
||||
const contract = await prisma.laborContract.create({
|
||||
data: {
|
||||
orgId,
|
||||
employeeId,
|
||||
signDate: new Date(),
|
||||
startDate: new Date(contractStartDate),
|
||||
endDate: contractEndDate ? new Date(contractEndDate) : null,
|
||||
contractType: contractType as any,
|
||||
signMethod: signMethod as any,
|
||||
contractYears: Number(contractYears) || 3,
|
||||
createdBy: userId,
|
||||
},
|
||||
const result = await addContract(orgId, userId, {
|
||||
employeeId,
|
||||
startDate: contractStartDate,
|
||||
endDate: contractEndDate || undefined,
|
||||
contractType,
|
||||
signMethod,
|
||||
contractYears: Number(contractYears) || 3,
|
||||
probationMonths: 0,
|
||||
probationSalary: 0,
|
||||
})
|
||||
return { employeeId, newContractId: contract.id }
|
||||
return { employeeId, newContractId: result.id }
|
||||
}
|
||||
return {}
|
||||
}
|
||||
case 'FLEXIBLE': {
|
||||
const { name, phone, idCardNumber, department, agreementStartDate, agreementEndDate, payMethod } = formData
|
||||
const idCardHash = idCardNumber ? crypto.createHash('sha256').update(idCardNumber).digest('hex') : null
|
||||
const employee = await prisma.employee.create({
|
||||
data: {
|
||||
orgId,
|
||||
name,
|
||||
department: department || '灵活用工',
|
||||
hireDate: new Date(agreementStartDate),
|
||||
monthlySalary: encrypt('0'),
|
||||
phone: phone || null,
|
||||
idCardNumber: idCardNumber ? encrypt(idCardNumber) : null,
|
||||
idCardHash,
|
||||
createdBy: userId,
|
||||
},
|
||||
const empResult = await createEmployee(orgId, userId, {
|
||||
name,
|
||||
department: department || '灵活用工',
|
||||
hireDate: agreementStartDate,
|
||||
monthlySalary: 0,
|
||||
phone,
|
||||
idCardNumber,
|
||||
})
|
||||
const contract = await prisma.laborContract.create({
|
||||
data: {
|
||||
orgId,
|
||||
employeeId: employee.id,
|
||||
signDate: new Date(),
|
||||
startDate: new Date(agreementStartDate),
|
||||
endDate: agreementEndDate ? new Date(agreementEndDate) : null,
|
||||
contractType: 'LABOR',
|
||||
signMethod: 'PAPER',
|
||||
contractYears: 1,
|
||||
createdBy: userId,
|
||||
},
|
||||
const contractResult = await addContract(orgId, userId, {
|
||||
employeeId: empResult.id,
|
||||
startDate: agreementStartDate,
|
||||
endDate: agreementEndDate || undefined,
|
||||
contractType: 'LABOR',
|
||||
contractYears: 1,
|
||||
probationMonths: 0,
|
||||
probationSalary: 0,
|
||||
})
|
||||
return { employeeId: employee.id, newContractId: contract.id }
|
||||
return { employeeId: empResult.id, newContractId: contractResult.id }
|
||||
}
|
||||
case 'INFO_SUBMIT': {
|
||||
const { employeeId, ...updateFields } = formData
|
||||
|
||||
@@ -108,11 +108,15 @@ const FORM_FIELDS: Record<string, { key: string; label: string; type: 'text' | '
|
||||
{ key: 'employeeId', label: '员工ID', type: 'text' },
|
||||
{ key: 'contractId', label: '合同ID', type: 'text' },
|
||||
{ key: 'terminateDate', label: '终止日期', type: 'date' },
|
||||
{ key: 'reason', label: '终止原因', type: 'select', options: ['EXPIRED', 'NEGOTIATED', 'FAULT', 'NONFAULT', 'LAYOFF'] },
|
||||
{ key: 'compensation', label: '经济补偿金', type: 'number' },
|
||||
],
|
||||
RESCIND: [
|
||||
{ key: 'employeeId', label: '员工ID', type: 'text' },
|
||||
{ key: 'contractId', label: '合同ID', type: 'text' },
|
||||
{ key: 'rescindDate', label: '解除日期', type: 'date' },
|
||||
{ key: 'reason', label: '解除原因', type: 'select', options: ['NEGOTIATED', 'FAULT', 'NONFAULT', 'LAYOFF'] },
|
||||
{ key: 'compensation', label: '经济补偿金', type: 'number' },
|
||||
],
|
||||
LEAVING_CERT: [
|
||||
{ key: 'employeeName', label: '员工姓名', type: 'text' },
|
||||
|
||||
Reference in New Issue
Block a user