¿Qué es Systema?
ERP de facturación y gestión comercial para freelancers y pequeñas empresas. Sin frameworks, sin dependencias complejas — PHP nativo que funciona en cualquier hosting compartido.
Systema es un ERP ligero de gestión comercial pensado para autónomos, freelancers y pequeñas empresas que necesitan una herramienta de facturación potente sin la complejidad de ERPs empresariales.
Funciona con PHP nativo y MySQL — sin Composer en producción, sin frameworks, sin dependencias externas que gestionar. Se instala subiendo los archivos por FTP y configurando la base de datos desde el propio panel.
🧾 Facturación completa
Crea, envía y cobra facturas con tracking de apertura, generación de PDF y acceso público para el cliente via token seguro.
📋 Presupuestos
Genera presupuestos y conviértelos a factura en un click cuando el cliente los acepta.
🏛️ Presentador AEAT
Calcula y genera automáticamente los modelos M303, M130 y M390 desde los datos de facturación.
⚡ Status & Mantenimiento
Panel de diagnóstico completo del sistema — BD, índices, SMTP, PDF, PHP y disco en tiempo real.
📁 Resultados Anuales
Genera cierres fiscales anuales o trimestrales. Portal seguro para el contable con ZIPs de facturas, Excel y PDFs de modelos AEAT incluidos.
🖥️ Interfaz adaptable
Zoom configurable (70%-125%) guardado en servidor. Sin flash visual. Ideal para distintos tamaños de pantalla.
📦 Catálogo de productos
Módulo de productos a medida con categorías, márgenes por categoría y cálculo automático de PVP. BD lista, UI en v1.3.
🧩 Apps dinámicas
Crea /apps/{slug}/index.php y aparece automáticamente en el sidebar como módulo extra. Sin tocar el core. Módulos específicos por instalación.
🔐 VeriFactu Fase A
QR en cada factura vinculado a un token único por documento. Visor público sin login con token validado en servidor — imposible acceder a facturas ajenas. Fase B (envío AEAT) en agosto 2026.
| Capa | Tecnología | Versión | Notas |
|---|---|---|---|
| Backend | PHP nativo | 7.4+ / 8.x | Sin frameworks. PDO + prepared statements. |
| Base de datos | MySQL InnoDB | 5.7+ / 8.x | utf8mb4_unicode_ci. FKs con ON DELETE CASCADE/RESTRICT. |
| Frontend | HTML + CSS + JS Vanilla | — | Sin React ni Vue. Chart.js 4.4 para gráficas (CDN). |
| PDF (visor) | HTML → print() | — | Plantilla HTML personalizable con marcadores. |
| PDF (export) | dompdf v2.0.4 | 2.0.4 | Requiere instalación aparte. Con Masterminds/html5-php 2.7.6. |
| PDF (AEAT) | FPDF 1.86 + FPDI | 1.86 / master | Rellena plantillas PDF oficiales de la AEAT. |
| PHPMailer | 6.x | SMTP con TLS/SSL. Incluido en /vendor/phpmailer/. | |
| Excel export | xlsx-js-style | 1.2.0 | Generación de Excel con estilos desde el navegador. CDN jsdelivr. |
| Auth | Sesiones PHP nativas | — | Password único en config/settings.php. |
| Config | File-based PHP | — | config/settings.php generado automáticamente. Nunca en git. |
Arquitectura de módulos
Cada acción del sistema es un endpoint PHP independiente en /modules/. El frontend llama a estos endpoints con fetch() via JSON. No hay estado compartido entre peticiones — cada endpoint valida sesión, conecta a BD y responde.
POST /modules/facturacion/create.php → { success, id, numero }
POST /modules/facturacion/send_email.php → { success, email }
GET /modules/facturacion/pdf_export.php?id=5 → factura.pdf
GET /modules/facturacion/pdf_render.php?token=XYZ → HTML público
systema/ al directorio deseado de tu servidor.tudominio.com/systema/ — redirige automáticamente a configuracion.php si no hay BD configurada.systema_5.0.5.sql automáticamente (incluye tabla resultados_anuales y vistas de dashboard).install_dompdf.php y install_mm.php, ejecútalos y bórralos. Alternativa: sube manualmente vendor/dompdf/ y vendor/masterminds/.systema_5.0.5.sql — incluye tablas, índices, vistas y la nueva tabla resultados_anuales. Para instalaciones existentes en v0.4, ejecutar solo el ALTER de añadir la nueva tabla.Configuración en el panel, rellena datos fiscales del emisor y credenciales SMTP para envío de facturas.index.php como constante SYSTEMA_PASSWORD. Cámbiala directamente en el archivo para mayor seguridad.Recuperación de contraseña
La pantalla de login incluye el modal "He olvidado mi contraseña". Al introducir el email, reset_password.php consulta la base de datos central de licencias, genera una contraseña temporal segura con random_int(), la hashea con password_hash(), la guarda en config/settings.php y la envía por email al cliente. La respuesta siempre es genérica — no revela si el email existe o no.
Pantalla principal del sistema. Ofrece una visión global del estado del negocio al momento de acceder.
KPIs en tiempo real
| Métrica | Cálculo |
|---|---|
| Ingresos cobrados | Suma de total de facturas con estado = 'cobrada' |
| Pendiente de cobro | Suma de total de facturas con estado = 'enviada' |
| Facturas vencidas | Count de facturas con estado = 'vencida' |
| Clientes activos | Count total de la tabla clientes |
Gráficos
- Flujo de ingresos — gráfico de área: cobrado vs pendiente por los últimos 6 meses. Usa Chart.js 4.4.
- Distribución por estado — donut chart con cobradas / enviadas / vencidas / borradores.
Últimas facturas
Tabla con las 6 facturas más recientes. Click en cualquier fila abre el PDF en nueva pestaña.
Notificaciones de vencidas v0.5.5
Badge rojo estilo iOS en la campana del topbar con el número de facturas vencidas. Se actualiza automáticamente al cargar los KPIs. Click abre el modal de vencidas.
Modal de facturas vencidas v0.5.5
Lista todas las facturas con estado vencida del período seleccionado. Incluye dos acciones por fila:
- Fecha hoy — actualiza
fecha_vencimientoa la fecha actual y cambia estado aenviadavíamodules/facturacion/update_vencimiento.php. - Enviar — se activa solo después de actualizar la fecha. Manda el email al cliente con la factura actualizada.
Filtros del Dashboard v0.5.3
Selector global que controla todos los KPIs y gráficas: Histórico total, año concreto (2019–2026) o trimestre del año actual. Los subfiltros de cada gráfica se adaptan dinámicamente según el global seleccionado.
| Filtro global | Subfiltros disponibles | Default |
|---|---|---|
| Histórico total | Solo "Histórico" | Histórico |
| Año pasado | Año, Histórico | Año |
| Año actual | Semana, Mes, Año, Histórico | Mes |
| Trimestre | Semana, Mes | Mes |
Acceso rápido v0.6.0
Botones de acción rápida en el Dashboard: Nueva Factura y Nuevo Presupuesto. Navegan directamente al módulo correspondiente y abren el modal de creación automáticamente via parámetro ?nuevo=1 en la URL.
Pipeline comercial para gestionar contactos antes de que se conviertan en clientes. Permite seguir el estado de cada oportunidad y convertirla a cliente cuando está lista.
Estados del pipeline
| Estado | Significado |
|---|---|
| nuevo | Lead recién creado, sin contacto todavía |
| contactado | Se ha establecido contacto inicial |
| cualificado | Hay oportunidad real de negocio |
| perdido | El lead no va a convertirse |
| convertido | Se creó un cliente a partir de este lead |
Convertir lead a cliente
La acción Convertir crea automáticamente un cliente con los datos del lead (nombre, email, teléfono) y marca el lead como convertido. Verifica que no exista ya un cliente con el mismo email antes de crear.
Rediseño completo v0.6.0
El módulo recibió un rediseño completo con multiselect, bulk actions y exportación:
- Multiselect — selección múltiple con checkbox por fila y selector global.
- Bulk eliminar — elimina múltiples leads seleccionados en una sola acción.
- Bulk convertir — convierte varios leads a clientes en lote.
- Exportar Excel — descarga todos los leads filtrados como
.xlsxcon SheetJS. - KPIs actualizados — Total leads · Valor activo · Cualificados · Convertidos este mes.
Base de datos de clientes y empresas. Cada cliente tiene ficha completa con datos fiscales, datos de contacto, forma de pago e IBAN para transferencias.
Campos disponibles
| Campo | Descripción |
|---|---|
tipo | empresa / particular |
nombre | Nombre comercial — aparece en listados |
nombre_fiscal | Razón social completa para facturas |
nif_cif | NIF/CIF para datos fiscales en factura |
email | Email de contacto general |
email_facturacion | Email específico para envío de facturas. Tiene prioridad sobre email. |
forma_pago | Texto libre: "Transferencia 30 días", etc. |
iban | IBAN para datos de pago en facturas |
activo | v0.6.0 TINYINT(1). Toggle en fila — activo (verde) / inactivo (gris). Filtra visibilidad en listados. |
notas | Notas internas — no aparecen en facturas |
Sistema Activo / Inactivo v0.6.0
Toggle por fila para marcar clientes como activos o inactivos. Disponible también en bulk actions (activar/desactivar seleccionados) y en la toolbar de filtrado. Los clientes inactivos no aparecen en los selectores de nueva factura/presupuesto.
Importación masiva desde Excel
Arrastra o selecciona un archivo .xlsx — el sistema lo parsea en el navegador con SheetJS y muestra una preview de 5 filas antes de importar. La plantilla Excel descargable está en /modules/clientes/clientes.xlsx.
Exportación XLSX v0.6.0
Exporta todos los clientes a .xlsx con cabecera profesional y estilos via SheetJS (antes exportaba a CSV). Compatible con Excel español sin problemas de codificación.
Crea presupuestos detallados con líneas de concepto y envíalos al cliente. Cuando el cliente acepta, conviértelo a factura en un click.
Flujo completo
aceptado. Solo los presupuestos en este estado pueden convertirse.convertido con referencia a la factura creada.Estados
| Estado | Descripción | Puede convertir |
|---|---|---|
| borrador | En preparación | No |
| enviado | Enviado al cliente | No |
| aceptado | Cliente confirma | ✅ Sí |
| rechazado | Cliente no acepta | No |
| caducado | Pasó la fecha de validez | No |
| convertido | Ya se generó factura | No |
Paridad con facturación v0.6.0
El módulo de presupuestos alcanzó paridad completa con facturación. Endpoints disponibles:
| Endpoint | Función |
|---|---|
modules/presupuestos/create.php | POST — crea presupuesto + snapshot emisor |
modules/presupuestos/update.php | POST — edita estado, cliente, líneas |
modules/presupuestos/delete.php | POST — elimina individual o bulk |
modules/presupuestos/convert.php | POST — convierte a factura |
modules/presupuestos/send_email.php | POST — envía por email con PHPMailer + tracking |
modules/presupuestos/pdf_export.php | GET — genera PDF con dompdf |
modules/presupuestos/pdf_render.php | GET — visor HTML público por token |
modules/presupuestos/duplicate.php | POST — duplica presupuesto |
modules/presupuestos/get_list.php | POST — lista con filtros, paginación y stats |
modules/presupuestos/bulk_estado.php | POST — bulk: marcar aceptado, rechazado |
modules/presupuestos/bulk_delete.php | POST — bulk: eliminar seleccionados |
create.php, convert.php y delete.php tenían referencias a tablas y columnas incorrectas del schema antiguo que causaban error SQL. Corregido completamente.Módulo principal de Systema. Gestiona el ciclo de vida completo de cada factura desde su creación hasta el cobro, incluyendo envío por email con tracking de apertura.
Estados de factura
| Estado | Descripción |
|---|---|
| borrador | Creada pero no enviada al cliente |
| enviada | Email enviado al cliente. Entra en "pendiente de cobro". |
| leída | v0.6.0 El cliente abrió el email. Chip visible en la tabla con timestamp. |
| cobrada | Pago recibido. Entra en "ingresos cobrados". |
| vencida | Pasó la fecha de vencimiento sin cobrar. |
Numeración automática
Cada factura recibe un número correlativo único por marca. El formato es configurable en marcas.prefijo_factura con soporte para el token {YEAR}. Ejemplo: RG{YEAR}- genera RG2026-0001.
El contador se actualiza con FOR UPDATE en una transacción MySQL para evitar números duplicados en caso de peticiones concurrentes.
Pipeline de envío por email
public_token de 48 caracteres hex único por factura. Este token permite al cliente ver la factura desde el email sin necesidad de login.tracking_id de 32 hex chars y se inyecta como imagen 1×1 px en el email. Cuando el cliente abre el email, el servidor registra IP, user agent y timestamp.enviada.facturas.email_enviado, email_enviado_at y email_tracking_id. Se crea entrada en la tabla email_tracking.Visor de factura (pdf_render.php)
Renderiza la factura como HTML en el navegador usando la plantilla personalizable. Admite dos modos de acceso:
?id=X— acceso interno con sesión activa. Abre el visor y lanzawindow.print()automáticamente.?token=XYZ— acceso público sin sesión. Es la URL que recibe el cliente en el email. Valida el token contra la BD antes de mostrar nada.?preview=1— preview desde configuración con datos de ejemplo, sin factura real.
Exportación PDF (pdf_export.php)
Genera PDFs con dompdf v2 usando HTML interno optimizado para el renderizador.
?id=5— descarga individual comofactura_RG2026-0001.pdf?ids=1,2,3— bulk hasta 100 facturas, descarga comofacturas_2026-03-14.zip
pdf_render.php usa la plantilla HTML personalizable del usuario. pdf_export.php usa un HTML interno simplificado para garantizar compatibilidad con dompdf — el resultado es funcional pero más austero visualmente.Tracking de apertura
Cuando el cliente abre el email y carga la imagen 1×1, track_open.php registra la apertura. Usa COALESCE(abierto_at, NOW()) para guardar solo la primera apertura, ignorando las siguientes. El estado visual de la factura cambia a "leída" en el listado.
Filtros y buscador v0.5.4
La carga inicial filtra solo el año actual via BETWEEN en lugar de YEAR() para aprovechar los índices. El año se persiste en localStorage con validación contra los años reales de la BD para evitar bucles infinitos de redirección.
- Búsqueda — por número de factura, cliente y concepto con debounce de 300ms.
- Filtro de estado — todas, borrador, enviada, leída, cobrada, vencida.
- Filtro de marca — multiempresa.
- Filtro de año — carga solo las facturas del año seleccionado.
- Filtro de trimestre — T1-T4 del año seleccionado.
URL ?buscar=FAC-00123 — navegar con este parámetro desde el dashboard carga todas las facturas, inyecta el número en el buscador y filtra automáticamente.
Buscador de cliente v0.5.4
El modal de nueva/editar factura usa un campo de búsqueda con dropdown en lugar del <select> nativo. Filtra por nombre y NIF simultáneamente, resalta coincidencias. El dropdown se renderiza en el body con position:fixed para evitar el overflow del modal.
Stats bar v0.5.4
Barra de resumen que aparece cuando hay cualquier filtro activo. Muestra: N resultados (tungsteno), facturado, desglose por estado y última factura (todo en gris). Los KPIs superiores se recalculan en tiempo real al filtrar.
Exportación Excel v0.5.4
Botón "Exportar" en el topbar genera un Excel con xlsx-js-style con cabecera profesional: título, fecha de exportación, período calculado automáticamente, datos fiscales del emisor y dos filas de totales (cobrado en verde + total general en azul). Siempre ordenado cronológicamente ascendente.
Snapshot del emisor v0.6.0
Al crear una factura, modules/facturacion/create.php lee los datos fiscales actuales de configuracion (grupo fiscal) y los guarda como snapshot en los campos emisor_nombre, emisor_nif y emisor_direccion de la tabla facturas. Aplica igualmente a presupuestos.
Módulo para generar, gestionar y enviar los cierres fiscales — anuales o trimestrales — al gestor o contable. Automatiza la generación de ZIPs con todas las facturas del período organizadas por trimestre, y proporciona un portal seguro de descarga sin necesidad de login.
Flujo completo
modules/resultados/generate.php genera los PDFs de las facturas del período con dompdf, los agrupa en ZIPs por trimestre y los guarda en assets/resultados/{año}/. Estado en tiempo real: Procesando → Preparado.resultado_publico.php?token=XYZ — sin login. Ve el desglose de facturas del período, importes y botones de descarga ZIP. Si se incluyeron modelos AEAT, aparecen botones morados para descargar cada PDF directamente. Los ZIPs caducan a los 14 días.Modo trimestral v0.6.0
Al crear un resultado, el selector de período permite elegir entre Anual (ejercicio completo, 4 ZIPs) o un trimestre específico (T1/T2/T3/T4, 1 ZIP). La BD filtra automáticamente las facturas del rango de fechas correcto. El portal público se adapta mostrando solo el trimestre relevante.
Modelos AEAT en el ZIP v0.6.0
Al crear un resultado se pueden marcar los modelos AEAT a incluir. M303 y M130 están marcados por defecto; M390 solo se activa para Anual o T4. Los PDFs de los modelos se sirven desde modules/presentador/pdf_publico.php — endpoint sin sesión que valida el token del resultado antes de servir el PDF.
| Modelo | Disponible en | Default |
|---|---|---|
| M303 — IVA trimestral | Todos los períodos | ✅ Marcado |
| M130 — IRPF fraccionado | Todos los períodos | ✅ Marcado |
| M390 — Resumen anual IVA | Solo Anual y T4 | — Desmarcado |
Tabla de resultados
Muestra una tabla comparativa con el desglose por ejercicio: facturas totales, cobrado, pendiente, vencidas, borradores, total emitido y barra de progreso de % cobrado. La columna Ejercicio muestra el trimestre bajo el año cuando el resultado no es anual.
Estados del ZIP
| Estado | Descripción |
|---|---|
| Procesando | generate.php está generando PDFs y ZIPs en background |
| Preparado | ZIPs generados en disco. Botón Enviar activo. |
| Error | Fallo durante la generación. Revisar plantilla PDF y logs. |
| Caducado | Han pasado 14 días. Los archivos fueron eliminados por el cron. |
Archivos del módulo
| Archivo | Función |
|---|---|
resultados.php | Página principal. Lista, stats, modal de creación con selector período y checkboxes AEAT. |
resultado_publico.php | Portal público del contable. Acceso por token, sin sesión. Soporte trimestral + botones PDF AEAT. |
modules/resultados/create.php | POST: Crea registro en BD con periodo y modelos_aeat. Lanza generate.php en background. |
modules/resultados/generate.php | GET interno: Genera PDFs con dompdf y ZIPs por trimestre. Actualiza zip_status en BD. |
modules/resultados/update.php | POST: Edita email_contable, nombre_contable, observaciones y estado. |
modules/resultados/send.php | POST: Envía email profesional al contable con enlace al portal. Actualiza estado a 'enviado'. |
modules/resultados/status.php | POST: Polling del estado zip_status para actualización en tiempo real (polling cada 5s). |
modules/resultados/cleanup.php | CLI/Cron: Elimina ZIPs caducados (+14 días) y resetea zip_status para permitir regeneración. |
modules/resultados/get_facturas.php | POST: Devuelve facturas del ejercicio para export Excel desde el módulo. |
modules/presentador/pdf_publico.php | Nuevo v0.6.0 Sirve PDFs de modelos AEAT sin sesión, autenticado por token del resultado. |
Schema BD: resultados_anuales
| Campo | Tipo | Descripción |
|---|---|---|
id | INT AUTO_INCREMENT | PK |
ejercicio | YEAR NOT NULL | Año fiscal del cierre |
periodo | ENUM(anual,T1,T2,T3,T4) DEFAULT anual | v0.6.0 Anual o trimestre específico |
modelos_aeat | VARCHAR(30) NULL | v0.6.0 Modelos incluidos. Ej: M303,M130 |
email_contable | VARCHAR(255) | Email del gestor |
nombre_contable | VARCHAR(150) | Nombre del gestor para personalizar el email |
observaciones | TEXT | Notas internas del usuario |
estado | ENUM(pendiente,enviado) | Estado de envío al contable |
zip_status | ENUM(procesando,preparado,error) | Estado de generación del ZIP |
zip_generado_at | DATETIME | Timestamp de generación |
zip_expires_at | DATETIME | Caducidad del ZIP (generado_at + 14 días) |
enviado_at | DATETIME | Timestamp de envío del email |
email_tracking_id | VARCHAR(64) NULL | v0.6.0 UUID pixel tracking apertura email |
email_abierto | TINYINT(1) DEFAULT 0 | v0.6.0 Flag apertura email por el contable |
email_abierto_at | DATETIME NULL | v0.6.0 Timestamp de apertura |
token | VARCHAR(64) UNIQUE | Token hex de 64 chars para URL pública |
created_at | DATETIME DEFAULT NOW() | Creación del registro |
ALTER TABLE resultados_anuales ADD COLUMN periodo y ADD COLUMN modelos_aeat (v0.6.0). Columnas de tracking email añadidas en v0.6.0. Charset homogeneizado a utf8mb4 y 3 índices restaurados en v0.6.0.Sistema de zoom configurable para adaptar la interfaz al tamaño de pantalla del usuario. El zoom se guarda de forma persistente en el servidor (config/settings.php) y en el navegador (localStorage), de modo que sobrevive a limpiezas de caché.
Configuración
Disponible en Configuración → Interfaz UI. Valores disponibles: 70%, 75%, 80%, 85%, 90%, 95%, 100%, 110%, 115%, 120%, 125%.
| Pantalla | Zoom recomendado |
|---|---|
| Portátil 13" / 14" | 80% |
| Portátil 15" / 16" | 85% – 90% |
| Portátil 17" | 90% – 100% |
| Monitor 24" | 100% – 110% |
| Monitor 27" / 32" | 110% – 120% |
| Pantalla 4K grande | 120% – 125% |
Implementación técnica
config/settings.php— claveui_zoomcon el valor numérico como string (ej:'85').layout.php— inyectadocument.documentElement.style.zoomen el<head>antes de renderizar para evitar flash visual.assets/core.js— funciónapplyZoom(z)para cambios en tiempo real desde el selector.modules/configuracion/save_ui.php— endpoint POST que valida y persiste el zoom ensettings.php.
Módulo que calcula automáticamente los valores de los modelos tributarios de la AEAT a partir de los datos de facturación almacenados en la BD. No necesitas introducir nada manualmente — Systema lee tus facturas y calcula las casillas.
Modelos soportados
M303 — IVA Trimestral
Declaración trimestral de IVA. Casillas 01-09 (bases y cuotas al 21%, 10% y 4%), C27 (total devengado), C46 (resultado a ingresar/devolver).
M130 — IRPF Fraccionado
Pagos fraccionados del IRPF. C01 ingresos, C03 rendimiento neto, C04 (20% de C03), C05 retenciones soportadas, C06 resultado.
M390 — Resumen Anual IVA
Resumen anual de IVA. Casillas anuales C01-C09 por tipo de gravamen, C95 volumen total de operaciones.
Filtros disponibles
- Marca — filtra solo las facturas de una marca específica o todas.
- Ejercicio — año fiscal (por defecto el año en curso).
- Período — 1T (ene-mar), 2T (abr-jun), 3T (jul-sep), 4T (oct-dic), ANUAL.
Generación de PDF oficial
Usa FPDI para importar las plantillas PDF oficiales de la AEAT (m303.pdf, m130.pdf, m390.pdf) y FPDF para escribir los valores calculados en las coordenadas exactas de cada casilla. El resultado es un PDF rellenado listo para presentar.
Historial de declaraciones
Cada presentación queda guardada en la tabla presentaciones_historial con el snapshot JSON completo de los datos calculados, permitiendo re-descargar cualquier declaración anterior sin recalcular.
| Sección | Qué configura | Guardado en |
|---|---|---|
| Base de datos | Host, puerto, usuario, contraseña, nombre de BD. Test de conexión incluido. | config/settings.php |
| Datos fiscales | Razón social, NIF, dirección, CP, ciudad, provincia, teléfono, email, IBAN del emisor. | configuracion (grupo: fiscal) |
| Marcas | Múltiples marcas/empresas bajo un mismo NIF. Cada marca tiene prefijo de facturación y color. | Tabla marcas |
| Email SMTP | Host, puerto, usuario, contraseña, cifrado (TLS/SSL/none), nombre, email del remitente y Reply-To global. | configuracion (grupo: smtp) |
| Plantilla PDF | HTML completo de la factura con marcadores {{variable}}. Preview en tiempo real. | configuracion (grupo: plantilla) |
| Numeración | Prefijos y padding de correlativo para facturas y presupuestos. Soporte para {YEAR}. | configuracion (grupo: numeracion) |
| Seguridad | v0.6.0 Contraseña del portal contable (portal_password). Protege resultado_publico.php. | configuracion (grupo: seguridad) |
| IA / Groq | API key de Groq, modelo LLM y activación. Fase 2 | configuracion (grupo: ia) |
| VeriFactu | Endpoint y API key. Próximamente | configuracion (grupo: verifactu) |
Reply-To SMTP v0.6.0
Campo reply_to opcional en la configuración SMTP. Cuando está definido, todos los emails enviados desde Systema (facturas, presupuestos, resultados) incluyen la cabecera Reply-To apuntando a esa dirección. Útil para redirigir respuestas de clientes a una bandeja específica.
Seguridad del portal contable v0.6.0
El campo portal_password (grupo seguridad) protege el acceso al portal público del contable con una pantalla de login. Si está vacío, el portal es de acceso libre por token.
Nuevos endpoints v0.6.0
| Endpoint | Función |
|---|---|
modules/configuracion/save_seguridad.php | POST — guarda portal_password en grupo seguridad |
modules/configuracion/save_acceso.php | POST — guarda configuración de acceso y sesión |
modules/configuracion/save_php.php | POST — diagnóstico y ajustes de entorno PHP |
Marcadores de plantilla PDF
La plantilla HTML acepta los siguientes marcadores que se sustituyen con los datos reales de cada factura:
{{numero}} {{fecha_emision}} {{fecha_vencimiento}}
{{cliente_nombre}} {{cliente_nif}} {{cliente_email}}
{{cliente_direccion}}{{cliente_cp}} {{cliente_ciudad}}
{{emisor_nombre}} {{emisor_nif}} {{emisor_direccion}}
{{emisor_email}} {{emisor_telefono}} {{emisor_iban}}
{{emisor_forma_pago}}{{base_imponible}} {{iva_porcentaje}}
{{iva_importe}} {{irpf_porcentaje}} {{irpf_importe}}
{{total}} {{notas_cliente}} {{lineas}}
Eliminar marcas
Desde Configuración → Marcas, cada marca dispone de un botón de eliminar (icono papelera). El endpoint modules/configuracion/delete_marca.php verifica antes de borrar que la marca no tenga facturas ni presupuestos vinculados. Si los tiene, devuelve un error descriptivo y la operación se cancela. Si no tiene documentos, la elimina de la tabla marcas.
Panel de control técnico del sistema. Accesible desde el sidebar en status.php. Monitoriza en tiempo real el estado de todos los componentes críticos de Systema.
Chip de estado global
Lo primero que ves al entrar. Barra a todo el ancho que resume el estado de todo el sistema en un único indicador:
| Color | Estado | Qué significa |
|---|---|---|
| ● VERDE | TODO NOMINAL | Todos los sistemas operativos. No hay nada que hacer. |
| ● NARANJA | ATENCIÓN REQUERIDA | Algo a vigilar pero el sistema funciona. El detalle indica qué. |
| ● ROJO | SISTEMA CON ERRORES | Hay un problema real que impide el funcionamiento correcto. |
Sectores A–J explicados
Muestra el estado de la conexión MySQL: versión del servidor, tiempo en marcha (uptime), conexiones activas, queries lentas y total de queries ejecutadas desde que arrancó el servidor.
Queries lentas > 5: el chip pasa a naranja. Indica que algunas queries tardan más de lo esperado — puede ser señal de que los índices necesitan revisión.
Verifica uno a uno los 20+ índices del sistema con SHOW INDEX FROM tabla. LED verde = índice presente y activo. LED rojo = índice faltante — el sistema funciona pero más lento.
¿Cuándo puede ponerse rojo? Si se restauró la BD desde un backup anterior a v0.4, o si hubo un fallo durante la migración de índices.
Consulta information_schema.TABLES para mostrar el número de filas y el tamaño en KB (datos + índices) de cada tabla. Útil para entender cómo crece la BD con el tiempo.
Muestra la configuración SMTP activa y el estado del tracking de emails. Si el campo Config Status dice NOT CONFIGURED, los envíos de facturas fallarán.
Tracking pendiente: número de emails enviados cuyo pixel no ha sido cargado todavía por el cliente (el cliente no ha abierto el email).
Verifica que todas las librerías de PDF estén instaladas. FPDF es obligatoria (AEAT). dompdf + Masterminds son necesarias para exportación PDF de facturas — si no están, solo funciona el visor HTML.
También verifica que /tmp sea escribible — necesario para generar ZIPs de PDFs en bulk.
Verifica que las 3 plantillas PDF oficiales de la AEAT estén en /presentador/templates/. Si alguna falta, el modelo correspondiente no podrá generar el PDF oficial rellenado.
Versión PHP, compatibilidad con 7.4+, límites de memoria y tiempos de ejecución. Si el chip está rojo, PHP es incompatible o hay un problema de configuración del servidor.
Extensiones PHP críticas: pdo_mysql (BD), openssl (SMTP TLS), mbstring (textos), json (API interna), zip (bulk PDF). Si alguna falta en rojo, esa funcionalidad no operará.
En hosting compartido, disk_free_space() devuelve 0 porque el servidor no expone esta información a PHP. Esto es completamente normal — el sector muestra "N/D (hosting compartido)" y permanece en verde si /tmp es escribible y config/settings.php existe.
Los datos de Systema van a MySQL, no al disco — el espacio de hosting no es un factor crítico.
Verifica la presencia e integridad de los 94 archivos core de Systema. Cada archivo se compara contra el manifest SHA256 incluido en el ZIP de distribución. Un chip verde confirma que ningún archivo core ha sido modificado o eliminado accidentalmente. Chip rojo indica archivos faltantes o alterados — útil tras actualizaciones manuales por FTP.
Acciones y niveles de riesgo
| Acción | Riesgo | Qué hace | Cuándo usarla |
|---|---|---|---|
| ANALYZE TABLES | Seguro | Actualiza estadísticas internas de MySQL para que use los índices de forma más eficiente. | Tras importaciones masivas de datos. |
| SMTP HANDSHAKE | Seguro | Abre conexión TCP al servidor SMTP y lee el banner. Solo comprueba conectividad, no autentica. | Para verificar que el host SMTP es alcanzable. |
| PURGE TEMP FILES | Seguro | Borra archivos /tmp/sys_fac_* y /tmp/dompdf_* — residuos de PDFs generados. |
Si Temp files muestra un número alto. |
| OPTIMIZE TABLES | Bloquea | Compacta y reorganiza el almacenamiento interno de InnoDB. Bloquea las tablas unos segundos. | Con el sistema sin usuarios activos, una vez al mes. |
| TEST SEND EMAIL | Envía | Manda un email de prueba real a la dirección email_from configurada en SMTP. |
Para verificar que el envío de facturas funcionará correctamente. |
| FLUSH QUEUE | Borra | Elimina logs de email_tracking de emails enviados hace más de 30 días que nunca fueron abiertos. |
Limpieza periódica del historial de tracking. |
| REINDEX ALL v0.4 | Peligroso | Borra y recrea todos los índices de rendimiento v0.4. Las tablas quedan temporalmente sin índices. | Solo si Sector B muestra índices en rojo. Siempre con el sistema sin usuarios activos. |
Índices de rendimiento v0.4
Migración aplicada en v0.4 para soportar volúmenes de 10.000+ facturas sin degradación. Se aplica ejecutando systema_v04_indexes.sql en phpMyAdmin.
| Índice | Tabla | Propósito |
|---|---|---|
idx_facturas_created_at | facturas | ORDER BY en el listado principal — sin él MySQL ordena 10k filas en memoria |
idx_facturas_public_token | facturas | WHERE public_token en pdf_render.php — lookup del cliente desde email |
idx_facturas_estado_fecha | facturas | Compuesto (estado, fecha) — Presentador AEAT y KPIs del dashboard |
idx_facturas_marca_fecha | facturas | Compuesto (marca_id, fecha) — Presentador AEAT filtrado por marca |
idx_presupuestos_fecha | presupuestos | COMPLETAMENTE AUSENTE antes de v0.4 — M390 anual hace WHERE BETWEEN fecha |
idx_tracking_doc_open | email_tracking | Compuesto 3 columnas — reemplaza idx_tracking_doc añadiendo abierto_at para index-only scan en la subquery correlated del listado (1 subquery por fila) |
| Tabla | Registros actuales | Descripción |
|---|---|---|
marcas | ~pocas | Marcas o empresas del emisor. Cada una tiene prefijo de numeración, color y contador de siguiente número. |
clientes | creciente | Ficha completa de clientes. Campo activo añadido en v0.6.0. Índices en nombre, NIF y email. |
facturas | creciente | Cabecera de cada factura. Incluye snapshot del emisor (v0.6.0), tracking de email y token público. |
factura_items | ~4x facturas | Líneas de detalle. ON DELETE CASCADE al borrar factura. |
presupuestos | creciente | Idéntica a facturas con estados adicionales y referencia a factura generada. Snapshot emisor desde v0.6.0. |
presupuesto_items | ~4x presupuestos | Líneas de presupuesto. ON DELETE CASCADE. |
leads | creciente | Pipeline comercial. FK opcional a clientes al convertir. |
configuracion | ~50 fijas | Key-value store de toda la configuración. Grupos: general, fiscal, smtp, numeracion, plantilla, seguridad, ia, verifactu. |
email_tracking | ~1 por email | Log de aperturas de email. abierto_at = NULL hasta que el cliente abre el email. |
resultados_anuales | por cierre | Cierres fiscales. 16 campos incluyendo periodo, modelos_aeat y tracking email contable (v0.6.0). |
presentaciones_historial | por presentación | Historial de modelos AEAT generados con snapshot JSON completo. |
series_numeracion | vacía por ahora | Preparada para numeración avanzada por series. Actualmente los contadores están en marcas. |
producto_categorias | vacía | Nueva v1.0 Categorías del catálogo de productos. Cada categoría tiene nombre y margen porcentual. |
productos | vacía | Nueva v1.0 Catálogo maestro de productos. SKU único, coste neto, FK a categoría, proveedor y flag activo. |
Vistas SQL
v_dashboard_facturas— JOIN facturas + clientes + marcas con campos calculados año y trimestre.v_dashboard_presupuestos— Ídem para presupuestos.
Catálogo maestro de productos y servicios para agilizar la creación de facturas y presupuestos. La base de datos está creada y migrada en producción — la UI (autocomplete en modales de factura/presupuesto) está pendiente para v1.0.
systema_productos_plantilla.xlsx. Endpoint modules/productos/search.php y JS autocomplete pendientes de implementación en v1.0.Tablas de BD
| Tabla | Campos clave | Descripción |
|---|---|---|
producto_categorias | id, nombre, margen_pct DECIMAL(5,2), activa | Categorías del catálogo. El margen porcentual por categoría se usa para calcular el PVP automáticamente. |
productos | id, sku UNIQUE, descripcion VARCHAR(500), unidad DEFAULT 'ud', coste_neto DECIMAL(12,4), categoria_id FK, proveedor, activo | Catálogo maestro. El PVP se calcula en runtime: coste_neto × (1 + margen_pct/100). |
Lógica de PVP
El PVP no se almacena en BD — se calcula al vuelo: pvp = coste_neto × (1 + categoria.margen_pct / 100). Cambiar el margen de una categoría actualiza automáticamente el PVP de todos sus productos sin necesidad de UPDATE masivo.
Importación masiva
El archivo systema_productos_plantilla.xlsx incluye 4 pestañas: instrucciones, categorias, productos y SQL de referencia. Compatible con el formato de importación habitual de proveedores tipo Saltoki.
Sistema de licencias para distribuir Systema a múltiples clientes. Cada instalación valida su licencia contra el servidor de licencias del autor mediante HMAC-SHA256 — sin enviar datos sensibles.
Funcionamiento
config/. Las llamadas al servidor de licencias no ocurren en cada request — solo al expirar la caché o al forzar revalidación.Dominios exentos
Los dominios localhost, rafelgil.com y entornos de desarrollo están exentos de validación para facilitar el desarrollo local sin necesidad de licencia activa.
Login Landing — Acceso desde systemafacil.com
Los clientes cloud acceden desde systemafacil.com introduciendo su email. El sistema LOGIN LANDING/login.php consulta lookup.php, que busca la url_instalacion en la BD central de licencias y redirige automáticamente al cliente a su instalación. No requiere contraseña en este paso — solo hace routing. La autenticación ocurre en la instalación destino.
Motor de actualizaciones automático que permite distribuir nuevas versiones de Systema a instalaciones en producción sin intervención manual por FTP. El proceso completo dura menos de 30 segundos.
Flujo de actualización
backups/pre-update-{fecha}/.config/settings.php, assets/resultados/ ni los datos de BD.Generador Core ZIP
Herramienta de desarrollo (actualizaciones.php) que genera automáticamente el ZIP de distribución con los 94 archivos core, el manifest SHA256 y los metadatos de versión. Solo accesible con credenciales de autor.
origen en facturas y presupuestos ya admiten los valores ia_voz e ia_chat.¿Qué hará?
El asistente IA permitirá crear facturas y presupuestos mediante lenguaje natural, tanto por texto como por voz. Ejemplos de instrucciones:
"Crea una factura para Rafel Gil por diseño web, 1.500€, con 21% de IVA y 15% de IRPF"
"Duplica la última factura de este mes para el mismo cliente"
"¿Cuánto tengo pendiente de cobro este trimestre?"
Arquitectura técnica
- Modelo: Groq API con
llama3-70b-8192(configurable en panel) - Endpoint:
ai_webhook.php— ya creado, pendiente de implementación - Autenticación: header
X-Systema-Key - Respuesta: Groq parsea la instrucción y devuelve JSON estructurado que Systema convierte en factura/presupuesto
Configuración necesaria
En Configuración → IA / Groq: introduce tu API key de Groq y activa el módulo con el toggle ia_activa.
¿Qué es VeriFactu?
Sistema de verificación de facturas de la AEAT que exige que cada factura emitida sea registrada en tiempo real en los servidores de Hacienda con una firma digital. Garantiza la integridad e imposibilidad de modificación de facturas una vez emitidas.
Estado actual en Systema
- Campos
verifactu_enviadayverifactu_idya presentes en tablafacturas. - Configuración
verifactu_activo,verifactu_endpointyverifactu_api_keyen tablaconfiguracion. - Tab de configuración ya visible en el panel (marcado como "Pronto").
- La implementación del envío a la AEAT está pendiente de la publicación de las especificaciones técnicas definitivas.
Systema incluye un script de limpieza automática que se ejecuta vía cron job. Elimina los ZIPs de resultados generados que han superado los 14 días de validez y resetea su estado para permitir regeneración.
Configuración en Plesk / cPanel
# Ejecutar cada día a las 3:00 AM
0 3 * * * /usr/bin/php -f /var/www/vhosts/DOMINIO/PATH/systema/modules/resultados/cleanup.php
¿Qué hace el cron?
- Busca registros en
resultados_anualesconzip_status = 'preparado'yzip_expires_at < NOW(). - Elimina los archivos
T1.zip,T2.zip,T3.zip,T4.zipdeassets/resultados/{año}/. - Resetea
zip_status = NULL,zip_generado_at = NULL,zip_expires_at = NULLpara permitir regenerar.
resultado_publico.php) detecta automáticamente si los ZIPs han caducado y muestra el mensaje "No disponible" en lugar del botón de descarga. El usuario puede regenerar desde resultados.php.modules/presentador/pdf_publico.php — sirve PDFs de modelos AEAT sin sesión, autenticado por token del resultado. URL dinámica sin paths hardcodeados.ADD COLUMN periodo ENUM y ADD COLUMN modelos_aeat VARCHAR(30) en resultados_anuales.modules/facturacion/create.php y modules/presupuestos/create.php — guardan snapshot de emisor_nombre, emisor_nif y emisor_direccion al crear. Cambiar datos fiscales ya no afecta retroactivamente a documentos existentes.concepto_global en export Excel del portal contable — campo referenciado como concepto (incorrecto) → concepto_global.activo TINYINT(1) en tabla clientes. Toggle por fila, bulk y filtro en toolbar. Inactivos excluidos de selectores de nueva factura/presupuesto.portal_password en Configuración → Seguridad. Protege resultado_publico.php con pantalla de login con toggle mostrar/ocultar contraseña.Reply-To si está configurado.resultados_anuales: 3 columnas de tracking email (email_tracking_id, email_abierto, email_abierto_at), charset utf8mb4, 3 índices restaurados.configuracion (ids 13–19).producto_categorias y productos. Lógica PVP calculada en runtime. BD pasa de 12 → 14 tablas.systema_productos_plantilla.xlsx con 4 pestañas. Compatible con Saltoki y otros proveedores.actualizaciones.php — genera el ZIP de distribución con manifest SHA256 de los 90 archivos core.assets/resultados/{año}/. Estado en tiempo real vía polling.resultados_anuales con 12 campos incluyendo zip_status, zip_expires_at y token único.modules/resultados/cleanup.php — cron de limpieza automática de ZIPs caducados (14 días).modules/facturacion/update_vencimiento.php — nuevo endpoint para actualizar fecha sin abrir el modal de edición.settings.php y localStorage. Sin flash visual al cargar.modules/configuracion/save_ui.php — endpoint para persistir el zoom en servidor.?buscar=FAC-XXXX ahora navega a facturación y filtra automáticamente.settings.php ya no se carga dos veces en dashboard — reutiliza $cfg en memoria.BETWEEN en lugar de YEAR() para aprovechar índice.position:fixed + getBoundingClientRect().json_encode en lugar de addslashes.curl_multi carga QRs en paralelo antes del bucle.kpi_engine.php reescrito con calcularRango() sin solapamientos.actualizarSubfiltros() que tumbaba todo el JS del dashboard.modules/presupuestos/create.php — corregidas referencias a tablas inexistentes (presupuestos_lineas → presupuesto_items) y columnas incorrectas del schema antiguo.modules/presupuestos/convert.php — corregidas tablas, columnas y FK convertido_factura_id + convertido_at. El flujo presupuesto → factura ahora funciona correctamente.modules/presupuestos/delete.php — corregida tabla presupuestos_lineas → presupuesto_items.systema_v04_indexes.sql) para soportar 10.000+ facturas sin degradación.email_tracking — índice compuesto de 3 columnas con abierto_at para index-only scan en subquery correlated del listado.presupuestos.fecha_emision — índice añadido (faltaba completamente, causaba full scan en Presentador AEAT).status.php — Panel de Status & Mantenimiento con 9 sectores, chip global de estado, acciones con niveles de riesgo y log en tiempo real.status.php guardado en localStorage.layout.php — enlace Status añadido al sidebar.doc/index.html — documentación completa del sistema.