7.1 🎯 Overview del módulo
El módulo más liviano y especializado. Es básicamente un consultor de
precios por canal/sucursal. No sincroniza activamente: delega el sync al módulo
/catalogo/admin/api_sync.php (fuera de /reportes/).
LISTAS_DISPONIBLESlista_0 a lista_21 en BDsync.php7.2 📋 Las 17 listas configuradas
Definidas en config/database.php como LISTAS_DISPONIBLES:
| id_lista | Nombre | Empresa |
|---|---|---|
1 | ZA | Delivery | ZA |
3 | ZA | Lista N° 1 | ZA |
4 | ZA | Lista N° 2 | ZA |
5 | ZA | Lista Costo Especial | ZA |
7 | ZA | Lista Veterinaria | ZA |
8 | ZA | Lista N° 3 C/VETE | ZA |
18 | ZA | Lista Feed Chasis | ZA |
19 | ZA | Lista Feed Equipo | ZA |
21 | ZA | SALON MINORISTA | ZA |
9 | TA | Precio Lista | TA |
10 | TA | Precio Contado | TA |
11 | TA | Precio Lunes | TA |
13 | TA | Desc. Especial | TA |
14 | EB | Lista C/Tarjeta | EB |
15 | EB | Lista Contado | EB |
16 | EB | Lista Mayorista | EB |
17 | EB | Lista Interna | EB |
articulos_precios
tiene 22 columnas (lista_0 a lista_21), pero el schema definido por
listas/api/_schema.php omite las no usadas (17 columnas + lista_0).
7.3 🗄️ Schema
3 tablas principales
┌─────────────────────────┐
│ articulos_formas_agrupar│ maestro
│ PK id_forma_agrupar │ (ej: MARCA, ACCESORI)
│ des_forma_agrupar │
└────────────┬────────────┘
│ 1
│
│ N
┌────────────▼────────────┐
│ articulos_agrupaciones │ N:N artículo × forma
│ PK(id_articulo, │
│ id_forma_agrupar) │
│ des_agrupacion │ (ej: COLLARES Y CORREA)
└─────────────────────────┘
│ N
│
│ 1
▼
┌─────────────────────────┐
│ articulos_precios │ 1 fila por artículo
│ PK id_articulo │
│ lista_0 (precio base) │
│ lista_1, 3, 4, …, 21 │ precios por canal
│ visible_mobile │
│ anulado │
│ sync_fecha │
└─────────────────────────┘
│
│ idx_des (búsqueda)
▼
(consultor)
listas_sync (metadata)
CREATE TABLE listas_sync (
id_lista TINYINT UNSIGNED PRIMARY KEY,
nombre_lista VARCHAR(100),
ultima_sync DATETIME,
total_filas INT UNSIGNED DEFAULT 0
);
Migraciones idempotentes en _schema.php
// Backfill de visible_mobile desde articulos_raw
try {
$pdo->exec(
"UPDATE articulos_precios ap
INNER JOIN articulos_raw ar ON ar.codigo = ap.id_articulo
SET ap.visible_mobile = IF(ar.usado_disp_movil = 'NO', 0, 1)"
);
} catch (Exception $e) {
// articulos_raw puede no existir en todos los entornos
}
Esto ejecuta en cada hit a listas/index.php → garantiza que
visible_mobile esté sincronizado con el catálogo. Pero ejecutar un
UPDATE en cada hit es costoso si la tabla crece. Ver propuesta P-LIS-2.
7.4 🔍 index.php — el consultor
Flujo de uso
- Usuario selecciona lista (de las 17) y forma de agrupar (MARCA, CATEGORÍA, etc.).
- Click "Buscar" → llama
api/precios.php?lista=N&forma=X. - Muestra tabla agrupada por
des_agrupacioncon precio + cod_barra_bulto + bultos.
Endpoint api/precios.php
SELECT
ap.id_articulo,
ap.des_articulo,
ap.cod_barra_bulto,
ap.unidades_bulto,
ap.lista_N AS precio,
ag.des_agrupacion
FROM articulos_precios ap
LEFT JOIN articulos_agrupaciones ag
ON ag.id_articulo = ap.id_articulo
AND ag.id_forma_agrupar = ?
WHERE ap.anulado = 0
AND ap.visible_mobile = 1
AND ap.lista_N IS NOT NULL
ORDER BY ag.des_agrupacion, ap.des_articulo;
UI
- Tema dark/light con clave
za-theme. - Tabla con
tr.group-headerpara cada agrupación. - Filtro de búsqueda incremental (cliente-side).
- Banner con
listas_sync.ultima_sync("Datos al 2026-05-20").
7.5 🔁 Sync delegado
// listas/sync.php
<?php
header('Location: /catalogo/admin/api_sync.php', true, 301);
exit;
Sólo 76 bytes. Redirige a /catalogo/admin/api_sync.php (fuera del módulo
Reportes). Esto significa que el sync efectivo de precios lo hace otro módulo
del sitio (/catalogo/), no el de Reportes.
/catalogo/admin/api_sync.php exista
y funcione. Si /catalogo se reorganiza, este redirect rompe sin warning.
Existe también listas/api/sync_process.php (11.7 KB) que parecería ser
una copia o backup del backend del sync — pero no se llama desde
sync.php. Posible código muerto.
7.6 ⚠️ Hallazgos específicos del módulo
| ID | Hallazgo | Prioridad |
|---|---|---|
LIS-01 |
listas/sync.php es un stub que redirige a otro módulo — acoplamiento implícito. |
Medio |
LIS-02 |
listas/api/sync_process.php (11.7 KB) no se llama desde el stub — posible código muerto. |
Medio |
LIS-03 |
Backfill de visible_mobile ejecuta UPDATE en CADA hit a index.php. |
Medio |
LIS-04 |
22 columnas lista_N en BD vs 17 en el schema PHP → divergencia. |
Bajo |
LIS-05 |
Sin versionado (version.php no existe). |
Medio |
LIS-06 |
Agregar una lista nueva (id 22) requiere editar config/database.php + _schema.php + ALTER TABLE. |
Bajo |
LIS-07 |
Sin auth — cualquiera puede consultar todos los precios (puede ser intencional para uso interno público). | Bajo |
7.7 🚀 Propuestas específicas del módulo
P-LIS-1 · Decidir si sync_process.php está vivo
Hacer grep -r "sync_process" /reportes/listas/ y si nadie lo llama,
eliminarlo. Si está vivo (algún cron o llamada manual), documentarlo en el header
del archivo.
P-LIS-2 · Mover el backfill a un cron / trigger
// En vez de UPDATE en cada hit:
-- Opción A: Cron nocturno
0 4 * * * php /reportes/listas/cron_backfill_visible.php
-- Opción B: Trigger SQL
CREATE TRIGGER trg_articulos_raw_to_precios
AFTER UPDATE ON articulos_raw FOR EACH ROW
BEGIN
UPDATE articulos_precios
SET visible_mobile = IF(NEW.usado_disp_movil = 'NO', 0, 1)
WHERE id_articulo = NEW.codigo;
END;
P-LIS-3 · Normalizar schema a tabla larga
22 columnas lista_N es denormalización extrema. Refactor:
CREATE TABLE articulos_precios_v2 (
id_articulo INT NOT NULL,
id_lista SMALLINT UNSIGNED NOT NULL,
precio DECIMAL(14,4),
sync_fecha DATETIME,
PRIMARY KEY (id_articulo, id_lista),
INDEX idx_lista (id_lista)
);
-- Migración: PIVOT desde la tabla actual
INSERT INTO articulos_precios_v2 (id_articulo, id_lista, precio, sync_fecha)
SELECT id_articulo, 0, lista_0, sync_fecha FROM articulos_precios WHERE lista_0 IS NOT NULL
UNION ALL
SELECT id_articulo, 1, lista_1, sync_fecha FROM articulos_precios WHERE lista_1 IS NOT NULL
UNION ALL
SELECT id_articulo, 3, lista_3, sync_fecha FROM articulos_precios WHERE lista_3 IS NOT NULL
-- ... etc
;
Ventajas: agregar una lista nueva no requiere ALTER TABLE; queries
más flexibles; historial por lista trivial.
P-LIS-4 · UI editor de precios
Hoy es solo lectura. Sería útil:
- Permitir editar precios (cuando exista auth) sin re-subir Excel completo.
- Bulk update por % (ej. "subir lista 7 un 10%").
- Preview del impacto antes de guardar.
- Audit log de cambios manuales.
P-LIS-5 · Catálogo de listas en DB
Mover LISTAS_DISPONIBLES de config/database.php a DB:
CREATE TABLE listas_catalogo (
id_lista SMALLINT UNSIGNED PRIMARY KEY,
empresa VARCHAR(10),
nombre_corto VARCHAR(50),
nombre_largo VARCHAR(100),
visible TINYINT(1) DEFAULT 1,
orden TINYINT DEFAULT 0
);
UI admin para editar sin tocar PHP.
P-LIS-6 · Export PDF de la lista
Botón "Exportar PDF" en el consultor → genera PDF con header de la lista, fecha, agrupación, total de productos. Útil para enviar a clientes finales por WhatsApp.