import { PrismaClient } from '@prisma/client'; const prisma = new PrismaClient(); async function ensureUser(name: string, username: string, deptName: string, employeeNo: string, passwordHash: string) { const existing = await prisma.user.findFirst({ where: { OR: [{ username }, { displayName: name }] } }); if (existing) return existing.id; const dept = (await prisma.department.findFirst({ where: { name: deptName } })) || (await prisma.department.findFirst({ where: { name: { contains: '研发' } } })) || (await prisma.department.findFirst({ where: { parentId: { not: null } } })); if (!dept) throw new Error(`没有部门可挂 ${name}`); const empRole = await prisma.role.findFirst({ where: { code: 'employee' } }); if (!empRole) throw new Error('没有 employee 角色'); let emp = await prisma.employee.findFirst({ where: { OR: [{ name }, { employeeNo }] } }); if (!emp) { emp = await prisma.employee.create({ data: { name, employeeNo, departmentId: dept.id, title: '员工', employmentStatus: 'LEFT', remark: `OA 报销有此人(原部门 ${deptName}),人事花名册未导入,补建后挂单据,账号停用。`, }, }); } const user = await prisma.user.create({ data: { username, displayName: name, passwordHash, status: 'DISABLED', employeeId: emp.id, }, }); await prisma.userRole.create({ data: { userId: user.id, roleId: empRole.id } }); console.log('created leftover', name, user.id, 'dept', dept.name); return user.id; } async function main() { const admin = await prisma.user.findFirst({ where: { username: 'admin' } }); if (!admin) throw new Error('no admin'); await ensureUser('李乐菡', 'lilehan', '项目一部', 'E0115', admin.passwordHash); const users = await prisma.user.findMany(); const byName = new Map(users.map((u) => [u.displayName, u.id])); const ALIAS: Record = { 张靖妍: '张婧妍' }; for (const [from, to] of Object.entries(ALIAS)) { const uid = byName.get(to); if (uid) byName.set(from, uid); } const expenses = await prisma.expenseClaim.findMany({ select: { id: true, remark: true, applicantId: true, status: true } }); let n = 0; for (const e of expenses) { const name = (e.remark || '').split(' / ')[0]?.trim(); if (!name || name === '系统管理员') continue; const uid = byName.get(name); if (!uid || uid === e.applicantId) continue; await prisma.expenseClaim.update({ where: { id: e.id }, data: { applicantId: uid } }); n += 1; } const loans = await prisma.loanRecord.findMany({ select: { id: true, remark: true, applicantId: true } }); let ln = 0; for (const e of loans) { const name = (e.remark || '').split(' / ')[0]?.trim(); if (!name || name === '系统管理员') continue; const uid = byName.get(name); if (!uid || uid === e.applicantId) continue; await prisma.loanRecord.update({ where: { id: e.id }, data: { applicantId: uid } }); ln += 1; } const approvers = await prisma.user.findMany({ where: { status: 'ACTIVE', roles: { some: { role: { code: { in: ['admin', 'finance', 'owner'] } } } } }, }); const pendingExp = await prisma.expenseClaim.findMany({ where: { status: 'PENDING' } }); const pendingLoan = await prisma.loanRecord.findMany({ where: { status: 'PENDING' } }); let tasks = 0; for (const row of pendingExp) { for (const u of approvers) { const hit = await prisma.approvalTask.findFirst({ where: { bizType: 'EXPENSE_APPROVAL', bizId: row.id, assigneeId: u.id, status: 'PENDING' }, }); if (hit) continue; await prisma.approvalTask.create({ data: { title: `报销确认:${row.claimNo}`, bizType: 'EXPENSE_APPROVAL', bizId: row.id, assigneeId: u.id, }, }); tasks += 1; } } for (const row of pendingLoan) { for (const u of approvers) { const hit = await prisma.approvalTask.findFirst({ where: { bizType: 'LOAN_APPROVAL', bizId: row.id, assigneeId: u.id, status: 'PENDING' }, }); if (hit) continue; await prisma.approvalTask.create({ data: { title: `借款确认:${row.loanNo}`, bizType: 'LOAN_APPROVAL', bizId: row.id, assigneeId: u.id, }, }); tasks += 1; } } const left = await prisma.expenseClaim.count({ where: { applicantId: admin.id } }); console.log(JSON.stringify({ rematchedExpenses: n, rematchedLoans: ln, approvalTasks: tasks, adminStillHolds: left })); } main() .catch((e) => { console.error(e); process.exit(1); }) .finally(() => prisma.$disconnect());