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 prisma from '../lib/prisma'
|
||||||
import { encrypt } from '../lib/crypto'
|
import { encrypt } from '../lib/crypto'
|
||||||
import crypto from '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类流程定义
|
// 13类流程定义
|
||||||
export const PROCESS_TYPES: Record<string, { label: string; description: string; icon: string }> = {
|
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) {
|
export async function executeWorkProcess(processId: string, type: string, formData: any, orgId: string, userId: string) {
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case 'HIRE': {
|
case 'HIRE': {
|
||||||
// 创建员工 + 合同
|
|
||||||
const { name, department, hireDate, monthlySalary, phone, idCardNumber, gender, contractStartDate, contractEndDate, contractType = 'FIXED' } = formData
|
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 result = await createEmployee(orgId, userId, {
|
||||||
const employee = await prisma.employee.create({
|
name,
|
||||||
data: {
|
department: department || '未分配',
|
||||||
orgId,
|
hireDate,
|
||||||
name,
|
monthlySalary: monthlySalary || 0,
|
||||||
department: department || '未分配',
|
phone,
|
||||||
hireDate: new Date(hireDate),
|
idCardNumber,
|
||||||
monthlySalary: encrypt(String(monthlySalary || 0)),
|
gender,
|
||||||
phone: phone || null,
|
contract: contractStartDate ? {
|
||||||
idCardNumber: idCardNumber ? encrypt(idCardNumber) : null,
|
contractType,
|
||||||
idCardHash,
|
startDate: contractStartDate,
|
||||||
gender: gender || null,
|
endDate: contractEndDate || undefined,
|
||||||
createdBy: userId,
|
contractYears: 3,
|
||||||
},
|
probationMonths: 0,
|
||||||
|
probationSalary: 0,
|
||||||
|
} : undefined,
|
||||||
})
|
})
|
||||||
if (contractStartDate) {
|
return { employeeId: result.id }
|
||||||
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 }
|
|
||||||
}
|
}
|
||||||
case 'ONBOARD': {
|
case 'ONBOARD': {
|
||||||
const { employeeId, hireDate } = formData
|
const { employeeId, hireDate } = formData
|
||||||
@@ -79,17 +69,26 @@ export async function executeWorkProcess(processId: string, type: string, formDa
|
|||||||
case 'CONFIRM': {
|
case 'CONFIRM': {
|
||||||
const { employeeId, confirmDate, regularSalary } = formData
|
const { employeeId, confirmDate, regularSalary } = formData
|
||||||
if (employeeId) {
|
if (employeeId) {
|
||||||
|
const updateData: any = {}
|
||||||
if (regularSalary) {
|
if (regularSalary) {
|
||||||
|
updateData.monthlySalary = encrypt(String(regularSalary))
|
||||||
|
}
|
||||||
|
if (confirmDate) {
|
||||||
|
updateData.probationEndDate = new Date(confirmDate)
|
||||||
|
}
|
||||||
|
if (Object.keys(updateData).length > 0) {
|
||||||
await prisma.employee.update({
|
await prisma.employee.update({
|
||||||
where: { id: employeeId },
|
where: { id: employeeId },
|
||||||
data: { monthlySalary: encrypt(String(regularSalary)) },
|
data: updateData,
|
||||||
})
|
})
|
||||||
|
await runRiskDetection(orgId)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return { employeeId }
|
return { employeeId }
|
||||||
}
|
}
|
||||||
case 'RENEW': {
|
case 'RENEW': {
|
||||||
const { employeeId, oldContractId, newStartDate, newEndDate, newSalary, contractType = 'FIXED', contractYears = 3 } = formData
|
const { employeeId, oldContractId, newStartDate, newEndDate, newSalary, contractType = 'FIXED', contractYears = 3 } = formData
|
||||||
|
// 截止旧合同
|
||||||
if (oldContractId) {
|
if (oldContractId) {
|
||||||
const oldEndDate = new Date(newStartDate)
|
const oldEndDate = new Date(newStartDate)
|
||||||
oldEndDate.setDate(oldEndDate.getDate() - 1)
|
oldEndDate.setDate(oldEndDate.getDate() - 1)
|
||||||
@@ -98,21 +97,16 @@ export async function executeWorkProcess(processId: string, type: string, formDa
|
|||||||
data: { endDate: oldEndDate },
|
data: { endDate: oldEndDate },
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
// 创建新合同(复用 addContract 的验证逻辑)
|
||||||
if (employeeId) {
|
if (employeeId) {
|
||||||
const oldContract = oldContractId ? await prisma.laborContract.findUnique({ where: { id: oldContractId } }) : null
|
const result = await addContract(orgId, userId, {
|
||||||
const contract = await prisma.laborContract.create({
|
employeeId,
|
||||||
data: {
|
startDate: newStartDate,
|
||||||
orgId,
|
endDate: newEndDate || undefined,
|
||||||
employeeId,
|
contractType,
|
||||||
signDate: new Date(),
|
contractYears: Number(contractYears) || 3,
|
||||||
startDate: new Date(newStartDate),
|
probationMonths: 0,
|
||||||
endDate: newEndDate ? new Date(newEndDate) : null,
|
probationSalary: 0,
|
||||||
contractType: contractType as any,
|
|
||||||
signMethod: 'PAPER',
|
|
||||||
contractYears: Number(contractYears) || 3,
|
|
||||||
renewalCount: (oldContract?.renewalCount || 0) + 1,
|
|
||||||
createdBy: userId,
|
|
||||||
},
|
|
||||||
})
|
})
|
||||||
if (newSalary) {
|
if (newSalary) {
|
||||||
await prisma.employee.update({
|
await prisma.employee.update({
|
||||||
@@ -120,39 +114,54 @@ export async function executeWorkProcess(processId: string, type: string, formDa
|
|||||||
data: { monthlySalary: encrypt(String(newSalary)) },
|
data: { monthlySalary: encrypt(String(newSalary)) },
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
return { employeeId, newContractId: contract.id }
|
return { employeeId, newContractId: result.id }
|
||||||
}
|
}
|
||||||
return { employeeId }
|
return { employeeId }
|
||||||
}
|
}
|
||||||
case 'TERMINATE': {
|
case 'TERMINATE': {
|
||||||
const { employeeId, contractId, terminateDate } = formData
|
const { employeeId, contractId, terminateDate, reason = 'EXPIRED', compensation = 0 } = formData
|
||||||
|
// 截止合同
|
||||||
if (contractId) {
|
if (contractId) {
|
||||||
await prisma.laborContract.update({
|
await prisma.laborContract.update({
|
||||||
where: { id: contractId },
|
where: { id: contractId },
|
||||||
data: { endDate: new Date(terminateDate) },
|
data: { endDate: new Date(terminateDate) },
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
// 通过 termination service 创建解聘记录(含风险评级、合规清单)
|
||||||
if (employeeId) {
|
if (employeeId) {
|
||||||
await prisma.employee.update({
|
const draft = await createTerminationDraft(orgId, userId, {
|
||||||
where: { id: employeeId },
|
employeeId,
|
||||||
data: { status: 'RESIGNED' },
|
type: 'TERMINATION',
|
||||||
|
reason,
|
||||||
|
terminationDate: terminateDate,
|
||||||
|
compensation,
|
||||||
})
|
})
|
||||||
|
// 直接执行(WorkProcess 流程审批已通过)
|
||||||
|
await executeTermination(orgId, draft.id, userId)
|
||||||
|
return { employeeId, terminationRecordId: draft.id }
|
||||||
}
|
}
|
||||||
return { employeeId }
|
return { employeeId }
|
||||||
}
|
}
|
||||||
case 'RESCIND': {
|
case 'RESCIND': {
|
||||||
const { employeeId, contractId, rescindDate } = formData
|
const { employeeId, contractId, rescindDate, reason = 'NEGOTIATED', compensation = 0 } = formData
|
||||||
|
// 截止合同
|
||||||
if (contractId) {
|
if (contractId) {
|
||||||
await prisma.laborContract.update({
|
await prisma.laborContract.update({
|
||||||
where: { id: contractId },
|
where: { id: contractId },
|
||||||
data: { endDate: new Date(rescindDate) },
|
data: { endDate: new Date(rescindDate) },
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
// 通过 termination service 创建解聘记录(含风险评级、合规清单)
|
||||||
if (employeeId) {
|
if (employeeId) {
|
||||||
await prisma.employee.update({
|
const draft = await createTerminationDraft(orgId, userId, {
|
||||||
where: { id: employeeId },
|
employeeId,
|
||||||
data: { status: 'RESIGNED' },
|
type: 'TERMINATION',
|
||||||
|
reason,
|
||||||
|
terminationDate: rescindDate,
|
||||||
|
compensation,
|
||||||
})
|
})
|
||||||
|
await executeTermination(orgId, draft.id, userId)
|
||||||
|
return { employeeId, terminationRecordId: draft.id }
|
||||||
}
|
}
|
||||||
return { employeeId }
|
return { employeeId }
|
||||||
}
|
}
|
||||||
@@ -179,53 +188,40 @@ export async function executeWorkProcess(processId: string, type: string, formDa
|
|||||||
case 'CUSTOM_CONTRACT': {
|
case 'CUSTOM_CONTRACT': {
|
||||||
const { employeeId, contractStartDate, contractEndDate, contractType = 'FIXED', signMethod = 'PAPER', contractYears = 3 } = formData
|
const { employeeId, contractStartDate, contractEndDate, contractType = 'FIXED', signMethod = 'PAPER', contractYears = 3 } = formData
|
||||||
if (employeeId) {
|
if (employeeId) {
|
||||||
const contract = await prisma.laborContract.create({
|
const result = await addContract(orgId, userId, {
|
||||||
data: {
|
employeeId,
|
||||||
orgId,
|
startDate: contractStartDate,
|
||||||
employeeId,
|
endDate: contractEndDate || undefined,
|
||||||
signDate: new Date(),
|
contractType,
|
||||||
startDate: new Date(contractStartDate),
|
signMethod,
|
||||||
endDate: contractEndDate ? new Date(contractEndDate) : null,
|
contractYears: Number(contractYears) || 3,
|
||||||
contractType: contractType as any,
|
probationMonths: 0,
|
||||||
signMethod: signMethod as any,
|
probationSalary: 0,
|
||||||
contractYears: Number(contractYears) || 3,
|
|
||||||
createdBy: userId,
|
|
||||||
},
|
|
||||||
})
|
})
|
||||||
return { employeeId, newContractId: contract.id }
|
return { employeeId, newContractId: result.id }
|
||||||
}
|
}
|
||||||
return {}
|
return {}
|
||||||
}
|
}
|
||||||
case 'FLEXIBLE': {
|
case 'FLEXIBLE': {
|
||||||
const { name, phone, idCardNumber, department, agreementStartDate, agreementEndDate, payMethod } = formData
|
const { name, phone, idCardNumber, department, agreementStartDate, agreementEndDate, payMethod } = formData
|
||||||
const idCardHash = idCardNumber ? crypto.createHash('sha256').update(idCardNumber).digest('hex') : null
|
const empResult = await createEmployee(orgId, userId, {
|
||||||
const employee = await prisma.employee.create({
|
name,
|
||||||
data: {
|
department: department || '灵活用工',
|
||||||
orgId,
|
hireDate: agreementStartDate,
|
||||||
name,
|
monthlySalary: 0,
|
||||||
department: department || '灵活用工',
|
phone,
|
||||||
hireDate: new Date(agreementStartDate),
|
idCardNumber,
|
||||||
monthlySalary: encrypt('0'),
|
|
||||||
phone: phone || null,
|
|
||||||
idCardNumber: idCardNumber ? encrypt(idCardNumber) : null,
|
|
||||||
idCardHash,
|
|
||||||
createdBy: userId,
|
|
||||||
},
|
|
||||||
})
|
})
|
||||||
const contract = await prisma.laborContract.create({
|
const contractResult = await addContract(orgId, userId, {
|
||||||
data: {
|
employeeId: empResult.id,
|
||||||
orgId,
|
startDate: agreementStartDate,
|
||||||
employeeId: employee.id,
|
endDate: agreementEndDate || undefined,
|
||||||
signDate: new Date(),
|
contractType: 'LABOR',
|
||||||
startDate: new Date(agreementStartDate),
|
contractYears: 1,
|
||||||
endDate: agreementEndDate ? new Date(agreementEndDate) : null,
|
probationMonths: 0,
|
||||||
contractType: 'LABOR',
|
probationSalary: 0,
|
||||||
signMethod: 'PAPER',
|
|
||||||
contractYears: 1,
|
|
||||||
createdBy: userId,
|
|
||||||
},
|
|
||||||
})
|
})
|
||||||
return { employeeId: employee.id, newContractId: contract.id }
|
return { employeeId: empResult.id, newContractId: contractResult.id }
|
||||||
}
|
}
|
||||||
case 'INFO_SUBMIT': {
|
case 'INFO_SUBMIT': {
|
||||||
const { employeeId, ...updateFields } = formData
|
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: 'employeeId', label: '员工ID', type: 'text' },
|
||||||
{ key: 'contractId', label: '合同ID', type: 'text' },
|
{ key: 'contractId', label: '合同ID', type: 'text' },
|
||||||
{ key: 'terminateDate', label: '终止日期', type: 'date' },
|
{ key: 'terminateDate', label: '终止日期', type: 'date' },
|
||||||
|
{ key: 'reason', label: '终止原因', type: 'select', options: ['EXPIRED', 'NEGOTIATED', 'FAULT', 'NONFAULT', 'LAYOFF'] },
|
||||||
|
{ key: 'compensation', label: '经济补偿金', type: 'number' },
|
||||||
],
|
],
|
||||||
RESCIND: [
|
RESCIND: [
|
||||||
{ key: 'employeeId', label: '员工ID', type: 'text' },
|
{ key: 'employeeId', label: '员工ID', type: 'text' },
|
||||||
{ key: 'contractId', label: '合同ID', type: 'text' },
|
{ key: 'contractId', label: '合同ID', type: 'text' },
|
||||||
{ key: 'rescindDate', label: '解除日期', type: 'date' },
|
{ key: 'rescindDate', label: '解除日期', type: 'date' },
|
||||||
|
{ key: 'reason', label: '解除原因', type: 'select', options: ['NEGOTIATED', 'FAULT', 'NONFAULT', 'LAYOFF'] },
|
||||||
|
{ key: 'compensation', label: '经济补偿金', type: 'number' },
|
||||||
],
|
],
|
||||||
LEAVING_CERT: [
|
LEAVING_CERT: [
|
||||||
{ key: 'employeeName', label: '员工姓名', type: 'text' },
|
{ key: 'employeeName', label: '员工姓名', type: 'text' },
|
||||||
|
|||||||
Reference in New Issue
Block a user