🏛️ Revolución Arquitectónica en Dolibarr ERP
Una transformación radical que convierte Dolibarr de un sistema PHP tradicional en un modelo cliente/servidor puro donde PostgreSQL es el cerebro que maneja toda la lógica de negocio mediante triggers automáticos y funciones avanzadas.
Cliente/Servidor Puro
PostgreSQL como servidor inteligente, PHP como cliente de presentación
Lógica Centralizada
Todas las reglas de negocio ejecutándose automáticamente en la base de datos
Consistencia Garantizada
Imposible omitir validaciones o cálculos, ejecución automática y transparente
🎯 Objetivos del Proyecto
Objetivo Principal
Transformar completamente la arquitectura de Dolibarr ERP de un sistema tradicional PHP a un modelo cliente/servidor puro donde toda la lógica de negocio reside en PostgreSQL mediante triggers y funciones.
🏗️ Arquitectura Cliente/Servidor
Implementar un modelo donde PostgreSQL es el servidor inteligente que maneja TODA la lógica de negocio, y PHP actúa únicamente como cliente de presentación.
⚡ Eliminación Total de Lógica PHP
Remover completamente las validaciones, cálculos y reglas de negocio del código PHP, trasladándolas a triggers PostgreSQL automáticos.
🎯 PostgreSQL Exclusivo
Abandonar la compatibilidad MySQL/MariaDB para aprovechar al máximo las capacidades avanzadas de PostgreSQL.
✅ Garantía de Consistencia
Asegurar que las reglas de negocio se ejecuten siempre, independientemente del cliente que acceda a la base de datos.
🏛️ Comparación Arquitectónica
❌ Dolibarr Original
PHP (Fat Client)
- Validaciones de campos
- Cálculos de totales
- Generación de códigos
- Reglas de negocio
- Control de flujo
MySQL/PostgreSQL (Dumb Storage)
- Almacenamiento de datos
- Constraints básicos
- Relaciones simples
❌ Problemas Identificados:
- Lógica dispersa y duplicada
- Inconsistencias entre accesos
- Validaciones fáciles de omitir
- Mantenimiento complejo
- Testing fragmentado
✅ Modelo Cliente/Servidor
PHP (Thin Client)
- Presentación de datos
- Interfaz de usuario
- Comandos SQL simples
- Sin lógica de negocio
PostgreSQL (Smart Server)
- 🔧 Triggers automáticos
- 📐 Funciones de validación
- 🧮 Cálculos garantizados
- 🏷️ Generación de códigos
- 🔒 Reglas de negocio
- 📊 Auditoría automática
✅ Beneficios Obtenidos:
- Lógica centralizada y consistente
- Validaciones automáticas siempre
- Performance mejorado
- Mantenimiento simplificado
- Testing unificado
🗄️ Arquitectura de Tres Bases de Datos
Para garantizar la máxima precisión en la migración, implementamos una arquitectura de testing con tres bases de datos especializadas:
dolibarrdev
DesarrolloBase de datos principal de desarrollo
- Contiene TODA la lógica PostgreSQL
- Triggers y funciones implementados
- Datos reales de prueba
- Entorno principal de trabajo
dolibarr_test_php
Test PHPReplica del comportamiento PHP original
- Solo estructura de tablas
- Sin triggers ni funciones
- Simula comportamiento PHP puro
- Base de comparación para tests
dolibarr_test_postgresql
Test PostgreSQLCopia exacta de dolibarrdev
- Triggers y funciones completos
- Comportamiento PostgreSQL puro
- Validación de implementación
- Tests comparativos automatizados
🔄 Flujo de Testing Comparativo
Capturar Comportamiento PHP
Ejecutar operaciones en dolibarr_test_php y registrar resultados
Ejecutar en PostgreSQL
Realizar las mismas operaciones en dolibarr_test_postgresql
Comparar Resultados
Validar que ambos comportamientos sean idénticos
Certificar Migración
Garantizar 100% de paridad funcional
📊 Métricas del Proyecto
Progreso por Categoría
📅 Cronología del Proyecto
Inicio del Proyecto
Análisis inicial de Dolibarr, definición de objetivos y establecimiento del modelo cliente/servidor como arquitectura objetivo.
Módulo Societe (Primer Éxito)
Implementación completa del primer módulo, estableciendo patrones y metodología para el resto del proyecto.
Infraestructura de Testing
Desarrollo de pgTAP testing y arquitectura de 3 bases de datos para tests comparativos rigurosos.
Alcance de 17 Módulos
Completados Societe, Product, User, Banque, Tax, Propale, Categories, Don, Contact, Commande, Facture, Stock, Bookkeeping, ExpenseReport, FournisseurCommande, Expeditions y Contracts con 100% tests pasando.
Documentación Comprensiva
Creación de este libro HTML interactivo documentando todo el proceso de transformación arquitectónica.
Módulos Avanzados
Finalización de los 4 módulos restantes: Fichinter, Expedition, Contrat, y otros módulos específicos.
💡 Justificación Técnica
🏗️ Problemas del Modelo Tradicional
- Lógica Dispersa: Validaciones y reglas esparcidas por múltiples archivos PHP
- Inconsistencia: Diferentes comportamientos según el punto de acceso
- Mantenimiento Complejo: Cambios requieren modificar múltiples archivos
- Testing Fragmentado: Difícil probar todas las combinaciones
- Performance: Múltiples roundtrips a la base de datos
✅ Ventajas del Modelo Cliente/Servidor
- Centralización: Toda la lógica en un lugar controlado
- Garantías: Triggers se ejecutan siempre, sin excepciones
- Performance: Cálculos optimizados en la base de datos
- Consistencia: Mismo comportamiento para todos los clientes
- Auditabilidad: Control total sobre las operaciones
📝 Ejemplo Técnico de Transformación
❌ Código PHP Original
public function verify() {
// Validar que el nombre no esté vacío
if (empty($this->nom)) {
$this->errors[] = "Le nom est obligatoire";
return -1;
}
// Validar email si está presente
if (!empty($this->email)) {
if (!filter_var($this->email, FILTER_VALIDATE_EMAIL)) {
$this->errors[] = "Email invalide";
return -1;
}
}
// Verificar que el código no exista
$sql = "SELECT COUNT(*) as nb FROM llx_societe WHERE code_client = '".$this->code_client."'";
$resql = $this->db->query($sql);
if ($resql) {
$obj = $this->db->fetch_object($resql);
if ($obj->nb > 0) {
$this->errors[] = "Code client déjà utilisé";
return -1;
}
}
return 0;
}
✅ Trigger PostgreSQL
CREATE OR REPLACE FUNCTION llx_societe_before_insert()
RETURNS trigger AS $$
BEGIN
-- Validar nombre obligatorio
IF NEW.nom IS NULL OR trim(NEW.nom) = '' THEN
RAISE EXCEPTION 'Le nom est obligatoire';
END IF;
-- Validar email
IF NEW.email IS NOT NULL AND NEW.email != '' THEN
IF NOT (NEW.email ~* '^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}$') THEN
RAISE EXCEPTION 'Email invalide: %', NEW.email;
END IF;
END IF;
-- Generar código automáticamente si está vacío
IF NEW.code_client IS NULL OR trim(NEW.code_client) = '' THEN
NEW.code_client := llx_societe_get_next_code('C');
ELSE
-- Verificar unicidad
IF EXISTS (SELECT 1 FROM llx_societe WHERE code_client = NEW.code_client) THEN
RAISE EXCEPTION 'Code client déjà utilisé: %', NEW.code_client;
END IF;
END IF;
-- Establecer defaults
NEW.entity := COALESCE(NEW.entity, 1);
NEW.status := COALESCE(NEW.status, 1);
NEW.datec := COALESCE(NEW.datec, NOW());
RETURN NEW;
END;
$$ LANGUAGE plpgsql;
🎯 Resultado de la Transformación
PHP Simplificado:
public function verify() {
return 0; // ¡Los triggers manejan TODO automáticamente!
}