Cotizador de Aberturas

Un cotizador de aberturas que da precios creíbles, no números inventados.

RolDesarrollador único: producto, motor de cálculo, backend, base de datos, seguridad y app móvilClienteGrupo CPS, industria de aberturas (aluminio + vidrio)Año2026CódigoPrivado · propiedad de Grupo CPS
Next.js 16ReactTypeScriptTailwindCSS 4Three.jsPostgreSQLSupabase self-hostedExpo / React NativeJest
2,44× → ~1%

Cuánto bajó el error al calcular el aluminio, comparado con el sistema de fábrica. No lo arreglé con un número de ajuste a dedo, sino entendiendo de dónde venía la diferencia.

Una web, y ahora también una app, donde el cliente arma su pedido de ventanas de aluminio y vidrio y recibe un precio. El desafío no era la pantalla, sino calcular bien el precio: lo que parecía una fórmula simple en realidad dependía de cuánto aluminio y vidrio usa cada ventana de verdad. Para acertar, estudié las 2.641 recetas reales del software de fábrica, saqué de ahí los números que mueven el costo y después lo validé con pedidos de prueba que la propia fábrica valoró en ese software.

Grupo CPS fabrica aberturas de aluminio y vidrio. Cotizar a mano cada pedido es lento y depende de personal técnico: cada consulta de un cliente ocupaba tiempo de alguien de fábrica antes de saber siquiera si el pedido iba en serio.

Querían una web sencilla donde el cliente se registre, arme un carrito con sus ventanas, envíe el pedido y le hagan seguimiento. El problema estaba en la palabra "sencilla": el precio de una ventana no sale de multiplicar el área por un precio por metro cuadrado. Depende de cuánto perfil de aluminio lleva cada tipo de ventana (marco, hoja, contravidrio, travesaños), de la medida real del vidrio, de herrajes, mano de obra, margen e IVA.

La empresa ya calculaba todo esto con precisión en su software de fábrica, WinMaker, que guarda una "receta" por cada tipo de ventana: 2.641 archivos en un formato cerrado, imposible de usar directo en una web. Mi primer cálculo simple contaba 2,44 veces menos aluminio del que la ventana usa en realidad.

Lo que había que tener en cuenta.

Sin acceso al software de fábrica desde la web

WinMaker es un sistema de escritorio con formato propio. No expone API ni se puede consultar en vivo: lo que necesitara de él tenía que extraerse una vez y quedar en mi modelo.

Costos internos que no pueden salir

El cliente tiene que ver un precio final, nunca el costo, el margen ni el precio por metro cuadrado. Cualquier diseño donde el navegador calcule quedaba descartado de entrada.

Datos que mantienen los técnicos, no el programador

Recetas, catálogos, colores y parámetros cambian con la fábrica. Tenían que poder cargarse desde un panel, sin tocar código.

Un solo desarrollador

Producto, motor, backend, base de datos y seguridad, en paralelo con otros sistemas de la empresa. Cada capa tenía que ser simple de mantener.

Sacar de las recetas solo los números que mueven el precio, sin copiar todo el software de fábrica.

Tenía dos caminos malos: una fórmula simple (rápida pero falsa) o reconstruir entero el software de fábrica (preciso pero inviable). Elegí el punto medio: leer de las recetas únicamente las medidas que afectan el costo.

El error no era un número mal puesto, era de fondo. La fórmula simple contaba solo el contorno del marco. Pero una ventana real lleva mucho más aluminio: el marco, la hoja que se abre, el contravidrio que sujeta el vidrio y los travesaños. Y el vidrio se mide por el hueco real que queda, no por el tamaño total de la ventana.

Así que armé un programa que lee esas 2.641 recetas y extrae, para cada tipo de ventana, las medidas exactas que la fábrica ya usa. Esas medidas alimentan el cálculo de precio que ya existía: cambia cuánto material se cuenta, no la forma de poner el precio.

Fórmula simple calculaba4,75 m
Ahora calcula (fábrica: 11,61 m)11,72 m

Ejemplo concreto, el que usé para medir: un paño fijo de 1200×1000 mm con un travesaño. La fórmula simple calculaba 4,75 m de perfil de aluminio. El software de fábrica, para esa misma ventana, despieza 11,61 m: el marco, el travesaño y el contravidrio de cada paño. Con las medidas sacadas de las recetas, mi cálculo da 11,72 m. De ahí sale el 2,44× y de ahí sale el ~1%.

Por qué está armado así.

Motor de cálculo puro, sin I/O

Todo el pricing son funciones puras, testeables sin base de datos. Por eso se pudo validar contra la fábrica sin levantar ningún servicio, y la app móvil lo reusa tal cual para cotizar sin conexión.

Geometría separada del costeo

Las recetas cambiaron cuánto material se cuenta sin tocar cómo se pone el precio. Después el costeo también se volvió real (cada perfil por su peso y el precio por kilo del color elegido, la mano de obra por receta) sin tocar la geometría. Cada mitad cambió sin romper la otra.

Parser propio y evaluador AST para el formato .PRO

