Manual Tecnico del
Presupuestador Conexia
Documentacion completa: funcionalidades actuales + desarrollo Fase 0
Version 1.0 | Abril 2026
URL: pedidos.conexiatec.com
Base de datos: conexiatec_adminpresupuestador
Autores: Conexia Telecomunicaciones
Indice de Contenidos
  1. Arquitectura del Sistema
    1. Stack Tecnologico
    2. Estructura de Archivos
    3. Dos Portales, Una Base de Datos
  2. Roles y Permisos
    1. Roles actuales
    2. Permisos granulares
    3. Super Admin
  3. Menus y Navegacion
    1. Sidebar del Distribuidor
    2. Sidebar del Admin
  4. Funcionalidades - Portal Distribuidor
    1. Presupuestos Realizados
    2. Nuevo Presupuesto
    3. Pipeline (Kanban comercial)
    4. Mi Actividad
    5. Dashboard Director
    6. Estadisticas
    7. Scoring / Gamificacion
    8. Cobertura
  5. Funcionalidades - Portal Admin
    1. Dashboard Admin
    2. Configuraciones (Hub)
    3. Productos
    4. Familias
    5. Webhooks
    6. Alertas
    7. Email Templates
    8. Config General
    9. Agentes / Usuarios Configurador
    10. Clientes
  6. API REST
    1. API actual
    2. Endpoints a agregar (Fase 0)
  7. Integraciones
    1. DoWISP
    2. Webhooks salientes
    3. Cobertura multi-proveedor
  8. Cambios en Base de Datos (Fase 0)
  9. Seguridad
  10. Plan de Implementacion Fase 0
  11. Apendice A: Mapa de archivos modificados
  12. Apendice B: Tabla de permisos por rol

1. Arquitectura del Sistema

1.1 Stack Tecnologico EXISTE

ComponenteDetalle
BackendPHP puro (sin framework) con clases OOP: BaseModel + subclases (AgenteModel, BudgetModel, ContactModel, DocumentModel, EmailModel, ListModel, UserModel)
Frontend JSjQuery 3.7.1 + Bootstrap 4/5 + Chart.js + ApexCharts + Select2
CSSapp.css v2.0 con DM Sans, variables CSS (--color-primary, --color-sidebar, etc.), design system moderno con radios, sombras y layout responsivo
Base de datosMySQL: conexiatec_adminpresupuestador
AutenticacionSesiones PHP: admin_session (portal admin) + agente_session (portal distribuidor). Hash SHA-256 + salt para passwords
API RESTdistribuidor/api/index.php con auth via header X-API-Key contra tabla config_api_keys
WebhooksHMAC-SHA256 con reintentos (backoff exponencial: 1m, 5m, 15m) y logs en BD
CSRFClase Security + csrf.js inyecta automaticamente token en todas las peticiones jQuery POST
CifradoAES-256-CBC via functions/crypt.php (openssl_encrypt con PBKDF2)
TimezoneEurope/Madrid configurado en config.php

1.2 Estructura de Archivos EXISTE

presupuestador_new/
  admin/                         <-- Portal administracion
    clases/                      <-- OOP: BaseModel.php, AgenteModel.php, BudgetModel.php,
                                       ContactModel.php, DocumentModel.php, EmailModel.php,
                                       ListModel.php, UserModel.php + legacy cls_*.php
    php/                         <-- Endpoints AJAX (~45 archivos _bd.php)
      agentes_bd.php               Gestion agentes/usuarios configurador
      alertas_bd.php               CRUD alertas
      budget_bd.php                Presupuestos admin
      comerciales_bd.php           Gestion comerciales
      company_bd.php               Datos empresa
      configuracion_bd.php         Config general unificada
      contacts_bd.php              CRUD clientes
      email_templates_bd.php       Templates email
      familias_bd.php              Familias de productos
      producto_bd.php              CRUD productos
      subfamilias_bd.php           Subfamilias
      webhooks_bd.php              Config webhooks admin
      ...
    js/                          <-- Frontend JS: app.js, csrf.js, budget.js, contacts.js, etc.
    content/                     <-- Vistas HTML parciales (configuraciones.php, etc.)
    inc/                         <-- Includes: _sidebar.php (UNIFICADO), _top.php, _footer.php
    config/                      <-- config.php (BD, constantes, includes funciones)
    functions/                   <-- crypt.php, Security.php, db.php, helpers.php, logins.php
    migrations/                  <-- SQL migrations
    pdf/                         <-- Generacion PDF: invoice.php, budget.php, border.php, advice.php

  distribuidor/                  <-- Portal operaciones
    api/                         <-- REST API: index.php (router principal)
    php/                         <-- Endpoints AJAX
      index_bd.php                 Nuevo presupuesto (~93KB, archivo central)
      presupuestos_bd.php          Listado presupuestos + substatus
      pipeline_bd.php              Pipeline kanban distribuidores
      actividades_bd.php           Actividades comerciales
      dashboard_director_bd.php    KPIs direccion
      estadisticas_bd.php          Estadisticas detalladas
      scoring_bd.php               Gamificacion y puntos
      permisos_helper.php          Sistema RBAC (deteccion rol + permisos)
      webhooks_helper.php          Motor webhooks (dispatch, send, log, retry, API auth)
      ...
    js/                          <-- Frontend JS
      index.js                     Nuevo presupuesto (familias, productos, carrito)
      presupuestos.js              Listado presupuestos
      actividades.js               Actividades comerciales
      estadisticas.js              Graficos estadisticas
      realizar.js                  Realizar pedido
      pedidos.js                   Gestion pedidos
      ...
    inc/                         <-- _topbar.php, _head.php, _sidebar.php (proxy a admin)
    assets/css/                  <-- app.css v2.0 (design system completo)
    content/                     <-- Vistas HTML: cobertura.php, etc.

  sql/                           <-- Migraciones SQL
    pipeline.sql                   Columnas pipeline + tablas umbrales/log
    actividades_comercial.sql      Tabla actividades comerciales
    scoring_actividad.sql          Config scoring por actividad
    sprint19_potenciales.sql       Pipeline potenciales vs activos
    zoho_sync_columns.sql          Columnas sincronizacion Zoho
    calendar_sync.sql              Sincronizacion calendario

