Presupuesto al cliente

Tutorial paso a paso sobre el módulo Presupuesto al cliente en Despiece: armar un PDF branded con datos del cliente, cinco secciones de costos (Mueble · Materiales · Herraje · Mano de obra · Extras) y el total con margen y multiplicador de obra. El modelo de ejemplo es CocinaV9.despiece; el módulo está separado del flujo 2D (BOM/nest) y vive en un panel propio que se abre con Shift+Q.

El draft de presupuesto (parts.quoteDraft) es un campo soft del proyecto .despiece — no bump de schema. Se guarda en el IDB despiece-quote-drafts y se restaura con la sesión. El PDF final se descarga como presupuesto-{nombre}-{yyyymmdd}.pdf.

01 Cargar el modelo y abrir el panel

Vista general al cargar el modelo
01 Vista general al cargar el modelo. La sidebar izquierda muestra el árbol jerárquico. El módulo Presupuesto se abre con Shift+Q o el botón [Q] del topbar.

Al importar el modelo, la sidebar izquierda muestra el árbol jerárquico. Para abrir el módulo Presupuesto hay dos formas:

Se abre un panel sheet full-screen con header Presupuesto y número correlativo. La primera sección visible es Cliente con los datos cargados del catálogo del taller o del proyecto activo.

Módulo gated. Si Configuración → Presupuesto → Activar módulo Presupuesto está apagado, el botón [Q] del topbar y Shift+Q no hacen nada — aparece el toast "Módulo Presupuesto desactivado". Lo que sigue asume módulo on (default off — hay que activarlo).

02 Header y datos del cliente

Header del panel + sección Cliente
02 Header del panel + sección Cliente. Kicker Presupuesto + número correlativo; debajo los datos del cliente con chevron colapsable.

El header del panel expone:

La sección Cliente debajo del header carga desde state.project.client (catálogo per-proyecto o workshop-global linkeado) y muestra: nombre, teléfono, email, dirección, CUIT y notas. Click en el chevron colapsa/expande la sección (persiste en localStorage).

Sin cliente configurado la sección queda vacía con un botón Abrir panel Cliente que dispara openClientPanel() desde la topbar. Editar el cliente actualiza el presupuesto en vivo — sin recargar ni perder foco.

03 Sección Mueble

Sección Mueble
03 Sección Mueble. Una sola línea resumen con descripción, cantidad (= ×N), unidad, unit price y subtotal. Toggle incluir en el header.

La sección Mueble resume el modelo cargado en una sola línea:

CampoSignificado
DescripciónNombre del proyecto activo (editable vía state.project.activeName)
Cantidadstate.settings.projectMultiplier (default 1)
Unidadunidad
Unit priceSubtotal / ×N (sin margen)
SubtotalSubtotal calculado sin multiplicar por ×N

Si no hay modelo cargado, la sección queda con warning: "Sin modelo cargado" y computable: false. Las notas del cliente se linkean al PDF como descripción extendida de la línea Mueble.

04 Sección Materiales (overrides)

Sección Materiales con overrides
04 Sección Materiales. Una línea por (material × thickness) del BOM. Filas con is-override muestran borde sutil cuando el catálogo no tiene costPerM2.

La sección Materiales agrega una línea por cada combinación (material × thickness) del BOM actual. Las columnas son descripción (auto-gen del catálogo), cantidad (m² o ml según tipo), unidad, unit price (del costPerM2 o costPerMl del catálogo), y subtotal.

Overrides por fila. Cuando el catálogo del taller no tiene costPerM2 para un material, la fila se renderiza con borde sutil (is-override) y permite tipear Cant., $ U. y Descripción directamente desde el panel. La multiplicación cant × unitPrice corre en vivo y los totales reflejan al instante. La key del override es bucketKey(material)|thicknessMm — el mismo que usa src/export-purchase/row-builders.ts:27.

El override vive en parts.quoteDraft.materialesOverrides (campo soft en el .despiece). Si después cargás costPerM2 en el catálogo, el override sigue ganando hasta que se borre manualmente.

05 Sección Herraje

Sección Herraje
05 Sección Herraje. Una línea por SKU del catálogo del proyecto; si hardwareList está vacía, la sección queda con warning y no aporta al subtotal.

La sección Herraje agrega una línea por cada SKU del catálogo de herraje del proyecto (state.project.hardwareList[]). Las columnas son descripción, cantidad (×N global), unidad, unit price (del costPerUnit del SKU), y subtotal.

Si el proyecto no tiene herraje configurado (hardwareList.length === 0), la sección queda vacía con warning: "Sin herraje" y no aporta al subtotal. Toggle incluir en el header de la sección la apaga del PDF sin perder los datos.

06 Sección Mano de obra (cycle-time del nest)

Sección Mano de obra con cycle-time
06 Sección Mano de obra. Una sola línea resumen basada en el cycle-time del último nest × tarifa por hora × ×N. Sin nest previo queda bloqueada con Calculá nest primero.

La sección Mano de obra se calcula desde el cycle-time del último resultado de nest (state.nesting.lastResult.cycleTimeMinutes) y la tarifa por hora configurada en el tab Corte de Settings.

Fórmula:

Sin nest previo, la sección queda bloqueada con el mensaje "Calculá nest primero" y computable: false. El resto del presupuesto se puede editar y exportar igual — la mano de obra es la única sección gateada por el nest.

La tarifa por hora (hourlyRate) es la misma del settings de corte, aplicada por hora. Default 0 (la sección queda en $0 si no la configurás).

