/** * Siembra los usuarios del ecosistema FRASA. * * - Lee reference/vendedores.json (gitignored). Si no existe, solo crea el * usuario admin y avisa. * - Username = nombre completo normalizado (minúsculas, sin acentos, espacios * simples). Password inicial de todos: 'Frasa2026' (bcrypt cost 12). * - Upsert por username: NO resetea el password de usuarios existentes. * Con `--reset-passwords` sí lo restablece al inicial. * - Admin: username 'admin', password de env ADMIN_PASSWORD (default * 'Frasa2026'), rol 'admin'. * * Uso: npm run seed:usuarios [-- --reset-passwords] */ import fs from 'node:fs' import path from 'node:path' import bcrypt from 'bcryptjs' import { prisma } from '../src/services/prisma.js' import { normalizarUsername } from '../src/services/auth.service.js' import { config } from '../src/config/index.js' const PASSWORD_INICIAL = 'Frasa2026' const BCRYPT_COST = 12 export interface DatosUsuarioSeed { username: string nombre: string rol: string asignacion: string | null empleadoId: number | null mondayUserId: number | null passwordHash: string } /** * Upsert por username. NO toca el password de un usuario existente salvo que * resetPasswords sea true (flag --reset-passwords). */ export async function upsertUsuario( datos: DatosUsuarioSeed, resetPasswords: boolean, ): Promise<'creado' | 'actualizado'> { const existente = await prisma.usuario.findUnique({ where: { username: datos.username } }) if (!existente) { await prisma.usuario.create({ data: datos }) return 'creado' } await prisma.usuario.update({ where: { username: datos.username }, data: { nombre: datos.nombre, rol: datos.rol, asignacion: datos.asignacion, empleadoId: datos.empleadoId, mondayUserId: datos.mondayUserId, ...(resetPasswords ? { passwordHash: datos.passwordHash } : {}), }, }) return 'actualizado' } interface VendedorJson { empleadoId: number | null nombre: string asignacion: string | null rol: string // User ID de Monday cuando el vendedor ya tiene cuenta (hoy solo Martin Zavala) mondayUserId?: number | null } async function main(): Promise { const resetPasswords = process.argv.includes('--reset-passwords') const rutaVendedores = path.resolve(process.cwd(), '..', 'reference', 'vendedores.json') const hashVendedores = bcrypt.hashSync(PASSWORD_INICIAL, BCRYPT_COST) const hashAdmin = bcrypt.hashSync(config.auth.adminPassword, BCRYPT_COST) let creados = 0 let actualizados = 0 if (fs.existsSync(rutaVendedores)) { const json = JSON.parse(fs.readFileSync(rutaVendedores, 'utf8')) as { vendedores: VendedorJson[] } for (const v of json.vendedores) { const resultado = await upsertUsuario( { username: normalizarUsername(v.nombre), nombre: v.nombre, rol: v.rol, asignacion: v.asignacion, empleadoId: v.empleadoId, mondayUserId: v.mondayUserId ?? null, passwordHash: hashVendedores, }, resetPasswords, ) if (resultado === 'creado') creados++ else actualizados++ } console.log(`[seed-usuarios] vendedores: ${creados} creados, ${actualizados} actualizados`) } else { console.warn(`[seed-usuarios] AVISO: no existe ${rutaVendedores}; se crea solo el admin`) } const admin = await upsertUsuario( { username: 'admin', nombre: 'Administrador FRASA', rol: 'admin', asignacion: null, empleadoId: null, mondayUserId: null, passwordHash: hashAdmin, }, resetPasswords, ) console.log(`[seed-usuarios] admin ${admin}${resetPasswords ? ' (password restablecido)' : ''}`) const total = await prisma.usuario.count() console.log(`[seed-usuarios] total de usuarios en BD: ${total}`) } // Solo se ejecuta como script (npm run seed:usuarios); al importarlo en tests no corre if (process.argv[1]?.endsWith('seed-usuarios.ts')) { main() .catch((err) => { console.error('[seed-usuarios] falló:', err) process.exitCode = 1 }) .finally(() => prisma.$disconnect()) }