📋 Visión general
Este CRM (Customer Relationship Management) es una aplicación web desarrollada en PHP + MySQL y alojada bajo Apache (XAMPP en local, VPS Ubuntu 24 con FastPanel en producción). Está diseñada específicamente para el sector del mobiliario (Hevea Mobiliario) y centraliza la gestión de leads, campañas publicitarias, clientes, productos, ferias y comunicación interna.
Características principales
- Board tipo Kanban con columnas configurables para cada etapa del proceso comercial.
- Sistema de roles: administradores con visión total y comerciales con vista restringida a sus propios leads.
- Filtros combinados avanzados: por fecha, comercial, campaña, estado, ganado, remarketing y etiquetas.
- Asignación rápida de comercial directamente desde la tarjeta sin abrir el lead.
- Gestión de campañas y subcampañas con estadísticas de rendimiento.
- Módulo de feria / checkin con tokens únicos por cliente.
- Catálogo de productos SKU con búsqueda y administración de precios.
- Sistema de backup automático a FTP y restauración.
- Envío de correos vía PHPMailer con OAuth2 (Gmail).
- Panel de mensajes internos entre usuarios.
- Galería de imágenes con subida y gestión.
- Dashboard con gráficas de rendimiento por comercial y campaña.
- Temas visuales personalizados por usuario (claro, oscuro, etc.).
🛠️ Stack tecnológico
| Capa | Tecnología | Versión mínima | Notas |
|---|---|---|---|
| Servidor web | Apache | 2.4 | mod_rewrite activado |
| Lenguaje backend | PHP | 8.2 | Extensiones: mysqli, mbstring, openssl, json |
| Base de datos | MySQL / MariaDB | 8.0 / 10.6 | InnoDB, UTF8MB4 |
| Entorno local | XAMPP | 8.2+ | Windows, localhost |
| Entorno producción | VPS Ubuntu 24 + FastPanel | — | Hostinger |
| Frontend | HTML5 + CSS3 + JavaScript (Vanilla) | — | Sin framework JS; jQuery mínimo vía CDN |
| Gráficas | Chart.js | 3.x | Cargado desde CDN |
| Correo | PHPMailer + OAuth2 | 6.x | Gmail API |
| Dependencias PHP | Composer | 2.x | vendor/ incluido |
| Excel/XLSX | SimpleXLSX | — | Importación de productos |
👥 Roles y permisos
El sistema tiene dos roles definidos en la tabla users mediante el campo role_id.
🛠️ Administrador (role_id = 1)
- Ve todas las órdenes, incluyendo sin asignar
- Asigna y reasigna comerciales
- Crea y edita campañas
- Gestiona etiquetas globales
- Accede al dashboard completo
- Accede a backup, DB, productos, galería
- Gestiona usuarios activos/inactivos
- Filtra por cualquier comercial
👨💼 Comercial (role_id = 2)
- Ve solo sus órdenes asignadas
- Gestiona sus leads (notas, etapas, ganado)
- Actualiza dirección, email, ingreso esperado
- Marca órdenes como gestionadas / ganadas
- Cambia su tema visual
- Accede a mensajes internos
- Sin acceso a backup ni DB
$_SESSION['role_id']. Los comerciales no pueden manipular parámetros para ver datos de otros usuarios porque el filtro WHERE comercial_id = $user_id se aplica en servidor.
📌 Board Kanban
La vista principal (index.php) muestra las órdenes distribuidas en columnas que representan etapas del proceso comercial. Las columnas se cargan desde la tabla columns y los cards se asignan a ellas mediante la tabla pivote column_orders.
Columnas típicas del board
Interacciones del card
- Click en card → abre el modal de detalle del lead (edit-ord.php).
- Arrastrar card → mueve la orden a otra columna (llama a
move_order.phpvía fetch). - ⚠️ Sin asignar → widget inline de asignación rápida; clic en el badge despliega un select con comerciales activos y botón de confirmar (llama a
edit_comercial.php). - Buscador → filtra tarjetas en tiempo real por nombre, email, teléfono, ciudad, país y badge "sin asignar".
- Checkbox "Sin asignar" → muestra solo cards sin comercial asignado.
Navbar de filtros
El botón 🔍 Filtros abre un panel deslizante con todos los filtros combinables. Un badge numérico muestra cuántos filtros están activos. Al aplicar, se llama a filtro_combinado.php y el resultado reemplaza completamente el board mediante updateColumnsWithOrders(orders).
Rendimiento del board
LIMIT 3000. Si el volumen crece, considerar paginación lazy o virtualización de DOM.
- Las etiquetas y campañas se pre-cargan en una sola query para evitar el problema N+1.
- El archivo
scripts/ine.jsgestiona búsqueda, drag-and-drop y la apertura del modal.
📦 Órdenes / Leads
Una orden es la unidad central del CRM: representa un lead o cliente potencial que entra al embudo comercial. Cada orden pertenece a un comercial, puede tener etiquetas, notas, campaña, historial de etapas y datos de contacto.
Flujo de vida de una orden
Campos principales de una orden
Notas / historial
Cada orden puede tener múltiples notas almacenadas en la tabla notes. Las notas se añaden desde el modal de detalle mediante add_note.php / save_or_update_note.php y se recuperan con get_notes.php.
Pasos recomendados al gestionar un lead
- Cambiar la etapa en el board según el momento del proceso.
- Marcar como gestionada (estado = 1) una vez contactada.
- Añadir una nota interna con el resumen de la conversación.
- Actualizar ingreso esperado si el cliente dio un presupuesto.
- Completar los datos de contacto que falten (email, ciudad, etc.).
- Asignar etiquetas relevantes para clasificación y búsqueda.
- Si se cierra el trato, marcar como ganada y registrar el ID de Timón en una nota.
- Si el lead procede de redes, marcar el checkbox de Instagram / LinkedIn.
🔍 Filtros combinados
El panel de filtros (botón 🔍 Filtros en el navbar) permite combinar múltiples criterios en una sola búsqueda. Se implementa mediante el endpoint filtro_combinado.php.
Filtros disponibles
| Filtro | Parámetro JSON | Tipo | Descripción |
|---|---|---|---|
| Fecha inicio | fecha_inicio | string YYYY-MM-DD | Filtra por fecha_subido |
| Fecha fin | fecha_fin | string YYYY-MM-DD | Filtra por fecha_subido |
| Comercial | comercial_id | int | Solo admin. 0 = todos |
| Sin asignar | sin_asignar | bool | Solo admin. Fuerza comercial_id IS NULL |
| Campaña | campana_id | int | 0 = todas las campañas |
| Estado | estado | -1 / 0 / 1 | -1 todos, 0 no gestionada, 1 gestionada |
| Ganado | ganado | -1 / 0 / 1 | -1 todos, 0 no ganada, 1 ganada |
| Remarketing activo | remarketing | bool | Filtra por old_cmal NOT NULL |
| Fue a remarketing | was_remarketing | bool | Filtra por remarkting = 1 |
| Etiquetas | etiquetas | int[] | Órdenes con AL MENOS una de las etiquetas seleccionadas |
Respuesta de filtro_combinado.php
{
"success": true,
"orders": [ { "order_id": 123, "title": "...", "tags": ["Interesado","VIP"], ... } ],
"total": 47
}
Accesos rápidos de fecha
Botones de acceso rápido que pre-rellenan el rango: Hoy, 7 días, 30 días, 90 días. Implementados con la función fcSetDays(n).
WHERE o.comercial_id = $user_id independientemente de los parámetros enviados. No pueden acceder a datos de otros.
🏢 Clientes
El módulo de clientes (clientes/) permite registrar y gestionar las empresas o personas que están detrás de los leads.
Funciones disponibles
- Listado paginado de clientes con búsqueda (
clientes/index.php). - Crear cliente con nombre, empresa, email, teléfono, dirección, token único (
clientes/create_client.php). - Editar datos de un cliente existente (
clientes/update_client.php). - Eliminar cliente, con advertencia si tiene órdenes asociadas (
clientes/delete_client.php). - Obtener clientes como JSON para selects dinámicos (
clientes/get_clients.php,get_fclient.php).
Token único de cliente
Cada cliente tiene un token generado con bin2hex(random_bytes(16)). Este token se usa en el módulo de Feria para identificar al cliente en el checkin sin requerir login.
📣 Campañas
Las campañas (ncampanas) son el origen del lead: publicidad en redes, ferias, referencias, etc. Cada orden lleva asignada una campaña.
Gestión
- Crear / editar campañas en
crear_campanas/index.phpocrear_campanas.php. - Cada campaña puede tener subcampañas (
search_subcampanas.php). - El módulo
campana/permite ver todas las órdenes de una campaña concreta. - Las estadísticas de campañas se exponen en
api/estadisticas_campanas.php.
Tabla ncampanas
🏷️ Etiquetas
Las etiquetas (tags) permiten clasificar órdenes con categorías personalizadas: "VIP", "Presupuesto alto", "Interesado en X", etc.
Tablas involucradas
etiquetas: catálogo global de etiquetas (id, nombre, color).orden_etiquetas: pivote que relaciona órdenes con etiquetas (id_orden, id_etiqueta).
Operaciones
- Crear etiqueta:
add_tag.php - Añadir etiqueta a orden:
add_tag_to_order.php,add_tags_to_order.php - Eliminar etiqueta de orden:
remove_tag_from_order.php - Obtener etiquetas de orden:
get_order_tag.php,get_tags.php - Panel de administración de etiquetas:
tag.php - Filtrar órdenes por etiqueta:
filter_by_tags.php, o viafiltro_combinado.php
📊 Dashboard
El dashboard (dashboard/index.php y dashboard.php) muestra métricas y gráficas de rendimiento del equipo comercial.
Métricas disponibles
- Órdenes por comercial en un rango de fechas.
- Comparativa de períodos (get_comparison_data.php).
- Detalle de órdenes ganadas y perdidas.
- Ingresos esperados vs reales por columna / etapa.
- Rendimiento por campaña.
Endpoints del dashboard
Parámetros: start_date, end_date, comercial_id (opcional)
Parámetros: period1_start, period1_end, period2_start, period2_end
🎪 Feria / Checkin
El módulo de feria (feria/) permite gestionar la asistencia y el check-in de clientes a eventos o ferias comerciales mediante tokens únicos.
Flujo del módulo
- El administrador genera tokens para los clientes invitados:
feria/generar_tokens_clients.php. - Cada cliente recibe un enlace con su token único.
- Al llegar al evento, se escanea / accede al enlace:
feria/checkin.php?token=XXX. - El sistema registra la visita y la hora en la base de datos.
- El panel de administración (
feria/panel.php) muestra en tiempo real quién ha hecho checkin. - La vista de verificación (
feria/veri.php) permite comprobar un token manualmente.
bin2hex(random_bytes(16)) — 32 caracteres hexadecimales aleatorios, prácticamente imposibles de adivinar.
📦 Catálogo de Productos SKU
El módulo productos-sku/ es un catálogo independiente de productos con SKU, descripción, precio y gestión de imágenes. Tiene su propio sistema de login.
Funcionalidades
- Listado y búsqueda de productos por SKU o nombre (
index.php,search_products.php). - Detalle de producto con imágenes y especificaciones (
details.php). - Importación masiva desde archivo Excel/XLSX (
upload.php, usa SimpleXLSX). - Edición de precio, descripción y estado (
update_product.php). - Admin con acceso total (
admin.php). - Cargar más con paginación lazy (
load_more.php).
login.php y session_check.php independientes del login principal del CRM.
🖼️ Galería
El módulo galeria/ permite subir, visualizar y eliminar imágenes asociadas a los recursos del CRM.
- Ver galería:
galeria/index.php - Subir imagen:
galeria/upload.php— recibe archivo vía POST multipart. - Eliminar imagen:
galeria/delete.php - Los estilos propios están en
galeria/estilos.css.
💬 Mensajes internos
El módulo msg/ ofrece un sistema básico de mensajería interna entre usuarios del CRM.
- Panel de mensajes:
msg/index.php— lista de conversaciones. - Enviar mensaje:
msg/cmsg.php— recibe destinatario y contenido. - Notificaciones:
obtener_notificaciones.php— endpoint JSON para badge de mensajes no leídos. verificarNotificaciones.php— verificación de nuevas notificaciones en polling.
💾 Backup y Restauración
El módulo backup/ permite generar, listar y restaurar copias de seguridad de la base de datos.
Flujo de backup
- Acceder a
backup/index.php(solo admin). - Pulsar "Generar backup" → llama a
backup/backup.phpque ejecutamysqldumpy guarda el.sql.gz. - Los archivos se listan mediante
backup/list_dirs.php. - Para restaurar, seleccionar el archivo y confirmar →
backup/restore.php.
FTP
El sistema puede configurarse para enviar el backup automáticamente a un servidor FTP externo. La conexión FTP se puede probar en backup/test_ftp.php.
📧 Correo electrónico
El envío de correos usa PHPMailer con autenticación OAuth2 / Gmail. Los archivos relacionados están en la raíz y en maile/ y PHPMailer/.
Archivos clave
| Archivo | Función |
|---|---|
sendMail.php | Función principal de envío; configura SMTP / OAuth |
sendEmail.php | Endpoint alternativo de envío |
email_helper.php | Helper con funciones reutilizables para construir emails |
maile/send_email.php | Envío desde el contexto del módulo maile |
PHPMailer/get_oauth_token.php | Generación / renovación del token OAuth2 |
pruebamail.php | Test de envío (solo desarrollo) |
PHPMailer/get_oauth_token.php y actualizando las credenciales.
📁 Estructura de archivos
mpcrm/
├── index.php ← Board principal Kanban
├── dashboard.php ← Redirige al dashboard
├── dashboard/ ← Módulo dashboard
│ ├── index.php
│ ├── get_orders_details.php
│ └── get_comparison_data.php
├── db/ ← Herramientas de base de datos (admin)
│ ├── connection.php ← Conexión MySQLi (USAR ESTE)
│ ├── config_db.php ← Credenciales DB
│ ├── index.php ← Consola SQL visual
│ ├── ver_ordenes.php ← Vista de todas las órdenes
│ └── export_excel.php ← Exportación a Excel
├── clientes/ ← CRUD de clientes
├── campana/ ← Órdenes por campaña
├── crear_campanas/ ← Gestión de campañas
├── feria/ ← Checkin de feria
├── productos-sku/ ← Catálogo de productos
├── galeria/ ← Galería de imágenes
├── msg/ ← Mensajería interna
├── backup/ ← Backup y restauración
├── maile/ ← Módulo de correo
├── padmin/ ← Panel admin alternativo
├── cuenta/ ← Perfil de usuario
├── registro/ ← Registro de usuarios
├── scripts/ ← JavaScript modular
│ ├── ine.js ← Board: búsqueda, drag, modal
│ └── main.js
├── api/ ← Endpoints API JSON
│ ├── orders.php
│ ├── campanas.php
│ ├── leads.php
│ └── estadisticas_campanas.php
├── PHPMailer/ ← Librería PHPMailer
├── vendor/ ← Dependencias Composer
├── estilos/ ← CSS globales adicionales
├── filtro_combinado.php ← Filtro avanzado combinado
├── filter_orders.php ← Filtro por fecha
├── filtro_campana.php ← Filtro por campaña
├── filtro_remarketing.php ← Filtro remarketing
├── add_order.php ← Crear nueva orden
├── edit-ord.php ← Modal de edición de orden
├── edit_comercial.php ← Asignar comercial a orden
├── move_order.php ← Mover orden a columna
├── mark_order_won.php ← Marcar como ganada
├── marcar_gestionada.php ← Marcar como gestionada
├── add_note.php ← Añadir nota a orden
├── add_tag_to_order.php ← Añadir etiqueta a orden
├── remove_tag_from_order.php ← Quitar etiqueta de orden
├── update_order_stage.php ← Actualizar etapa
├── update_priority.php ← Actualizar prioridad
├── actualizar_pago.php ← Registrar pago
├── assign_order.php ← Asignar orden
├── get_order_details.php ← Detalle orden (JSON)
├── get_comerciales.php ← Lista comerciales activos
├── get_campanas.php ← Lista campañas
├── get_tags.php ← Lista etiquetas
├── buscar_ordenes.php ← Búsqueda de órdenes
├── docs.html ← Esta documentación
└── connection.php ← Alias de db/connection.php
🗄️ Base de datos
El archivo de conexión principal es db/connection.php. Usa MySQLi con prepared statements en todos los endpoints actualizados. Las credenciales se configuran en db/config_db.php.
Tablas principales
| Tabla | Descripción | Relaciones clave |
|---|---|---|
orders | Órdenes / leads | → users, clients, ncampanas |
users | Comerciales y admins | role_id → roles |
clients | Empresas / clientes | ← orders |
ncampanas | Campañas | ← orders.campana |
columns | Columnas del board Kanban | ← column_orders |
column_orders | Pivote orden ↔ columna | order_id, column_id |
etiquetas | Catálogo de etiquetas | ← orden_etiquetas |
orden_etiquetas | Pivote orden ↔ etiqueta | id_orden, id_etiqueta |
notes | Notas por orden | → orders, users |
roles | Definición de roles | ← users.role_id |
Conexión a la base de datos
// db/connection.php
$conn = new mysqli(DB_HOST, DB_USER, DB_PASS, DB_NAME);
$conn->set_charset('utf8mb4');
if ($conn->connect_error) die("Error de conexión: " . $conn->connect_error);
Importar la base de datos
- Acceder a phpMyAdmin en
localhost/phpmyadmin. - Crear la base de datos si no existe:
CREATE DATABASE mpcrm CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; - Seleccionar la BD → pestaña Importar → subir el archivo
.sql. - Si aparece error de foreign key constraint, ejecutar primero:
SET FOREIGN_KEY_CHECKS=0;y al finalSET FOREIGN_KEY_CHECKS=1; - Si hay error de charset, asegurarse de que el archivo
.sqlincluyaSET NAMES utf8mb4;al inicio.
Panel de base de datos (admin)
La ruta /db/index.php ofrece una interfaz visual para ejecutar consultas SQL, ver órdenes ganadas, exportar datos a Excel y otras utilidades de solo-admin.
🔌 API / Endpoints de referencia
Todos los endpoints devuelven Content-Type: application/json y requieren sesión activa. Los endpoints marcados con 🔒 requieren role_id = 1.
Órdenes
Body JSON: { fecha_inicio, fecha_fin, comercial_id, campana_id, estado, ganado, sin_asignar, remarketing, was_remarketing, etiquetas[] }
Retorna: { success, orders[], total }
Body JSON: { start_date, end_date }
Retorna datos completos de la orden incluyendo notas, etiquetas y campaña.
Body JSON: { order_id, column_id }
Body JSON: { order_id, comercial_id }
Body JSON: { order_id }
Body JSON: { order_id, note }
Clientes y campañas
Retorna: [ { id, username } ]
Retorna: [ { id, nombre } ]
Body JSON: { campaign_id, start_date, end_date }
⚙️ Scripts JavaScript
| Archivo | Función principal |
|---|---|
scripts/ine.js | Motor principal del board: drag & drop de cards, búsqueda en tiempo real, apertura del modal de edición, inicialización de la vista Kanban. Incluye el selector de búsqueda para .quick-assign-badge (leads sin asignar). |
scripts/main.js | Funciones auxiliares globales del board. |
main.js (raíz) | Script principal cargado en algunas vistas fuera del board. |
Funciones globales JS en index.php
| Función | Descripción |
|---|---|
updateColumnsWithOrders(orders) | Redibuja todo el board a partir de un array JSON de órdenes. Usada por el sistema de filtros. |
qaShowForm(badge) | Muestra el form inline de asignación rápida de comercial. |
qaCancel(btn) | Oculta el form inline de asignación. |
qaSubmit(btn) | Envía la asignación vía fetch a edit_comercial.php. |
abrirFiltrosCombinado() | Abre el panel deslizante de filtros. |
cerrarFiltrosCombinado() | Cierra el panel deslizante de filtros. |
fcSetDays(n) | Rellena el rango de fechas con los últimos N días. |
fcAplicar() | Recoge todos los filtros activos, llama a filtro_combinado.php y actualiza el board. |
fcLimpiar() | Resetea todos los filtros y recarga el board original. |
fcContarActivos() | Cuenta cuántos filtros están activos para el badge. |
🔒 Seguridad
Autenticación y sesiones
- Autenticación basada en sesiones PHP (
$_SESSION['user_id'],$_SESSION['role_id']). - Todos los endpoints verifican la sesión al inicio; si no existe, devuelven HTTP 401 o redirigen al login.
- Las contraseñas se almacenan con
password_hash()y se verifican conpassword_verify().
Consultas SQL seguras
- Todos los endpoints actualizados usan prepared statements MySQLi con
bind_param(). - Los parámetros se castean explícitamente (
(int),trim()) antes de usar. - No se concatenan variables directamente en SQL.
Control de acceso por rol
- Los comerciales solo pueden ver/modificar sus propias órdenes — el filtro
WHERE comercial_id = $user_idse aplica en servidor, nunca depende del cliente. - Las rutas sensibles (
/db/,/backup/,/padmin/) compruebanrole_id == 1.
Recomendaciones pendientes
- Activar HTTPS en producción (certificado SSL en FastPanel).
- Añadir protección CSRF en formularios POST críticos.
- Limitar intentos de login (rate limiting).
- Revisar
ini_set('display_errors', 1)enfiltro_campana.phpyfilter_orders.php— debe ser 0 en producción. - Mover
db/config_db.phpfuera del webroot o proteger con.htaccess.
🚀 Guía de despliegue
Entorno local (XAMPP)
- Copiar la carpeta del proyecto en
C:\xampp\htdocs\mpcrm\. - Importar el SQL en phpMyAdmin (ver sección Base de datos).
- Ajustar credenciales en
db/config_db.php: host, usuario, contraseña, nombre de BD. - Iniciar Apache y MySQL desde el panel de XAMPP.
- Acceder a
http://localhost/mpcrm/.
Producción (VPS Ubuntu 24 + FastPanel)
- Subir los archivos modificados vía SFTP o FTP al directorio del dominio en el VPS.
- Verificar que
db/config_db.phpapunta a las credenciales de producción. - Si hay cambios de esquema SQL, ejecutarlos en phpMyAdmin de producción.
- Limpiar la caché de OPcache si está activo:
opcache_reset()o reiniciar PHP-FPM. - Verificar permisos:
chmod 644en archivos PHP,755en directorios,777en directorios de subida (galería, backup). - Comprobar que
display_errors = Offen elphp.inide producción.
Archivos que NO deben subirse a producción
pruebamail.php— test de correo, expone credenciales.test_conexion.php— expone configuración de BD.opcache-status.php— información sensible del servidor.debug.log,logs.txt,debug_edit_ord.txt— archivos de log de desarrollo.
Reiniciar FastPanel tras caída
ssh usuario@vps
systemctl restart fastpanel2
systemctl status fastpanel2
Hostname en VPS (cloud-init)
/etc/hosts se regenera en cada reinicio. Para añadir entradas permanentes, editar /etc/cloud/templates/hosts.debian.tmpl en lugar de /etc/hosts.
🔄 Flujo de trabajo diario
Para el comercial
- Acceder al board y revisar los leads nuevos en la columna de entrada.
- Contactar al lead y moverlo a la columna correspondiente.
- Añadir una nota con el resumen de la conversación.
- Marcar como gestionada una vez contactado.
- Actualizar ingreso esperado si el cliente dio un presupuesto.
- Completar los datos de contacto y ubicación que falten.
- Si se cierra el trato: marcar como ganada y registrar el ID de Timón en una nota.
- Si no hay respuesta tras varios intentos: mover a Perdido o Remarketing.
Para el administrador
- Revisar el dashboard para ver el rendimiento del equipo.
- Asignar leads sin comercial usando el widget de asignación rápida o desde la edición de la orden.
- Crear campañas nuevas para leads entrantes de nuevas fuentes.
- Usar el panel de filtros para análisis: leads de X campaña que no están ganados, etc.
- Generar backup semanal desde el módulo de backup.
- Revisar etiquetas y limpiar las que ya no se usen.
❓ Preguntas frecuentes
¿Por qué no veo todas las órdenes en el board?
Si eres comercial, solo ves las órdenes asignadas a ti — esto es correcto. Si eres administrador y no ves alguna orden, puede que tenga un filtro activo. Revisa el badge de filtros en el navbar y pulsa "Limpiar" en el panel de filtros.
¿Cómo busco un lead por nombre o email?
Usa el campo de búsqueda en el navbar del board. Filtra en tiempo real por título, email, teléfono, ciudad, país y también por el texto "sin asignar".
¿Qué significa el badge numérico en el botón "🔍 Filtros"?
Indica cuántos filtros están activos actualmente. Si el badge muestra "2", hay 2 criterios de filtro aplicados sobre el board.
¿Por qué al aplicar un filtro el board cambia completamente?
Cuando se aplica un filtro combinado, el servidor devuelve solo las órdenes que cumplen los criterios, y el JavaScript redibuja el board completo con esas órdenes. Para volver a la vista normal, pulsa "Limpiar filtros".
¿Puedo asignar un comercial sin abrir el lead?
Sí. Si la tarjeta muestra "⚠️ Sin asignar", haz clic en ese badge — se desplegará un selector inline con todos los comerciales activos. Selecciona uno y pulsa "Asignar".
¿Qué pasa si marco una orden como ganada por error?
Un administrador puede desmarcarlo editando el campo ganado = 0 directamente desde /db/index.php o mediante la edición avanzada de la orden.
¿Cómo limpio la caché de la web en producción?
El servidor usa OPcache. Para vaciarlo: accede a /opcache-status.php (o elimina ese archivo si está en producción) o reinicia PHP-FPM desde FastPanel. A nivel de navegador, usa Ctrl+Shift+R para un hard reload.
¿Cómo regenero el token OAuth2 para el correo?
Accede a /PHPMailer/get_oauth_token.php en el navegador y sigue las instrucciones. Necesitarás las credenciales de la app de Google Cloud configurada.
¿Qué requisitos técnicos tiene el servidor?
- PHP 8.2+ con extensiones:
mysqli,mbstring,openssl,json,gd - MySQL 8.0+ o MariaDB 10.6+
- Apache 2.4+ con
mod_rewrite - Composer 2.x instalado
- Acceso SFTP/SSH al servidor para despliegues
¿Dónde reporto un bug?
Contacta al desarrollador en lil2c@2cmonsterx.com o mediante los mensajes internos del CRM.