1.3 Dos Portales, Una Base de Datos EXISTE

Portal Admin (/admin/): Configuracion, productos, familias, webhooks, alertas, clientes, agentes, comerciales, email templates.

Portal Distribuidor (/distribuidor/): Presupuestos, pipeline, actividades, estadisticas, scoring, cobertura, dashboard director.

Sidebar UNIFICADO: El archivo admin/inc/_sidebar.php se incluye desde ambos portales. Detecta automaticamente el contexto ($_inAdmin / $_inDist) via $_SERVER['REQUEST_URI'] y adapta los menus segun rol y permisos.

Comparten la BD MySQL conexiatec_adminpresupuestador. Sesiones separadas: admin_session vs agente_session.

2. Roles y Permisos

2.1 Roles actuales EXISTE

Sistema RBAC implementado en distribuidor/php/permisos_helper.php con tabla config_roles que almacena permisos como JSON. Actualmente 4 roles:

RolDeteccionAcceso
admin_superEmail @conexiatec.com o session admin activaTodo el sistema (permiso wildcard *)
directorCampo comerciales.role = 'director' (legacy) o agentes.rol = 'director'Admin + distribuidor + config
distribuidorAgente no @conexiatec.com, no admin, con distribuidor asignadoPortal distribuidor: presupuestos, sus pedidos
agenteDefault (sin distribuidor, sin rol asignado)Portal distribuidor limitado

Cadena de deteccion de rol (permisos_helper.php)

La funcion get_rol_usuario() sigue esta prioridad estricta:

  1. agentes.rol (BD) - Asignado desde panel admin_permisos. Si el campo tiene valor, se usa directamente.
  2. comerciales.role (legacy) - Si agentes.rol esta vacio, busca en tabla comerciales por email. Soporte para directores/jefes historicos.
  3. @conexiatec.com - Si el email contiene @conexiatec.com y no tiene rol asignado en los pasos anteriores, se asigna admin_super.
  4. Admin en session - Si $_SESSION['admin_user'] tiene valor y no se detecto rol, se asigna admin_super.
  5. Agente con distribuidor - Si no es @conexiatec.com ni admin, se asigna distribuidor.
  6. Default - Si nada aplica: agente (sin permisos extra).

Cache: El rol y los permisos se almacenan en $_SESSION['_rol_cache'] y $_SESSION['_permisos_cache'] con TTL de 5 minutos (time() - 300). Se limpian con limpiar_cache_permisos().

2.2 Permisos granulares EXISTE

Almacenados en tabla config_roles como JSON en columna permisos. La funcion tiene_permiso($permiso) verifica contra el array decodificado. admin_super tiene siempre ['*'] (failsafe).

PermisoControla acceso a
pipeline.leerPipeline kanban + Pipeline presupuestos
pipeline.editarMover tarjetas, editar etapas
actividad.leerMi Actividad + Actividad Equipo
actividad.crearRegistrar nuevas actividades
stats.leerEstadisticas avanzadas
dashboard.directorDashboard Director con KPIs ejecutivos
admin.configSeccion Administracion (roles, pipeline config, panel admin)
distribuidor.leerAPI: listar/ver distribuidores
distribuidor.crearAPI: crear prospecto
distribuidor.editarAPI: actualizar distribuidor
distribuidor.activarAPI: convertir prospecto a activo

Funciones de verificacion disponibles

FuncionUso
tiene_permiso('pipeline.leer')Verifica un permiso especifico
tiene_algun_permiso(['stats.leer','dashboard.director'])Verifica si tiene AL MENOS uno
tiene_todos_permisos([...])Verifica si tiene TODOS
es_rol('director')Verifica rol exacto (acepta string o array)
es_admin()True si admin_super o director
es_interno()True si @conexiatec.com o admin session
requiere_permiso('admin.config')Bloquea y redirige a presupuestos.php si no tiene
requiere_rol('director')Bloquea y redirige si no tiene el rol
get_usuario_info()Devuelve array con email, nombre, rol, permisos, es_admin, es_interno

2.3 Super Admin EXISTE FASE 0

[EXISTE] Cualquier email @conexiatec.com es admin_super automaticamente (detectado en paso 3 de get_rol_usuario()). Cualquier session admin activa tambien es admin_super (paso 4).

[FASE 0] Mejoras planificadas:

Archivos a modificar: distribuidor/php/permisos_helper.php (agregar logica nivel_simulado), nuevo endpoint en distribuidor/php/ para cambiar nivel con verificacion 2FA.

3. Menus y Navegacion

Todo el sistema de navegacion se controla desde un unico archivo: admin/inc/_sidebar.php. El sidebar detecta automaticamente si esta en /admin/ o /distribuidor/ y renderiza las secciones correspondientes.

3.1 Sidebar del Distribuidor EXISTE

Se muestra cuando $_inDist = true (URL contiene /distribuidor/).

Seccion Principal (todos los roles)

MenuArchivoCondicion
Presupuestospresupuestos.phpSiempre visible (landing page)
Pipeline Ptos.pipeline_presupuestos.phppipeline.leer o admin
Nuevo Presupuestoindex.phpSiempre visible
Documentosdocumentos.phpSiempre visible
Coberturacobertura.phpSiempre visible

Seccion Comercial (requiere actividad.leer o pipeline.leer)

