- Circuit breaker saludMonday (3 fallos → modo local; ping cada 60s)
- Endpoint GET /api/sistema/estado {mondayOk, pendientesSync}
- LeadCaptura extendida (board, etapa, origen, motivo, pendienteSync)
- Tablas Unidad (espejo inventario, 288 seed) + SyncPendiente
- crmLocal: crearLead, afluencia, cambio etapa, descarte, conversión, apartar
- Ruteo en controllers: fallback local ante 502 o Monday caído
- Mi día local: resumen completo desde SQLite + unión con Monday
- Fallbacks: unidades, contactos, reportes, prefill, buscador
- Sync worker cada 2min + handlers 15 tipos (con DependenciaPendienteError)
- Gate automatizaciones: skip si !mondayOk
- Banner 'Modo local' en 5 apps + badge pendiente en mi-dia
- 597 API tests + 263 front tests verdes
Env MODO_LOCAL_FORZADO=true para testing sin Monday.
78 lines
2.8 KiB
JavaScript
78 lines
2.8 KiB
JavaScript
/**
|
|
* Siembra la tabla local `Unidad` (espejo del inventario para el modo local)
|
|
* desde el INVENTARIO_SEED curado del cotizador
|
|
* (apps/cotizador/src/data/unidades.ts, generado de los Excel de precios).
|
|
*
|
|
* Idempotente: upsert por `codigo`. Se corre una vez en el deploy y cuando el
|
|
* seed del cotizador se regenere; el write-through de
|
|
* monday.service.getUnidades() mantiene fresco el espejo en operación normal.
|
|
*
|
|
* Uso: npm run seed:unidades (tsx, porque la fuente es TypeScript)
|
|
*/
|
|
import path from 'node:path'
|
|
import { fileURLToPath } from 'node:url'
|
|
import dotenv from 'dotenv'
|
|
import { PrismaClient } from '@prisma/client'
|
|
import { INVENTARIO_SEED } from '../../apps/cotizador/src/data/unidades.ts'
|
|
|
|
const raizApi = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..')
|
|
dotenv.config({ path: [path.resolve(raizApi, '.env'), path.resolve(raizApi, '..', '.env')] })
|
|
|
|
const prisma = new PrismaClient()
|
|
|
|
const numero = (v) => (typeof v === 'number' && Number.isFinite(v) ? v : 0)
|
|
const texto = (v) => (v === null || v === undefined ? '' : String(v))
|
|
|
|
function mapearUnidad(u) {
|
|
const extras = u.extras ?? {}
|
|
return {
|
|
codigo: u.codigo,
|
|
desarrollo: texto(u.desarrollo) || 'DIAGONAL',
|
|
modelo: texto(u.modelo),
|
|
manzana: texto(extras.manzana),
|
|
lote: texto(extras.lote),
|
|
supConstruccion: numero(u.supConstruccion),
|
|
supExcedente: numero(u.supExcedente),
|
|
supEstacionamiento: numero(u.supEstacionamiento),
|
|
precioLista: numero(u.precioSinAcabados),
|
|
precioAcabados: numero(u.precioConAcabados),
|
|
status: texto(u.status) || 'DISPONIBLE',
|
|
// En SOLANA la etapa de obra vive en extras.etapa; en el tablero Monday es
|
|
// la columna "Etapa" (top-level en el tipo del cotizador)
|
|
etapa: texto(u.etapa) || texto(extras.etapa),
|
|
}
|
|
}
|
|
|
|
async function main() {
|
|
let insertadas = 0
|
|
let actualizadas = 0
|
|
for (const cruda of INVENTARIO_SEED) {
|
|
const u = mapearUnidad(cruda)
|
|
const previa = await prisma.unidad.findUnique({ where: { codigo: u.codigo }, select: { id: true } })
|
|
await prisma.unidad.upsert({
|
|
where: { codigo: u.codigo },
|
|
update: u,
|
|
create: u,
|
|
})
|
|
if (previa) actualizadas++
|
|
else insertadas++
|
|
}
|
|
const total = await prisma.unidad.count()
|
|
const porDesarrollo = await prisma.unidad.groupBy({ by: ['desarrollo'], _count: { codigo: true } })
|
|
// eslint-disable-next-line no-console
|
|
console.log(
|
|
`[seed-unidades] ${insertadas} insertada(s), ${actualizadas} actualizada(s); total en tabla: ${total}`,
|
|
)
|
|
for (const d of porDesarrollo) {
|
|
// eslint-disable-next-line no-console
|
|
console.log(` ${d.desarrollo}: ${d._count.codigo}`)
|
|
}
|
|
}
|
|
|
|
main()
|
|
.catch((err) => {
|
|
console.error('[seed-unidades] error:', err)
|
|
process.exitCode = 1
|
|
})
|
|
.finally(() => prisma.$disconnect())
|