En vez de ejecutar las recetas, un parser estático extrae por tipología solo las constantes geométricas (74, 126, 82/148 mm según el tipo) y cada una queda citada a su archivo de origen.

Snapshot inmutable por pedido

Cada pedido congela precios y nombres del momento, con folio asignado de forma atómica en la base (FOR UPDATE). Dos pedidos simultáneos nunca comparten número y un precio enviado no cambia por detrás.

Todo el cálculo del lado del servidor

Los endpoints devuelven DTOs sin datos sensibles. La service role vive solo en el servidor y RLS está habilitado sin políticas públicas.

Sin receta completa, no hay precio

Una combinación de línea y tipo de ventana sin receta completa no se ofrece, y una abertura que necesita revisión técnica se guarda sin precio. Prefiero no cotizar a cotizar con una estimación disfrazada de precio.

El pedido vuelve al software de fábrica

Cada pedido genera un archivo .pto que la fábrica abre en WinMaker, que lo dibuja y lo despieza con su propia receta. El formato que al principio había que descifrar terminó siendo el destino del pedido.

Lo que descarté en el camino.

Fórmula área × precio por m²

Rápida, pero contaba 2,44 veces menos aluminio del real. Un factor de ajuste a dedo habría escondido el error en vez de corregirlo.

Portar WinMaker entero a la web

Preciso, pero inviable: 2.641 recetas en un formato cerrado y un motor de fabricación completo, para lo que tenía que ser un cotizador de entrada.

Links de resumen con ID secuencial

Permitían enumerar pedidos ajenos cambiando un número. Se reemplazaron por tokens UUID imposibles de adivinar.

Calcular con costos en el navegador

Habría expuesto costos y márgenes a cualquiera que abriera las herramientas de desarrollo. El cálculo con costos corre en el servidor; la app móvil cotiza sin conexión, pero solo con precios de venta.

Una app full-stack con un motor de cálculo en el núcleo.

  1. 01

    Armado paso a paso, con la ventana en 3D

    El cliente elige tipo, medidas, línea, vidrio, color y accesorios en cuatro pantallas, con el precio en vivo. Ve la abertura en 3D, que puede girar, y el dibujo técnico, y puede comparar líneas y vidrios antes de decidir.

  2. 02

    Cotizar sin crear cuenta

    Primero deja sus datos de contacto y después arma la ventana. Quien tiene cuenta guarda borradores y pedidos.

  3. 03

    Varias aberturas por pedido

    Suma, duplica y ajusta aberturas en un mismo pedido hasta dejarlo como quiere.

  4. 04

    Cotización en PDF

    Un PDF prolijo con todas las ventanas, sus especificaciones y el total. Los revendedores tienen una versión con su propia marca para dársela a su cliente.

  5. 05

    Pedido congelado y seguimiento

    Al enviarlo se guardan los precios y nombres de ese momento, y nada se recalcula por detrás. En "Mis pedidos" ve el estado de cada uno y puede compartir un resumen por un link privado.

  6. 06

    App móvil sin conexión (en desarrollo)

    Una app que usa el mismo motor de cálculo que la web y cotiza sin señal, con los precios de venta descargados. Los pedidos quedan en cola y se envían solos cuando vuelve la conexión.

El cotizador no reemplaza a WinMaker, el sistema con el que la fábrica trabaja desde siempre: es la puerta de entrada para el cliente, y el pedido termina ahí, como un archivo que WinMaker abre. El cliente nunca ve costos internos ni margen: al navegador y a la app solo llega el precio final.

Un panel interno donde los técnicos cargan la realidad de la fábrica.

Recetas técnicas parametrizables

Los técnicos cargan qué lleva cada abertura: perfiles con sus cortes, accesorios, vidrios y límites fabricables. Cada receta elige componentes de catálogos reales: perfiles con su precio por color, accesorios, cámaras de DVH y mano de obra.

Estado de carga por receta

Un tablero muestra qué le falta a cada receta para cotizar con costo real: perfiles sin cargar, perfiles sin precio en el color, límites o accesorios. Lo que no está completo no se le ofrece al cliente.

Del pedido al taller

Cada pedido se ve con su desglose de costo y pasa por estados alineados al tablero comercial de la empresa. Desde ahí se genera el archivo .pto que la fábrica abre en WinMaker.

Parámetros que gobiernan el motor

Margen, IVA, desperdicios, colores con su código WinMaker, el tipo de cambio del dólar tomado del Banco Central (con historial y carga manual de respaldo) y usuarios con roles y descuentos: todo lo que afecta el precio se administra desde el panel, detrás de APIs con control de acceso por rol.

Esto es lo que hace que el sistema viva sin el programador: los dueños de los datos son los técnicos de la fábrica, no el código. La página del cliente es la mitad visible; esta es la mitad que la mantiene honesta.

Cómo encaja todo, en un diagrama que se puede tocar.

