Saltar al contenido principal

Personalización y Configuración

Esta guía explica cómo personalizar y configurar OmniCRM para que coincida con la identidad de su marca, los requisitos operativos y las necesidades de integración.

Variables de Entorno (.env Files)

OmniCRM utiliza variables de entorno para configurar tanto la API del backend como la interfaz de usuario del frontend. Hay dos archivos .env separados que controlan diferentes aspectos del sistema.

Configuración de la API del Backend (.env)

Ubicado en la raíz del directorio de OmniCRM, este archivo configura las conexiones a la base de datos y la integración de CGRates.

Ubicación: /OmniCRM/.env

Configuración de la Base de Datos:

# Base de Datos MySQL/MariaDB (Datos del CRM)
MYSQL_ROOT_PASSWORD=your_secure_password
MYSQL_USER=omnitouch
MYSQL_PASSWORD=your_database_password
MYSQL_DATABASE=crm
DB_SERVER=db

# Base de Datos PostgreSQL (Datos de CGRates)
POSTGRES_USER=cgrates
POSTGRES_PASSWORD=cgrates_password
POSTGRES_DB=cgrates_db

Configuración de CGRates:

# Credenciales de la API de CGRates
CGRATES_API_USER=admin
CGRATES_API_PASS=secret
CGRATES_DB_USER=cgrates
CGRATES_DB_PASS=cgrates_password
CGRATES_DB_NAME=cgrates_db
CGRATES_DB_PORT=5432

Consideraciones de Seguridad:

  • Nunca comprometa archivos .env en el control de versiones - Use .env.example como plantilla
  • Use contraseñas fuertes - Mínimo 16 caracteres con mezcla de mayúsculas, minúsculas, números y símbolos
  • Gire las credenciales regularmente - Especialmente para implementaciones en producción
  • Restringa el acceso a la base de datos - Use listas blancas de IP y reglas de firewall

Configuración de la Interfaz de Usuario del Frontend (.env)

Ubicado en el directorio OmniCRM-UI, este archivo controla la marca, la apariencia, las integraciones y las banderas de características.

Ubicación: /OmniCRM/OmniCRM-UI/.env

Claves API e Integración:

# API de Google Maps (para autocompletar direcciones y geocodificación)
REACT_APP_GOOGLE_API_KEY=your_google_api_key

# Pasarela de Pago Stripe
REACT_APP_STRIPE_PUBLISHABLE_KEY=pk_test_xxxxx

# Deshabilitar el lanzamiento automático del navegador al iniciar npm
BROWSER=none

Información de Marca y Empresa:

# Marca de la Empresa
REACT_APP_COMPANY_NAME="ShellFone"
REACT_APP_PORTAL_NAME="ShellManager"
REACT_APP_SELF_CARE_NAME="ShellCare"
REACT_APP_COMPANY_TAGLINE="Phones with Shells"

Estos valores aparecen en toda la interfaz de usuario:

  • COMPANY_NAME - Mostrado en títulos de página, correos electrónicos y comunicaciones con clientes
  • PORTAL_NAME - Nombre del portal de administración/personal (por ejemplo, "ShellManager")
  • SELF_CARE_NAME - Nombre del portal de autoservicio para clientes (por ejemplo, "ShellCare")
  • COMPANY_TAGLINE - Aparece en pantallas de inicio de sesión y materiales de marketing

Localización y Configuraciones Regionales:

# Idioma y Localidad
# Idiomas soportados: ar, ch, en, fr, gr, it, ru, sp
REACT_APP_DEFAULT_LANGUAGE=en
REACT_APP_LOCALE="en-GB"

# Ubicación Predeterminada (para autocompletar direcciones)
REACT_APP_DEFAULT_LOCATION="Sydney, Australia"
REACT_APP_DEFAULT_COUNTRY="Australia"

# Configuraciones de Moneda
REACT_APP_CURRENCY_CODE="GBP"
REACT_APP_CURRENCY_SYMBOL="£"

Personalización del Esquema de Color:

# Color Primario (color principal de la marca)
REACT_APP_PRIMARY_COLOR=#405189

# Opciones de Color Adicionales (ejemplos comentados)
# REACT_APP_SECONDARY_COLOR=#2bFFcf
# REACT_APP_TERTIARY_COLOR=#1a9fbf
# REACT_APP_SUCCESS_COLOR=#28a745
# REACT_APP_INFO_COLOR=#17a2b8
# REACT_APP_WARNING_COLOR=#ffc107
# REACT_APP_DANGER_COLOR=#dc3545