07 Sección Extras (CRUD libre)

Sección Extras con líneas
07 Sección Extras. CRUD libre de líneas con Descripción / Cant / Unidad / $ U. Cada fila suma cant × unitPrice al subtotal en vivo.

La sección Extras es un CRUD libre de líneas para agregar costos que no entran en las otras secciones: flete, instalación, mano de obra adicional, descuentos, etc.

Cada línea expone 4 inputs editables: Descripción, Cant., Unidad, $ U.. El subtotal se calcula como cant × unitPrice y se actualiza en vivo. Botones + Agregar y × (en cada row) para agregar/quitar filas. Sin filas, la sección queda vacía y no aporta al subtotal.

08 Totales: subtotal, margen, ×N, total

Footer de totales
08 Footer de totales. Tres inputs (Moneda / Margen % / ×N) editables; la cascada subtotal → margen → ×N → total se recalcula en vivo abajo.

El footer de totales se renderiza debajo de las 5 secciones y explica la cascada:

Tres inputs editables (sin recargar el panel):

CampoRangoDefault
Monedastring hasta 8 charsARS
Margen (%)0–20030
×N (multiplicador de obra)1–991

El multiplicador se lee del proyecto (state.settings.projectMultiplier) y se aplica después del margen: un proyecto ×3 con $1000 subtotal y 30% margen da total = (1000 + 300) × 3 = 3900. Toggle incluir en cada sección la apaga del PDF sin perder los datos — el subtotal refleja solamente lo efectivamente cotizado.

09 Términos y Exportar PDF

Términos + barra de export
09 Términos + barra de export. Textarea libre para los términos (se omiten si están vacíos); botón primario Exportar PDF dispara la descarga presupuesto-{nombre}-{yyyymmdd}.pdf.

La sección Términos y condiciones es un textarea libre. Si está vacía, se omite del PDF; si tiene texto, se imprime al pie del documento antes de la firma. Persiste en localStorage (settings) y sobrevive al cierre del panel.

La barra inferior tiene el botón Exportar PDF + un indicador de último cálculo. Click dispara exportHandler() que serializa el draft a PDF vía src/presupuesto/builder.ts:buildPresupuestoPdfOptionsexport-build-pdf.ts. El archivo se descarga con la forma:

presupuesto-{nombre-proyecto}-{yyyymmdd}.pdf
Hoja de armado no entra acá. El PDF de Presupuesto es ortogonal al PDF de Hoja de armado (src/assembly-sheet/) — son dos exports distintos con dos botones distintos.

10 Configuración → Presupuesto

Tab Presupuesto en Configuración
10 Tab Presupuesto en Configuración. Dos bloques: toggle maestro y Cotización por defecto (moneda / margen / validez / términos).

10.1 · Master toggle

Habilitar Presupuesto
10a Habilitar Presupuesto. Default off; controla la disponibilidad del botón [Q], Shift+Q y la persistencia de borradores.

Activar módulo Presupuesto (default off) controla el módulo entero:

El campo parts.quoteDraft es soft (src/types/project.ts) — no bump de schema del .despiece. Sobrevive entre proyectos. Los proyectos viejos sin presupuesto siguen abriendo normalmente.

10.2 · Cotización por defecto

Defaults de cotización
10b Defaults de cotización. 4 campos que prefilledan cada nuevo presupuesto (moneda / margen / validez / términos).

Cuatro campos que prefilledan cada nuevo presupuesto:

CampoTipoDefaultSignificado
quoteCurrencystring (≤8 chars)ARSPrefijo/sufijo del importe ($, US$, )
quoteMarginPctnúmero (0–200)30Porcentaje sobre el subtotal
quoteValidityDaysnúmero (1–365)15Días hasta la fecha de vencimiento
quoteFooterTermstextarea (≤6000)""Texto libre al pie del PDF

Persiste en localStorage (vía despiece.settings.v1) y sí entra en el export de Configuración (la sección presupuesto del IO config).

El brand del taller (logo + nombre fantasía + CUIT + dirección) ya no vive acá — pasó al tab Taller en la fase de reducción 2026-07-21. El módulo de Presupuesto consume el brand global vía getWorkshopBrand(). Si querés cambiar el logo, editás en Configuración → Taller (no en Presupuesto).

11 Atajos de teclado

Hoja de atajos
11 Hoja de atajos. Help (botón de la topbar o ?) abre la hoja completa; abajo el subset que toca al flujo de presupuesto.

Help (botón de la topbar o ?) abre la hoja completa. Los más usados en el flujo de presupuesto:

AtajoAcción
Shift+QAbre / cierra el panel Presupuesto
EscCierra el panel
Shift+CAbre el panel Cliente (per-proyecto)
Shift+KAbre la Agenda de clientes (workshop-global CRM; gated por Settings → Agenda)
/Filtrar lista de piezas (sidebar 2D)
B / Shift+BAuto-cantos ✦ (complementario)
IAislar selección
F / HomeFit / Fit + iso

En Mac el modificador de sistema es ; en otros sistemas Ctrl.

Recalculo automático. El panel Presupuesto re-renderiza cuando cambian epochs estructurales (settingsEpoch, nestingEpoch, modelKind, hardwareEpoch, herrajeriaEpoch). Las ediciones del usuario (cliente, extras CRUD, margin, currency local edits) NO causan re-render — los handlers aplican updates quirúrgicos al DOM preservando foco y scroll entre keystrokes.

Ver también