import prisma from '../lib/prisma' import { decrypt } from '../lib/crypto' import { RiskAssessment } from '@prisma/client' function daysBetween(a: Date, b: Date): number { return Math.floor((a.getTime() - b.getTime()) / (1000 * 60 * 60 * 24)) } export function getChecklistForReason(reason: string): { key: string; label: string }[] { switch (reason) { case 'NEGOTIATED': return [ { key: 'compensation_paid', label: '是否已支付经济补偿金' }, { key: 'agreement_signed', label: '是否签署协商解除协议' }, { key: 'final_pay_ready', label: '是否结清最后工资' }, ] case 'FAULT': return [ { key: 'has_rules', label: '是否有规章制度依据' }, { key: 'has_evidence', label: '是否有违纪证据' }, { key: 'notify_union', label: '是否事先通知工会' }, { key: 'written_notice', label: '是否出具书面解除通知' }, ] case 'NONFAULT': return [ { key: 'medical_period_end', label: '医疗期是否已届满' }, { key: 'training_given', label: '是否经过培训或调岗' }, { key: 'compensation_paid', label: '是否支付经济补偿金' }, { key: 'advance_notice', label: '是否提前30天通知或支付代通知金' }, ] case 'LAYOFF': return [ { key: 'advance_notice_30', label: '是否提前30天向工会或全体职工说明' }, { key: 'listen_opinions', label: '是否听取工会或职工意见' }, { key: 'report_labor_dept', label: '是否向劳动行政部门报告' }, { key: 'compensation_paid', label: '是否支付经济补偿金' }, ] case 'EXPIRED': return [ { key: 'compensation_paid', label: '是否支付经济补偿金(如需)' }, { key: 'written_notice', label: '是否提前通知员工不续签' }, ] default: return [] } } export function assessRisk(employee: any, reason: string): { level: RiskAssessment; warnings: string[] } { const warnings: string[] = [] if (employee.isPregnant) { warnings.push('该员工在孕期/哺乳期,法律禁止以非过错理由解除') } if (employee.isWorkInjured) { warnings.push('工伤期间不得解除劳动合同') } if (employee.isInMedicalPeriod && reason !== 'FAULT') { warnings.push('医疗期内不得解除劳动合同(非过错理由)') } let level: RiskAssessment = 'SAFE' if (warnings.length > 0) { level = 'DANGER' } return { level, warnings } } export async function createTermination(orgId: string, userId: string, data: any) { const employee = await prisma.employee.findFirst({ where: { id: data.employeeId, orgId } }) if (!employee) { throw { code: 'NOT_FOUND', message: '员工不存在' } } const { level } = assessRisk(employee, data.reason) const record = await prisma.terminationRecord.create({ data: { orgId, employeeId: data.employeeId, reason: data.reason, terminationDate: new Date(data.terminationDate), compensation: data.compensation || 0, riskLevel: level, checklist: data.checklist || {}, remark: data.remark, createdBy: userId, }, }) await prisma.employee.update({ where: { id: data.employeeId }, data: { status: 'RESIGNED' }, }) await prisma.riskItem.updateMany({ where: { employeeId: data.employeeId, status: 'PENDING' }, data: { status: 'RESOLVED', resolvedAt: new Date() }, }) return { id: record.id } } export async function getTerminations(orgId: string, page: number, pageSize: number) { const skip = (page - 1) * pageSize const [total, records] = await Promise.all([ prisma.terminationRecord.count({ where: { orgId } }), prisma.terminationRecord.findMany({ where: { orgId }, include: { employee: true }, orderBy: { createdAt: 'desc' }, skip, take: pageSize, }), ]) return { items: records.map((r) => ({ id: r.id, employeeName: r.employee.name, department: r.employee.department, reason: r.reason, terminationDate: r.terminationDate.toISOString().slice(0, 10), compensation: r.compensation, riskLevel: r.riskLevel, createdAt: r.createdAt.toISOString().slice(0, 10), })), total, page, pageSize, totalPages: Math.ceil(total / pageSize), } } export function calculateCompensation(hireDate: Date, leaveDate: Date, monthlyWage: number, socialAvgWage: number = 0): { years: number remainingMonths: number compMonths: number totalPay: number capped: boolean } { const totalMonths = (leaveDate.getFullYear() - hireDate.getFullYear()) * 12 + (leaveDate.getMonth() - hireDate.getMonth()) const years = Math.floor(totalMonths / 12) const remainingMonths = totalMonths % 12 let compMonths: number if (remainingMonths >= 6) compMonths = years + 1 else if (remainingMonths > 0) compMonths = years + 0.5 else compMonths = years if (compMonths <= 0) compMonths = 0.5 let wage = monthlyWage let capped = false if (socialAvgWage > 0 && monthlyWage > socialAvgWage * 3) { wage = socialAvgWage * 3 compMonths = Math.min(compMonths, 12) capped = true } return { years, remainingMonths, compMonths, totalPay: wage * compMonths, capped } }