El color primario se aplica a:

  • Encabezados de navegación
  • Botones de acción
  • Enlaces y resaltados
  • Estados activos
  • Elementos de marca

Integraciones de Aplicaciones Web:

Configure hasta 6 aplicaciones web de acceso rápido que aparecen en el panel de administración:

# Aplicación Web 1: GitHub
REACT_APP_WEB_APP_1_NAME="GitHub"
REACT_APP_WEB_APP_1_URL="https://github.com"
REACT_APP_WEB_APP_1_ICON_PATH="resources/webapp_icons/github.png"

# Aplicación Web 2: Xero
REACT_APP_WEB_APP_2_NAME="Xero"
REACT_APP_WEB_APP_2_URL="https://go.xero.com/"
REACT_APP_WEB_APP_2_ICON_PATH="resources/webapp_icons/xero.png"

# Aplicación Web 3-6: Integraciones adicionales
# (Configurar de manera similar con NAME, URL y ICON_PATH)

Monitoreo y Análisis:

# Integración del Panel de Grafana
REACT_APP_GRAFANA_URLS=url1,url2,url3
REACT_APP_GRAFANA_LABELS=label1,label2,label3
REACT_APP_GRAFANA_API_KEY=your-api-key

Banderas de Características:

# URLs de Soporte y Documentación
REACT_APP_FAQS_URL=https://docs.yourcompany.com/faqs
REACT_APP_SUPPORT_URL=https://support.yourcompany.com

# Inicio de sesión social (Google, Facebook, etc.)
REACT_APP_ALLOW_SOCIAL_LOGINS=yes

Personalización del Logo y de la Imagen de Carga

OmniCRM le permite reemplazar las imágenes de marca predeterminadas con el logo y las pantallas de carga de su empresa sin modificar el código.

Los logos se almacenan en /OmniCRM-UI/src/assets/images/omnitouch/ y utilizan un sistema de respaldo:

Logos Predeterminados (siempre presentes):

  • DefaultLogoDark.png - Logo de tema oscuro (utilizado en fondos claros)
  • DefaultLogoLight.png - Logo de tema claro (utilizado en fondos oscuros)

Logos Personalizados (opcional, tienen prioridad cuando están presentes):

  • logoSm.png - Logo pequeño para la barra lateral colapsada (recomendado: 100x100px)
  • logoDark.png - Logo oscuro de tamaño completo para encabezados (recomendado: 200x50px)
  • logoLight.png - Logo claro de tamaño completo para pantallas de autenticación (recomendado: 200x50px)

Cómo Funciona el Respaldo de Logos:

El sistema intenta cargar primero los logos personalizados. Si no existe un archivo de logo personalizado, se recurre al predeterminado:

// Desde Header.js
const tryImport = (filename) => {
try {
return require(`../assets/images/omnitouch/${filename}`);
} catch (err) {
return null; // Recurre al predeterminado
}
};

const userLogoSm = tryImport("logoSm.png");
const userLogoDark = tryImport("logoDark.png");
const userLogoLight = tryImport("logoLight.png");

Dónde Aparecen los Logos:

  • logoSm.png - Barra lateral colapsada, navegación móvil, pantallas de encabezado pequeñas
  • logoDark.png - Barra de encabezado principal (modo claro), encabezado del panel de administración
  • logoLight.png - Pantallas de inicio de sesión/registro, fondos oscuros, carrusel de autenticación

Reemplazo de Logos:

  1. Cree Sus Archivos de Logo:

    • Use formato PNG para soporte de transparencia
    • Coincida con las dimensiones recomendadas arriba
    • Asegúrese de que los logos sean claros tanto en resoluciones regulares como en retina
  2. Agregue a OmniCRM:

    # Copie sus archivos de logo al directorio de imágenes de omnitouch
    cp /path/to/your/logoSm.png OmniCRM-UI/src/assets/images/omnitouch/
    cp /path/to/your/logoDark.png OmniCRM-UI/src/assets/images/omnitouch/
    cp /path/to/your/logoLight.png OmniCRM-UI/src/assets/images/omnitouch/
  3. Reconstruya la Interfaz de Usuario:

    cd OmniCRM-UI
    npm run build
  4. Verifique los Cambios:

    • Verifique el encabezado en modo claro (debería mostrar logoDark.png)
    • Verifique el encabezado en modo oscuro (debería mostrar logoLight.png)
    • Verifique la barra lateral colapsada (debería mostrar logoSm.png)
    • Verifique la pantalla de inicio de sesión (debería mostrar logoLight.png)

