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>
This commit is contained in:
@@ -0,0 +1,59 @@
|
||||
# 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.
|
||||
Reference in New Issue
Block a user