import crypto from 'crypto' import prisma from '../lib/prisma' // 从证件号码提取出生日期 export function extractBirthDateFromIdCard(idCard: string): Date | null { // 18位身份证:7-14位为出生日期 YYYYMMDD if (idCard.length === 18) { const year = parseInt(idCard.substring(6, 10)) const month = parseInt(idCard.substring(10, 12)) const day = parseInt(idCard.substring(12, 14)) if (year && month && day) { return new Date(year, month - 1, day) } } // 15位老身份证:7-12位为出生日期 YYMMDD if (idCard.length === 15) { const year = parseInt('19' + idCard.substring(6, 8)) const month = parseInt(idCard.substring(8, 10)) const day = parseInt(idCard.substring(10, 12)) if (year && month && day) { return new Date(year, month - 1, day) } } return null } // 从证件号码提取性别(18位:第17位奇数为男,偶数为女;15位:第15位) export function extractGenderFromIdCard(idCard: string): string | null { if (idCard.length === 18) { const genderCode = parseInt(idCard.substring(16, 17)) return genderCode % 2 === 1 ? '男' : '女' } if (idCard.length === 15) { const genderCode = parseInt(idCard.substring(14, 15)) return genderCode % 2 === 1 ? '男' : '女' } return null } // 渐进式延迟退休固定算法 // 改革起始日:2025-01-01,过渡期15年至2039-12-31 // 男性:60→63岁,每4个月延迟1个月 // 女性干部:55→58岁,每4个月延迟1个月 // 女性工人:50→55岁,每2个月延迟1个月 const REFORM_START = new Date(2025, 0, 1) const BASE_MALE = 60 const BASE_FEMALE_CADRE = 55 const BASE_FEMALE_WORKER = 50 const TARGET_MALE = 63 const TARGET_FEMALE_CADRE = 58 const TARGET_FEMALE_WORKER = 55 const MALE_DELAY_INTERVAL = 4 // 每4个月延迟1个月 const FEMALE_CADRE_DELAY_INTERVAL = 4 const FEMALE_WORKER_DELAY_INTERVAL = 2 // 每2个月延迟1个月 // 计算从改革起始日到指定日期经过的完整月数 function calcMonthsSinceReform(date: Date = new Date()): number { const months = (date.getFullYear() - REFORM_START.getFullYear()) * 12 + (date.getMonth() - REFORM_START.getMonth()) return Math.max(0, months) } // 根据出生日期和性别计算个人基准退休年龄 function getBaseRetireAge(gender: string, femaleWorkerType: string | null): number { if (gender === '男') return BASE_MALE if (gender === '女') { return femaleWorkerType === 'WORKER' ? BASE_FEMALE_WORKER : BASE_FEMALE_CADRE } return BASE_MALE } // 根据出生日期和性别计算延迟间隔 function getDelayInterval(gender: string, femaleWorkerType: string | null): number { if (gender === '男') return MALE_DELAY_INTERVAL if (gender === '女') { return femaleWorkerType === 'WORKER' ? FEMALE_WORKER_DELAY_INTERVAL : FEMALE_CADRE_DELAY_INTERVAL } return MALE_DELAY_INTERVAL } // 根据出生日期和性别计算最大延迟月数 function getMaxDelayMonths(gender: string, femaleWorkerType: string | null): number { if (gender === '男') return (TARGET_MALE - BASE_MALE) * 12 if (gender === '女') { return femaleWorkerType === 'WORKER' ? (TARGET_FEMALE_WORKER - BASE_FEMALE_WORKER) * 12 : (TARGET_FEMALE_CADRE - BASE_FEMALE_CADRE) * 12 } return (TARGET_MALE - BASE_MALE) * 12 } // 计算个人的实际退休年龄(基于出生日期) // 原理:先算出此人达到基准退休年龄的日期,再算该日期距改革起始日过了多少个月, // 每N个月延迟1个月,得到个人实际退休年龄 export function calcIndividualRetireAge(birthDate: Date, gender: string, femaleWorkerType: string | null = null): { retireAge: number retireDate: Date delayMonths: number } { const baseAge = getBaseRetireAge(gender, femaleWorkerType) const delayInterval = getDelayInterval(gender, femaleWorkerType) const maxDelay = getMaxDelayMonths(gender, femaleWorkerType) // 达到基准退休年龄的日期 const baseRetireDate = new Date(birthDate) baseRetireDate.setFullYear(baseRetireDate.getFullYear() + baseAge) // 从改革起始日到达到基准退休年龄日期,经过的月数 const monthsSinceReform = calcMonthsSinceReform(baseRetireDate) // 延迟月数 = floor(月数 / 间隔),不超过最大延迟 const delayMonths = Math.min(maxDelay, Math.floor(monthsSinceReform / delayInterval)) // 实际退休年龄 = 基准年龄 + 延迟月数/12 const retireAge = baseAge + delayMonths / 12 // 实际退休日期 = 基准退休日期 + 延迟月数 const retireDate = new Date(baseRetireDate) retireDate.setMonth(retireDate.getMonth() + delayMonths) return { retireAge, retireDate, delayMonths } } // 计算当前改革进度(用于政策展示) export function calcCurrentRetireAges(date: Date = new Date()): { maleRetireAge: number femaleRetireAge: number femaleWorkerAge: number description: string } { const monthsElapsed = calcMonthsSinceReform(date) const maleDelayMonths = Math.min(36, Math.floor(monthsElapsed / MALE_DELAY_INTERVAL)) const femaleCadreDelayMonths = Math.min(36, Math.floor(monthsElapsed / FEMALE_CADRE_DELAY_INTERVAL)) const femaleWorkerDelayMonths = Math.min(60, Math.floor(monthsElapsed / FEMALE_WORKER_DELAY_INTERVAL)) const maleRetireAge = BASE_MALE + maleDelayMonths / 12 const femaleRetireAge = BASE_FEMALE_CADRE + femaleCadreDelayMonths / 12 const femaleWorkerAge = BASE_FEMALE_WORKER + femaleWorkerDelayMonths / 12 const description = `渐进式延迟退休改革(2025年1月1日起实施) 【改革规则】 - 男性职工:60岁 → 63岁,每4个月延迟1个月 - 女性干部/管理岗:55岁 → 58岁,每4个月延迟1个月 - 女性工人/操作岗:50岁 → 55岁,每2个月延迟1个月 【当前进度】截至${date.getFullYear()}年${date.getMonth() + 1}月,改革已实施${monthsElapsed}个月 - 男性当月退休年龄:${BASE_MALE}岁${maleDelayMonths > 0 ? `+${maleDelayMonths}个月` : ''} - 女性干部当月退休年龄:${BASE_FEMALE_CADRE}岁${femaleCadreDelayMonths > 0 ? `+${femaleCadreDelayMonths}个月` : ''} - 女性工人当月退休年龄:${BASE_FEMALE_WORKER}岁${femaleWorkerDelayMonths > 0 ? `+${femaleWorkerDelayMonths}个月` : ''} 【个人退休年龄】根据出生年月逐人计算: 达到基准退休年龄的时间点不同,延迟月数也不同。 例如:1965年1月出生的男性,2025年1月满60岁,延迟0个月,60岁退休;1965年5月出生的男性,2025年5月满60岁,延迟1个月,60岁1个月退休。 改革依据:2024年9月13日全国人大常委会《关于实施渐进式延迟法定退休年龄的决定》 过渡期:2025年1月1日至2039年12月31日(15年)` return { maleRetireAge, femaleRetireAge, femaleWorkerAge, description } } // 计算距退休天数(基于个人出生日期逐人计算) export function calcRetirementDaysLeft(birthDate: Date, gender: string, femaleWorkerType: string | null = null): number | null { const { retireDate } = calcIndividualRetireAge(birthDate, gender, femaleWorkerType) const now = new Date() const diffMs = retireDate.getTime() - now.getTime() return Math.floor(diffMs / (1000 * 60 * 60 * 24)) } // 检查并获取最新退休政策(懒加载:每月最多获取一次,存为 PENDING 待用户确认) export async function checkAndUpdateRetirementPolicy(orgId: string): Promise { const now = new Date() const latestPolicy = await prisma.retirementPolicy.findFirst({ where: { orgId }, orderBy: { createdAt: 'desc' }, }) // 如果本月已获取过(无论是否确认),则跳过 if (latestPolicy) { const updatedThisMonth = latestPolicy.createdAt.getMonth() === now.getMonth() && latestPolicy.createdAt.getFullYear() === now.getFullYear() if (updatedThisMonth) return } // 用固定算法计算当前退休年龄 const { maleRetireAge, femaleRetireAge, femaleWorkerAge, description } = calcCurrentRetireAges(now) // 计算内容 hash,判断内容是否变化 const contentHash = crypto.createHash('sha256').update(description).digest('hex') // 如果最新政策的 hash 相同,则不新增版本 if (latestPolicy && latestPolicy.contentHash === contentHash) { return } // 新建版本(PENDING 状态,待用户确认) const version = latestPolicy ? latestPolicy.version + 1 : 1 await prisma.retirementPolicy.create({ data: { orgId, version, content: description, contentHash, status: 'PENDING', maleRetireAge, femaleRetireAge, femaleWorkerAge, }, }) } // 用户确认退休政策,正式生效并更新员工退休天数 export async function confirmRetirementPolicy(orgId: string, policyId: string): Promise { const policy = await prisma.retirementPolicy.findFirst({ where: { id: policyId, orgId }, }) if (!policy) throw new Error('政策不存在') if (policy.status === 'CONFIRMED') return // 将旧的 CONFIRMED 政策标记为 SUPERSEDED await prisma.retirementPolicy.updateMany({ where: { orgId, status: 'CONFIRMED', id: { not: policyId } }, data: { status: 'SUPERSEDED' }, }) // 确认新政策生效 await prisma.retirementPolicy.update({ where: { id: policyId }, data: { status: 'CONFIRMED', confirmedAt: new Date() }, }) // 更新所有正式合同员工的距退休天数 await updateEmployeesRetirementDays(orgId) } // 批量更新员工距退休天数(基于个人出生日期 individually 计算) export async function updateEmployeesRetirementDays(orgId: string): Promise { // 查询有正式劳动合同的员工 const employees = await prisma.employee.findMany({ where: { orgId, contracts: { some: { contractType: { in: ['FIXED', 'UNFIXED'] } } }, }, select: { id: true, birthDate: true, gender: true, femaleWorkerType: true }, }) for (const emp of employees) { if (!emp.birthDate) continue const gender = emp.gender || '男' const daysLeft = calcRetirementDaysLeft(emp.birthDate, gender, emp.femaleWorkerType) if (daysLeft !== null) { await prisma.employee.update({ where: { id: emp.id }, data: { retirementDaysLeft: daysLeft }, }) } } }