Mejores Prácticas para el Diseño de Logos:

  • Contraste - Asegúrese de que los logos sean visibles tanto en fondos claros como oscuros
  • Simplicidad - Los logos deben ser reconocibles en tamaños pequeños
  • Formato - Use PNG con fondos transparentes
  • Retina - Proporcione resolución 2x para pantallas de alta DPI
  • Consistencia - Use los mismos colores de marca en todas las variantes de logos

Pantallas de Carga y Fondos de Autenticación

Las pantallas de autenticación (inicio de sesión, registro, restablecimiento de contraseña) utilizan un fondo de carrusel con imágenes personalizables.

Ubicación: /OmniCRM-UI/src/pages/AuthenticationInner/authCarousel.js

Configuración Predeterminada:

import logoLight from "../../assets/images/logo-light.png";

// Logo mostrado en pantallas de autenticación
<img src={logoLight} alt="" height="18" />

Personalizando Pantallas de Autenticación:

  1. Reemplace logo-light.png en /OmniCRM-UI/src/assets/images/
  2. Agregue CSS de fondo personalizado a la clase .auth-one-bg
  3. Modifique las citas del carrusel en authCarousel.js para que coincidan con la voz de su marca

Ejemplo de Personalización:

/* Agregue a su CSS personalizado */
.auth-one-bg {
background-image: url('/assets/images/custom-auth-bg.jpg');
background-size: cover;
background-position: center;
}

Archivo de Configuración del CRM (crm_config.yaml)

El archivo crm_config.yaml es la configuración central para la API de OmniCRM, controlando integraciones, aprovisionamiento, plantillas de correo electrónico y servicios externos.

Ubicación: /OmniCRM/OmniCRM-API/crm_config.yaml

Configuración de la Base de Datos

database:
username: omnitouch
password: omnitouch2024
server: localhost

Nota: Esto debe coincidir con sus credenciales de base de datos en .env. En implementaciones en contenedores, el servidor es típicamente db (nombre del servicio de Docker).

Tipos de Servicio

Defina tipos de servicio válidos para su implementación:

service_types:
- omnicharge
- mobile
- fixed
- fixed-voice
- hotspot
- dongle

Estos se utilizan en todo el sistema para:

  • Categorización de productos
  • Filtrado de complementos (los complementos coinciden con los tipos de servicio)
  • Flujos de trabajo de aprovisionamiento
  • Informes y análisis

Integración HSS (Home Subscriber Server)

Para operadores de redes móviles con integración HSS:

hss:
hss_peers:
- 'http://10.179.2.140:8080'
apn_list: "1,2,3,4,5,6"

Configuración:

  • hss_peers - Lista de puntos finales HSS para aprovisionamiento de suscriptores
  • apn_list - Lista separada por comas de IDs de APN disponibles para aprovisionamiento

Configuración de Plantillas de Correo Electrónico de Mailjet

OmniCRM utiliza Mailjet para correos electrónicos transaccionales. Cada tipo de correo electrónico tiene su propia configuración de plantilla:

mailjet:
api_key: your_mailjet_api_key
api_secret: your_mailjet_api_secret

# Correo Electrónico de Bienvenida al Cliente
api_crmCommunicationCustomerWelcome:
from_email: "support@yourcompany.com"
from_name: "Soporte de Su Empresa"
template_id: 5977509
subject: "Bienvenido a YourCompany"

# Correo Electrónico de Factura al Cliente
api_crmCommunicationCustomerInvoice:
from_email: "billing@yourcompany.com"
from_name: "Facturación de Su Empresa"
template_id: 6759851
subject: "Su Factura - "

# Recordatorio de Factura
api_crmCommunicationCustomerInvoiceReminder:
from_email: "billing@yourcompany.com"
from_name: "Facturación de Su Empresa"
template_id: 5977570
subject: "Recordatorio de Pago de Factura"

# Correo Electrónico de Bienvenida al Usuario (Personal/Admin)
api_crmCommunicationUserWelcome:
from_email: "admin@yourcompany.com"
from_name: "Admin de Su Empresa"
template_id: 6118112
subject: "Bienvenido al Equipo"

