1. Sube los archivos de Salesforce
Arrastra aquí los archivos o haz clic para seleccionarlos
Se aceptan hasta 3 archivos: PDC P. FISICAS, PDC P. MORALES y LCV CEM VENTAS (NADIN)
2. Resultados del proceso
Historial reciente
Cargando…
Historial de procesos
Cargando historial...
Bitácora de limpiezas
Cargando bitácora...
Bienvenido al pipeline
Vas a procesar los 3 reportes de Salesforce (PDC Físicas, PDC Morales, LCV CEM Ventas NADIN) en 4 etapas: Normalización → Base de Limpieza → Archivos MX → Concentrado. En cada paso podrás revisar la tabla resultante antes de continuar — nada se encadena automáticamente.
Concentrado Histórico
Base de datos local de todos los registros procesados. Consulta, filtra, exporta o importa archivos externos. Cada importación permite rollback durante 30 días.
Historial de ejecuciones
Carga el historial para ver las últimas ejecuciones.
Manual de Usuario y Documentación Técnica
Guía completa del pipeline de limpieza de datos VWVC. Documenta la lógica del sistema, cómo operarlo día a día, los archivos que produce y el esquema de la base de datos histórica.
1. Flujo del pipeline — paso a paso
El sistema procesa tres reportes de Salesforce (PDC Físicas, PDC Morales y LCV CEM Ventas NADIN) y los transforma en archivos limpios listos para entrega a Volkswagen. El flujo se ejecuta en 4 etapas observables vía la pestaña Pipeline. Lo que sigue describe en orden lo que el código realmente hace.
Paso 1 — Carga y lectura de archivos
Qué hace: abre cada Excel crudo de Salesforce con tolerancia a fallos: tipos mixtos, AutoFilters problemáticos y errores de XML interno. Salta las filas de metadata iniciales (skiprows) hasta encontrar los encabezados reales.
Por qué: los archivos exportados de Salesforce traen 2-4 filas de metadata (fecha de exportación, usuario, totales) antes del header real. Si se leyera "directo" pandas tomaría esas filas como encabezados y todo lo demás reventaría.
Paso 2 — Normalización de nombres de columna
Qué hace: remueve acentos, reemplaza espacios y caracteres especiales por guiones bajos, deja todo en un formato canónico. "Cliente de Venta: Nombre" se vuelve Cliente_de_Venta_Nombre.
Por qué: Salesforce exporta encabezados con espacios, dos puntos, signos y acentos. Estos son difíciles de manejar en código (escapes, codificación) y rompen joins con el directorio oficial. La normalización vuelve las columnas referenciables sin ambigüedad.
Paso 3 — Eliminación de la fila de totales
Qué hace: detecta la fila donde la columna centinela contiene la palabra "Total" y corta el DataFrame justo antes. Si no hay total, se queda con todo.
Por qué: Salesforce concatena una fila resumen al final de cada export ("Total: 142"). Si no se eliminara, sería procesada como un registro real y produciría estados inválidos en la cascada de validación.
Paso 4 — Limpieza de valores (mapeos, teléfonos, fechas)
Qué hace: aplica mapeos globales de valores categóricos (sexo M/F → 1/2, permisos Sí/No → 1/0, etc.), limpia teléfonos eliminando notación científica y caracteres no numéricos, normaliza fechas a formato MX YYYYMMDD.
Por qué: Excel convierte teléfonos largos a notación científica (5.5512e+9) o a float (5551234567.0) si la celda no está en formato texto. La limpieza preserva los 10 dígitos como string y la celda final en el Excel queda con formato '@' (texto) para que VW pueda usarla tal cual.
Paso 5 — Identificación y normalización de modelo (incluyendo inferencia por VIN)
Qué hace: primero intenta usar el valor de la columna Modelo directamente. Si está vacío, busca el modelo en un catálogo VIN→modelo precalculado (data/concentrado_modelos.csv, ~10 000 entradas). Si encuentra coincidencia, completa el modelo automáticamente. Después normaliza el resultado a uno de los 5 modelos válidos.
Por qué: el campo "Modelo" en Salesforce viene vacío en ~5-8% de los registros, pero el VIN siempre está. El catálogo histórico permite recuperar la información sin perder al registro en la cascada de validación. Modelos no comerciales (Jetta, Polo, etc.) se filtran fuera.
Paso 6 — Validación con cascada de penalizaciones
Qué hace: aplica 11 reglas de evaluación en orden estricto. La primera que matche "gana" — un registro solo recibe un motivo de penalización, no se acumulan.
- Red no oficial — dealer fuera del directorio VW vigente
- Fecha no válida (no penalizado) — fuera del rango de la ola
- Órdenes internas (no penalizado) — tipos 3,5,7,8,9,10,11,12 en postventa
- Chasis repetido (no penalizado) — VIN duplicado intra-reporte
- Otros modelos (no penalizado) — Jetta, Polo, etc.
- Sin permiso (penalizado) — cliente no autorizó contacto
- Sin modelo (penalizado) — modelo vacío + VIN no rescatable por catálogo
- Sin nombre (penalizado) — nombre vacío, basura o "Volkswagen"/"SAPI de CV"/etc.
- Sin email (penalizado) — ninguna de las 4 columnas alternativas de correo tiene un email válido
- Cargado — pasa todas las reglas, se entrega a la encuesta
- Cliente repetido (no penalizado) — mismo cliente ya cargado en este lote
Por qué cascada y no flags independientes: el SP original en SQL Server tenía esta lógica de exclusión mutua. Si un registro no tiene modelo y tampoco nombre, queremos reportarlo UNA sola razón (la primera detectada) — replicar el comportamiento original es clave para no romper auditoría histórica.
Paso 7 — Asignación de Status y Observaciones
Qué hace: traduce el _estatus interno a 2 columnas user-facing:
- Status = CARGADO si _estatus="Cargado", sino NO CARGADO.
- Observaciones = el texto exacto del _estatus (e.g. "Sin email (penalizado)").
Por qué: el operador ve dos columnas claras: una para filtrar (Status binario) y otra para auditar el motivo (texto descriptivo). VW solo recibe los registros con Status=CARGADO en el MX final, pero la Base de Limpieza conserva los NO CARGADO con su razón para análisis.
Paso 8 — Generación de la Base de Limpieza
Qué hace: genera dos archivos Excel para el operador interno con TODOS los registros (CARGADO + NO CARGADO) más hojas auxiliares:
- Base_limpieza_ventas_YYYYMMDD.xlsx: Hoja1 (datos), NADIN (DWH), ARCO, td
- Base_limpieza_postventa_YYYYMMDD.xlsx: Hoja1 (físicas + morales unificadas), ARCO, TD
Por qué: es el entregable que revisa el operador antes de mandar a VW. La hoja ARCO traza los derechos de cliente (Aplicación de derechos ARCO según LFPDPPP), la hoja TD/td lista las redes territoriales, NADIN es referencia del DWH histórico.
Paso 9 — Generación de los archivos MX (entregables a VW)
Qué hace: filtra SOLO los registros con Status=CARGADO y los proyecta a la estructura exacta que VW espera para la encuesta CEM:
- MX_CV_SA_YYYY_YYYYMMDD.xlsx — Ventas (63 columnas)
- MX_CV_AS_YYYY_YYYYMMDD.xlsx — Postventa (Físicas + Morales consolidadas, 64 columnas)
El nombre incluye el número de "ola" (001 si día ≤ 15, 002 si día ≥ 16) y un consecutivo que se calcula leyendo el último MX previo del directorio.
Por qué solo CARGADO: los NO CARGADO no van a encuesta — solo los registros elegibles que pasaron todas las reglas. El consecutivo y el wave son requeridos por VW para correlacionar con su lado.
Paso 10 — Carga al Concentrado Histórico (SQLite)
Qué hace: inserta los registros (TODOS, no solo CARGADO) en la BD local SQLite db/concentrado.db, creando una fila padre en ejecuciones y filas hijas en ventas y postventa. Registra un rollback disponible por 30 días.
Por qué: sin esta etapa cada ejecución se perdería. El concentrado permite consultar cualquier registro procesado en el pasado, exportar rangos de fechas, detectar VINs duplicados entre ejecuciones, y hacer rollback de una carga errónea. El rollback de 30 días balancea seguridad operativa vs. crecimiento de tabla.
2. Guía de operación diaria
1. Obtener los tres reportes de Salesforce
- Entra a Salesforce → reportes guardados.
- Ejecuta los tres reportes del día:
- PDC P. FISICAS VW 2025 — postventa de personas físicas
- PDC P. MORALES VW 2025 — postventa de personas morales
- LCV CEM VENTAS NADIN FISICAS & Base 10 — ventas
- Exporta cada uno como Excel (.xlsx), sin modificar el nombre del archivo (el sistema reconoce por palabras clave: FISICAS, MORALES, NADIN/LCV).
2. Subir los archivos a la interfaz web
- Abre https://bivwvc.base10.mx/ e inicia sesión.
- Ve a la pestaña Pipeline.
- Arrastra los 3 archivos al área de carga (o haz clic para seleccionarlos).
- Verifica que aparezcan los tres con su tipo correctamente clasificado.
- Selecciona el modo:
- Automático — corre las 4 etapas seguidas
- Manual — avanza una etapa a la vez (recomendado para diagnóstico)
- Pulsa Iniciar pipeline.
3. Interpretar el progreso de las etapas
- Las 4 etapas se muestran como cards con ícono de estado: ⏱ (pendiente), spinner (en proceso), ✓ (completado), ✗ (error).
- Haz clic en cualquier etapa para ver sus logs en tiempo real en el panel inferior (polling cada 2 s mientras la etapa esté en proceso).
- Cada etapa muestra: registros procesados, OK, errores, duración, y archivo de salida cuando aplica.
4. Descargar los archivos generados
- Al terminar el proceso, ve a la pestaña Historial de Procesos.
- Localiza tu proceso por ID o fecha.
- Descarga: Plantillas intermedias, Bases de Limpieza, y archivos MX (los que VW recibe).
5. Consultar el Concentrado Histórico
- Ve a la pestaña Concentrado Histórico.
- Por defecto muestra el mes actual. Cambia el filtro de fechas si necesitas otro rango.
- Alterna entre Ventas y Postventa.
- Búsqueda libre por nombre, VIN, correo (campo de texto arriba de la tabla).
- Filtros: Fecha inicio/fin, Status, Dealer ID, Modelo, Tipo persona (solo postventa).
- Personaliza columnas visibles con el botón Columnas (se recuerda en localStorage).
6. Exportar datos del concentrado
- Aplica los filtros que quieras (mes, status, dealer, etc.).
- Pulsa Exportar Excel o Exportar CSV.
- El archivo descargado tiene TODOS los registros que matchean los filtros (sin paginación).
7. Importar archivos externos
- Pulsa Importar datos en la pestaña Concentrado.
- Selecciona archivo .xlsx o .csv (máx 50 MB).
- Elige el tipo (Ventas o Postventa).
- Pulsa Validar: el sistema lee el archivo y muestra preview + errores.
- Revisa errores críticos (que bloquean la importación) vs advertencias (duplicados históricos).
- Si todo OK, pulsa Confirmar importación. Se crea una ejecución con rollback disponible por 30 días.
8. Ejecutar un rollback
- En la pestaña Concentrado, sección Historial de ejecuciones.
- Localiza la ejecución a revertir (debe tener rollback disponible, no haber pasado 30 días).
- Pulsa el botón Rollback de esa fila.
- Confirma. Se eliminan todos los registros de ventas y postventa de esa ejecución y se marca el rollback como ejecutado (no se puede deshacer).
3. Archivos de salida
| Archivo | Hojas | Cols | Contenido | Para quién |
|---|---|---|---|---|
| Plantilla_ventas_YYYYMMDD.xlsx Plantilla_p_fisicas_YYYYMMDD.xlsx Plantilla_p_morales_YYYYMMDD.xlsx |
1 | variable | Datos normalizados (post limpieza, pre validación). Incluye Status y Observaciones. | Uso interno — paso intermedio. |
| Base_limpieza_ventas_YYYYMMDD.xlsx | 4 (Hoja1, NADIN DWH, ARCO, td) | 51+ | TODOS los registros de ventas (CARGADO + NO CARGADO) + hojas auxiliares legales. | Operador / auditoría. Revisión antes de envío. |
| Base_limpieza_postventa_YYYYMMDD.xlsx | 3 (Hoja1, ARCO, TD) | 58+ | Postventa consolidada (físicas + morales). Todos los registros. | Operador / auditoría. |
| MX_CV_SA_YYYY_YYYYMMDD.xlsx | 1 | 63 | SOLO registros CARGADO de ventas, estructura exacta esperada por VW. | Entregable a VW. |
| MX_CV_AS_YYYY_YYYYMMDD.xlsx | 1 | 64 | SOLO registros CARGADO de postventa (físicas + morales). | Entregable a VW. |
4. Preguntas frecuentes / casos de error
¿Qué pasa si un VIN no tiene modelo en Salesforce?
El pipeline consulta el catálogo histórico data/concentrado_modelos.csv (VIN → modelo) y completa el campo automáticamente. Si el VIN tampoco está en el catálogo, el registro se marca como "Sin modelo (penalizado)" en la cascada de validación y su Status queda en NO CARGADO.
¿Por qué un registro queda como NO CARGADO?
Cualquiera de estas razones, en orden de prioridad:
- Red no oficial — el dealer no aparece en el directorio VW del periodo.
- Fecha no válida — fuera del rango de la ola.
- Órdenes internas — tipos administrativos de servicio (solo postventa).
- Chasis repetido — el mismo VIN aparece más de una vez en el archivo.
- Otros modelos — no es AMAROK/CADDY/CRAFTER/EUROVAN/TRANSPORTER.
- Sin permiso — el cliente no autorizó contacto (penaliza al dealer).
- Sin modelo — modelo vacío y VIN no rescatable.
- Sin nombre — nombre vacío, basura o lista negra (Volkswagen, SAPI, etc.).
- Sin email — ninguna de las 4 columnas alternativas tiene un email válido.
- Cliente repetido — mismo cliente ya cargado en este lote (solo si pasó todo lo anterior).
La columna Observaciones indica el motivo exacto.
¿Qué significa cada valor en la columna Observaciones?
Los valores literales que pueden aparecer son:
- Cargado — pasó todas las reglas, va a encuesta.
- Red no oficial
- Fecha no válida (no penalizado)
- Órdenes internas (no penalizado)
- Chasis repetido (no penalizado)
- Otros modelos (no penalizado)
- Sin permiso (penalizado)
- Sin modelo (penalizado)
- Sin nombre (penalizado)
- Sin email (penalizado)
- Cliente repetido (no penalizado)
El sufijo (penalizado) indica que el dealer responsable recibe puntos en contra en el índice de calidad. Las marcas (no penalizado) son filtros operativos sin impacto en el KPI del dealer.
¿Qué hacer si el pipeline falla en una etapa?
- Abre la etapa con error en la pestaña Pipeline.
- Revisa el panel de logs — la última línea típicamente describe el error (e.g. [ERROR] Plantilla intermedia no encontrada).
- Causas comunes:
- Archivo corrupto — el Excel exportado de Salesforce quedó truncado; re-exportarlo.
- Columna esperada faltante — Salesforce cambió el nombre de una columna; revisar los mapeos en backend/pipeline.py (config_fisicas, etc.).
- Catálogo no encontrado — data/concentrado_modelos.csv o Directorio_Febrero_2026.xlsx ausentes.
- Si necesitas re-correr solo desde una etapa, sube los archivos de nuevo en modo manual y avanza etapa por etapa.
- Si el error persiste, contacta al equipo de plataforma con el ID del proceso (visible en la tarjeta del proceso).
¿Cómo recuperar un error de importación al concentrado?
- Si la importación se completó pero los datos están mal: ejecuta Rollback desde el historial de ejecuciones (disponible los primeros 30 días).
- El rollback elimina todos los registros de ventas y postventa de esa ejecución; la fila padre en ejecuciones se conserva pero queda marcada como eliminada en rollbacks.
- Si pasaron más de 30 días: el rollback no está disponible. Hay que limpiar manualmente con SQL en db/concentrado.db (requiere acceso al servidor).
- Si la importación falló a media inserción: el sistema usa transacciones, así que NO debería quedar estado parcial. Revisa los logs de la ejecución para confirmar.
5. Esquema de la base de datos histórica
Toda la persistencia vive en un solo archivo SQLite: /opt/vwvc-pipeline/db/concentrado.db. Cuatro tablas, relación 1:N de ejecuciones hacia ventas/postventa, y 1:1 hacia rollbacks. Sin ORM — sqlite3 estándar.
ejecuciones PK: id
registro maestro de cada corrida| Campo | Tipo | Descripción | Ejemplo |
|---|---|---|---|
| 🔑 id | INTEGER PK AUTOINCREMENT | Identificador interno autoincremental | 142 |
| proceso_id | TEXT NOT NULL UNIQUE | UUID4 del proceso (mismo que en estado_pipeline) | f52e796c-087d-... |
| fecha_carga | TEXT NOT NULL | ISO8601 timestamp | 2026-05-20T14:23:11 |
| usuario | TEXT | Email del operador | jl@base10.mx |
| tipo_carga | TEXT NOT NULL | 'automatico' (pipeline) o 'manual' (importación) | automatico |
| resultado | TEXT NOT NULL | 'exitoso', 'error' o 'parcial' | exitoso |
| logs | TEXT | JSON array de líneas de log | ["...", "..."] |
| estado | TEXT NOT NULL DEFAULT 'completado' | Estado del registro (completado/eliminado) | completado |
| total_ventas | INTEGER DEFAULT 0 | Conteo de filas insertadas en ventas | 174 |
| total_pv | INTEGER DEFAULT 0 | Conteo de filas insertadas en postventa | 83 |
ventas PK: id · FK: ejecucion_id → ejecuciones.id
19 campos · 5 índices| Campo | Tipo | Descripción | Ejemplo |
|---|---|---|---|
| 🔑 id | INTEGER PK AUTOINCREMENT | Identificador interno | 87432 |
| FK ejecucion_id | INTEGER NOT NULL → ejecuciones.id | A qué ejecución pertenece el registro | 142 |
| vin | TEXT (idx) | VIN del vehículo (17 chars) | WV1ZZZ70ZNH012345 |
| dealer_id | TEXT (idx) | Construido por validador desde No.Concesionaria + directorio | MX1234 |
| modelo | TEXT | AMAROK / CADDY / CRAFTER / EUROVAN / TRANSPORTER | AMAROK |
| nombre_factura | TEXT | Razón social en factura | JUAN PEREZ LOPEZ |
| fecha_facturacion | TEXT | Fecha de factura (texto MX) | 20260315 |
| fecha | TEXT (idx) | Fecha canónica del evento (FECHA_MX) | 20260315 |
| nombre_cliente | TEXT | Nombre del cliente | JUAN |
| apellido_paterno | TEXT | Apellido paterno | PEREZ |
| apellido_materno | TEXT | Apellido materno | LOPEZ |
| nombre_completo | TEXT | Concatenación normalizada | JUAN PEREZ LOPEZ |
| correo | TEXT | Email rescatado por validador (4 columnas, typo-corregido) | juan@gmail.com |
| telefono | TEXT | Teléfono principal limpio (sin notación científica) | 5551234567 |
| permiso_transferencia | TEXT | 1/0 — permiso transferencia a marca | 1 |
| permiso_marketing | TEXT | 1/0 — permiso contacto marketing | 0 |
| status | TEXT (idx) | CARGADO / NO CARGADO | CARGADO |
| observaciones | TEXT | Motivo de la cascada (e.g. "Sin email (penalizado)") | Cargado |
| ola | TEXT | "1Q", "2Q", "1a", "2a" | 1Q |
| fecha_carga | TEXT NOT NULL | Cuándo se insertó este registro | 2026-05-20T14:23:11 |
postventa PK: id · FK: ejecucion_id → ejecuciones.id
16 campos · 4 índices| Campo | Tipo | Descripción | Ejemplo |
|---|---|---|---|
| 🔑 id | INTEGER PK AUTOINCREMENT | Identificador interno | 52891 |
| FK ejecucion_id | INTEGER NOT NULL → ejecuciones.id | Ejecución a la que pertenece | 142 |
| vin | TEXT (idx) | VIN del vehículo | WV1ZZZ70ZNH012345 |
| dealer_id | TEXT | Construido por validador | MX1234 |
| modelo | TEXT | Modelo válido | CRAFTER |
| fecha | TEXT (idx) | FECHA_MX o Fecha_Salida | 20260315 |
| nombre | TEXT | Nombre del cliente | ANA |
| apellido | TEXT | Apellido principal | TORRES |
| nombre_completo | TEXT | Concatenado | ANA TORRES |
| correo | TEXT | Email rescatado | ana@empresa.mx |
| telefono | TEXT | Teléfono limpio | 5559876543 |
| legal_consent_online | TEXT | 1/0 — permiso transferencia marca | 1 |
| status | TEXT (idx) | CARGADO / NO CARGADO | CARGADO |
| observaciones | TEXT | Motivo cascada | Cargado |
| ola | TEXT | Ola CEM (si aplica) | 1a |
| tipo_persona | TEXT | 'fisica' o 'moral' — discriminador de origen | fisica |
| fecha_carga | TEXT NOT NULL | Timestamp de inserción | 2026-05-20T14:23:11 |
rollbacks PK: id · FK: ejecucion_id → ejecuciones.id (UNIQUE)
ventana de reversión por ejecución| Campo | Tipo | Descripción | Ejemplo |
|---|---|---|---|
| 🔑 id | INTEGER PK AUTOINCREMENT | Identificador | 142 |
| FK ejecucion_id | INTEGER NOT NULL UNIQUE → ejecuciones.id | Ejecución reversable (1:1) | 142 |
| disponible_hasta | TEXT NOT NULL | Fecha límite del rollback (ISO8601) | 2026-06-19T14:23:11 |
| eliminado_por | TEXT (NULL si disponible) | Email del que ejecutó el rollback | jl@base10.mx |
| eliminado_en | TEXT | Timestamp del rollback ejecutado | 2026-06-01T09:15:00 |
6. Diagrama del modelo de datos (ER)
Relaciones entre las 4 tablas. 🔑 marca llave primaria, FK marca llave foránea.
- Una ejecución produce N filas de ventas y N de postventa.
- Una ejecución tiene como máximo 1 rollback (UNIQUE en ejecucion_id).
- El borrado en cascada NO está activado por integridad histórica — un rollback solo elimina las filas de ventas/postventa, conserva la fila padre en ejecuciones y marca el rollback como ejecutado.