0df8aa77d9
- 员工花名册管理(加密存储、导入导出) - 薪酬管理(发薪批次、薪酬模版、加班费计算、工资条) - 社保公积金(多城市配置、版本管理、基数调整) - 解聘管理(6步流程、证据链、工作交接) - AI 助手(合同审查、风险预测、RAG 知识库) - Dashboard 仪表盘 - 设置与通知
151 lines
4.5 KiB
TypeScript
151 lines
4.5 KiB
TypeScript
/**
|
|
* 一次性迁移脚本:为现有员工创建初始版本记录
|
|
* 运行方式:npx tsx scripts/migrate-records.ts
|
|
*/
|
|
import prisma from '../src/lib/prisma.js'
|
|
import { decrypt } from '../src/lib/crypto.js'
|
|
|
|
function dateToMonth(date: Date): string {
|
|
const y = date.getFullYear()
|
|
const m = String(date.getMonth() + 1).padStart(2, '0')
|
|
return `${y}-${m}`
|
|
}
|
|
|
|
function prevMonth(month: string): string {
|
|
const [y, m] = month.split('-').map(Number)
|
|
const d = new Date(y, m - 2, 1)
|
|
return `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, '0')}`
|
|
}
|
|
|
|
async function main() {
|
|
const employees = await prisma.employee.findMany({
|
|
include: {
|
|
terminations: { orderBy: { terminationDate: 'desc' }, take: 1 },
|
|
salaryChanges: { orderBy: { createdAt: 'desc' }, take: 1 },
|
|
socialInsRecords: { take: 1 },
|
|
housingFundRecords: { take: 1 },
|
|
departmentRecords: { take: 1 },
|
|
},
|
|
})
|
|
|
|
console.log(`Found ${employees.length} employees to migrate`)
|
|
|
|
for (const emp of employees) {
|
|
const hireMonth = dateToMonth(emp.hireDate)
|
|
const termination = emp.terminations[0]
|
|
const endMonth = termination ? dateToMonth(termination.terminationDate) : null
|
|
|
|
// 解密月薪获取数值
|
|
let salaryNum = 0
|
|
try {
|
|
salaryNum = parseFloat(decrypt(emp.monthlySalary)) || 0
|
|
} catch {
|
|
salaryNum = parseFloat(emp.monthlySalary) || 0
|
|
}
|
|
|
|
const socialInsBase = emp.socialInsBase ?? salaryNum
|
|
const housingFundBase = emp.housingFundBase ?? salaryNum
|
|
|
|
// 1. 社保缴费记录(仅当尚无记录时创建)
|
|
if (emp.socialInsRecords.length === 0) {
|
|
await prisma.employeeSocialInsRecord.create({
|
|
data: {
|
|
orgId: emp.orgId,
|
|
employeeId: emp.id,
|
|
startMonth: emp.socialInsStartMonth || hireMonth,
|
|
endMonth: endMonth || emp.socialInsEndMonth || null,
|
|
base: socialInsBase,
|
|
changeType: 'ONBOARDING',
|
|
createdBy: emp.createdBy,
|
|
},
|
|
})
|
|
}
|
|
|
|
// 2. 公积金缴费记录
|
|
if (emp.housingFundRecords.length === 0) {
|
|
await prisma.employeeHousingFundRecord.create({
|
|
data: {
|
|
orgId: emp.orgId,
|
|
employeeId: emp.id,
|
|
startMonth: emp.housingFundStartMonth || hireMonth,
|
|
endMonth: endMonth || emp.housingFundEndMonth || null,
|
|
base: housingFundBase,
|
|
changeType: 'ONBOARDING',
|
|
createdBy: emp.createdBy,
|
|
},
|
|
})
|
|
}
|
|
|
|
// 3. 薪资变更记录(仅当尚无记录时创建)
|
|
if (emp.salaryChanges.length === 0) {
|
|
await prisma.salaryChangeRecord.create({
|
|
data: {
|
|
orgId: emp.orgId,
|
|
employeeId: emp.id,
|
|
oldSalary: 0,
|
|
newSalary: salaryNum,
|
|
effectiveDate: emp.hireDate,
|
|
effectiveMonth: hireMonth,
|
|
endMonth: null,
|
|
changeType: 'ONBOARDING',
|
|
createdBy: emp.createdBy,
|
|
},
|
|
})
|
|
} else {
|
|
// 已有记录但缺少 effectiveMonth/endMonth/changeType,补充
|
|
const latest = emp.salaryChanges[0]
|
|
if (!latest.effectiveMonth || !latest.changeType) {
|
|
await prisma.salaryChangeRecord.update({
|
|
where: { id: latest.id },
|
|
data: {
|
|
effectiveMonth: dateToMonth(latest.effectiveDate),
|
|
changeType: latest.changeType || 'SALARY_CHANGE',
|
|
},
|
|
})
|
|
}
|
|
}
|
|
|
|
// 4. 部门变更记录
|
|
if (emp.departmentRecords.length === 0) {
|
|
await prisma.employeeDepartmentRecord.create({
|
|
data: {
|
|
orgId: emp.orgId,
|
|
employeeId: emp.id,
|
|
oldDepartment: '',
|
|
newDepartment: emp.department,
|
|
effectiveMonth: hireMonth,
|
|
endMonth: null,
|
|
changeType: 'ONBOARDING',
|
|
createdBy: emp.createdBy,
|
|
},
|
|
})
|
|
}
|
|
|
|
// 5. 同步 Employee 便捷字段
|
|
await prisma.employee.update({
|
|
where: { id: emp.id },
|
|
data: {
|
|
socialInsStartMonth: emp.socialInsStartMonth || hireMonth,
|
|
socialInsEndMonth: endMonth || emp.socialInsEndMonth || null,
|
|
socialInsBase,
|
|
housingFundStartMonth: emp.housingFundStartMonth || hireMonth,
|
|
housingFundEndMonth: endMonth || emp.housingFundEndMonth || null,
|
|
housingFundBase,
|
|
},
|
|
})
|
|
|
|
console.log(` ✓ ${emp.name} (${emp.department}) — records created/synced`)
|
|
}
|
|
|
|
console.log('\nMigration complete!')
|
|
}
|
|
|
|
main()
|
|
.catch((e) => {
|
|
console.error('Migration failed:', e)
|
|
process.exit(1)
|
|
})
|
|
.finally(async () => {
|
|
await prisma.$disconnect()
|
|
})
|