# Solicitud de Restablecimiento de Contraseña
api_crmCommunicationUserPasswordReset:
from_email: "security@yourcompany.com"
from_name: "Seguridad de Su Empresa"
template_id: 6735666
subject: "Solicitud de Restablecimiento de Contraseña"

# Confirmación de Éxito en el Restablecimiento de Contraseña
api_crmCommunicationUserPasswordResetSuccess:
from_email: "security@yourcompany.com"
from_name: "Seguridad de Su Empresa"
template_id: 6118378
subject: "Restablecimiento de Contraseña Exitoso"

# Notificación de Cambio de Contraseña
api_crmCommunicationUserPasswordChange:
from_email: "security@yourcompany.com"
from_name: "Seguridad de Su Empresa"
template_id: 6118423
subject: "Contraseña Cambiada"

# Verificación de Correo Electrónico
api_crmCommunicationEmailVerification:
from_email: "verify@yourcompany.com"
from_name: "Verificación de Su Empresa"
template_id: 6267350
subject: "Verifique Su Dirección de Correo Electrónico"

# Notificación de Saldo Expirado
api_crmCommunicationsBalanceExpired:
from_email: "alerts@yourcompany.com"
from_name: "Alertas de Su Empresa"
template_id: 7238252
subject: "Saldo de Servicio Expirado"

# Advertencia de Bajo Saldo
api_crmCommunicationsBalanceLow:
from_email: "alerts@yourcompany.com"
from_name: "Alertas de Su Empresa"
template_id: 7238263
subject: "Advertencia de Bajo Saldo"

