Files
FRASA-CAS/scripts/generar-seeds.py
Consult AS Technology afb454b54c feat(cotizador): multi-desarrollo — ATELIER, ESTANZA, SENDA, SOLANA + DIAGONAL
- Motor de cálculo parametrizado por desarrollo (enganches, descuentos, splits,
  fuente de N, quirk Infonavit-lista); DIAGONAL byte-idéntico
- 285 unidades (5 desarrollos) en seeds, API (?desarrollo=) y board Monday
- Selector de desarrollo en UI, propuestas por config, PDF multi-desarrollo
- Knowledge IA: catálogo por desarrollo + matriz de diferencias (10 docs)
- Tests: cotizador 53, api 99 — fixtures de los Excel validados al centavo
2026-08-22 04:31:21 +00:00

126 lines
4.7 KiB
Python

#!/usr/bin/env python3
"""Genera apps/cotizador/src/data/unidades-{dev}.ts desde reference/cotizadores/{DEV}.json.
- Prefija el código con el desarrollo (ATELIER-10, ESTANZA-52, SENDA-411-1-7, SOLANA-6)
para que sea único en todo el ecosistema (board Monday compartido).
- En desarrollos de precio único, precioSinAcabados/precioConAcabados replican
precioLista (el tipo los requiere numéricos; el flag precioUnico del desarrollo
es el que manda en la UI).
"""
import json
import re
import sys
ROOT = '/root/frasa-ecosystem'
def num(v):
return v if isinstance(v, (int, float)) else None
def ts_num(v):
return 'null' if v is None else repr(float(v)).rstrip('0').rstrip('.') if isinstance(v, float) and v == int(v) else repr(v)
def ts_str(v):
if v is None:
return 'null'
s = str(v).replace('\\', '\\\\').replace("'", "\\'")
return f"'{s}'"
def slug(codigo):
return re.sub(r'[^A-Za-z0-9]+', '_', str(codigo)).strip('_')
def extras_ts(pairs):
items = ', '.join(f'{k}: {ts_str(v) if isinstance(v, str) or v is None else ts_num(v)}' for k, v in pairs)
return '{ ' + items + ' }'
def gen(dev, codigo_fn, map_fn, nota):
data = json.load(open(f'{ROOT}/reference/cotizadores/{dev}.json'))
unidades = data['unidades']
lines = [
"import type { Unidad } from '../types'",
'',
f'// Inventario {dev} — {len(unidades)} unidades. {nota}',
f'// Generado desde reference/cotizadores/{dev}.json (NO editar a mano; regenerar con scripts/generar-seeds.py).',
f'// Precio único por unidad: precioSinAcabados/precioConAcabados replican precioLista.',
f'export const UNIDADES_{dev}: Unidad[] = [',
]
for u in unidades:
precio = map_fn('precio', u)
campos = {
'codigo': ts_str(codigo_fn(u)),
'modelo': ts_str(u.get('modelo') or ''),
'desarrollo': ts_str(dev),
'fechaEntrega': ts_str(u.get('fechaEntrega')),
'supEstacionamiento': ts_num(num(u.get('supEstacionamiento'))),
'supConstruccion': ts_num(num(u.get('supConstruccion'))),
'supExcedente': ts_num(num(u.get('supExcedente'))),
'precioSinAcabados': ts_num(precio if precio is not None else 0),
'precioConAcabados': ts_num(precio if precio is not None else 0),
'precioLista': ts_num(precio),
'status': ts_str(u.get('status')),
'mesesParaFirma': ts_num(num(map_fn('mesesParaFirma', u))),
'extras': extras_ts(map_fn('extras', u)),
}
body = ', '.join(f'{k}: {v}' for k, v in campos.items() if v is not None)
lines.append(f' {{ {body} }},')
lines.append(']')
lines.append('')
out = f'{ROOT}/apps/cotizador/src/data/unidades-{dev.lower()}.ts'
open(out, 'w').write('\n'.join(lines))
print(f'{out}: {len(unidades)} unidades')
def precio_de(u, *claves):
ex = u.get('extras') or {}
for c in claves:
v = ex.get(c)
if isinstance(v, (int, float)):
return v
return None
gen(
'ATELIER',
lambda u: f"ATELIER-{u['codigo']}",
lambda k, u: {
'precio': precio_de(u, 'precioLista'),
'mesesParaFirma': None,
'extras': [('prototipo', u['extras'].get('prototipo')), ('manzana', u['extras'].get('manzana')),
('lote', u['extras'].get('lote')), ('cajones', u['extras'].get('cajones'))],
}[k],
'Departamentos, MZA 32 LOTE 1.',
)
gen(
'ESTANZA',
lambda u: f"ESTANZA-{str(u['codigo']).replace('CASA-', '')}",
lambda k, u: {
'precio': precio_de(u, 'precioLista'),
'mesesParaFirma': None,
'extras': [('manzana', u['extras'].get('manzana')), ('lote', u['extras'].get('lote')),
('cajones', u['extras'].get('cajones'))],
}[k],
'Casas DUPLO A/B, MZA 92 LOTE 32.',
)
gen(
'SENDA',
lambda u: f"SENDA-{u['codigo']}",
lambda k, u: {
'precio': precio_de(u, 'precioPreventa'),
'mesesParaFirma': None,
'extras': [('prototipo', u['extras'].get('prototipo')), ('manzana', u['extras'].get('manzana')),
('lote', u['extras'].get('lote')), ('cajones', u['extras'].get('cajones'))],
}[k],
'Casas; fechaEntrega null cuando la unidad no está en la tabla TERM (mensualidades no calculables).',
)
gen(
'SOLANA',
lambda u: f"SOLANA-{u['codigo']}",
lambda k, u: {
'precio': precio_de(u, 'precioPreventa'),
'mesesParaFirma': u['extras'].get('mesesParaFirma'),
'extras': [('prototipo', u['extras'].get('prototipo')), ('etapa', u['extras'].get('etapa')),
('cajones', u['extras'].get('cajones'))],
}[k],
'Casas etapas SOLANA I/II; mesesParaFirma (1-4) es el plazo de mensualidades.',
)