Identificar cuándo una planilla deja de servir, y ver con sus propias manos cómo la forma plana destruye el margen bruto que Finanzas le rinde al directorio —24,59 % real contra 14,90 % naive— antes de aprender la forma que lo arregla.
El notebook de esta clase: https://gaa1104.vercel.app/notebooks/clase-09.ipynb
Ing. en Administración · mención Finanzas · Prof. Tomás Fernández
Toda la clase es una comparación de dos números: el margen que sale sumando plano contra el que sale bien calculado. La forma más simple posible, porque el hallazgo tiene que golpear solo.
La forma la decide el trabajo que hace el dato —magnitud, identidad, polaridad, cambio en el tiempo, distribución—, no el gusto. Regla del curso: un solo eje.
Lo que quedó planteado la sesión anterior (se proyecta la pregunta, NO la respuesta):
«Todo lo del Parcial 1 salió de una planilla plana y limpia. ¿Por qué el margen todavía puede salir equivocado?»
Entregas: las tres respuestas escritas en tu cuaderno. 90 segundos en silencio, 2 minutos con el de al lado, 3 de puesta en común.
Contéstalas de memoria, sin abrir apuntes ni el notebook de la clase anterior (espaciado 1–3–7–21):
Par (2 min) → plenaria (3 min).
La pregunta colgada se recoge, no se responde todavía. Se anotan en la pizarra las hipótesis que digan —van a decir "porque faltan datos", "porque el archivo estaba sucio", "porque el catálogo no pegaba". Todas razonables. Y entonces:
«Ninguna de esas es la de hoy. Hoy el archivo va a estar perfecto: sin errores de escritura, sin fechas dadas vuelta, sin nada que reclamarle. Y el margen va a salir mal igual, por casi 10 puntos. A las 22:10 volvemos a esta pizarra.»
«EA1 está cerrada. Lo que empieza ahora es lo que separa a alguien que sabe consultar de alguien que sabe modelar. Y es lo que más se paga.»
La pregunta que abre EA2, escrita en la pizarra y ahí se queda siete semanas:
¿Qué representa exactamente UNA fila de esta tabla?
Esta consulta viene resuelta: la corres y miras la salida. Acá todavía no hay nada que escribir.
-- 👀 SE MIRA · una factura entera, con sus tres líneas SELECT numero_factura, cliente, fecha_emision, sku, linea_negocio, cantidad, precio_unitario, descuento_factura, flete_despacho FROM ventas WHERE numero_factura = 'F-2022-000023';
Tres filas. Tres productos distintos —una luminaria, un tornillo autoperforante, un set de llaves— y en las tres:
Y la pregunta, contando hasta cinco antes de contestar: «¿la empresa cobró ese flete una vez o tres?»
Cuando alguien diga "una vez", el hallazgo es de esa persona. Nombrarla.
Una fila no es una factura. Una fila es una LÍNEA de una factura. Y hay dos cosas viviendo aplastadas en la misma tabla: lo que pasa por producto (cantidad, precio, costo) y lo que pasa por documento (descuento, flete, condición de pago, cliente, fecha).
MAX()También viene resuelta. Es la primera verificación del semestre que autoriza una decisión de modelamiento: mírala correr antes de creerle al MAX().
-- 👀 SE MIRA · ¿el cargo cambia entre las líneas de una misma factura? SELECT numero_factura, COUNT(*) AS lineas, MIN(descuento_factura) AS desc_min, MAX(descuento_factura) AS desc_max, MIN(flete_despacho) AS flete_min, MAX(flete_despacho) AS flete_max FROM ventas GROUP BY 1 ORDER BY lineas DESC LIMIT 5; -- las facturas de 7 líneas repiten exactamente el mismo par de valores en las 7
-- 👀 SE MIRA · cuántas facturas tienen el cargo inconsistente SELECT COUNT(*) AS facturas_con_cargo_inconsistente FROM (SELECT numero_factura FROM ventas GROUP BY 1 HAVING MIN(descuento_factura) <> MAX(descuento_factura) OR MIN(flete_despacho) <> MAX(flete_despacho)); -- 0
«Cero. En ninguna de las 2.951 facturas el descuento cambia entre líneas. Ese cero es lo que me autoriza a usar MAX() para recuperar el cargo una sola vez. Si hubiera dado 12, tendríamos que ir a preguntar antes de tocar nada.»
Medidas vs atributos, la regla que se llevan escrita:
| Si te dan ganas de… | Entonces es… | Ejemplo en Austral |
|---|---|---|
| sumarla | medida | cantidad, precio_unitario × cantidad, costo_unitario × cantidad |
| filtrar o agrupar por ella | atributo | segmento, linea_negocio, canal, vendedor, region_cliente |
| sumarla y te da un número absurdo | atributo disfrazado de número | tipo_cambio, condicion_pago_dias |
El dato del día, dicho al pasar: de las 2.951 facturas, 1.970 tienen más de una línea (66,8 %). El problema no es un caso raro: son dos de cada tres documentos.
Declarar en voz alta que el dataset es sintético. Los clientes no existen; el patrón de repetición es exactamente el que exporta un ERP real.
Pararse, estirar, subir la luz. Clase nocturna: el cuerpo también aprende. Y lo que viene es lo más importante del semestre.
Entregas: los cuatro números anotados a mano en tu cuaderno —2,60 · 2,04 · 14,90 · 24,59— más la celda final de este bloque completada con los que te dieron a ti. 30 minutos, cada uno en su máquina.
Nadie mira la pantalla del de al lado. Corres tú las consultas de este bloque, en orden, y anotas cada resultado a mano antes de pasar a la siguiente. Los tres pasos de abajo son los pasos de la actividad.
-- 🔨 ACTIVIDAD · córrela y anota los dos factores WITH por_factura AS ( SELECT numero_factura, MAX(descuento_factura) AS d, MAX(flete_despacho) AS f FROM ventas WHERE moneda = 'CLP' GROUP BY 1 ) SELECT ROUND((SELECT SUM(descuento_factura) FROM ventas WHERE moneda = 'CLP') / (SELECT SUM(d) FROM por_factura), 2) AS factor_descuento, ROUND((SELECT SUM(flete_despacho) FROM ventas WHERE moneda = 'CLP') / (SELECT SUM(f) FROM por_factura), 2) AS factor_flete; -- factor_descuento 2.60 · factor_flete 2.04
«Sumar la columna descuento_factura cuenta el descuento comercial 2,60 veces. El flete, 2,04 veces. Nadie se equivocó al escribir la consulta: la consulta hizo exactamente lo que le pediste.»
En plata, para que se vea:
| Cargo | Sumando la columna plana | Cobrado de verdad |
|---|---|---|
| Descuento comercial | 1.083.814.288 | 416.964.602 |
| Flete de despacho | 427.498.928 | 209.502.530 |
(Se filtra moneda = 'CLP' a propósito: las 395 líneas en dólares no se suman con las de pesos. Ese es el reflejo que se instaló en la sesión 06 y no se pierde.)
Se arma en tres pasos, y cada paso se proyecta entero. Paso 1: poner al lado de cada línea el total de su propia factura.
-- 🔨 ACTIVIDAD · paso uno de tres -- 1) Cada línea, con el total de SU factura al lado. CREATE OR REPLACE VIEW linea_clp AS SELECT numero_factura, cantidad * precio_unitario AS venta_bruta, cantidad * costo_unitario AS costo_venta, descuento_factura, flete_despacho, SUM(cantidad * precio_unitario) OVER (PARTITION BY numero_factura) AS bruto_factura, COUNT(*) OVER (PARTITION BY numero_factura) AS lineas_factura FROM ventas WHERE moneda = 'CLP';
Paso 2: la cuota — qué parte de los cargos le toca a cada línea.
-- 🔨 ACTIVIDAD · paso dos de tres -- 2) Qué parte de los cargos le toca a cada línea. CREATE OR REPLACE VIEW reparto AS SELECT *, CASE WHEN bruto_factura <> 0 THEN venta_bruta / bruto_factura ELSE 1.0 / lineas_factura END AS cuota FROM linea_clp;
Paso 3: el margen de las dos maneras, uno al lado del otro.
-- 🔨 ACTIVIDAD · paso tres de tres: anota los dos márgenes -- 3) El número de la noche. SELECT ROUND(SUM(venta_bruta)) AS venta_clp, ROUND(100.0 * (SUM(venta_bruta) - SUM(costo_venta) - SUM(descuento_factura) - SUM(flete_despacho)) / SUM(venta_bruta), 2) AS margen_naive_pct, ROUND(100.0 * (SUM(venta_bruta) - SUM(costo_venta) - SUM((descuento_factura + flete_despacho) * cuota)) / SUM(venta_bruta), 2) AS margen_real_pct FROM reparto; -- venta 9.129.005.786 · naive 14,90 % · real 24,59 %
Silencio de tres segundos ante la pantalla. Y recién ahí, la pizarra:
## Margen bruto real 24,59 % · Margen bruto naive 14,90 %
## 9,7 puntos porcentuales — y en pesos: 884.846.084 de margen que sí existen y el informe no ve.
«Ese número —el margen bruto por línea de negocio— es lo que Finanzas le rinde al directorio. Con 14,90 % en la lámina, la conversación es "hay que subir precios o cortar costos". Con 24,59 %, la conversación es otra completamente distinta. Y las dos salieron del mismo archivo, sin un solo error de tipeo.»
Y ahora se dibuja, porque el número de la noche tiene que golpear solo. La consulta ya lo calculó; el gráfico es la forma más simple que existe —dos barras, lado a lado— y ésa es la elección, no un descuido: cuando el hallazgo es una comparación de dos números, cualquier cosa más elaborada lo tapa.
# 👀 SE MIRA · el gráfico ya viene escrito: se corre y se mira import matplotlib.pyplot as plt GRIS, TINTA, ALERTA = "#b8b8b8", "#102a38", "#8c2b20" m = bd.sql(""" SELECT ROUND(100.0 * (SUM(venta_bruta) - SUM(costo_venta) - SUM(descuento_factura) - SUM(flete_despacho)) / SUM(venta_bruta), 2) AS margen_naive_pct, ROUND(100.0 * (SUM(venta_bruta) - SUM(costo_venta) - SUM((descuento_factura + flete_despacho) * cuota)) / SUM(venta_bruta), 2) AS margen_real_pct, ROUND(SUM(descuento_factura) + SUM(flete_despacho) - SUM((descuento_factura + flete_despacho) * cuota)) AS margen_invisible_clp FROM reparto""").iloc[0] fig, eje = plt.subplots(figsize=(7.2, 5)) eje.bar(["sumando la columna plana\n(naive)", "repartiendo a prorrata\n(real)"], [m.margen_naive_pct, m.margen_real_pct], color=[GRIS, TINTA], width=0.5) for x, valor in enumerate([m.margen_naive_pct, m.margen_real_pct]): eje.text(x, valor + 0.4, f"{valor:.2f} %".replace(".", ","), ha="center", fontsize=14, color=TINTA) eje.annotate("", xy=(1, m.margen_real_pct), xytext=(1, m.margen_naive_pct), arrowprops=dict(arrowstyle="<->", color=ALERTA, linewidth=1.6)) eje.text(0.68, (m.margen_real_pct + m.margen_naive_pct) / 2, f"{m.margen_real_pct - m.margen_naive_pct:.2f} pp".replace(".", ",") + "\n= CLP " + f"{m.margen_invisible_clp:,.0f}".replace(",", "."), ha="right", va="center", fontsize=11, color=ALERTA) eje.set_title("El mismo archivo da 14,90 % o 24,59 % según dónde se sume\n" "el descuento: 9,69 puntos de margen que sí existen", fontsize=13, color=TINTA, loc="left") eje.set_ylabel("margen bruto sobre la venta", fontsize=9) eje.set_ylim(0, 30) for lado in ("top", "right"): eje.spines[lado].set_visible(False) fig.tight_layout() plt.show()
Qué se mira en el resultado:
Volver a F-2022-000023, la de las tres líneas, y repartir sus cargos (56.882 + 112.864 = 169.746) a prorrata de la venta de cada línea:
| Línea | Venta | Peso en la factura | Cargo que le toca | Cargo que le asigna el método plano | Margen real | Margen naive |
|---|---|---|---|---|---|---|
| ELE-1004 · Eléctrico | 975.520 | 36,8 % | 62.516 | 169.746 | 22,2 % | 11,2 % |
| FIJ-4003 · Fijaciones | 217.664 | 8,2 % | 13.949 | 169.746 | 20,8 % | −50,8 % |
| HER-2003 · Herramientas | 1.455.588 | 55,0 % | 93.281 | 169.746 | 25,0 % | 19,8 % |
«Mira la fila del medio. Es un tornillo autoperforante que participa con el 8 % de esta factura, y el método plano le carga el descuento y el flete completos. Le da margen de menos 50,8 %. Un gerente que ve eso propone cerrar la línea de Fijaciones. La línea gana 20,8 % en esta factura.»
Y antes de cerrar el bloque, cada uno deja sus cuatro números escritos donde no se pierdan:
# 🔨 ACTIVIDAD — deja acá los cuatro números que te dieron a TI. # Anótalos también a mano en el cuaderno: eso es lo que se recoge hoy. factor_descuento = 0.0 # cuántas veces se cuenta el descuento al sumar la columna plana factor_flete = 0.0 # lo mismo, para el flete de despacho margen_naive_pct = 0.0 # el margen que sale sumando plano margen_real_pct = 0.0 # el margen que sale repartiendo a prorrata print("Doble conteo — descuento:", factor_descuento, "· flete:", factor_flete) print("Margen naive:", margen_naive_pct, "% · margen real:", margen_real_pct, "%")
La animación del deck, narrada lámina a lámina. Un clic, una dimensión.
rut_cliente, cliente, segmento, region_cliente) → dim_cliente.sku, descripcion_producto, linea_negocio) → dim_producto.dim_tiempo.canal, vendedor, centro_costo) → dim_comercial.En el centro queda fact_venta_linea: puras llaves y puros números. Larga y flaca.
«Un centro, cinco puntas. Y la razón por la que esto existe no es estética: es que cada cosa vive en la tabla que le corresponde a su grano. El descuento vivía en la tabla equivocada, y eso costó 9,7 puntos de margen.»
Hilo 3 — salir de Excel rápido. Esta partición en cinco tablas no tiene equivalente en una planilla. En Excel el modelo existe igual —tiene que existir, porque alguien decidió qué va en las filas y qué en los valores— pero vive en la cabeza del que armó la tabla dinámica. Cuando esa persona cambia de trabajo, el modelo se va con ella. Aquí el modelo son cinco CREATE TABLE que cualquiera puede leer, discutir y corregir.
Dónde vive esto en la organización (30 segundos, importa):
«Esto es el conflicto clásico del cierre mensual: Contabilidad dice un margen y Comercial dice otro, y los dos tienen razón en su planilla. Casi siempre es esto: están sumando a granos distintos. El área que puede explicarlo en una reunión es la que gobierna el número.»
El experto de esta sesión — Jefe de Administración de Ventas:
«Antes de repartir un solo peso, hay una pregunta que no está en el archivo: ¿el descuento se negocia sobre el total de la factura, o línea por línea?
Si es sobre el total —y en Austral lo es—, el reparto a prorrata es una decisión de asignación que tú tomas y declaras, no un dato. Si fuera línea por línea, la columna debería venir distinta y el proveedor del ERP tendría un problema que reportar.
De esa respuesta, y no de la consulta, depende cuál de los dos márgenes es el verdadero. La consulta la escribes en cuatro minutos. La conversación es la que decide si sirve.»
Y la regla del curso, otra vez en la pizarra: una consulta SQL sin una conversación previa es una opinión con formato de tabla.
Síntesis, construida con ellos (se pregunta y se escribe lo que ellos digan):
Volver a la pizarra de las 20:30 y tachar las hipótesis del inicio. Ninguna era. La respuesta era el grano.
Entregas: media hoja con las tres respuestas, antes de salir. 3 minutos, sin nota. Las mismas tres van también en la celda final del notebook, que se descarga y se sube a klearning.
a) ¿Qué representa una fila del libro de ventas de Austral, y por qué esa pregunta vale plata? b) SUM(descuento_factura) sobre la planilla plana da un número ¿menor o mayor que la verdad? ¿Por qué, y con qué dos factores? c) Del 1 al 5, ¿dónde te sientes hoy y qué te falta?
Y el anuncio: la clase de hoy queda filmada en el sitio del curso; revísenla cuando estudien, no cuando estén perdidos.
Preguntas que quedan planteadas (se escriben en la pizarra y no se responden):
→ El descuento se cuenta 2,60 veces y el flete 2,04. Si los dos se repiten en las mismas líneas de las mismas facturas, ¿por qué los factores son distintos?
→ Si el promedio de líneas por factura es 2,03, ¿por qué ninguno de los dos factores es exactamente 2,03?
Tres minutos. No suma nota. Sirve para armar la apertura de la próxima clase.
El notebook de esta clase:
https://gaa1104.vercel.app/notebooks/clase-09.ipynb