MenuArchivoCondicion
Mi Actividadactividades.phpactividad.leer o admin
Pipelinepipeline.phppipeline.leer o admin
Actividad Equipoactividad_equipo.phpactividad.leer o admin

Seccion Direccion (requiere dashboard.director o stats.leer)

MenuArchivoCondicion
Dashboard Directordashboard_director.phpdashboard.director o admin
Estadisticasestadisticas.phpstats.leer o admin

Seccion Administracion (requiere admin.config)

MenuArchivoCondicion
Roles y Permisosadmin_permisos.phpadmin.config o admin
Config Pipelinepipeline_admin.phpadmin.config o admin
Panel Adminadmin_bridge.phpadmin.config o admin

3.2 Sidebar del Admin EXISTE

Se muestra cuando $_inAdmin = true (URL contiene /admin/ pero no /distribuidor/).

Seccion Principal

MenuArchivo
Dashboard Adminindex.php

Seccion Contactos

MenuArchivo
Usuarios Configuradoragentes.php
Potencialesagentes.php?p=1
Clientescontacts1.php
Documentos Admindocumentos.php

Seccion Administracion

MenuArchivoDescripcion
Panel ComercialEnlace a distribuidor/presupuestos.phpAcceso al portal distribuidor
Configuracionesconfiguraciones.phpHub de configuracion (3 secciones)
Comercialescomerciales.phpGestion de comerciales
Webhookswebhooks.phpConfiguracion webhooks
Alertasalertas.phpSistema de alertas
Email Templatesemail_templates.phpPlantillas email
Config Generalconfiguracion.phpSubstatus, SMTP, scoring, badges, objetivos

4. Funcionalidades - Portal Distribuidor

4.1 Presupuestos Realizados EXISTE

Archivo PHP:
distribuidor/presupuestos.php
JS Frontend:
distribuidor/js/presupuestos.js
Backend AJAX:
distribuidor/php/presupuestos_bd.php
Acceso:
Todos los roles (filtrado por distribuidor si no es admin)

Estados de presupuesto

Status numericoNombreSubstatus posibles
0EN CURSOPENDING
1TRAMITADOSTRAMITADO
2RECHAZADOSRECHAZADO, CADUCADO, TIENE PERMANENCIA

Endpoints AJAX

AccionParametro GETDescripcion
Listar presupuestosreadPresupuestos={status}Lista por status (0/1/2) con filtros q, f1, f2. LIMIT 500. No carga campos longtext.
Cambiar substatusupdateSubstatus={uuid}POST con substatus. Si TRAMITADO: status=1 + dteTramitado=NOW(). Si RECHAZADO/CADUCADO: status=2.

Operaciones batch disponibles

Webhooks disparados

Al cambiar substatus: _wh_fire($res, 'substatus_cambiado', [...]) - funcion inline que busca en config_webhook y envia con HMAC-SHA256, timeout 5s/2s connect, log a webhook_log.


4.2 Nuevo Presupuesto EXISTE FASE 0

Archivo PHP:
distribuidor/index.php
JS Frontend:
distribuidor/js/index.js
Backend AJAX:
distribuidor/php/index_bd.php (93KB - archivo central del sistema)
Acceso:
Todos los roles

Flujo completo paso a paso [EXISTE]

#PasoEndpoint / Funcion
1Seleccionar tipo: PARTICULARES (uuid: 2b3343ba...) o AUTONOMOS Y EMPRESAS (uuid: 8ce373...)php/index_bd.php?setTipo={uuid}
2Cargar familias del tipo seleccionado. Empresas: 8 familias (Pack Fibra, Conectividad, Linea Movil, PBX VoIP, IA, TIME, eSIM, TV). Particulares: 4 familias.GET php/index_bd.php?readFamilias={tipoUUID}
3Click en familia: cargar productos de esa familia y tipoGET php/index_bd.php?readProducts={familiaUUID}&tipo={tipoUUID}
4Tarjeta de producto: imagen, nombre (h3), descripcion, servicios adicionales (checkboxes con precio), campo direccion/observacion, precio, boton ANADIR, +info (base64)Renderizado en HTML por index_bd.php
5Anadir producto al carrito con extras (checkboxes), cantidad, extensionesPOST php/index_bd.php?add=1 con uuid, tipo, extras[], qty, extensiones, precioExtensiones
6Leer carrito: DOS carritos separados (servicios + alarmas)GET php/index_bd.php?readCarrito=1 (servicios) + readCarrito=1&ALARMA=1 (alarmas)
7Logica IVA en JS (readCarrito):
- Particular (uuid 2b3343...): precios con IVA incluido
- Empresa (uuid 8ce373...): precios sin IVA + total con IVA (*1.21)
Logica en index.js funcion readCarrito()
8Modificar precio del producto en carritoPOST php/index_bd.php?updatePrecio=1 con uuid, precio
9Modificar descuentoPOST php/index_bd.php?updateDTO=1 con uuid, dto
10Modificar cantidadPOST php/index_bd.php?updateCantidad=1 con uuid, cantidad
11Eliminar producto del carritoGET php/index_bd.php?remove={uuid}
12Formulario cliente: Cliente potencial*, Contacto, Email, Movil, Observaciones, Agente (Select2)Campos en formulario HTML
13Guardar presupuestoPOST php/index_bd.php?savePTO=1 con nombreCliente, nombreContacto, nombreEmail, nombreMovil, nombreObservaciones, nombreAgente
14Redirect automatico a presupuestos.phpJavaScript redirect post-save

[FASE 0] Mejoras planificadas para Nuevo Presupuesto:


4.3 Pipeline (Kanban comercial) EXISTE

Archivo PHP:
distribuidor/pipeline.php
Backend AJAX:
distribuidor/php/pipeline_bd.php
Acceso:
Requiere pipeline.leer

