Files
aurgi/reports/0003-2026-06-17-dead-stock-dash851.md
T
egutierrez 14d3025182 chore: auto-commit (1 archivos)
- reports/0003-2026-06-17-dead-stock-dash851.md

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-06-23 17:49:48 +02:00

4.9 KiB
Raw Blame History

Report 0003 — Dead stock (productos en stock sin venta) — dashboard 851

  • Fecha: 17/06/2026
  • Autor: Claude (sesión egutierrez)
  • Ámbito: Aurgi · Metabase reports.autingo.es · dashboard 851 "Seguimiento Stock y Compras" · BigQuery db 6
  • Estado: parcial (card standalone creada y validada; falta engancharla al dashboard a confirmación del usuario)

Resumen

Se identifican los productos con stock disponible cuya última venta es anterior a un corte configurable (default 12 meses). Resultado depurado: ≈ 1,46M € de dead stock en ~10.900 productos (corte 12 meses, snapshot 2026-06-17). Se creó la card standalone 11801 "Productos en stock sin venta (dead stock)" (https://reports.autingo.es/question/11801) con variable {{meses_sin_venta}}. La métrica naïve daba ~20M € falsos; tras corregir tres errores de datos (sentinela de fecha, almacén de distribución, grano producto×centro) baja a 1,46M € reales.

Cambios

Artefacto Acción Detalle
Card Metabase 11801 Creada + actualizada SQL nativo BigQuery sobre anjana_bi_amg.stock_actual, display tabla, variable meses_sin_venta (default 12), formato € en valor_stock.
Memoria project_aurgi_dash851_dead_stock.md Creada Tabla/campos correctos + gotchas de la métrica.
temp/stock_*.py Exploración Probes de tablas 4592 (stock_actual) y 2233 (Stock_diario_mas_precio).

Modelo de la métrica

Fuente: anjana_bi_amg.stock_actual (Metabase table 4592) — es la única tabla con última venta estricta (ultimo_mov_venta, field 288864). Stock_diario_mas_precio (table 2233) solo tiene fecha_ultimo_movimiento genérico, no sirve.

stock_actual es un ledger (~48M filas) con columnas denormalizadas constantes por producto×centro: stock_hoy (stock actual), ultimo_mov_venta, ultimo_mov_compra, coste_actual; atributos en structs product.* y center.*. Se deduplica con GROUP BY item_no_, location_code + ANY_VALUE/MAX (sumar stock_hoy sobre el ledger crudo multiplica por nº de movimientos).

Definición de "dead stock" (a nivel producto): producto con stock>0 cuya última venta en cualquier centro es anterior al corte; los nunca-vendidos cuentan solo si su última compra también supera el corte (excluye novedades).

Tres correcciones imprescindibles (sin ellas: ~20M € falsos)

  1. Sentinela 1999-01-01 = "sin venta registrada", no venta real → NULLIF(ultimo_mov_venta,'1999-01-01'). Afecta 18,3M €.
  2. Almacen Central no vende (distribución a tiendas; 0% combos con venta, 15,7M €) → excluir de la deadness; su ultimo_mov_venta es siempre sentinela.
  3. Grano producto, no producto×centro: un producto activo en tiendas con stock parado en un hub logístico daba falso positivo (balizas V16, neumáticos 205/55). La deadness se calcula con la última venta global del producto.

Verificación

Snapshot MAX(Fecha)=2026-06-17. Ejecución de la card (corte default 12 meses), agregado por estado:

estado                    prods  líneas   uds     valor €
Vendido (parado)          6073   16884    42295   942.504
Nunca vendido (parado)    2208    3155     7802   357.367
Sin actividad             2624    3263     9010   163.219
                                                  ---------
TOTAL DEAD STOCK                                  1.463.090

Validación cruzada del impacto de cada corrección (Productos, stock>0):

  • Naïve (todo, sin corregir): ~20,4M € (dominado por Almacen Central + sentinela 1999).
  • Solo excluyendo central + sentinela, grano producto×centro: 3,82M € (incluye stock parado de productos que sí venden en otro centro → útil para redistribución).
  • Grano producto (definición final): 1,46M € (referencias que no venden en ningún centro → candidatas a liquidación).

Top de la card tras corrección: neumático Bridgestone DUELER (última venta 2022-09, 45 meses), máquinas/kits nunca vendidos. Desaparecieron los falsos positivos (baliza V16, neumáticos de rotación alta).

Gaps / pendientes

  • Enganche al dashboard 851 (tab 317 "Ultimo movimiento de producto"): pendiente de confirmación del usuario. Plan: añadir scalars (valor total + nº productos dead) + la tabla 11801 vía metabase_dashboard_append_row. El param existente "Fecha ultimo mov" NO se reutiliza tal cual (filtra ultimo_mov_venta crudo, sin normalizar sentinela ni excluir central); la card usa su variable propia meses_sin_venta.
  • Decisión de negocio abierta: nivel-producto (1,46M €, liquidación) vs producto×centro (3,82M €, redistribución). La card está en nivel-producto; cambiar a combo es un ajuste menor del SQL.
  • Sin actividad (0,16M €): productos sin venta NI compra registrada — posible falta de datos vs stock realmente congelado. No desglosado.
  • Cap de 2000 filas en la tabla (orden por valor desc); el conteo real es ~23k líneas. Para el listado completo, exportar la card.