Cinco vistas con cajas que se pueden mover y un recorrido explicado paso a paso: el circuito completo, lo que hace el cliente, cómo se calcula el precio, lo que carga el técnico y cómo llega el pedido a la fábrica. Es la misma pieza que uso para explicar el sistema en diez minutos.

Una frontera estricta entre lo público y lo privado.

UI

Web y app móvil

Configurador · pedidos · app Expo que cotiza sin conexión.

API

app/api/*

Frontera HTTP: auth, autorización y DTOs sin datos sensibles.

SRV

src/server/*

Lógica privada: pedidos, PDF, archivo .pto y tipo de cambio.

CALC

src/lib/cotizador/*

Motor de cálculo puro, sin I/O; la app lo reusa para cotizar offline.

DOM

src/technical/* · src/shared/*

Tipologías, validaciones y contratos compartidos por web y móvil.

DB

PostgreSQL

Esquema canónico en Supabase self-hosted, con Row-Level Security.

La parte que calcula medidas está separada de la parte que arma el precio, y ninguna de las dos toca la base. Por eso traer los números de la fábrica no rompió los precios, el costeo real no rompió la geometría y la app móvil pudo usar el mismo motor sin reescribirlo.

Hay datos de clientes y costos internos en juego: la seguridad fue requisito, no agregado.

Ningún dato directo de la base

Todo pasa por el servidor con login. La llave maestra de la base vive solo ahí, nunca llega al navegador del cliente.

Links para compartir imposibles de adivinar

El link de un resumen no es un número seguido (1, 2, 3…) sino un código aleatorio, así nadie puede cambiarlo para espiar pedidos ajenos.

Entradas siempre acotadas

Medidas dentro de los límites de cada receta, cantidades enteras con tope, textos limitados. Un color desconocido frena la cotización en vez de cotizar mal.

Costos internos nunca expuestos

El cliente ve el precio final, nunca el costo ni el margen. El cálculo con costos ocurre en el servidor, y la app móvil solo recibe precios de venta.

Pedidos congelados y auditables

Cada pedido guarda un snapshot inmutable de precios y nombres, con folio asignado de forma atómica en la base: dos pedidos simultáneos jamás comparten número, y nada cambia después por detrás.

Control de acceso verificado en cada build

Un test hace fallar el build si alguna ruta de la API queda sin control de acceso. Una auditoría propia cerró además una fuga de costos en una ruta pública y endureció los headers.

Lo que se puede medir.

2,44× → ~1%

de error en el cálculo de aluminio frente al sistema de fábrica, corregido en la geometría y no con un factor de ajuste.

2.641

recetas reales de fábrica analizadas por reverse engineering.

Validado

con pedidos de prueba que la propia fábrica valoró en WinMaker: el costo de la web nunca queda por debajo del de taller.

En producción

en cotizador.grupocps.com.uy, la puerta de entrada de los clientes de Grupo CPS.

Cómo sé que los números están bien.

Recetas de fábrica analizadas
2.641
Formato cerrado .PRO descifrado
Parser propio + evaluador AST seguro
Error de material vs. el sistema de fábrica
2,44× → ~1%
Validación
Pedidos de prueba valorados por la fábrica en WinMaker
Calibración
Archivo histórico de cotizaciones de la empresa
Control de acceso
Verificado por test en cada ruta de la API
Calidad de código
TypeScript estricto, sin errores de tipo

El "modo sombra": una herramienta que compara, ventana por ventana, lo que calcula mi sistema contra el desglose real de piezas del software de fábrica. Sirve para medir cuánto me desvío antes de dar un precio por bueno. Después vino la prueba de verdad: pedidos que la fábrica valoró en su software y devolvió, con una regla fija: cada diferencia se cierra con una causa, no con un coeficiente.

El cotizador en acción.

Recorrido por el sistema: del armado de la abertura en 3D al pedido enviado.
Visualización 3D: la ventana cotizada gira para verse desde cualquier ángulo.
PDF generado con la cotización armada
PDF generado automáticamente con la cotización armada, listo para guardar o compartir.
Panel interno de carga técnica del cotizador
El panel interno: recetas técnicas, catálogos y parámetros que alimentan el motor.
Estado de carga de recetas con semáforo de costo real
El "estado de carga": qué le falta a cada receta para cotizar con costo real.
  • El problema difícil rara vez es el que se ve: la pantalla era lo fácil, el valor estaba en calcular bien y validar los números.
  • No copié las 2.641 recetas a la fuerza: saqué solo lo que mueve el costo y dejé el resto como investigación aparte.
  • Medir antes de afirmar: el "modo sombra" convirtió una corazonada ("el precio no cierra") en un número (2,44×) y después en una validación (~1%).
  • El sistema completo incluye a quien lo mantiene: el panel interno y su estado de carga hacen que los técnicos, no el programador, sean los dueños de los datos.
  • Un núcleo puro paga dividendos: como el motor nunca tocó la base, la app móvil sin conexión salió reusándolo, sin reescribir el cálculo.

¿Querés hablar de este proyecto?

El código es privado, pero puedo contar en detalle cómo está hecho. Escribime si te interesa esto o querés hablar de una posición.