Caso Real: Módulo de Comisiones en Dolibarr (PHP + Charts)
Módulo de comisiones para Dolibarr ERP: cálculo automático sobre facturas, múltiples reglas, historial de pagos y dashboards con KPIs en tiempo real.
Tabla de contenidos
TL;DR
La empresa perdía 2 días al mes calculando comisiones en Excel, con errores y disputas. Desarrollé un módulo para Dolibarr que calcula comisiones automáticamente desde facturas y pedidos, soporta múltiples reglas, mantiene historial completo y muestra dashboards con KPIs. Resultado: de 2 días a 5 minutos, cero errores, cero disputas.
<video src=“/videos/comisiones.mp4” controls muted playsinline class=“w-full rounded-xl my-6 shadow-lg” style=“max-height: 480px; object-fit: cover;”
Tu navegador no soporta vídeo HTML5.
El problema de la empresa
Cada final de mes, la misma pesadilla:
- Descargar facturas del mes en Dolibarr
- Cruzar con Excel quién vendió qué, a qué cliente, con qué porcentaje
- Aplicar reglas — que cambiaban según el producto, el cliente y el volumen
- Revisar manualmente porque siempre había errores
- Discutir con los comerciales que decían “a mí me corresponde más”
Tiempo: 2 días completos de una persona de administración. Errores: al menos 2-3 comisiones mal calculadas por mes. Conflictos: disputas mensuales con el equipo comercial.
Lo que me pidieron: “Esto tiene que ser automático. Que se calcule solo y que no haya discusiones.”
Diseño del módulo
Modelo de datos
-- Reglas de comisión configurables
CREATE TABLE commission_rules (
id INT PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(100),
salesperson_id INT, -- NULL = aplica a todos
product_category_id INT, -- NULL = todos los productos
client_id INT, -- NULL = todos los clientes
percentage DECIMAL(5,2),
min_amount DECIMAL(10,2), -- Umbral mínimo para aplicar
type ENUM('fixed', 'tiered', 'product', 'client'),
active TINYINT DEFAULT 1,
created_at DATETIME,
INDEX idx_salesperson (salesperson_id),
INDEX idx_active (active)
);
-- Comisiones calculadas (inmutables una vez generadas)
CREATE TABLE commissions (
id INT PRIMARY KEY AUTO_INCREMENT,
rule_id INT,
salesperson_id INT,
invoice_id INT,
order_id INT,
base_amount DECIMAL(10,2), -- Monto de la factura
commission_amount DECIMAL(10,2), -- Comisión calculada
percentage_applied DECIMAL(5,2),
period VARCHAR(7), -- '2026-04'
status ENUM('pending', 'approved', 'paid'),
paid_date DATE,
created_at DATETIME,
INDEX idx_period (period),
INDEX idx_salesperson_period (salesperson_id, period)
);
-- Historial de cambios (auditoría completa)
CREATE TABLE commission_history (
id INT PRIMARY KEY AUTO_INCREMENT,
commission_id INT,
action ENUM('created', 'approved', 'paid', 'modified'),
old_value TEXT,
new_value TEXT,
user_id INT,
created_at DATETIME
);
Tres tablas. Las reglas son configurables, las comisiones son inmutables una vez generadas (se puede auditar cualquier mes pasado), y el historial guarda cada cambio con quién lo hizo y cuándo.
Tipos de comisión que implementé
1. Comisión fija por porcentaje
La más simple: el comercial se lleva un % de cada factura que cierra.
// Ejemplo: 5% de cada factura
$commission = $invoice->total_ht * ($rule->percentage / 100);
2. Comisión escalonada (tiered)
El porcentaje aumenta con el volumen de ventas. Esto incentiva al comercial a vender más.
// Ejemplo de tramos:
// 0 - 5.000€ → 3%
// 5.001 - 15.000€ → 5%
// > 15.000€ → 8%
function calculateTieredCommission($totalSales, $tiers) {
$commission = 0;
$remaining = $totalSales;
foreach ($tiers as $tier) {
$tierAmount = min($remaining, $tier['max'] - $tier['min']);
if ($tierAmount <= 0) break;
$commission += $tierAmount * ($tier['percentage'] / 100);
$remaining -= $tierAmount;
}
return $commission;
}
3. Comisión por producto
Diferentes productos tienen diferentes márgenes. Un producto de alto margen paga más comisión.
4. Comisión por cliente
Clientes nuevos pueden tener un bonus de captación. Clientes existentes tienen un porcentaje estándar.
La combinación
Las reglas se evalúan en orden de prioridad. Si hay una regla específica (producto + cliente + comercial), se aplica esa. Si no, se busca la regla más general. Nunca se aplican dos reglas al mismo concepto.
Integración con Dolibarr (sin romper nada)
Dolibarr tiene su propia estructura de módulos. No puedes parchear archivos core — tienes que hacerlo “a la Dolibarr”:
- Directorio del módulo:
custom/commissions/ - Descriptor del módulo: declara menús, permisos, tablas
- Modelos de datos: clases PHP que extienden
CommonObject - Páginas: PHP con la UI integrada en el look de Dolibarr
- API REST: endpoints adicionales para integraciones externas
// Clase principal del módulo
class Commission extends CommonObject {
public $table_element = 'commissions';
public function calculate($salesperson_id, $period) {
// 1. Obtener facturas del período
$invoices = $this->getInvoicesByPeriod($salesperson_id, $period);
// 2. Obtener reglas aplicables
$rules = $this->getApplicableRules($salesperson_id);
// 3. Calcular comisión por cada factura
$total = 0;
foreach ($invoices as $invoice) {
$rule = $this->findBestRule($rules, $invoice);
$amount = $this->applyRule($rule, $invoice);
$this->saveCommission($salesperson_id, $invoice, $rule, $amount);
$total += $amount;
}
return $total;
}
}
Clave: el módulo solo lee facturas y pedidos de Dolibarr. No modifica nada existente. Si desactivas el módulo, Dolibarr funciona exactamente igual que antes.
Dashboards con KPIs
El equipo de dirección quería ver de un vistazo cómo iba el mes. Desarrollé dashboards con Chart.js:
KPIs principales
- Comisiones del mes: total acumulado vs mes anterior
- Top comerciales: ranking por comisiones generadas
- Comisiones pendientes de pago: cuánto se debe al equipo
- Evolución mensual: gráfica de 12 meses con tendencia
- Desglose por tipo: fija, escalonada, por producto, por cliente
Tabla de detalle
Cada comercial puede ver su desglose:
| Factura | Cliente | Producto | Base | % | Comisión | Estado |
|---|---|---|---|---|---|---|
| FA-2026-001 | Empresa A | Servicio Premium | 3.500€ | 5% | 175€ | Pagada |
| FA-2026-002 | Empresa B | Producto Estándar | 1.200€ | 3% | 36€ | Pendiente |
Transparencia total: el comercial ve exactamente de dónde viene cada céntimo de su comisión. Cero disputas.
API REST para integraciones
Además de la interfaz web, el módulo expone endpoints REST:
GET /api/commissions?period=2026-04 → Listar comisiones del mes
GET /api/commissions/salesperson/{id} → Comisiones de un comercial
POST /api/commissions/calculate?period=2026-04 → Lanzar cálculo del mes
PUT /api/commissions/{id}/approve → Aprobar comisión
PUT /api/commissions/{id}/pay → Marcar como pagada
GET /api/commissions/stats?year=2026 → KPIs anuales
Todos los endpoints requieren autenticación con token y permisos RBAC de Dolibarr.
Retos técnicos
1. No alterar datos históricos
Las comisiones ya pagadas no se pueden recalcular. Si cambian las reglas, solo aplican a partir del mes siguiente. Esto parece simple pero requiere inmutabilidad en el modelo de datos.
Solución: la tabla commissions tiene status paid que congela el registro. Las reglas tienen fecha de vigencia. El cálculo siempre usa las reglas vigentes en el período que se calcula.
2. Reglas con conflicto de prioridad
¿Qué pasa si hay una regla “5% para todos” y otra “8% para el producto X”? ¿Se aplican las dos?
Solución: sistema de prioridad — la regla más específica gana. Orden: comercial + producto + cliente > comercial + producto > comercial > general. Nunca se aplican dos reglas al mismo concepto.
3. Performance con muchas facturas
Un cálculo mensual puede tocar 500+ facturas y 20 comerciales. Con queries mal optimizadas, tarda minutos.
Solución: índices compuestos en MySQL, precarga de reglas en memoria (son pocas), y batch insert para las comisiones generadas.
Lo que consiguió la empresa
| Antes | Después |
|---|---|
| 2 días de cálculo manual | 5 minutos (click → resultado) |
| 2-3 errores por mes | 0 errores |
| Disputas mensuales | Cero disputas (transparencia total) |
| Sin histórico | Auditoría completa de cada comisión |
| Excel compartido | Dashboard con KPIs en tiempo real |
| Sin API | Endpoints REST para integraciones |
Impacto real: la persona de administración que dedicaba 2 días al mes ahora dedica 5 minutos a revisar y aprobar. El equipo comercial confía en los números porque pueden ver el desglose.
Stack técnico
- Backend: PHP 8.x (módulo Dolibarr)
- Base de datos: MySQL con índices optimizados
- Dashboards: Chart.js para gráficas interactivas
- API: REST con autenticación por token
- Seguridad: SSL/TLS, tokens JWT, permisos RBAC de Dolibarr
- Infraestructura: Linux, Apache
Lo que aprendí
- La inmutabilidad protege — registros de comisiones pagadas nunca se modifican. Si hay corrección, se crea un nuevo registro. Esto elimina el “alguien cambió mi comisión”.
- Las reglas de negocio parecen simples hasta que no lo son — “5% por factura” se convierte en escalonada + por producto + por cliente + con umbral mínimo.
- La transparencia elimina conflictos — cuando el comercial puede ver el desglose exact de su comisión, las disputas desaparecen.
- Dolibarr es extensible — su sistema de módulos permite añadir funcionalidad compleja sin tocar el core.
- Charts.js es suficiente para dashboards empresariales. No necesitas D3.js ni Recharts para KPIs básicos.
¿Tu empresa necesita automatizar procesos?
Si pierdes tiempo con Excels, cálculos manuales o procesos que deberían ser automáticos, cuéntame qué necesitas.
Más casos reales: