#!/usr/bin/env node import { PrismaClient } from '@prisma/client' import XLSX from 'xlsx' const prisma = new PrismaClient() const toStr = (v) => v == null ? null : String(v).trim() || null const toNum = (v) => { if (v == null) return null const n = Number(String(v).replace(/[$,\s]/g, '')) return Number.isFinite(n) ? n : null } const wb = XLSX.readFile('/root/Reporte maestro de clientesAGO26.xlsx') const rows = XLSX.utils.sheet_to_json(wb.Sheets[wb.SheetNames[0]], { header: 1, defval: null }) console.log(`Filas: ${rows.length}`) const map = new Map() for (let i = 1; i < rows.length; i++) { const nc = toStr(rows[i][0]) if (nc) map.set(nc, rows[i]) } console.log(`Clientes: ${map.size}`) let ok = 0, fail = 0 let idx = 0 for (const [nc, r] of map) { idx++ const d = { numCliente: nc, nombre: toStr(r[1]) || 'SIN NOMBRE', apellidoPaterno: toStr(r[2]) || '', apellidoMaterno: toStr(r[3]), sexo: toStr(r[4]), telefono: toStr(r[5]), email: toStr(r[6]), estadoCivil: toStr(r[7]), rangoEdad: toStr(r[8]), ocupacion: toStr(r[16]), rangoIngresos: toStr(r[15]), credito: toStr(r[10]), institucion: toStr(r[11]), medioContacto: toStr(r[13]), canal: toStr(r[14]), desarrollo: toStr(r[19]), manzana: toStr(r[20]), lote: toStr(r[21]), interior: toStr(r[22]), tipoCasa: toStr(r[24]), etapa: toStr(r[27]), valorTotal: toNum(r[26]), estatus: toStr(r[27]), fechaLiberacion: r[28] instanceof Date ? r[28] : null, vendedor: toStr(r[29]), vendedorId: toStr(r[30]), } try { await prisma.clienteMaestro.upsert({ where: { numCliente: nc }, update: d, create: d }) ok++ } catch (e) { fail++ if (fail <= 5) console.log(`ERR ${nc}: ${e.message.slice(0, 120)}`) } if (idx % 500 === 0) console.log(` ${idx}/${map.size} ok=${ok} fail=${fail}`) } console.log(`\nListo: ${ok} ok, ${fail} fail / ${map.size}`) await prisma.$disconnect()