feat(cobranza): importar datos de COBRANZA PREVENTA 060926.xlsx
- 93 planes de pago importados (10 desarrollos) - 448 pagos mensuales creados - Desarrollos: Zafiro, Mutuo, Sole, Atelier, Estanza, Solana I/II, Diagonal 40, Senda - Script importador: scripts/importar-cobranza-preventa.js - Soporte para fechas Excel serial y fórmulas
This commit is contained in:
128
api-gateway/scripts/importar-cobranza-preventa.js
Executable file
128
api-gateway/scripts/importar-cobranza-preventa.js
Executable file
@@ -0,0 +1,128 @@
|
|||||||
|
#!/usr/bin/env node
|
||||||
|
/**
|
||||||
|
* Importa el archivo COBRANZA PREVENTA a PlanPago + Pago.
|
||||||
|
* Lee cada hoja de desarrollo, extrae clientes y sus pagos mensuales.
|
||||||
|
*/
|
||||||
|
import { PrismaClient } from '@prisma/client'
|
||||||
|
import XLSX from 'xlsx'
|
||||||
|
|
||||||
|
const prisma = new PrismaClient()
|
||||||
|
const toStr = (v) => v == null ? null : String(v).trim() || null
|
||||||
|
const toFloat = (v) => {
|
||||||
|
if (v == null) return null
|
||||||
|
if (typeof v === 'number') return v
|
||||||
|
const n = parseFloat(String(v).replace(/[$,\s]/g, ''))
|
||||||
|
return Number.isFinite(n) ? n : null
|
||||||
|
}
|
||||||
|
const toDate = (v) => {
|
||||||
|
if (v == null) return null
|
||||||
|
if (v instanceof Date) return v
|
||||||
|
const n = Date.parse(String(v).trim())
|
||||||
|
return isNaN(n) ? null : new Date(n)
|
||||||
|
}
|
||||||
|
|
||||||
|
const DESARROLLOS = ['ZAFIRO', 'MUTUO', 'SOLE', 'ATELIER', 'ESTANZA', 'SOLANA I', 'SOLANA II', 'UMBRAL', 'DIAGONAL 40', 'SENDA']
|
||||||
|
|
||||||
|
const ruta = '/root/COBRANZA PREVENTA 060926.xlsx'
|
||||||
|
console.log(`Leyendo: ${ruta}`)
|
||||||
|
const wb = XLSX.readFile(ruta)
|
||||||
|
|
||||||
|
let totalPlanes = 0, totalPagos = 0, errores = 0
|
||||||
|
|
||||||
|
for (const nombreHoja of DESARROLLOS) {
|
||||||
|
const sheet = wb.Sheets[nombreHoja]
|
||||||
|
if (!sheet) { console.log(` Hoja "${nombreHoja}" no encontrada, saltando`); continue }
|
||||||
|
|
||||||
|
const rows = XLSX.utils.sheet_to_json(sheet, { header: 1, defval: null })
|
||||||
|
console.log(`\n ${nombreHoja}: ${rows.length} filas`)
|
||||||
|
|
||||||
|
// Header row is typically row 2 (index 2), data starts at row 3 (index 3)
|
||||||
|
// Find the header row with 'NOMBRE' or 'CTE'
|
||||||
|
let headerIdx = -1
|
||||||
|
for (let i = 0; i < Math.min(rows.length, 5); i++) {
|
||||||
|
if (rows[i]?.[2] && String(rows[i][2]).includes('NOMBRE')) {
|
||||||
|
headerIdx = i
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (headerIdx === -1) {
|
||||||
|
console.log(` No se encontró header en ${nombreHoja}, saltando`)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
const dataRows = rows.slice(headerIdx + 1)
|
||||||
|
let hojaPlanes = 0, hojaPagos = 0
|
||||||
|
|
||||||
|
for (const row of dataRows) {
|
||||||
|
const unidadCodigo = toStr(row[0])
|
||||||
|
const clienteId = toStr(row[1])
|
||||||
|
const clienteNombre = toStr(row[2])
|
||||||
|
if (!clienteNombre || clienteNombre.length < 3) continue
|
||||||
|
|
||||||
|
const precioVenta = toFloat(row[3]) || 0
|
||||||
|
const fechaVenta = toDate(row[4])
|
||||||
|
const tipoVenta = toStr(row[5]) || ''
|
||||||
|
const asesor = toStr(row[6]) || ''
|
||||||
|
const apartadoPagado = toFloat(row[10]) || 0
|
||||||
|
const enganchePagado = toFloat(row[11]) || 0
|
||||||
|
const meses = parseInt(String(row[13] || '0')) || 0
|
||||||
|
const mesInicio = toDate(row[14])
|
||||||
|
const mensualidad = toFloat(row[16]) || 0
|
||||||
|
const totalPagado = toFloat(row[58]) || 0
|
||||||
|
|
||||||
|
// Create PlanPago
|
||||||
|
try {
|
||||||
|
const plan = await prisma.planPago.create({
|
||||||
|
data: {
|
||||||
|
ventaRef: clienteId || null,
|
||||||
|
clienteNombre,
|
||||||
|
clienteTelefono: null,
|
||||||
|
unidadCodigo: unidadCodigo || '',
|
||||||
|
proyecto: nombreHoja,
|
||||||
|
fechaInicio: mesInicio || fechaVenta || new Date(),
|
||||||
|
engancheTotal: apartadoPagado + enganchePagado,
|
||||||
|
numPagos: meses || 1,
|
||||||
|
mensualidad,
|
||||||
|
tasaMoraMensual: 0,
|
||||||
|
status: 'ACTIVO',
|
||||||
|
vendedorId: null,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
hojaPlanes++
|
||||||
|
|
||||||
|
// Create Pago records for each month with a value
|
||||||
|
let numPago = 1
|
||||||
|
for (let col = 20; col <= 43; col++) {
|
||||||
|
const montoMes = toFloat(row[col])
|
||||||
|
if (montoMes && montoMes > 0) {
|
||||||
|
// Calculate date for this payment month
|
||||||
|
const fechaMes = new Date(2025, 7 + (col - 20), 1) // Starting from Aug 2025
|
||||||
|
await prisma.pago.create({
|
||||||
|
data: {
|
||||||
|
planId: plan.id,
|
||||||
|
numPago,
|
||||||
|
fechaVencimiento: fechaMes,
|
||||||
|
monto: montoMes,
|
||||||
|
montoPagado: 0, // Will be updated if we have payment data
|
||||||
|
},
|
||||||
|
})
|
||||||
|
hojaPagos++
|
||||||
|
numPago++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
errores++
|
||||||
|
if (errores <= 3) console.log(` Error: ${clienteNombre} - ${err.message?.slice(0, 100)}`)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
totalPlanes += hojaPlanes
|
||||||
|
totalPagos += hojaPagos
|
||||||
|
console.log(` ${hojaPlanes} planes, ${hojaPagos} pagos`)
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log(`\n=== Resumen ===`)
|
||||||
|
console.log(`Planes creados: ${totalPlanes}`)
|
||||||
|
console.log(`Pagos creados: ${totalPagos}`)
|
||||||
|
console.log(`Errores: ${errores}`)
|
||||||
|
|
||||||
|
await prisma.$disconnect()
|
||||||
Reference in New Issue
Block a user