Creando Plantillas de Mailjet:

  1. Inicie sesión en el panel de Mailjet (<https://app.mailjet.com>)
  2. Navegue a TransaccionalPlantillas
  3. Cree una nueva plantilla o clone una existente
  4. Anote el ID de Plantilla (valor numérico)
  5. Agregue variables de plantilla que coincidan con la estructura de datos de OmniCRM
  6. Actualice crm_config.yaml con el ID de plantilla

Variables de Plantilla Disponibles:

Cada tipo de correo electrónico recibe variables específicas. Ejemplos comunes:

  • {{customer_name}} - Nombre del cliente o usuario
  • {{service_name}} - Nombre del servicio o producto
  • {{invoice_id}} - Número de factura
  • {{invoice_amount}} - Monto total de la factura
  • {{due_date}} - Fecha de vencimiento del pago
  • {{reset_link}} - URL de restablecimiento de contraseña
  • {{verification_link}} - URL de verificación de correo electrónico
  • {{balance}} - Saldo actual de la cuenta
  • {{expiry_date}} - Fecha de vencimiento del saldo o servicio

Configuración de Aprovisionamiento

provisioning:
failure_list: ['admin@yourcompany.com', 'ops@yourcompany.com']

Propósito:

  • failure_list - Direcciones de correo electrónico notificadas cuando falla el aprovisionamiento de Ansible
  • Las notificaciones incluyen el nombre del playbook, detalles del error y la información del cliente
  • Permite al equipo de operaciones responder rápidamente a problemas de aprovisionamiento

Configuración de Facturas

invoice:
template_filename: 'yourcompany_invoice_template.html'

Propósito:

Especifica qué plantilla HTML de Jinja2 utilizar para la generación de facturas en PDF.

Ubicación de la Plantilla: /OmniCRM-API/invoice_templates/

Consulte la sección Generación de PDF de Factura a continuación para obtener detalles sobre cómo crear plantillas personalizadas.

URL Base del CRM

crm:
base_url: 'http://localhost:5000'

Propósito:

  • Utilizado por los playbooks de Ansible para hacer llamadas a la API
  • Utilizado en plantillas de correo electrónico para generar enlaces al CRM
  • Debe ser la URL accesible públicamente de su API (no nombres de contenedor internos)

Ejemplos:

  • Desarrollo: http://localhost:5000
  • Producción: https://api.yourcompany.com
  • Docker: http://omnicrm-api:5000 (comunicación interna entre contenedores)

Configuración de OCS y CGRates

ocs:
ocsApi: 'http://10.179.2.142:8080/api'
ocsTenant: 'mnc380.mcc313.3gppnetwork.org'
cgrates: 'localhost:2080'

Configuración:

  • ocsApi - Punto final de la API de OCS para gestión de suscriptores
  • ocsTenant - Identificador de inquilino para implementaciones OCS multi-inquilino
  • cgrates - Punto final de la API JSON-RPC de CGRates (host:port)

Configuración de SMSC (Puerta de Enlace SMS)

smsc:
source_msisdn: 'YourCompany'
smsc_url: 'http://10.179.2.216/SMSc/'
api_key: 'your_smsc_api_key'

Propósito:

  • Enviar notificaciones SMS a los clientes (bajo saldo, alertas de servicio, códigos 2FA)
  • source_msisdn - ID del remitente mostrado a los destinatarios (alfanumérico o número de teléfono)
  • smsc_url - Punto final de la API de la puerta de enlace SMSC
  • api_key - Autenticación para la API de SMSC

Clave Secreta JWT

jwt_secret: '2b93110f723db60172c8e9a1eaa80027a9a9c3f05b44e50dc3fcf38dba68d87e'

Seguridad:

  • Utilizado para firmar y verificar tokens de autenticación
  • DEBE ser cambiado del valor predeterminado en producción
  • Genere una cadena aleatoria segura (mínimo 64 caracteres)
  • Nunca comparta ni comprometa en el control de versiones

Generando una Nueva Clave Secreta JWT:

# Generar una clave aleatoria segura criptográficamente
python3 -c "import secrets; print(secrets.token_hex(32))"

Configuración de Pagos de Stripe

stripe:
secret_key: 'sk_live_xxxxxxxxxx'
publishable_key: 'pk_live_xxxxxxxxxx'
currency: 'aud'
statement_descriptor_suffix: 'YOURCOMPANY'

Configuración:

  • secret_key - Clave API secreta de Stripe (lado del servidor, mantenga confidencial)
  • publishable_key - Clave publicable de Stripe (lado del cliente, seguro para exponer)
  • currency - Código de moneda ISO 4217 (aud, usd, gbp, eur, etc.)
  • statement_descriptor_suffix - Aparece en los estados de cuenta de tarjetas de crédito de los clientes

Uso del Descriptor de Estado:

  • Mostrado en los estados de cuenta bancarios de los clientes como "YOURCOMPANY"
  • Máximo 22 caracteres
  • Ayuda a los clientes a identificar los cargos
  • También se utiliza en los nombres de archivo de PDF de facturas (por ejemplo, YOURCOMPANY_12345.pdf)

Claves API y Listado Blanco de IP

Defina claves API con acceso basado en roles y restricciones de IP:

api_keys:
"YOUR_API_KEY_1":
roles: ["admin"]
ips: ["127.0.0.1", "::1"]
"YOUR_API_KEY_2":
roles: ["customer_service_agent_1"]
ips: ["127.0.0.1", "::1", "10.0.1.0/24"]

# Lista Blanca de IP (independiente, sin clave API)
ip_whitelist:
"10.179.2.142":
roles: ["admin"]

Propósito:

  • Permitir que sistemas externos se autentiquen a través de la clave API
  • Restringir el acceso por dirección IP
  • Conceder roles específicos a los consumidores de la API
  • Útil para integraciones (sistemas de facturación, monitoreo, automatización)

Mejores Prácticas de Seguridad:

  • Use claves API largas y aleatorias (mínimo 32 caracteres)
  • Restringa las IPs a fuentes conocidas solamente
  • Conceda los roles mínimos necesarios
  • Gire las claves API regularmente
  • Monitoree el uso de claves API en los registros

Generación de PDF de Factura

OmniCRM genera facturas PDF profesionales utilizando plantillas HTML de Jinja2 y renderizado PDF de WeasyPrint.

Cómo Funciona la Generación de PDF

  1. Selección de Plantilla:
    • El nombre del archivo de plantilla se especifica en crm_config.yaml bajo invoice.template_filename
    • La plantilla se carga desde el directorio /OmniCRM-API/invoice_templates/
  2. Preparación de Datos:
    • Los datos de la factura (ID, fechas, montos, estado) se obtienen de la base de datos
    • La información del cliente (nombre, dirección) se recupera
    • Se compila la lista de transacciones (todos los cargos/créditos en la factura)
  3. Renderizado de Plantilla:
    • Jinja2 renderiza la plantilla HTML con los datos de la factura
    • Variables como {{ invoice_number }}, {{ total_amount }}, etc. son reemplazadas
    • El HTML renderizado se guarda en invoice_templates/rendered/ para depuración
  4. Generación de PDF:
    • WeasyPrint convierte el HTML renderizado a PDF
    • El PDF admite estilos CSS, imágenes, saltos de página, encabezados/pies de página
    • Los datos binarios del PDF se generan en memoria
  5. Caché:
    • El PDF se codifica en Base64 y se almacena en la tabla Invoice_PDF_Cache
    • Se calcula un hash SHA256 para verificación de integridad
    • Las solicitudes subsiguientes devuelven el PDF en caché (entrega instantánea)
  6. Invalidación de Caché:
    • La caché se invalida cuando la factura se modifica, anula o reembolsa
    • Los cambios en la plantilla no invalidan automáticamente las cachés existentes

Estructura de Plantilla de Factura

Las plantillas de factura son archivos HTML de Jinja2 con variables y lógica incrustadas.

Ubicación de la Plantilla: /OmniCRM-API/invoice_templates/yourcompany_invoice_template.html

Variables Disponibles:

{
'invoice_number': 12345,
'date': '2025-01-04',
'client': {
'name': 'John Smith',
'address': {
'address_line_1': '123 Main St',
'city': 'Sydney',
'state': 'NSW',
'zip_code': '2000',
'country': 'Australia'
}
},
'transaction_list': [
[
{
'transaction_id': 1,
'title': 'Servicio Móvil - Cuota Mensual',
'retail_cost': 30.00,
'wholesale_cost': 10.00,
'created': '2025-01-01'
},
{
'transaction_id': 2,
'title': 'Complemento de Datos - 5GB',
'retail_cost': 15.00,
'wholesale_cost': 5.00,
'created': '2025-01-15'
}
]
],
'total_amount': 45.00,
'due_date': '2025-01-31',
'start_date': '2025-01-01',
'end_date': '2025-01-31',
'paid': False,
'void': False
}

Fragmento de Plantilla de Ejemplo:

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Factura {{ invoice_number }}</title>
<style>
body {
font-family: Arial, sans-serif;
margin: 40px;
}
.header {
text-align: center;
margin-bottom: 30px;
}
.invoice-details {
margin-bottom: 20px;
}
table {
width: 100%;
border-collapse: collapse;
}
th, td {
border: 1px solid #ddd;
padding: 12px;
text-align: left;
}
th {
background-color: #405189;
color: white;
}
.total {
text-align: right;
font-size: 18px;
font-weight: bold;
margin-top: 20px;
}
</style>
</head>
<body>
<div class="header">
<img src="file:///path/to/logo.png" alt="Logo de la Empresa" height="60">
<h1>FACTURA</h1>
</div>

<div class="invoice-details">
<p><strong>Número de Factura:</strong> {{ invoice_number }}</p>
<p><strong>Fecha:</strong> {{ date }}</p>
<p><strong>Fecha de Vencimiento:</strong> {{ due_date }}</p>
<p><strong>Período de Facturación:</strong> {{ start_date }} a {{ end_date }}</p>
</div>

<div class="customer-details">
<h3>Facturar a:</h3>
<p>{{ client.name }}</p>
<p>{{ client.address.address_line_1 }}</p>
<p>{{ client.address.city }}, {{ client.address.state }} {{ client.address.zip_code }}</p>
<p>{{ client.address.country }}</p>
</div>

<table>
<thead>
<tr>
<th>Descripción</th>
<th>Fecha</th>
<th>Monto</th>
</tr>
</thead>
<tbody>
{% for transaction in transaction_list[0] %}
<tr>
<td>{{ transaction.title }}</td>
<td>{{ transaction.created }}</td>
<td>${{ "%.2f"|format(transaction.retail_cost) }}</td>
</tr>
{% endfor %}
</tbody>
</table>

<div class="total">
<p>Total a Pagar: ${{ "%.2f"|format(total_amount) }}</p>
</div>

{% if paid %}
<div style="text-align: center; color: green; font-weight: bold;">
PAGADO
</div>
{% endif %}

{% if void %}
<div style="text-align: center; color: red; font-weight: bold;">
ANULADO
</div>
{% endif %}
</body>
</html>

Mejores Prácticas para Plantillas:

  • Use rutas absolutas para imágenes - file:///absolute/path/to/image.png
  • CSS en línea - WeasyPrint no carga hojas de estilo externas de manera confiable
  • Pruebe con datos de muestra - Use invoice_templates/rendered/ para inspeccionar HTML
  • Saltos de página - Use <div style="page-break-after: always;"></div> para facturas de varias páginas
  • Encabezados y pies de página - Use reglas CSS @page para elementos repetidos
  • Formato de moneda - Use filtros de Jinja2: {{ "%.2f"|format(amount) }}

Creando una Plantilla de Factura Personalizada

  1. Copie la Plantilla de Ejemplo:

    cd /OmniCRM/OmniCRM-API/invoice_templates
    cp norfone_invoice_template.html yourcompany_invoice_template.html
  2. Edite la Plantilla:

    • Reemplace el nombre de la empresa, el logo, la información de contacto
    • Ajuste el estilo (colores, fuentes, diseño) para que coincida con la marca
    • Agregue o elimine secciones según sea necesario (desglose de impuestos, instrucciones de pago, etc.)
  3. Actualice la Configuración:

    Edite crm_config.yaml:

    invoice:
    template_filename: 'yourcompany_invoice_template.html'
  4. Pruebe la Generación de Facturas:

    • Cree una factura de prueba en el CRM
    • Descargue el PDF y verifique el formato
    • Verifique invoice_templates/rendered/{invoice_id}.html para depuración
  5. Invalidar Cachés Antiguos (si es necesario):

    Si ha cambiado la plantilla y desea regenerar facturas existentes:

    -- Limpiar todos los PDFs en caché (fuerza la regeneración)
    DELETE FROM Invoice_PDF_Cache;

Sistema de Caché de PDF

Para mejorar el rendimiento, OmniCRM almacena en caché los PDFs generados:

Comportamiento de Caché:

  • Primera Solicitud - Se genera, almacena en caché y devuelve el PDF
  • Solicitudes Subsiguientes - Se devuelve inmediatamente el PDF en caché (sin regeneración)
  • Invalidación de Caché - Ocurre cuando la factura se modifica, anula o reembolsa
  • Limpieza de Caché - Las cachés antiguas se purgan automáticamente después de 30 días de inactividad

Almacenamiento de Caché:

  • PDF codificado en Base64 almacenado en la tabla Invoice_PDF_Cache
  • Hash SHA256 del contenido para verificación de integridad
  • Incluye nombre de archivo, marca de tiempo de creación, marca de tiempo de último acceso

Gestión Manual de Caché:

# En la API de OmniCRM o en el shell de Python
from services.invoice_service import cleanup_old_pdf_cache, invalidate_invoice_cache
from utils.db_helpers import get_db_session

session = get_db_session()

# Limpiar cachés más antiguas de 30 días
result = cleanup_old_pdf_cache(session, days_old=30)
print(result) # {'status': 'success', 'deleted_count': 15}

# Invalidar caché de factura específica
invalidate_invoice_cache(session, invoice_id='12345')

Puntos Finales de la API:

Generar/descargar PDF de factura:

GET /invoice/pdf/{invoice_id}

Respuesta: Descarga del archivo PDF con nombre de archivo del descriptor de estado de Stripe

Encabezados de Caché:

  • Primera solicitud: Respuesta más lenta (tiempo de generación)
  • Solicitudes en caché: Respuesta instantánea
  • El acierto/fallo de caché es transparente para el usuario

Solución de Problemas

La Generación de PDF Falla:

  • Verifique que WeasyPrint esté instalado: pip install weasyprint
  • Verifique que el nombre del archivo de plantilla coincida con crm_config.yaml
  • Verifique invoice_templates/rendered/ en busca de errores de renderizado HTML
  • Revise los registros de la API en busca de errores de plantilla Jinja2

Las Imágenes No Aparecen en el PDF:

  • Use rutas de archivo absolutas: file:///full/path/to/image.png
  • Asegúrese de que los archivos de imagen existan y sean legibles
  • Verifique el formato de imagen (PNG y JPEG funcionan mejor)
  • Verifique que las rutas de imagen no contengan caracteres especiales

Problemas de Estilo:

  • Inline todo el CSS (no se admiten hojas de estilo externas)
  • Evite características CSS complejas (flexbox, grid pueden no renderizarse correctamente)
  • Pruebe primero con diseños simples, agregue complejidad gradualmente
  • Use tablas para el diseño en lugar de divs cuando sea posible

La Caché No se Invalida:

  • Verifique que invalidate_invoice_cache() se llame cuando se modifique la factura
  • Verifique que las actualizaciones de transacciones desencadenen la invalidación de caché
  • Elimine manualmente de la tabla Invoice_PDF_Cache si es necesario

Lista de Verificación de Configuración

Use esta lista de verificación al implementar OmniCRM:

Configuración del Backend

  • [ ] Copie .env.example a .env
  • [ ] Establezca contraseñas de base de datos fuertes
  • [ ] Configure las credenciales de CGRates
  • [ ] Actualice crm_config.yaml con su configuración:
    • [ ] Conexión a la base de datos
    • [ ] Tipos de servicio
    • [ ] Claves API de Mailjet e IDs de plantilla
    • [ ] Correos electrónicos de notificación de fallos de aprovisionamiento
    • [ ] Nombre de archivo de plantilla de factura
    • [ ] URL base del CRM (accesible públicamente)
    • [ ] Puntos finales de OCS/CGRates
    • [ ] Configuración de SMSC
    • [ ] Genere una nueva clave secreta JWT
    • [ ] Claves de Stripe (en vivo, no de prueba)
    • [ ] Claves API y listado blanco de IP

Configuración del Frontend

  • [ ] Copie OmniCRM-UI/.env.example a OmniCRM-UI/.env
  • [ ] Establezca la clave de API de Google Maps
  • [ ] Establezca la clave publicable de Stripe
  • [ ] Actualice la marca de la empresa:
    • [ ] Nombre de la empresa
    • [ ] Nombre del portal
    • [ ] Nombre de autoservicio
    • [ ] Lema de la empresa
  • [ ] Configure la localización:
    • [ ] Idioma predeterminado
    • [ ] Localidad
    • [ ] Ubicación y país predeterminados
    • [ ] Código y símbolo de moneda
  • [ ] Establezca el color primario de la marca
  • [ ] Configure integraciones de aplicaciones web (opcional)
  • [ ] Agregue URLs de soporte y FAQ (opcional)

Activos de Marca

  • [ ] Cree archivos de logo (logoSm.png, logoDark.png, logoLight.png)
  • [ ] Cargue los logos en OmniCRM-UI/src/assets/images/omnitouch/
  • [ ] Cree HTML de plantilla de factura personalizada
  • [ ] Cargue la plantilla de factura en OmniCRM-API/invoice_templates/
  • [ ] Actualice crm_config.yaml con el nombre de archivo de la plantilla de factura
  • [ ] Pruebe la generación de PDF de factura
  • [ ] Reconstruya la interfaz de usuario: npm run build

Seguridad

  • [ ] Cambie todas las contraseñas predeterminadas
  • [ ] Genere un secreto JWT único
  • [ ] Use claves de Stripe en producción (no claves de prueba)
  • [ ] Gire las claves API de Mailjet
  • [ ] Habilite reglas de firewall
  • [ ] Configure el listado blanco de IP para el acceso a la API
  • [ ] Configure certificados SSL/TLS
  • [ ] Habilite HTTPS para todos los puntos finales
  • [ ] Revise la configuración de CORS
  • [ ] Implemente limitación de tasa
  • [ ] Configure procedimientos de respaldo y recuperación

Pruebas

  • [ ] Pruebe el flujo de registro de clientes
  • [ ] Pruebe el aprovisionamiento de servicios de extremo a extremo
  • [ ] Verifique que las notificaciones por correo electrónico se envíen correctamente
  • [ ] Pruebe la generación de facturas y la descarga de PDF
  • [ ] Verifique el procesamiento de pagos (Stripe)
  • [ ] Verifique la autenticación de usuarios y 2FA
  • [ ] Pruebe la suplantación y el registro de auditoría
  • [ ] Verifique que los datos de uso se sincronicen desde OCS
  • [ ] Pruebe la creación y renovación de ActionPlan
  • [ ] Confirme que la asignación de inventario funcione correctamente

Implementación

  • [ ] Construya imágenes de Docker o implemente en servidores
  • [ ] Inicie contenedores de base de datos (MySQL, PostgreSQL)
  • [ ] Inicie CGRates
  • [ ] Inicie la API de OmniCRM
  • [ ] Inicie la interfaz de usuario de OmniCRM
  • [ ] Configure el proxy inverso (nginx, traefik)
  • [ ] Configure monitoreo (Grafana, Prometheus)
  • [ ] Configure agregación de registros
  • [ ] Configure respaldos automáticos
  • [ ] Documente la arquitectura de implementación
  • [ ] Capacite al personal en el uso del sistema

Documentación Relacionada