Dos vistas

VistaEtapas (fallback si no hay BD)dist_tipo filtrado
Potenciales prospecto (#6b7280) → contactado (#3b82f6) → negociacion (#f59e0b) → propuesta (#fb923c) → onboarding (#8b5cf6) potencial
Activos activo (#10b981) → top (#8b5cf6) → en_riesgo (#ef4444) activo

Las etapas se cargan dinamicamente desde tabla config_pipeline_etapas (company, pipeline_tipo, nombre, codigo, color, orden, es_final). Si la tabla esta vacia, se usan los fallback hardcoded.

Tablas BD involucradas

Endpoints API pipeline_bd.php

actionMetodoDescripcion
boardGETKanban board filtrado por vista (potenciales/activos) + filtro comercial
movePOSTMover tarjeta entre etapas (drag & drop)
recalcGETRecalcular etapas automaticas segun umbrales
logGETHistorial cambios de un distribuidor
reset_manualPOSTDevolver etapa a calculo automatico
fichaGETFicha completa del distribuidor
crear_potencialPOSTCrear prospecto nuevo
editar_potencialPOSTEditar datos potencial
convertirPOSTConvertir potencial a activo
statsGETContadores por vista

4.4 Mi Actividad EXISTE

Archivo PHP:
distribuidor/actividades.php
JS Frontend:
distribuidor/js/actividades.js
Backend AJAX:
distribuidor/php/actividades_bd.php
Tabla BD:
actividades_comercial
Acceso:
Requiere actividad.leer

Tipos de actividad

nota | llamada | visita | email | reunion

Resultados posibles

contactado | interesado | no_interesado | no_disponible

Scoring vinculado

Seguimiento

Campos: siguiente_accion_fecha, siguiente_accion_tipo, siguiente_accion_completada

Endpoints actividades_bd.php

actionDescripcion
listListar actividades con filtros: periodo (hoy/semana/mes), tipo, comercial, dist_uuid, busqueda texto. Admin ve todas; no-admin solo las suyas. LIMIT 200.
statsKPIs del comercial: actividades hoy, ayer, variacion
carteraCartera del comercial
quehacerAgenda de pendientes
savePOST: registrar nueva actividad
completar_siguientePOST: marcar siguiente accion como completada
historialHistorial por distribuidor

4.5 Dashboard Director EXISTE

Archivo PHP:
distribuidor/dashboard_director.php
Backend AJAX:
distribuidor/php/dashboard_director_bd.php
Acceso:
Requiere dashboard.director

Endpoints dashboard_director_bd.php

actionKPIs / Datos
resumenFacturacion mes/ano, objetivo anual (8M por defecto), forecast, promedio mensual, tramitaciones mes, presupuestos mes, conversion 90d, actividades semana, distribuidores activos vs total, comerciales activos, KPIs captacion potenciales (total, conversiones mes, nuevos mes, actividades potenciales semana)
equipoRendimiento por comercial
pipelineDistribucion por etapa (potenciales + activos)
evolucionUltimos 12 meses
alertasAlertas activas
top_distTop distribuidores por facturacion

Soporta autenticacion por session Y por API key (para n8n via X-API-Key).


4.6 Estadisticas EXISTE

Archivo PHP:
distribuidor/estadisticas.php
JS Frontend:
distribuidor/js/estadisticas.js
Backend AJAX:
distribuidor/php/estadisticas_bd.php
Acceso:
Requiere stats.leer (solo admin/@conexiatec.com)

Filtros disponibles

9 Endpoints de estadisticas

actionDatos
kpisTotal presupuestos, en_curso, tramitados, rechazados, valores, ticket medio, conversion
monthlyDesglose mensual (12 meses)
by_comercialAgrupado por comercial
by_distribuidorAgrupado por distribuidor
by_estadoDistribucion por estados
trendTendencia temporal
distributionDistribucion de valores
comparisonComparativa interanual
timerangeRango temporal personalizado

4.7 Scoring / Gamificacion EXISTE

Backend AJAX:
distribuidor/php/scoring_bd.php
Tablas BD:
scoring_log, config_scoring, config_badges, agente_badges

Acciones puntuadas

AccionPuntosDescripcion
presupuesto_creadoConfigurable en BDAl crear presupuesto
actividad_registrada3Registrar actividad comercial
actividad_visita5Bonus por visita presencial
login_diarioConfigurablePrimer login del dia (prevencion duplicados)

Sistema de Badges

Tipos de condicion: puntos_total (suma total ≥ valor), tram_total (tramitaciones totales), ptos_mes (presupuestos este mes), conversion_alta (% conversion con min 10 presupuestos), racha_dias (dias consecutivos activo).

Evaluacion automatica via checkBadges() despues de cada registro de puntos.

Endpoints scoring_bd.php

actionDescripcion
leaderboardTop 50 agentes con puntos, badges, distribuidor. Filtro periodo: mes/ano/total
mis_puntosPuntos del agente: total, mes, semana, hoy, rank, racha, next_badge
mis_badgesBadges desbloqueados + bloqueados del agente
todos_badgesCatalogo completo de badges
historialHistorial de puntos recientes (max 50)
config_scoringConfiguracion de puntos por accion (solo admin)
registrar_puntosRegistrar puntos manualmente (admin/sistema/webhook)
check_badgesEvaluar y otorgar badges pendientes
stats_gamificacionStats globales: puntos total, mes, agentes participando, badges otorgados, accion top

4.8 Cobertura EXISTE FASE 0

Archivo PHP:
distribuidor/cobertura.php
Vista:
distribuidor/content/cobertura.php
Acceso:
Todos los roles

[EXISTE] Pagina con iframe embebido de https://iframe.api-eligibility.fr/?i=2159 (proveedor frances de consulta de elegibilidad). Auto-redimensionamiento de altura via postMessage.

[FASE 0] Multi-proveedor planificado:

  1. Sarenet: Busqueda en CSV local (ya se tiene el CSV de nodos Sarenet)
  2. Onivia B2B: API REST cobertura v2.3 (documentacion disponible: "AI - Onivia B2B - Coverage v2.3.docx")
  3. CableMovil/Orange: Consulta cobertura via orange.es/contratacion/cobertura

Implementacion: Nuevo archivo distribuidor/php/cobertura_bd.php con 3 funciones de busqueda. Frontend muestra tabla comparativa de disponibilidad por proveedor.

Trigger adicional: Al rellenar campo direccion en formulario de nuevo presupuesto (distribuidor/js/index.js), disparar busqueda automatica.

5. Funcionalidades - Portal Admin

5.1 Dashboard Admin EXISTE

Archivo PHP:
admin/index.php
Acceso:
Sesion admin o @conexiatec.com

Pagina principal del portal admin con calendario de eventos.


5.2 Configuraciones (Hub) EXISTE

Archivo PHP:
admin/configuraciones.php
Vista:
admin/content/configuraciones.php

Hub central de configuracion organizado en 3 secciones:

Sistema

EnlaceArchivoDescripcion
Conexiac_company.phpDatos de la empresa
Agentes comercialesc_edistribuidor.phpDistribuidores y comerciales
Agentes potencialesc_edistribuidor.php?p=1Agentes en proceso
Tipo accionesc_acciones.phpTipos de acciones del sistema
Usuarios ADMIN/MASTERc_usuarios.phpGestion de accesos
Estado pedidosc_estadopedidos.phpEstados del workflow
IVAc_iva.phpTipos impositivos
Unidadesc_unidades.phpUnidades de medida

Productos

EnlaceArchivoDescripcion
Productosc_producto.phpCatalogo de productos
Anexosc_anexos.phpDocumentos anexos
Tiposc_tipos.phpClasificacion de productos
Familiasc_familias.phpFamilias de productos
Subfamiliasc_subfamilias.phpSubcategorias

Gestor Documental

EnlaceArchivoDescripcion
Categoriasc_catdocs.phpCategorias de documentos
Tipo documentosc_tipodocumentos.phpTipos de documentos
Documentosdocumentos.phpTodos los documentos

5.3 Productos EXISTE FASE 0

Archivo PHP:
admin/c_producto.php
Backend AJAX:
admin/php/producto_bd.php

[EXISTE] Campos: Referencia, Nombre, Precio ALTA con IVA, Dto ALTA %, Precio con IVA, Dto %, Subvencion gobierno, imagenes, servicios extras (JSON), y mas. 36 productos con mapeo DoWISP (dowisp_producto_id, dowisp_tarifa_id).

[FASE 0] Agregar campo es_servicio (BOOLEAN DEFAULT false) para distinguir productos puntuales de servicios recurrentes, necesario para calculo MRR.

SQL: ALTER TABLE product ADD COLUMN es_servicio BOOLEAN DEFAULT false;

Archivo UI a modificar: admin/php/producto_bd.php (agregar campo en save/load)


5.4 Familias EXISTE FASE 0

Archivo PHP:
admin/c_familias.php
Backend AJAX:
admin/php/familias_bd.php

[EXISTE] Campos actuales: Nombre, Tipo (AUTONOMOS Y EMPRESAS / PARTICULARES / PRUEBA), Orden, Descripcion, imagen.

[FASE 0] Agregar campos de margen:

ALTER TABLE config_familias ADD COLUMN margen_master_pct DECIMAL(5,2) NULL;
ALTER TABLE config_familias ADD COLUMN margen_distrib_pct DECIMAL(5,2) NULL;

Igualmente en subfamilias (NULL = hereda de familia):

ALTER TABLE config_subfamilias ADD COLUMN margen_master_pct DECIMAL(5,2) NULL;
ALTER TABLE config_subfamilias ADD COLUMN margen_distrib_pct DECIMAL(5,2) NULL;

Herencia de margenes: Producto.margen ?? Subfamilia.margen ?? Familia.margen

Archivos a modificar: admin/php/familias_bd.php, admin/php/subfamilias_bd.php


5.5 Webhooks EXISTE FASE 0

Archivo PHP:
admin/webhooks.php
Backend Admin:
admin/php/webhooks_bd.php
Motor:
distribuidor/php/webhooks_helper.php
Tabla BD:
config_webhook

[EXISTE] Sistema completo:

[FASE 0] Configurar URLs destino (CRM Conexia + n8n Skynet) + agregar eventos:

Implementacion: INSERT en config_webhook con URLs destino + agregar llamadas a webhook_dispatch() en los puntos del codigo donde ocurren estos eventos (index_bd.php para tramitacion, pipeline_bd.php para leads).


5.6 Alertas EXISTE

Archivo PHP:
admin/alertas.php
Backend AJAX:
admin/php/alertas_bd.php
Tabla BD:
config_alertas

Tipos de alerta: budget (presupuestos), activity (actividad), performance (rendimiento). Gestion via admin/php/configuracion_bd.php (action=alertas, alerta_toggle).


5.7 Email Templates EXISTE

Archivo PHP:
admin/email_templates.php
Backend AJAX:
admin/php/email_templates_bd.php
Tabla BD:
config_email_templates

Campos: nombre, tipo (sistema/custom), subject, body_html, body_text, variables (JSON con placeholders disponibles). Envio via admin/php/MailerService.php usando PHPMailer.


5.8 Config General EXISTE FASE 0

Archivo PHP:
admin/configuracion.php
Backend AJAX:
admin/php/configuracion_bd.php

[EXISTE] Configuracion unificada con secciones accesibles via parametro action:

[FASE 0] Cifrar token DoWISP almacenado en BD usando phpencrypt() / phpdecrypt() de admin/functions/crypt.php (AES-256-CBC via openssl con PBKDF2). Actualmente el token 2edb962a... esta en texto plano.


5.9 Agentes / Usuarios Configurador EXISTE FASE 0

Archivo PHP:
admin/agentes.php
Backend AJAX:
admin/php/agentes_bd.php

[EXISTE] Campos: ID CRM, Nombre, DNI, Email, Password (hash SHA-256 + salt), Puede modificar precios (SI/NO), IVA (SI/NO), Agente comercial, Distribuidor (edistribuidor UUID), activo/inactivo.

[FASE 0] Agregar campo rol (dropdown con roles de config_roles) para asignacion directa de rol desde panel admin, sin depender de deteccion automatica.

Archivo a modificar: admin/php/agentes_bd.php


5.10 Clientes EXISTE FASE 0

Archivo PHP:
admin/contacts1.php
Backend AJAX:
admin/php/contacts_bd.php
Clase OOP:
admin/clases/ContactModel.php

[EXISTE] Campos: Nombre comercial, NIF, Contacto, Email, Telefono. Tabs: Facturacion | Contacto General. Sub-endpoints: comments, contactslist, direcciones, documents.

[FASE 0] Agregar vinculacion con DoWISP:

ALTER TABLE contacts ADD COLUMN dowisp_cliente_id INT NULL;
ALTER TABLE contacts ADD INDEX idx_dowisp_id (dowisp_cliente_id);

Logica al tramitar: Buscar contacto.dowisp_cliente_id. Si NULL, buscar en DoWISP por CIF. Si existe, guardar ID. Si no existe, crear via POST /clientes/.

Archivos a modificar: admin/php/contacts_bd.php (agregar campo), distribuidor/php/index_bd.php (logica tramitacion)

6. API REST

6.1 API actual EXISTE

Archivo:
distribuidor/api/index.php
Auth:
Header X-API-Key contra tabla config_api_keys
CORS:
Habilitado (Access-Control-Allow-Origin: *)
Logging:
Tabla log_api_requests con tiempo ejecucion en ms
Response:
{"ok": true/false, "data": [...], "total": N, "error": "msg"}

Autenticacion

La funcion api_authenticate() en webhooks_helper.php busca la API key en config_api_keys, verifica IP whitelist si configurada, actualiza ultimo_uso y total_peticiones, y decodifica los permisos JSON.

Endpoints existentes

MetodoEndpointPermiso requeridoDescripcion
GETdistribuidor/listardistribuidor.leerListar distribuidores por dist_tipo (default: activo). Paginacion limit/offset (max 500).
GETdistribuidor/ver/{uuid}distribuidor.leerDetalle distribuidor con sus agentes vinculados.
POSTdistribuidor/creardistribuidor.crearCrear prospecto (dist_tipo='potencial', origen='api'). Dispara webhook distribuidor.creado.
PUT/POSTdistribuidor/actualizardistribuidor.editarActualizar campos (nombre, email, phone, town, province, cif, comercial, scoring, notas_comercial). Dispara webhook distribuidor.actualizado.
POSTdistribuidor/activardistribuidor.activarConvertir prospecto a activo: crea agente con password temporal, actualiza dist_tipo='activo'. Dispara webhooks distribuidor.activado + agente.creado.
GETpresupuesto/listar-Listar presupuestos (endpoint registrado en router pero no implementado como funcion independiente).
GETstats/resumenstats.leerResumen: distribuidores por tipo + presupuestos del mes (total + tramitados).

Ejemplo de uso

curl -H "X-API-Key: tu_api_key" \
  "https://pedidos.conexiatec.com/presupuestador_new/distribuidor/api/index.php?endpoint=distribuidor/listar&dist_tipo=activo&limit=50"

6.2 Endpoints a agregar FASE 0

Implementacion: Agregar cases en el switch de distribuidor/api/index.php + funciones handler correspondientes.

MetodoEndpointDescripcion
GETpresupuesto/ver/{uuid}Detalle presupuesto con lineas de productos
GETpedido/listarListar pedidos con filtros
GETpedido/ver/{uuid}Detalle pedido
GETcontacto/listarListar contactos
GETcontacto/ver/{uuid}Detalle contacto con dowisp_cliente_id
POSTcontacto/buscarBuscar por CIF/email (datos sensibles via POST body, nunca en URL)
GETproducto/listarCatalogo activo completo
GETagente/listarListar agentes
GETpipeline/boardEstado pipeline actual (potenciales + activos)
POSTwebhook/testVerificar conectividad webhook

7. Integraciones

7.1 DoWISP EXISTE FASE 0

[EXISTE] Integracion activa:

[FASE 0] Mejoras:

Archivo principal a modificar: distribuidor/php/index_bd.php (logica de tramitacion)


7.2 Webhooks salientes EXISTE FASE 0

[EXISTE] Sistema completo en produccion:

Eventos que ya se disparan:

[FASE 0] Agregar:

Payload de webhook (formato estandar)

{
  "evento": "presupuesto_creado",
  "timestamp": "2026-04-09T10:30:00+02:00",
  "ref_tipo": "presupuesto",
  "ref_uuid": "abc123...",
  "datos": {
    "uuid": "abc123...",
    "cliente": "Empresa SL",
    "total": 1200.00,
    ...
  }
}

7.3 Cobertura multi-proveedor FASE 0

3 proveedores a integrar:

ProveedorMetodoFuente
SarenetBusqueda en CSV localCSV de nodos Sarenet (disponible)
Onivia B2BAPI REST v2.3Documentacion "AI - Onivia B2B - Coverage v2.3.docx"
CableMovil/OrangeConsulta weborange.es/contratacion/cobertura

Implementacion:

8. Cambios en Base de Datos FASE 0

Todos los cambios son ALTER TABLE aditivos (columnas NULL o con DEFAULT). No rompen queries existentes. Rollback: DROP COLUMN.

-- =============================================
-- 1. Vincular contactos con DoWISP
-- =============================================
ALTER TABLE contacts ADD COLUMN dowisp_cliente_id INT NULL;
ALTER TABLE contacts ADD INDEX idx_dowisp_id (dowisp_cliente_id);

-- =============================================
-- 2. Margenes en familias
-- =============================================
ALTER TABLE config_familias ADD COLUMN margen_master_pct DECIMAL(5,2) NULL;
ALTER TABLE config_familias ADD COLUMN margen_distrib_pct DECIMAL(5,2) NULL;

-- =============================================
-- 3. Margenes en subfamilias (herencia: NULL = hereda de familia)
-- =============================================
ALTER TABLE config_subfamilias ADD COLUMN margen_master_pct DECIMAL(5,2) NULL;
ALTER TABLE config_subfamilias ADD COLUMN margen_distrib_pct DECIMAL(5,2) NULL;

-- =============================================
-- 4. Producto: flag servicio para calculo MRR
-- =============================================
ALTER TABLE product ADD COLUMN es_servicio BOOLEAN DEFAULT false;

-- =============================================
-- 5. Motor IGIC/IPSI en distribuidores
-- =============================================
ALTER TABLE config_edistribuidor ADD COLUMN tipo_impuesto
    ENUM('IVA','IGIC','IPSI') DEFAULT 'IVA';
ALTER TABLE config_edistribuidor ADD COLUMN porcentaje_impuesto
    DECIMAL(5,2) DEFAULT 21.00;

-- =============================================
-- 6. Jerarquia organizativa (ampliar distribuidores)
-- =============================================
ALTER TABLE config_edistribuidor ADD COLUMN parent_uuid VARCHAR(40) NULL;
ALTER TABLE config_edistribuidor ADD COLUMN org_tipo
    ENUM('conexia','master','distribuidor','delegacion') DEFAULT 'distribuidor';
ALTER TABLE config_edistribuidor ADD COLUMN observaciones_privadas TEXT NULL;
ALTER TABLE config_edistribuidor ADD INDEX idx_parent (parent_uuid);

Nota de seguridad: Todos los cambios son aditivos. Columnas nuevas tienen valor NULL o DEFAULT, lo que significa que las queries existentes que no referencian estas columnas seguiran funcionando exactamente igual. Para rollback: ALTER TABLE {tabla} DROP COLUMN {columna};

9. Seguridad

Medidas existentes EXISTE

MedidaImplementacionArchivo(s)
Prepared statements (PDO) BaseModel y todas las subclases usan queries parametrizadas. API usa $db->prepare() con bind_param(). admin/clases/BaseModel.php, distribuidor/api/index.php, webhooks_helper.php
CSRF tokens Clase Security::generateCsrfToken() genera token (bin2hex random_bytes(32)). csrf.js lo inyecta automaticamente en header X-CSRF-Token de todo POST jQuery. Verificacion: Security::verifyCsrfToken() con hash_equals(). admin/functions/Security.php, admin/js/csrf.js
HMAC-SHA256 webhooks Firma del payload JSON con secret_key del webhook. Header X-Webhook-Signature + X-Webhook-Timestamp. distribuidor/php/webhooks_helper.php
Session auth Verificacion de sesion en config.php - redirige a login si sesion invalida. Funciones admin_check() y agente_check(). admin/config/config.php, admin/functions/logins.php
X-API-Key auth API keys en tabla config_api_keys con IP whitelist, permisos JSON, rate_limit, total_peticiones, ultimo_uso. distribuidor/php/webhooks_helper.php (api_authenticate())
Cifrado AES-256-CBC phpencrypt() / phpdecrypt() con PBKDF2 (SHA-256, PARAMS_PASSPHRASE, PARAMS_SALT, PARAMS_ITERATIONS). admin/functions/crypt.php
Soft deletes Campo deleted = 0/1 en todas las tablas. Nunca borrado fisico. Todas las queries incluyen WHERE deleted = 0
Company-level isolation Campo company en todas las tablas. Todas las queries filtran por company del usuario autenticado. Todos los archivos _bd.php
XSS prevention Security::escape() para output HTML. htmlspecialchars() en sidebar. admin/functions/Security.php
Audit log evento_log() registra evento, ref_tipo, ref_uuid, datos_antes, datos_despues, usuario, origen, IP en tabla log_eventos. distribuidor/php/webhooks_helper.php
API request logging Tabla log_api_requests: api_key_uuid, endpoint, metodo, IP, request_body, response_code, duracion_ms. distribuidor/api/index.php
Password hashing SHA-256 + salt aleatorio (bin2hex random_bytes(16)). Salt almacenado en tabla agentes. distribuidor/api/index.php (activar distribuidor)

Medidas a agregar FASE 0

MedidaImplementacionArchivo(s) a modificar
2FA TOTP Obligatorio para escalar a Super Admin desde nivel inferior. Usar TOTP library + functions/crypt.php para almacenar secret. distribuidor/php/permisos_helper.php + nuevo endpoint
Cifrado token DoWISP Cifrar con phpencrypt(), descifrar con phpdecrypt() al usar. admin/php/configuracion_bd.php, distribuidor/php/index_bd.php
Regla de Oro Validacion servidor: if ($precio < $precio_coste) reject() en endpoints add y updatePrecio. distribuidor/php/index_bd.php
Rate limiting En login y API. Actualmente hay TODO en api_authenticate() para implementar con Redis. distribuidor/php/webhooks_helper.php, login.php

Regla critica: NIF, email, IBAN, tokens y datos sensibles SIEMPRE deben enviarse por POST body, NUNCA en URL. El endpoint contacto/buscar usa POST precisamente por esto.

10. Plan de Implementacion Fase 0

Semana 1 - Riesgo nulo (solo cosas nuevas)

TareaDescripcionArchivo(s)Dependencia
Ampliar API 10 nuevos endpoints en el switch del router (presupuesto/ver, pedido/listar, pedido/ver, contacto/listar, contacto/ver, contacto/buscar, producto/listar, agente/listar, pipeline/board, webhook/test) distribuidor/api/index.php Ninguna
dowisp_cliente_id ALTER TABLE contacts + INDEX SQL directo en BD Ninguna
Cifrar token DoWISP Usar phpencrypt() para cifrar el token en BD. Modificar lectura para usar phpdecrypt(). admin/php/configuracion_bd.php, distribuidor/php/index_bd.php Ninguna

Semana 2 - Riesgo bajo (cambios aditivos)

TareaDescripcionArchivo(s)Dependencia
Margenes familias/subfamilias ALTER TABLE config_familias + config_subfamilias (4 columnas nuevas) SQL + admin/php/familias_bd.php, subfamilias_bd.php Ninguna
es_servicio ALTER TABLE product ADD COLUMN SQL + admin/php/producto_bd.php Ninguna
tipo_impuesto / parent_uuid ALTER TABLE config_edistribuidor (5 columnas + 1 indice) SQL + admin/php/edistribuidor_bd.php Ninguna
Roles en config_roles Agregar roles nuevos, asignar permisos granulares INSERT en config_roles Ninguna

Semana 3 - Riesgo medio (toca logica existente)

TareaDescripcionArchivo(s)Dependencia
Logica dowisp_cliente_id Al tramitar: buscar/crear cliente en DoWISP, guardar ID en contacts distribuidor/php/index_bd.php Semana 1 (dowisp_cliente_id)
Motor IGIC/IPSI En readCarrito(), reemplazar *1.21 hardcoded por % segun tipo_impuesto del distribuidor distribuidor/js/index.js Semana 2 (tipo_impuesto)
Regla de Oro Validacion servidor precio >= precio_coste en add=1 y updatePrecio=1 distribuidor/php/index_bd.php Ninguna
Configurar webhooks INSERT URLs destino en config_webhook + agregar webhook_dispatch() en tramitacion y pipeline distribuidor/php/index_bd.php, pipeline_bd.php Semana 1 (API para test)
Switch de nivel + 2FA $_SESSION['nivel_simulado'] + endpoint 2FA distribuidor/php/permisos_helper.php + nuevo endpoint Semana 2 (roles)

Apendice A: Mapa de archivos modificados en Fase 0

ArchivoCambioSemana
distribuidor/api/index.php Agregar 10 endpoints nuevos (cases en switch + funciones handler) 1
distribuidor/php/index_bd.php Regla de Oro (validacion precio >= coste en add=1, updatePrecio=1). Logica dowisp_cliente_id al tramitar. Descifrar token DoWISP al usar. 1, 3
distribuidor/js/index.js Motor IGIC/IPSI: reemplazar *1.21 hardcoded en readCarrito() por porcentaje dinamico. Trigger cobertura al rellenar direccion. 3
distribuidor/php/permisos_helper.php Agregar soporte $_SESSION['nivel_simulado'] en get_rol_usuario(). Restringir admin_super a emails especificos. 3
distribuidor/php/pipeline_bd.php Agregar webhook_dispatch() en crear_potencial y move (lead.creado, lead.etapa_cambiada) 3
admin/php/configuracion_bd.php Cifrar token DoWISP con phpencrypt() al guardar 1
admin/php/producto_bd.php Agregar campo es_servicio en save/load 2
admin/php/familias_bd.php Agregar campos margen_master_pct, margen_distrib_pct en save/load 2
admin/php/subfamilias_bd.php Agregar campos margen_master_pct, margen_distrib_pct en save/load 2
admin/php/edistribuidor_bd.php Agregar campos tipo_impuesto, porcentaje_impuesto, parent_uuid, org_tipo, observaciones_privadas en save/load 2
admin/php/contacts_bd.php Agregar campo dowisp_cliente_id en save/load 1
admin/php/agentes_bd.php Agregar campo rol (dropdown) 2
Archivo nuevo:
distribuidor/php/cobertura_bd.php Nuevo: 3 funciones de busqueda cobertura (Sarenet CSV, Onivia API, CableMovil) 3

Apendice B: Tabla de permisos por rol

Matriz completa de permisos. SI = tiene acceso. NO = no tiene acceso.

Permiso admin_super director distribuidor agente
* (wildcard) SI NO NO NO
pipeline.leer SI SI NO NO
pipeline.editar SI SI NO NO
actividad.leer SI SI SI NO
actividad.crear SI SI SI NO
stats.leer SI SI NO NO
dashboard.director SI SI NO NO
admin.config SI SI NO NO
distribuidor.leer SI SI SI NO
distribuidor.crear SI SI NO NO
distribuidor.editar SI SI NO NO
distribuidor.activar SI SI NO NO
Acceso a paginas (implicito por rol)
Presupuestos (listar/crear) SI SI SI SI
Documentos SI SI SI SI
Cobertura SI SI SI SI
Portal Admin SI SI NO NO

Nota: admin_super tiene permiso wildcard * que otorga acceso a todo automaticamente. La tabla muestra permisos explicitos para los demas roles, que se configuran en config_roles.permisos como array JSON. Los valores mostrados para director y distribuidor son la configuracion recomendada; los valores reales dependen de lo que se haya insertado en la tabla config_roles.


Manual Tecnico del Presupuestador Conexia - Version 1.0 - Abril 2026
Conexia Telecomunicaciones | pedidos.conexiatec.com