Initial commit: Horux Strategy Platform

- Laravel 11 backend with API REST
- React 18 + TypeScript + Vite frontend
- Multi-parser architecture for accounting systems (CONTPAQi, Aspel, SAP)
- 27+ financial metrics calculation
- PDF report generation with Browsershot
- Complete documentation (10 documents)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
2026-01-31 22:24:00 -06:00
commit 4c3dc94ff2
107 changed files with 10701 additions and 0 deletions

View File

@@ -0,0 +1,86 @@
# 1. Descripción General
## ¿Qué es Horux Strategy?
Horux Strategy es una plataforma web para generar reportes financieros automatizados a partir de balanzas de comprobación. Permite a empresas subir sus datos contables de múltiples sistemas (CONTPAQi, Aspel, SAP, Odoo, etc.) y obtener:
- Dashboard interactivo con métricas financieras
- Exportación a PDF profesional (32 páginas)
- Clasificación automática de cuentas contables
- Comparativos entre periodos
- Semáforos de rendimiento (indicadores de salud financiera)
## Características Principales
### Para Analistas
- Gestión de múltiples clientes
- Subida y procesamiento de balanzas de comprobación
- Revisión y corrección de anomalías contables
- Generación de reportes financieros
- Exportación a PDF
### Para Clientes
- Dashboard personalizado de su empresa
- Descarga de reportes en PDF
- Gestión de empleados y permisos
### Para Administradores
- Gestión completa de usuarios
- Configuración de umbrales por industria
- Reglas de mapeo contable por sistema
- Catálogo de giros de negocio
## Stack Tecnológico
| Componente | Tecnología |
|------------|------------|
| Backend | Laravel 11 (PHP 8.2+) |
| Frontend | React 18 + TypeScript |
| Build Tool | Vite |
| Base de Datos | MySQL / PostgreSQL |
| Autenticación | Laravel Sanctum (tokens) |
| Gráficas | Recharts |
| Estilos | Tailwind CSS |
| PDF | Browsershot (Puppeteer) |
| Parsing PDF | spatie/pdf-to-text |
| Excel | PhpSpreadsheet |
## Flujo de Trabajo
```
1. Crear Cliente
└── Nombre, logo, giro, moneda
2. Subir Balanzas (2+ archivos)
└── PDF, Excel o CSV de diferentes periodos
3. Detección Automática
└── Sistema identifica origen (CONTPAQi, Aspel, etc.)
4. Clasificación Automática
└── Mapeo a categorías contables
5. Revisión de Anomalías
└── Corregir cuentas mal clasificadas
6. Limpieza de Cuentas
└── Excluir cuentas de estrategia fiscal
7. Generación de Reporte
└── Cálculo de 27+ métricas
8. Dashboard Interactivo
└── Visualización de resultados
9. Exportar PDF
└── Reporte profesional de 32 páginas
```
## Roles de Usuario
| Rol | Descripción | Permisos |
|-----|-------------|----------|
| **Admin** | Superusuario del sistema | Acceso total, configuración global, gestión de umbrales |
| **Analista** | Operador de la plataforma | Gestionar clientes asignados, procesar balanzas, generar reportes |
| **Cliente** | Usuario empresarial | Ver dashboard propio, descargar PDFs, gestionar empleados |
| **Empleado** | Colaborador del cliente | Permisos configurables por el cliente |

169
docs/02-arquitectura.md Normal file
View File

@@ -0,0 +1,169 @@
# 2. Arquitectura del Sistema
## Diagrama de Componentes
```
┌─────────────────────────────────────────────────────────────────┐
│ FRONTEND (React) │
│ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐ │
│ │ Login │ │Clientes │ │Dashboard│ │ Admin │ │ PdfView │ │
│ └────┬────┘ └────┬────┘ └────┬────┘ └────┬────┘ └────┬────┘ │
│ └───────────┴───────────┴───────────┴───────────┘ │
│ │ │
│ ┌─────────┴─────────┐ │
│ │ API Service │ │
│ │ (Axios) │ │
│ └─────────┬─────────┘ │
└──────────────────────────────┼──────────────────────────────────┘
│ HTTP/REST
┌──────────────────────────────┴──────────────────────────────────┐
│ BACKEND (Laravel) │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ Controllers │ │
│ │ Auth │ Cliente │ Balanza │ Cuenta │ Reporte │ Admin │ │
│ └───────────────────────────┬─────────────────────────────┘ │
│ │ │
│ ┌───────────────────────────┴─────────────────────────────┐ │
│ │ Services │ │
│ │ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │ │
│ │ │ Parsers │ │ Clasificador │ │ Calculador │ │ │
│ │ │ - CONTPAQi │ │ Cuentas │ │ Métricas │ │ │
│ │ │ - Genérico │ │ │ │ │ │ │
│ │ └──────────────┘ └──────────────┘ └──────────────┘ │ │
│ │ ┌──────────────┐ │ │
│ │ │ Generador │ │ │
│ │ │ PDF │ │ │
│ │ └──────────────┘ │ │
│ └─────────────────────────────────────────────────────────┘ │
│ │ │
│ ┌───────────────────────────┴─────────────────────────────┐ │
│ │ Models │ │
│ │ User │ Cliente │ Balanza │ Cuenta │ Reporte │ etc. │ │
│ └───────────────────────────┬─────────────────────────────┘ │
└──────────────────────────────┼──────────────────────────────────┘
┌──────────────────┐
│ Database │
│ MySQL/PostgreSQL│
└──────────────────┘
```
## Estructura de Directorios
```
horux-strategy-platform/
├── backend/ # Laravel 11 API
│ ├── app/
│ │ ├── Http/
│ │ │ ├── Controllers/
│ │ │ │ ├── AuthController.php
│ │ │ │ ├── ClienteController.php
│ │ │ │ ├── BalanzaController.php
│ │ │ │ ├── CuentaController.php
│ │ │ │ ├── ReporteController.php
│ │ │ │ └── Admin/
│ │ │ │ ├── UsuarioController.php
│ │ │ │ ├── GiroController.php
│ │ │ │ ├── UmbralController.php
│ │ │ │ └── ReglaMapeeoController.php
│ │ │ └── Middleware/
│ │ │ └── RoleMiddleware.php
│ │ ├── Models/
│ │ │ ├── User.php
│ │ │ ├── Cliente.php
│ │ │ ├── Giro.php
│ │ │ ├── Balanza.php
│ │ │ ├── Cuenta.php
│ │ │ ├── Reporte.php
│ │ │ ├── ReporteContable.php
│ │ │ ├── CategoriaContable.php
│ │ │ ├── Umbral.php
│ │ │ ├── ReglaMapeo.php
│ │ │ ├── MapeoCuenta.php
│ │ │ └── PermisoEmpleado.php
│ │ └── Services/
│ │ ├── Parsers/
│ │ │ ├── ParserInterface.php
│ │ │ ├── DetectorFormato.php
│ │ │ ├── ContpaqiParser.php
│ │ │ └── GenericoParser.php
│ │ ├── ClasificadorCuentas.php
│ │ ├── CalculadorMetricas.php
│ │ └── GeneradorPdf.php
│ ├── database/
│ │ ├── migrations/
│ │ └── seeders/
│ ├── routes/
│ │ └── api.php
│ └── config/
├── frontend/ # React + TypeScript
│ ├── src/
│ │ ├── components/
│ │ │ ├── charts/
│ │ │ │ ├── BarChart.tsx
│ │ │ │ └── LineChart.tsx
│ │ │ ├── cards/
│ │ │ │ ├── KPICard.tsx
│ │ │ │ └── MetricTable.tsx
│ │ │ ├── forms/
│ │ │ │ ├── ClienteForm.tsx
│ │ │ │ ├── UploadBalanza.tsx
│ │ │ │ └── GenerarReporte.tsx
│ │ │ └── layout/
│ │ │ ├── Layout.tsx
│ │ │ ├── Sidebar.tsx
│ │ │ └── Header.tsx
│ │ ├── pages/
│ │ │ ├── Login.tsx
│ │ │ ├── Clientes/
│ │ │ ├── Dashboard/
│ │ │ ├── PdfView/
│ │ │ └── Admin/
│ │ ├── context/
│ │ │ └── AuthContext.tsx
│ │ ├── services/
│ │ │ └── api.ts
│ │ ├── types/
│ │ │ └── index.ts
│ │ └── hooks/
│ └── public/
└── docs/ # Documentación
└── plans/
```
## Flujo de Datos
### Subida de Balanza
```
1. Usuario sube archivo (PDF/Excel/CSV)
2. DetectorFormato identifica sistema origen
3. Parser específico extrae datos
4. ClasificadorCuentas aplica reglas de mapeo
5. Cuentas se guardan en BD con clasificación
6. Cuentas con anomalías se marcan para revisión
```
### Generación de Reporte
```
1. Usuario selecciona balanzas a incluir
2. CalculadorMetricas procesa datos
3. Se calculan estados financieros
4. Se calculan 27+ métricas
5. Se evalúan umbrales para semáforos
6. Se guardan resultados en JSON
7. Dashboard muestra resultados
```
### Exportación PDF
```
1. Usuario solicita PDF
2. GeneradorPdf prepara URL con token
3. Browsershot renderiza PdfView de React
4. Se genera PDF de 32 páginas
5. Se guarda en storage
6. Se descarga al usuario
```

205
docs/03-instalacion.md Normal file
View File

@@ -0,0 +1,205 @@
# 3. Instalación y Configuración
## Requisitos del Sistema
### Backend
- PHP 8.2 o superior
- Composer 2.x
- MySQL 8.0+ o PostgreSQL 14+
- Extensiones PHP: pdo_mysql, openssl, mbstring, fileinfo, gd
### Frontend
- Node.js 18 o superior
- npm o yarn
### Para generación de PDF
- Node.js (para Puppeteer)
- Chromium (se instala automáticamente)
---
## Instalación en Windows
### Opción 1: Usando Laragon (Recomendado)
1. **Descargar Laragon**
- Visita https://laragon.org/download/
- Descarga la versión "Full" (incluye PHP, MySQL, Composer)
- Instala y ejecuta Laragon
2. **Configurar el proyecto**
```bash
# Copia el proyecto a C:\laragon\www\horux-strategy-platform
# Abre la terminal de Laragon (clic derecho > Terminal)
cd horux-strategy-platform\backend
composer install
copy .env.example .env
php artisan key:generate
```
3. **Crear base de datos**
- En Laragon, clic en "Database" > "MySQL"
- Crea una base de datos llamada `horux_strategy`
4. **Ejecutar migraciones**
```bash
php artisan migrate --seed
```
5. **Iniciar backend**
```bash
php artisan serve
```
6. **Iniciar frontend** (otra terminal)
```bash
cd horux-strategy-platform\frontend
npm install
npm run dev
```
### Opción 2: Instalación Manual
1. **Instalar PHP**
- Descarga de https://windows.php.net/download/
- Versión: VS16 x64 Thread Safe
- Extrae en `C:\php`
- Agrega `C:\php` al PATH del sistema
- Copia `php.ini-development` a `php.ini`
- Edita `php.ini` y habilita:
```ini
extension=pdo_mysql
extension=openssl
extension=mbstring
extension=fileinfo
extension=gd
```
2. **Instalar Composer**
- Descarga de https://getcomposer.org/download/
- Ejecuta el instalador
3. **Instalar MySQL**
- Descarga de https://dev.mysql.com/downloads/mysql/
- Durante instalación, anota usuario y contraseña
4. **Configurar proyecto** (igual que Opción 1, pasos 2-6)
---
## Instalación en Linux/Mac
```bash
# Clonar o copiar el proyecto
cd horux-strategy-platform
# Backend
cd backend
composer install
cp .env.example .env
php artisan key:generate
# Configurar .env con datos de MySQL
nano .env
# Migraciones
php artisan migrate --seed
php artisan serve
# Frontend (otra terminal)
cd ../frontend
npm install
npm run dev
```
---
## Configuración del Archivo .env
```env
# Aplicación
APP_NAME="Horux Strategy"
APP_ENV=local
APP_DEBUG=true
APP_URL=http://localhost:8000
FRONTEND_URL=http://localhost:5173
# Base de Datos
DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=horux_strategy
DB_USERNAME=root
DB_PASSWORD=tu_password
# Sanctum (autenticación)
SANCTUM_STATEFUL_DOMAINS=localhost:5173,127.0.0.1:5173
```
---
## Verificación de Instalación
### Backend
```bash
# Verificar que el servidor responde
curl http://localhost:8000/api/giros
# Debe retornar lista de giros en JSON
```
### Frontend
```bash
# Abrir en navegador
http://localhost:5173
# Debe mostrar página de login
```
### Credenciales de Prueba
- **Email**: admin@horux360.com
- **Password**: password
---
## Solución de Problemas
### Error: "php" no es reconocido
- Verifica que PHP está en el PATH del sistema
- Reinicia la terminal
### Error: SQLSTATE Connection refused
- Verifica que MySQL está corriendo
- Verifica credenciales en .env
### Error: CORS
- Verifica FRONTEND_URL en .env
- Verifica config/cors.php
### Error: 419 Page Expired
- Ejecuta `php artisan config:clear`
- Verifica SANCTUM_STATEFUL_DOMAINS
---
## Despliegue en Producción
### Backend
```bash
composer install --optimize-autoloader --no-dev
php artisan config:cache
php artisan route:cache
php artisan view:cache
```
### Frontend
```bash
npm run build
# Servir carpeta dist/ con nginx/apache
```
### Variables de Producción
```env
APP_ENV=production
APP_DEBUG=false
FRONTEND_URL=https://tu-dominio.com
```

322
docs/04-api-reference.md Normal file
View File

@@ -0,0 +1,322 @@
# 4. API Reference
## Base URL
```
http://localhost:8000/api
```
## Autenticación
Todos los endpoints (excepto login) requieren token Bearer:
```
Authorization: Bearer {token}
```
---
## Endpoints de Autenticación
### POST /login
Iniciar sesión
**Request:**
```json
{
"email": "admin@horux360.com",
"password": "password"
}
```
**Response 200:**
```json
{
"user": {
"id": 1,
"nombre": "Administrador",
"email": "admin@horux360.com",
"role": "admin",
"cliente_id": null
},
"token": "1|abc123..."
}
```
### POST /logout
Cerrar sesión (requiere autenticación)
**Response 200:**
```json
{
"message": "Sesión cerrada exitosamente"
}
```
### GET /user
Obtener usuario actual
**Response 200:**
```json
{
"id": 1,
"nombre": "Administrador",
"email": "admin@horux360.com",
"role": "admin",
"cliente_id": null,
"cliente": null
}
```
---
## Endpoints de Giros
### GET /giros
Listar giros activos
**Response 200:**
```json
[
{ "id": 1, "nombre": "Hotelería", "activo": true },
{ "id": 2, "nombre": "Comercio", "activo": true }
]
```
---
## Endpoints de Clientes
### GET /clientes
Listar clientes (filtrado por rol)
**Response 200:**
```json
[
{
"id": 1,
"nombre_empresa": "Hotel Boutique HSA",
"logo": "logos/abc123.png",
"giro_id": 1,
"moneda": "MXN",
"giro": { "id": 1, "nombre": "Hotelería" }
}
]
```
### POST /clientes
Crear cliente (multipart/form-data)
**Request:**
```
nombre_empresa: Hotel Ejemplo
giro_id: 1
moneda: MXN
logo: [archivo imagen]
```
**Response 201:**
```json
{
"id": 2,
"nombre_empresa": "Hotel Ejemplo",
"giro_id": 1,
"moneda": "MXN",
"logo": "logos/xyz789.png"
}
```
### GET /clientes/{id}
Obtener cliente con balanzas y reportes
### PUT /clientes/{id}
Actualizar cliente
### DELETE /clientes/{id}
Eliminar cliente (solo admin)
---
## Endpoints de Balanzas
### GET /clientes/{id}/balanzas
Listar balanzas de un cliente
**Response 200:**
```json
[
{
"id": 1,
"cliente_id": 1,
"periodo_inicio": "2024-01-01",
"periodo_fin": "2024-12-31",
"sistema_origen": "contpaqi",
"status": "completado"
}
]
```
### POST /clientes/{id}/balanzas
Subir balanza (multipart/form-data)
**Request:**
```
archivo: [archivo PDF/Excel/CSV]
periodo_inicio: 2024-01-01
periodo_fin: 2024-12-31
```
**Response 201:**
```json
{
"id": 2,
"sistema_origen": "contpaqi",
"status": "procesando"
}
```
### GET /balanzas/{id}/cuentas
Listar cuentas de una balanza
**Response 200:**
```json
[
{
"id": 1,
"codigo": "001-100-000",
"nombre": "ACTIVO CIRCULANTE",
"nivel": 1,
"saldo_final_deudor": 1500000.00,
"saldo_final_acreedor": 0,
"excluida": false,
"es_cuenta_padre": true,
"requiere_revision": false,
"categoria_contable": {
"id": 1,
"nombre": "Activos Circulantes"
}
}
]
```
### PUT /balanzas/{id}/exclusiones
Actualizar cuentas excluidas
**Request:**
```json
{
"exclusiones": [5, 12, 23]
}
```
---
## Endpoints de Cuentas
### PUT /cuentas/{id}/clasificacion
Corregir clasificación de cuenta
**Request:**
```json
{
"reporte_contable_id": 1,
"categoria_contable_id": 3,
"requiere_revision": false
}
```
### POST /cuentas/{id}/toggle-exclusion
Alternar exclusión de cuenta
### GET /anomalias
Listar cuentas que requieren revisión
---
## Endpoints de Reportes
### GET /clientes/{id}/reportes
Listar reportes de un cliente
### POST /clientes/{id}/reportes
Generar nuevo reporte
**Request:**
```json
{
"nombre": "Reporte Anual 2024",
"balanza_ids": [1, 2, 3]
}
```
**Response 201:**
```json
{
"id": 1,
"nombre": "Reporte Anual 2024",
"periodo_tipo": "anual",
"status": "completado",
"data_calculada": { ... }
}
```
### GET /reportes/{id}
Obtener reporte con datos calculados
### GET /reportes/{id}/pdf
Descargar PDF del reporte
**Response:** Archivo PDF
### DELETE /reportes/{id}
Eliminar reporte
---
## Endpoints de Administración
Requieren rol `admin`.
### Usuarios
- `GET /admin/usuarios` - Listar usuarios
- `POST /admin/usuarios` - Crear usuario
- `PUT /admin/usuarios/{id}` - Actualizar usuario
- `DELETE /admin/usuarios/{id}` - Eliminar usuario
### Giros
- `GET /admin/giros` - Listar todos los giros
- `POST /admin/giros` - Crear giro
- `PUT /admin/giros/{id}` - Actualizar giro
- `DELETE /admin/giros/{id}` - Eliminar giro
### Umbrales
- `GET /admin/umbrales` - Listar umbrales
- `POST /admin/umbrales` - Crear umbral
- `PUT /admin/umbrales/{id}` - Actualizar umbral
- `DELETE /admin/umbrales/{id}` - Eliminar umbral
### Reglas de Mapeo
- `GET /admin/reglas-mapeo` - Listar reglas
- `POST /admin/reglas-mapeo` - Crear regla
- `PUT /admin/reglas-mapeo/{id}` - Actualizar regla
- `DELETE /admin/reglas-mapeo/{id}` - Eliminar regla
---
## Códigos de Error
| Código | Descripción |
|--------|-------------|
| 401 | No autenticado |
| 403 | No autorizado |
| 404 | Recurso no encontrado |
| 422 | Error de validación |
| 500 | Error del servidor |
**Ejemplo error 422:**
```json
{
"message": "The email field is required.",
"errors": {
"email": ["The email field is required."]
}
}
```

271
docs/05-frontend.md Normal file
View File

@@ -0,0 +1,271 @@
# 5. Guía del Frontend
## Stack Tecnológico
- **React 18** - Biblioteca de UI
- **TypeScript** - Tipado estático
- **Vite** - Build tool y dev server
- **React Router** - Navegación
- **Axios** - Cliente HTTP
- **Recharts** - Gráficas
- **Tailwind CSS** - Estilos
- **react-hot-toast** - Notificaciones
- **react-dropzone** - Upload de archivos
---
## Estructura de Carpetas
```
frontend/src/
├── components/
│ ├── charts/ # Componentes de gráficas
│ │ ├── BarChart.tsx
│ │ └── LineChart.tsx
│ ├── cards/ # Tarjetas y tablas
│ │ ├── KPICard.tsx
│ │ └── MetricTable.tsx
│ ├── forms/ # Formularios
│ │ ├── ClienteForm.tsx
│ │ ├── UploadBalanza.tsx
│ │ └── GenerarReporte.tsx
│ └── layout/ # Estructura de página
│ ├── Layout.tsx
│ ├── Sidebar.tsx
│ └── Header.tsx
├── pages/
│ ├── Login.tsx
│ ├── Clientes/
│ │ ├── ClientesList.tsx
│ │ └── ClienteDetail.tsx
│ ├── Dashboard/
│ │ └── index.tsx
│ ├── PdfView/
│ │ └── index.tsx
│ └── Admin/
│ ├── Usuarios.tsx
│ ├── Giros.tsx
│ ├── Umbrales.tsx
│ └── ReglasMapeeo.tsx
├── context/
│ └── AuthContext.tsx
├── services/
│ └── api.ts
├── types/
│ └── index.ts
└── hooks/
```
---
## Contexto de Autenticación
```tsx
// Uso del contexto
import { useAuth } from '../context/AuthContext';
function MyComponent() {
const { user, login, logout, isAdmin, isAnalista } = useAuth();
if (!user) return <Navigate to="/login" />;
return <div>Hola {user.nombre}</div>;
}
```
### Propiedades disponibles:
- `user` - Usuario actual o null
- `loading` - Estado de carga inicial
- `login(email, password)` - Iniciar sesión
- `logout()` - Cerrar sesión
- `isAdmin` - Es administrador
- `isAnalista` - Es analista
- `isCliente` - Es cliente
- `isEmpleado` - Es empleado
---
## Servicio API
```tsx
import { clientesApi, balanzasApi, reportesApi } from '../services/api';
// Listar clientes
const clientes = await clientesApi.list();
// Crear cliente
const formData = new FormData();
formData.append('nombre_empresa', 'Mi Empresa');
formData.append('giro_id', '1');
const cliente = await clientesApi.create(formData);
// Subir balanza
const balanza = await balanzasApi.upload(clienteId, formData);
// Generar reporte
const reporte = await reportesApi.create(clienteId, 'Reporte 2024', [1, 2]);
// Descargar PDF
const blob = await reportesApi.downloadPdf(reporteId);
```
---
## Tipos TypeScript
```tsx
// Principales tipos disponibles
interface User {
id: number;
nombre: string;
email: string;
role: 'admin' | 'analista' | 'cliente' | 'empleado';
cliente_id: number | null;
}
interface Cliente {
id: number;
nombre_empresa: string;
logo: string | null;
giro_id: number;
moneda: string;
giro?: Giro;
}
interface Balanza {
id: number;
cliente_id: number;
periodo_inicio: string;
periodo_fin: string;
sistema_origen: string;
status: 'pendiente' | 'procesando' | 'completado' | 'error';
}
interface Reporte {
id: number;
nombre: string;
periodo_tipo: 'mensual' | 'trimestral' | 'anual';
data_calculada: DataCalculada | null;
status: string;
}
type Tendencia = 'muy_positivo' | 'positivo' | 'neutral' | 'negativo' | 'muy_negativo';
```
---
## Componentes Reutilizables
### KPICard
```tsx
<KPICard
title="Ingresos"
value="$1,500,000"
subtitle="12% vs mes anterior"
tendencia="positivo"
/>
```
### MetricTable
```tsx
<MetricTable
title="Márgenes"
metricas={[
{ nombre: 'Margen Bruto', valor: 0.45, tendencia: 'positivo' },
{ nombre: 'Margen Neto', valor: 0.12, tendencia: 'neutral' },
]}
/>
```
### BarChart
```tsx
<BarChartComponent
data={[
{ name: 'Ingresos', valor: 1500000 },
{ name: 'Gastos', valor: -800000 },
]}
horizontal={false}
/>
```
### LineChart
```tsx
<LineChartComponent
data={periodos.map(p => ({
periodo: p.periodo,
'Margen Bruto': p.margen_bruto * 100,
'Margen Neto': p.margen_neto * 100,
}))}
lines={['Margen Bruto', 'Margen Neto']}
/>
```
---
## Estilos con Tailwind
### Clases personalizadas (index.css)
```css
.btn { @apply px-4 py-2 rounded-lg font-medium transition-colors; }
.btn-primary { @apply bg-primary-600 text-white hover:bg-primary-700; }
.btn-secondary { @apply bg-gray-200 text-gray-800 hover:bg-gray-300; }
.input { @apply w-full px-3 py-2 border rounded-lg focus:ring-2 focus:ring-primary-500; }
.card { @apply bg-white rounded-xl shadow-sm border border-gray-100 p-6; }
.label { @apply block text-sm font-medium text-gray-700 mb-1; }
```
### Colores de marca (tailwind.config.js)
```js
colors: {
horux: {
dark: '#1a1a2e',
primary: '#16213e',
accent: '#0f3460',
highlight: '#e94560',
},
status: {
'muy-positivo': '#10b981',
'positivo': '#34d399',
'neutral': '#fbbf24',
'negativo': '#f97316',
'muy-negativo': '#ef4444',
},
}
```
---
## Rutas
| Ruta | Componente | Rol requerido |
|------|------------|---------------|
| `/login` | Login | Público |
| `/clientes` | ClientesList | Autenticado |
| `/clientes/:id` | ClienteDetail | Autenticado |
| `/dashboard/:clienteId/:reporteId` | Dashboard | Autenticado |
| `/pdf-view/:id` | PdfView | Token especial |
| `/admin/usuarios` | AdminUsuarios | Admin |
| `/admin/giros` | AdminGiros | Admin |
| `/admin/umbrales` | AdminUmbrales | Admin |
| `/admin/reglas-mapeo` | AdminReglasMapeeo | Admin |
---
## Desarrollo
```bash
# Instalar dependencias
npm install
# Servidor de desarrollo
npm run dev
# Build para producción
npm run build
# Preview del build
npm run preview
# Linting
npm run lint
```

241
docs/06-base-de-datos.md Normal file
View File

@@ -0,0 +1,241 @@
# 6. Base de Datos
## Diagrama Entidad-Relación
```
┌─────────────┐ ┌─────────────┐ ┌─────────────┐
│ giros │ │ clientes │ │ users │
├─────────────┤ ├─────────────┤ ├─────────────┤
│ id │◄──────┤ giro_id │ │ id │
│ nombre │ │ id │◄──────┤ cliente_id │
│ activo │ │ nombre_emp │ │ nombre │
└─────────────┘ │ logo │ │ email │
│ moneda │ │ password │
│ config │ │ role │
└──────┬──────┘ └─────────────┘
┌──────────────┼──────────────┐
▼ ▼ ▼
┌─────────────┐┌─────────────┐┌─────────────┐
│ balanzas ││ reportes ││mapeo_cuentas│
├─────────────┤├─────────────┤├─────────────┤
│ id ││ id ││ id │
│ cliente_id ││ cliente_id ││ cliente_id │
│ periodo_ini ││ nombre ││ codigo_pat │
│ periodo_fin ││ periodo_tipo││ categoria_id│
│ sistema_orig││ data_calc │└─────────────┘
│ status ││ pdf_path │
└──────┬──────┘└─────────────┘
┌─────────────┐
│ cuentas │
├─────────────┤
│ id │
│ balanza_id │
│ codigo │
│ nombre │
│ nivel │
│ saldos... │
│ excluida │
│ categoria_id│
└─────────────┘
┌─────────────────┐ ┌─────────────────┐
│reportes_contable│ │categorias_contab│
├─────────────────┤ ├─────────────────┤
│ id │◄────┤ reporte_cont_id │
│ nombre │ │ id │
└─────────────────┘ │ nombre │
│ orden │
└────────┬────────┘
┌────────┴────────┐
▼ ▼
┌─────────────┐ ┌─────────────┐
│reglas_mapeo │ │ umbrales │
├─────────────┤ ├─────────────┤
│ sistema_orig│ │ metrica │
│ rango_ini │ │ muy_positivo│
│ rango_fin │ │ positivo │
│ categoria_id│ │ neutral │
│ prioridad │ │ negativo │
└─────────────┘ │ muy_negativo│
│ giro_id │
└─────────────┘
```
---
## Tablas
### users
Usuarios del sistema.
| Campo | Tipo | Descripción |
|-------|------|-------------|
| id | bigint | PK |
| nombre | varchar(255) | Nombre completo |
| email | varchar(255) | Email único |
| password | varchar(255) | Hash de contraseña |
| role | enum | admin, analista, cliente, empleado |
| cliente_id | bigint | FK a clientes (nullable) |
### clientes
Empresas registradas.
| Campo | Tipo | Descripción |
|-------|------|-------------|
| id | bigint | PK |
| nombre_empresa | varchar(255) | Nombre de la empresa |
| logo | varchar(255) | Path al logo |
| giro_id | bigint | FK a giros |
| moneda | varchar(3) | MXN, USD, EUR |
| configuracion | json | Configuración adicional |
### giros
Catálogo de giros de negocio.
| Campo | Tipo | Descripción |
|-------|------|-------------|
| id | bigint | PK |
| nombre | varchar(255) | Nombre del giro |
| activo | boolean | Estado |
### balanzas
Archivos de balanza subidos.
| Campo | Tipo | Descripción |
|-------|------|-------------|
| id | bigint | PK |
| cliente_id | bigint | FK a clientes |
| periodo_inicio | date | Inicio del periodo |
| periodo_fin | date | Fin del periodo |
| sistema_origen | varchar(50) | contpaqi, aspel, etc. |
| archivo_original | varchar(255) | Path al archivo |
| status | enum | pendiente, procesando, completado, error |
| error_mensaje | text | Mensaje de error si aplica |
### cuentas
Cuentas extraídas de balanzas.
| Campo | Tipo | Descripción |
|-------|------|-------------|
| id | bigint | PK |
| balanza_id | bigint | FK a balanzas |
| codigo | varchar(20) | Código de cuenta (ej: 001-100-000) |
| nombre | varchar(255) | Nombre de la cuenta |
| nivel | int | Nivel jerárquico (1, 2, 3) |
| reporte_contable_id | bigint | FK a reportes_contables |
| categoria_contable_id | bigint | FK a categorias_contables |
| cuenta_padre_id | bigint | FK a cuentas (self-reference) |
| saldo_inicial_deudor | decimal(18,2) | |
| saldo_inicial_acreedor | decimal(18,2) | |
| cargos | decimal(18,2) | |
| abonos | decimal(18,2) | |
| saldo_final_deudor | decimal(18,2) | |
| saldo_final_acreedor | decimal(18,2) | |
| excluida | boolean | Excluida del cálculo |
| es_cuenta_padre | boolean | Es cuenta padre |
| requiere_revision | boolean | Necesita revisión manual |
| nota_revision | text | Nota sobre la anomalía |
### reportes_contables
Tipos de reporte (Balance, Estado de Resultados).
| Campo | Tipo | Descripción |
|-------|------|-------------|
| id | bigint | PK |
| nombre | varchar(255) | "Balance General", "Estado de Resultados" |
### categorias_contables
Categorías dentro de cada reporte.
| Campo | Tipo | Descripción |
|-------|------|-------------|
| id | bigint | PK |
| reporte_contable_id | bigint | FK a reportes_contables |
| nombre | varchar(255) | Nombre de la categoría |
| orden | int | Orden de aparición |
**Categorías de Balance General:**
1. Activos Circulantes
2. Activos No Circulantes
3. Pasivo Circulante
4. Pasivo No Circulante
5. Capital Social
6. Pérdidas Ejercicios Anteriores
7. Utilidades Ejercicios Anteriores
**Categorías de Estado de Resultados:**
1. Ingresos
2. Costo de Venta
3. Gastos Operativos
4. Otros Gastos
5. Gastos Financieros
### reglas_mapeo
Reglas para clasificar cuentas automáticamente.
| Campo | Tipo | Descripción |
|-------|------|-------------|
| id | bigint | PK |
| sistema_origen | varchar(50) | contpaqi, aspel, etc. |
| cuenta_padre_codigo | varchar(20) | Código de cuenta padre |
| rango_inicio | varchar(20) | Inicio del rango de códigos |
| rango_fin | varchar(20) | Fin del rango |
| patron_regex | varchar(255) | Patrón regex alternativo |
| reporte_contable_id | bigint | FK |
| categoria_contable_id | bigint | FK |
| prioridad | int | Mayor = se evalúa primero |
| activo | boolean | Regla activa |
### umbrales
Umbrales para semáforos de métricas.
| Campo | Tipo | Descripción |
|-------|------|-------------|
| id | bigint | PK |
| metrica | varchar(100) | Nombre de la métrica |
| muy_positivo | decimal(10,4) | Umbral muy positivo |
| positivo | decimal(10,4) | Umbral positivo |
| neutral | decimal(10,4) | Umbral neutral |
| negativo | decimal(10,4) | Umbral negativo |
| muy_negativo | decimal(10,4) | Umbral muy negativo |
| giro_id | bigint | FK a giros (nullable = general) |
### reportes
Reportes generados.
| Campo | Tipo | Descripción |
|-------|------|-------------|
| id | bigint | PK |
| cliente_id | bigint | FK a clientes |
| nombre | varchar(255) | Nombre del reporte |
| periodo_tipo | enum | mensual, trimestral, anual |
| periodo_inicio | date | |
| periodo_fin | date | |
| fecha_generacion | timestamp | |
| data_calculada | json | Métricas y estados financieros |
| pdf_path | varchar(255) | Path al PDF generado |
| status | enum | pendiente, procesando, completado, error |
### reporte_balanza
Tabla pivote reporte-balanza.
| Campo | Tipo | Descripción |
|-------|------|-------------|
| reporte_id | bigint | FK a reportes |
| balanza_id | bigint | FK a balanzas |
---
## Seeders
Los seeders iniciales crean:
1. **GirosSeeder** - 24 giros de negocio
2. **ReportesContablesSeeder** - 2 reportes + 12 categorías
3. **ReglasMapeeoContpaqiSeeder** - 12 reglas para CONTPAQi
4. **UmbralesSeeder** - 24 umbrales por defecto
5. **AdminUserSeeder** - Usuario admin inicial

253
docs/07-parsers.md Normal file
View File

@@ -0,0 +1,253 @@
# 7. Parsers de Balanzas
## Arquitectura
```
Upload archivo
┌─────────────────┐
│ DetectorFormato │ ← Detecta el sistema origen
└────────┬────────┘
┌─────────────────┐
│ Parser Específico│
│ - ContpaqiParser│
│ - GenericoParser│
│ - (futuro: Aspel)│
└────────┬────────┘
┌─────────────────┐
│ Formato Standard│ ← Estructura normalizada
└────────┬────────┘
┌─────────────────┐
│ ClasificadorCtas│ ← Aplica reglas de mapeo
└─────────────────┘
```
---
## Interface ParserInterface
Todos los parsers deben implementar:
```php
interface ParserInterface
{
/**
* Parsea archivo y retorna array de cuentas normalizadas
*/
public function parsear(string $filePath): array;
/**
* Verifica si puede manejar el archivo
*/
public function puedeManej(string $filePath): bool;
/**
* Retorna identificador del sistema
*/
public function getSistema(): string;
}
```
### Estructura de cuenta normalizada:
```php
[
'codigo' => '001-100-000',
'nombre' => 'ACTIVO CIRCULANTE',
'nivel' => 1,
'saldo_inicial_deudor' => 1500000.00,
'saldo_inicial_acreedor' => 0.00,
'cargos' => 500000.00,
'abonos' => 200000.00,
'saldo_final_deudor' => 1800000.00,
'saldo_final_acreedor' => 0.00,
'es_cuenta_padre' => true,
'cuenta_padre_codigo' => null, // opcional
]
```
---
## DetectorFormato
Detecta automáticamente el sistema origen del archivo.
```php
class DetectorFormato
{
private array $parsers = [
new ContpaqiParser(),
// new AspelParser(),
// new SapParser(),
new GenericoParser(), // Fallback
];
public function detectar(string $filePath): array
{
foreach ($this->parsers as $parser) {
if ($parser->puedeManej($filePath)) {
return [
'sistema' => $parser->getSistema(),
'parser' => $parser,
];
}
}
throw new Exception('Formato no reconocido');
}
}
```
---
## ContpaqiParser
Parser para balanzas de CONTPAQi.
### Detección
Busca patrones característicos en el PDF:
- Texto "CONTPAQ" o "CONTPAQi"
- Patrón de códigos: `\d{3}-\d{3}-\d{3}`
- Encabezados típicos: "Saldo Inicial", "Debe", "Haber"
### Formato de código CONTPAQi
```
XXX-XXX-XXX
│ │ │
│ │ └── Detalle (000 = padre)
│ └────── Subcuenta (000 = padre)
└────────── Mayor
```
Ejemplos:
- `001-100-000` → Nivel 1 (Mayor: Activo Circulante)
- `101-000-000` → Nivel 2 (Subcuenta: Caja)
- `101-001-000` → Nivel 3 (Detalle)
### Reglas de mapeo CONTPAQi
| Cuenta Padre | Rango Hijos | Categoría |
|--------------|-------------|-----------|
| 001-100-000 | 101-000-000 a 154-999-999 | Activos Circulantes |
| 001-200-000 | 155-000-000 a 199-999-999 | Activos No Circulantes |
| 002-100-000 | 200-000-000 a 209-999-999 | Pasivo Circulante |
| 002-200-000 | 210-000-000 a 220-999-999 | Pasivo No Circulante |
| 30X-XXX-XXX | - | Capital Social |
| 310-XXX-XXX | - | Pérdidas Anteriores |
| 311-XXX-XXX | - | Utilidades Anteriores |
| 40X-XXX-XXX | - | Ingresos |
| 5XX-XXX-XXX | - | Gastos Operativos |
| 6XX-XXX-XXX | - | Otros Gastos |
| 7XX-XXX-XXX | - | Gastos Financieros |
---
## GenericoParser
Parser para archivos Excel/CSV genéricos.
### Formatos soportados
- `.xlsx` - Excel 2007+
- `.xls` - Excel 97-2003
- `.csv` - Valores separados por coma/punto y coma
### Detección de columnas
Busca headers similares a:
| Campo | Aliases aceptados |
|-------|-------------------|
| codigo | codigo, cuenta, code, account, cta, numero |
| nombre | nombre, descripcion, name, description, concepto |
| saldo_inicial_deudor | saldo_inicial_deudor, inicial_debe, opening_debit |
| cargos | cargos, debe, debit, debits, movs_deudor |
| abonos | abonos, haber, credit, credits, movs_acreedor |
| saldo_final_deudor | saldo_final_deudor, final_debe, closing_debit |
### Detección de delimitador CSV
Detecta automáticamente: `,`, `;`, `\t`, `|`
---
## Agregar Nuevo Parser
1. **Crear clase** en `app/Services/Parsers/`:
```php
<?php
namespace App\Services\Parsers;
class AspelParser implements ParserInterface
{
public function getSistema(): string
{
return 'aspel';
}
public function puedeManej(string $filePath): bool
{
// Lógica de detección para Aspel
$text = file_get_contents($filePath);
return str_contains(strtoupper($text), 'ASPEL');
}
public function parsear(string $filePath): array
{
// Lógica de parsing
$cuentas = [];
// ... extraer datos ...
return $cuentas;
}
}
```
2. **Registrar en DetectorFormato**:
```php
// En DetectorFormato::__construct()
$this->parsers = [
new ContpaqiParser(),
new AspelParser(), // ← Agregar antes de GenericoParser
new GenericoParser(),
];
```
3. **Agregar reglas de mapeo** en seeder:
```php
// Crear nuevo seeder: ReglasMapeeoAspelSeeder.php
ReglaMapeo::create([
'sistema_origen' => 'aspel',
'patron_regex' => '/^1\d{3}/',
'reporte_contable_id' => $balance->id,
'categoria_contable_id' => $activosCirc->id,
'prioridad' => 10,
]);
```
---
## ClasificadorCuentas
Aplica reglas de mapeo a las cuentas importadas.
### Proceso:
1. Buscar mapeo específico del cliente
2. Si no existe, buscar regla del sistema
3. Si no existe regla, marcar para revisión
### Detección de anomalías:
- Cuentas 45X (normalmente pasivo) usadas como gasto
- Cuentas 8XX-9XX (cuentas de orden)
- Códigos sin regla de mapeo
```php
// Ejemplo de nota de revisión automática
"Código 45X normalmente es pasivo pero podría ser gasto. Verificar clasificación."
```

232
docs/08-metricas.md Normal file
View File

@@ -0,0 +1,232 @@
# 8. Métricas Financieras
## Resumen
El sistema calcula **27+ métricas financieras** organizadas en 6 categorías:
| Categoría | # Métricas |
|-----------|------------|
| Márgenes | 7 |
| Retorno | 4 |
| Eficiencia | 6 |
| Liquidez | 3 |
| Solvencia | 3 |
| Gestión | 4 |
---
## Estados Financieros Base
### Balance General
```
ACTIVOS
├── Activos Circulantes
│ ├── Efectivo
│ ├── Cuentas por Cobrar
│ └── Inventarios
├── Activos No Circulantes
│ ├── Propiedad, Planta y Equipo
│ └── Activos Intangibles
└── TOTAL ACTIVOS
PASIVOS
├── Pasivo Circulante
│ ├── Cuentas por Pagar
│ └── Deuda Corto Plazo
├── Pasivo No Circulante
│ └── Deuda Largo Plazo
└── TOTAL PASIVOS
CAPITAL
├── Capital Social
├── Utilidades Retenidas
└── TOTAL CAPITAL
TOTAL PASIVOS + CAPITAL = TOTAL ACTIVOS
```
### Estado de Resultados
```
Ingresos
(-) Costo de Venta
= Utilidad Bruta
(-) Gastos Operativos
= Utilidad Operativa (EBIT)
(-) Otros Gastos
(-) Gastos Financieros
= Utilidad Antes de Impuestos (EBT)
(-) Impuestos
= UTILIDAD NETA
```
### Flujo de Efectivo (Método Indirecto)
```
FLUJO DE OPERACIÓN
Utilidad Neta
+ Depreciación
- Cambios en Capital de Trabajo
FLUJO DE INVERSIÓN
- Adquisición de Activos Fijos
+ Venta de Activos
FLUJO DE FINANCIAMIENTO
+ Nueva Deuda
- Pago de Deuda
+ Aportaciones de Capital
- Dividendos
= FLUJO NETO
```
---
## Métricas por Categoría
### 1. Márgenes
| Métrica | Fórmula | Interpretación |
|---------|---------|----------------|
| **Margen Bruto** | Utilidad Bruta / Ingresos | Rentabilidad después de costos directos |
| **Margen EBITDA** | EBITDA / Ingresos | Rentabilidad operativa antes de D&A |
| **Margen Operativo** | EBIT / Ingresos | Rentabilidad operativa |
| **Margen Neto** | Utilidad Neta / Ingresos | Rentabilidad final |
| **Margen NOPAT** | NOPAT / Ingresos | Utilidad operativa después de impuestos |
| **Margen OCF** | Flujo Operación / Ingresos | Generación de efectivo operativo |
| **Margen FCF** | Flujo Libre / Ingresos | Efectivo disponible |
Donde:
- EBITDA = EBIT + Depreciación + Amortización
- NOPAT = EBIT × (1 - Tasa Impuestos)
- FCF = Flujo Operación - CapEx
### 2. Retorno
| Métrica | Fórmula | Interpretación |
|---------|---------|----------------|
| **ROIC** | NOPAT / Capital Invertido | Retorno sobre capital invertido |
| **ROE** | Utilidad Neta / Capital | Retorno para accionistas |
| **ROA** | Utilidad Neta / Activo Total | Eficiencia de activos |
| **ROCE** | EBIT / Capital Empleado | Retorno sobre capital empleado |
Donde:
- Capital Invertido = Activo Total - Pasivo Circulante
- Capital Empleado = Activo Total - Pasivo Circulante
### 3. Eficiencia
| Métrica | Fórmula | Interpretación |
|---------|---------|----------------|
| **Asset Turnover** | Ingresos / Activo Total | Rotación de activos |
| **Inventory Turnover** | Costo Venta / Inventario | Rotación de inventario |
| **Días Clientes** | (Clientes / Ingresos) × 365 | Días para cobrar |
| **Días Proveedores** | (Proveedores / Costo) × 365 | Días para pagar |
| **Días Inventario** | (Inventario / Costo) × 365 | Días de inventario |
| **Ciclo Conversión** | Días Clientes + Días Inv. - Días Prov. | Ciclo de efectivo |
### 4. Liquidez
| Métrica | Fórmula | Interpretación |
|---------|---------|----------------|
| **Current Ratio** | Activo Circ. / Pasivo Circ. | Capacidad de pago corto plazo |
| **Quick Ratio** | (Activo Circ. - Inv.) / Pasivo Circ. | Liquidez sin inventario |
| **Cash Ratio** | Efectivo / Pasivo Circ. | Liquidez inmediata |
### 5. Solvencia
| Métrica | Fórmula | Interpretación |
|---------|---------|----------------|
| **Net Debt/EBITDA** | (Deuda - Efectivo) / EBITDA | Años para pagar deuda |
| **Interest Coverage** | EBITDA / Gastos Financieros | Cobertura de intereses |
| **Debt Ratio** | Deuda Total / Activo Total | Apalancamiento |
### 6. Gestión
| Métrica | Fórmula | Interpretación |
|---------|---------|----------------|
| **Revenue Growth** | (Ingreso Actual - Anterior) / Anterior | Crecimiento de ventas |
| **Key Score** | Crec. Ingreso 12m + Margen EBITDA 12m | Score compuesto |
| **CapEx/Revenue** | CAPEX / Ingresos | Inversión en activos |
| **Effective Tax Rate** | Impuestos / EBT | Tasa impositiva efectiva |
---
## Sistema de Semáforos
Cada métrica se evalúa contra umbrales para determinar su "tendencia":
| Tendencia | Color | Significado |
|-----------|-------|-------------|
| muy_positivo | Verde oscuro | Excelente desempeño |
| positivo | Verde claro | Buen desempeño |
| neutral | Amarillo | Desempeño aceptable |
| negativo | Naranja | Área de atención |
| muy_negativo | Rojo | Área crítica |
### Ejemplo de umbrales (Margen Neto):
| Tendencia | Umbral |
|-----------|--------|
| muy_positivo | ≥ 20% |
| positivo | ≥ 10% |
| neutral | ≥ 5% |
| negativo | ≥ 2% |
| muy_negativo | < 2% |
### Umbrales por Giro
Los umbrales pueden personalizarse por industria. Por ejemplo, hotelería puede tener diferentes expectativas de margen que manufactura.
---
## Comparativos
Para cada métrica se calculan:
| Comparativo | Descripción |
|-------------|-------------|
| Valor Actual | Valor del periodo actual |
| Periodo Anterior | Valor del periodo inmediato anterior |
| Variación Absoluta | Diferencia numérica |
| Variación % | Cambio porcentual |
| Promedio 3 Periodos | Media de últimos 3 periodos |
| Mismo Periodo Año Anterior | Para comparación interanual |
---
## Implementación
```php
// CalculadorMetricas.php
public function calcular(Reporte $reporte): array
{
// 1. Calcular estados financieros por periodo
foreach ($balanzas as $balanza) {
$periodos[] = [
'periodo' => $balanza->periodo_fin,
'balance_general' => $this->calcularBalanceGeneral($balanza),
'estado_resultados' => $this->calcularEstadoResultados($balanza),
];
}
// 2. Calcular métricas del último periodo
$metricas = $this->calcularTodasLasMetricas($ultimoPeriodo);
// 3. Calcular comparativos
$comparativos = $this->calcularComparativos($periodos, $metricas);
// 4. Calcular flujo de efectivo
$flujoEfectivo = $this->calcularFlujoEfectivo($periodos);
return [
'periodos' => $periodos,
'metricas' => $metricas,
'comparativos' => $comparativos,
'flujo_efectivo' => $flujoEfectivo,
];
}
```

479
docs/09-pdf.md Normal file
View File

@@ -0,0 +1,479 @@
# 9. Generación de PDF
## Descripción
El sistema genera reportes PDF profesionales de **32 páginas** usando Browsershot (wrapper de Puppeteer para Laravel).
---
## Arquitectura
```
┌─────────────────┐
│ ReporteController│
│ /pdf │
└────────┬────────┘
┌─────────────────┐
│ GeneradorPdf │
└────────┬────────┘
┌─────────────────┐
│ Browsershot │ ← Puppeteer headless Chrome
└────────┬────────┘
┌─────────────────┐
│ React PdfView │ ← Componente optimizado para impresión
└────────┬────────┘
┌─────────────────┐
│ PDF 32 págs │
└─────────────────┘
```
---
## Estructura del PDF (32 páginas)
| # | Sección | Contenido |
|---|---------|-----------|
| 1 | Portada | Logo, nombre empresa, periodo |
| 2 | Índice | Tabla de contenidos |
| 3-4 | Resumen Ejecutivo | KPIs principales, semáforos |
| 5-8 | Balance General | Activos, Pasivos, Capital |
| 9-12 | Estado de Resultados | Ingresos, Costos, Gastos |
| 13-14 | Flujo de Efectivo | Operación, Inversión, Financiamiento |
| 15-18 | Análisis de Márgenes | 7 métricas con gráficas |
| 19-20 | Análisis de Retorno | ROIC, ROE, ROA, ROCE |
| 21-22 | Análisis de Eficiencia | Rotaciones, ciclo conversión |
| 23-24 | Análisis de Liquidez | Ratios de liquidez |
| 25-26 | Análisis de Solvencia | Deuda, cobertura |
| 27-28 | Análisis de Gestión | Crecimiento, inversión |
| 29-30 | Comparativos | Tendencias históricas |
| 31 | Notas | Observaciones y anomalías |
| 32 | Glosario | Definiciones de métricas |
---
## Implementación Backend
### GeneradorPdf.php
```php
<?php
namespace App\Services;
use App\Models\Reporte;
use Spatie\Browsershot\Browsershot;
use Illuminate\Support\Facades\Storage;
class GeneradorPdf
{
public function generar(Reporte $reporte): string
{
// URL del frontend con datos del reporte
$url = config('app.frontend_url') . '/pdf/' . $reporte->id;
// Nombre del archivo
$filename = sprintf(
'reportes/%s/%s-%s.pdf',
$reporte->cliente_id,
$reporte->periodo_fin->format('Y-m'),
now()->timestamp
);
$fullPath = storage_path('app/public/' . $filename);
// Asegurar directorio existe
$dir = dirname($fullPath);
if (!is_dir($dir)) {
mkdir($dir, 0755, true);
}
// Generar PDF con Browsershot
Browsershot::url($url)
->setNodeBinary(config('browsershot.node_binary'))
->setNpmBinary(config('browsershot.npm_binary'))
->setChromePath(config('browsershot.chrome_path'))
->format('Letter')
->margins(10, 10, 10, 10)
->showBackground()
->waitUntilNetworkIdle()
->timeout(120)
->save($fullPath);
// Actualizar reporte
$reporte->update([
'pdf_path' => $filename,
'status' => 'completado',
]);
return $filename;
}
}
```
### Configuración Browsershot
```php
// config/browsershot.php
return [
'node_binary' => env('NODE_BINARY', '/usr/bin/node'),
'npm_binary' => env('NPM_BINARY', '/usr/bin/npm'),
'chrome_path' => env('CHROME_PATH', null), // null = usa Chromium de Puppeteer
];
```
---
## Implementación Frontend
### PdfView Component
```tsx
// src/pages/PdfView/index.tsx
import { useEffect, useState } from 'react';
import { useParams } from 'react-router-dom';
import { api } from '@/services/api';
import { Reporte } from '@/types';
// Importar secciones
import Portada from './sections/Portada';
import Indice from './sections/Indice';
import ResumenEjecutivo from './sections/ResumenEjecutivo';
import BalanceGeneral from './sections/BalanceGeneral';
import EstadoResultados from './sections/EstadoResultados';
import FlujoEfectivo from './sections/FlujoEfectivo';
import AnalisisMargenes from './sections/AnalisisMargenes';
import AnalisisRetorno from './sections/AnalisisRetorno';
import AnalisisEficiencia from './sections/AnalisisEficiencia';
import AnalisisLiquidez from './sections/AnalisisLiquidez';
import AnalisisSolvencia from './sections/AnalisisSolvencia';
import AnalisisGestion from './sections/AnalisisGestion';
import Comparativos from './sections/Comparativos';
import Notas from './sections/Notas';
import Glosario from './sections/Glosario';
export default function PdfView() {
const { id } = useParams<{ id: string }>();
const [reporte, setReporte] = useState<Reporte | null>(null);
const [loading, setLoading] = useState(true);
useEffect(() => {
const fetchReporte = async () => {
try {
const data = await api.reportes.get(Number(id));
setReporte(data);
} finally {
setLoading(false);
}
};
fetchReporte();
}, [id]);
if (loading || !reporte) {
return <div>Cargando...</div>;
}
return (
<div className="pdf-container">
<Portada reporte={reporte} />
<Indice />
<ResumenEjecutivo reporte={reporte} />
<BalanceGeneral reporte={reporte} />
<EstadoResultados reporte={reporte} />
<FlujoEfectivo reporte={reporte} />
<AnalisisMargenes reporte={reporte} />
<AnalisisRetorno reporte={reporte} />
<AnalisisEficiencia reporte={reporte} />
<AnalisisLiquidez reporte={reporte} />
<AnalisisSolvencia reporte={reporte} />
<AnalisisGestion reporte={reporte} />
<Comparativos reporte={reporte} />
<Notas reporte={reporte} />
<Glosario />
</div>
);
}
```
### Estilos de Impresión
```css
/* src/styles/pdf.css */
@media print {
/* Ocultar elementos no imprimibles */
.no-print {
display: none !important;
}
/* Saltos de página */
.page-break {
page-break-after: always;
}
.page-break-before {
page-break-before: always;
}
.avoid-break {
page-break-inside: avoid;
}
}
/* Contenedor PDF */
.pdf-container {
width: 8.5in;
margin: 0 auto;
background: white;
font-family: 'Inter', sans-serif;
}
/* Página individual */
.pdf-page {
width: 8.5in;
min-height: 11in;
padding: 0.5in;
box-sizing: border-box;
position: relative;
}
/* Header de página */
.pdf-header {
display: flex;
justify-content: space-between;
align-items: center;
padding-bottom: 0.25in;
border-bottom: 2px solid #1A1F36;
margin-bottom: 0.25in;
}
/* Footer de página */
.pdf-footer {
position: absolute;
bottom: 0.25in;
left: 0.5in;
right: 0.5in;
display: flex;
justify-content: space-between;
font-size: 10px;
color: #666;
}
/* Tabla de datos */
.pdf-table {
width: 100%;
border-collapse: collapse;
font-size: 11px;
}
.pdf-table th,
.pdf-table td {
padding: 6px 8px;
text-align: left;
border-bottom: 1px solid #e5e7eb;
}
.pdf-table th {
background: #f3f4f6;
font-weight: 600;
}
/* Semáforos */
.indicator {
display: inline-block;
width: 12px;
height: 12px;
border-radius: 50%;
}
.indicator-muy_positivo { background: #059669; }
.indicator-positivo { background: #10b981; }
.indicator-neutral { background: #f59e0b; }
.indicator-negativo { background: #f97316; }
.indicator-muy_negativo { background: #ef4444; }
```
---
## Componentes de Sección
### Portada
```tsx
// src/pages/PdfView/sections/Portada.tsx
interface PortadaProps {
reporte: Reporte;
}
export default function Portada({ reporte }: PortadaProps) {
return (
<div className="pdf-page flex flex-col items-center justify-center">
{/* Logo */}
<img
src={reporte.cliente.logo || '/logo-horux.png'}
alt="Logo"
className="w-48 mb-8"
/>
{/* Nombre empresa */}
<h1 className="text-4xl font-bold text-horux-dark mb-4">
{reporte.cliente.nombre_empresa}
</h1>
{/* Tipo de reporte */}
<h2 className="text-2xl text-gray-600 mb-8">
Reporte Financiero
</h2>
{/* Periodo */}
<p className="text-xl text-gray-500">
{formatPeriodo(reporte.periodo_tipo, reporte.periodo_inicio, reporte.periodo_fin)}
</p>
{/* Fecha generación */}
<p className="text-sm text-gray-400 mt-4">
Generado: {formatDate(reporte.fecha_generacion)}
</p>
{/* Branding */}
<div className="absolute bottom-8">
<p className="text-sm text-gray-400">
Powered by Horux 360
</p>
</div>
</div>
);
}
```
### Resumen Ejecutivo
```tsx
// src/pages/PdfView/sections/ResumenEjecutivo.tsx
export default function ResumenEjecutivo({ reporte }: { reporte: Reporte }) {
const { metricas, comparativos } = reporte.data_calculada;
const kpis = [
{ nombre: 'Ingresos', valor: metricas.ingresos, formato: 'currency' },
{ nombre: 'Margen EBITDA', valor: metricas.margen_ebitda, formato: 'percent' },
{ nombre: 'Margen Neto', valor: metricas.margen_neto, formato: 'percent' },
{ nombre: 'ROIC', valor: metricas.roic, formato: 'percent' },
{ nombre: 'Current Ratio', valor: metricas.current_ratio, formato: 'number' },
{ nombre: 'Net Debt/EBITDA', valor: metricas.net_debt_ebitda, formato: 'number' },
];
return (
<>
<div className="pdf-page page-break">
<PdfHeader titulo="Resumen Ejecutivo" pagina={3} />
<div className="grid grid-cols-3 gap-4 mb-8">
{kpis.map((kpi) => (
<KpiCard key={kpi.nombre} {...kpi} />
))}
</div>
<h3 className="text-lg font-bold mb-4">Semáforos de Rendimiento</h3>
<SemaforoTable metricas={metricas} />
<PdfFooter pagina={3} />
</div>
<div className="pdf-page page-break">
<PdfHeader titulo="Resumen Ejecutivo" pagina={4} />
<h3 className="text-lg font-bold mb-4">Tendencias Principales</h3>
<TrendCharts comparativos={comparativos} />
<PdfFooter pagina={4} />
</div>
</>
);
}
```
---
## Requisitos del Servidor
### Instalación de Dependencias
```bash
# Node.js 18+
curl -fsSL https://deb.nodesource.com/setup_18.x | sudo -E bash -
sudo apt-get install -y nodejs
# Puppeteer dependencies (Ubuntu/Debian)
sudo apt-get install -y \
libnss3 \
libatk1.0-0 \
libatk-bridge2.0-0 \
libcups2 \
libdrm2 \
libxkbcommon0 \
libxcomposite1 \
libxdamage1 \
libxfixes3 \
libxrandr2 \
libgbm1 \
libasound2
# Instalar Puppeteer
cd backend
npm install puppeteer
```
### Configuración en Producción
```env
# .env
NODE_BINARY=/usr/bin/node
NPM_BINARY=/usr/bin/npm
CHROME_PATH=/usr/bin/google-chrome-stable
FRONTEND_URL=https://app.horux360.com
```
---
## Troubleshooting
### Error: "Unable to launch browser"
```bash
# Verificar Chrome instalado
which google-chrome-stable
# Instalar Chrome si no existe
wget https://dl.google.com/linux/direct/google-chrome-stable_current_amd64.deb
sudo dpkg -i google-chrome-stable_current_amd64.deb
sudo apt-get -f install
```
### Error: "Timeout exceeded"
Aumentar timeout en `GeneradorPdf.php`:
```php
Browsershot::url($url)
->timeout(300) // 5 minutos
->waitUntilNetworkIdle(false) // No esperar red
->save($fullPath);
```
### Error: "Missing fonts"
```bash
# Instalar fuentes
sudo apt-get install -y fonts-liberation fonts-noto-color-emoji
```

392
docs/10-administracion.md Normal file
View File

@@ -0,0 +1,392 @@
# 10. Panel de Administración
## Descripción
El panel de administración permite a usuarios con rol **admin** gestionar la configuración global del sistema.
---
## Acceso
- **URL**: `/admin`
- **Rol requerido**: `admin`
- **Middleware**: `auth:sanctum`, `role:admin`
---
## Secciones
### 1. Gestión de Usuarios
**Ruta**: `/admin/usuarios`
Permite crear, editar y eliminar usuarios del sistema.
| Campo | Descripción |
|-------|-------------|
| nombre | Nombre completo |
| email | Email único |
| password | Contraseña (mínimo 8 caracteres) |
| role | admin, analista, cliente, empleado |
| cliente_id | Cliente asignado (requerido para cliente/empleado) |
| activo | Estado del usuario |
#### API Endpoints
```
GET /api/admin/usuarios - Listar usuarios
POST /api/admin/usuarios - Crear usuario
GET /api/admin/usuarios/{id} - Ver usuario
PUT /api/admin/usuarios/{id} - Actualizar usuario
DELETE /api/admin/usuarios/{id} - Eliminar usuario
```
#### Ejemplo de creación
```bash
curl -X POST /api/admin/usuarios \
-H "Authorization: Bearer {token}" \
-H "Content-Type: application/json" \
-d '{
"nombre": "Juan Pérez",
"email": "juan@empresa.com",
"password": "password123",
"role": "analista"
}'
```
---
### 2. Gestión de Giros
**Ruta**: `/admin/giros`
Catálogo de giros de negocio (industrias).
| Campo | Descripción |
|-------|-------------|
| nombre | Nombre del giro |
| activo | Estado |
#### Giros predeterminados
1. Agricultura
2. Alimentación y Bebidas
3. Automotriz
4. Comercio Mayorista
5. Comercio Minorista
6. Construcción
7. Consultoría
8. Educación
9. Energía
10. Farmacéutico
11. Financiero
12. Hotelería
13. Inmobiliario
14. Logística
15. Manufactura
16. Minería
17. Publicidad
18. Salud
19. Seguros
20. Software
21. Telecomunicaciones
22. Textil
23. Transporte
24. Turismo
#### API Endpoints
```
GET /api/admin/giros - Listar giros
POST /api/admin/giros - Crear giro
PUT /api/admin/giros/{id} - Actualizar giro
DELETE /api/admin/giros/{id} - Eliminar giro
```
---
### 3. Gestión de Umbrales
**Ruta**: `/admin/umbrales`
Configuración de umbrales para el sistema de semáforos.
| Campo | Descripción |
|-------|-------------|
| metrica | Nombre de la métrica |
| muy_positivo | Umbral verde oscuro |
| positivo | Umbral verde claro |
| neutral | Umbral amarillo |
| negativo | Umbral naranja |
| muy_negativo | Umbral rojo |
| giro_id | Giro específico (null = general) |
#### Umbrales por defecto
| Métrica | Muy Positivo | Positivo | Neutral | Negativo |
|---------|--------------|----------|---------|----------|
| margen_bruto | ≥40% | ≥30% | ≥20% | ≥10% |
| margen_ebitda | ≥25% | ≥15% | ≥10% | ≥5% |
| margen_operativo | ≥20% | ≥12% | ≥8% | ≥4% |
| margen_neto | ≥15% | ≥10% | ≥5% | ≥2% |
| roic | ≥20% | ≥15% | ≥10% | ≥5% |
| roe | ≥20% | ≥15% | ≥10% | ≥5% |
| roa | ≥12% | ≥8% | ≥5% | ≥2% |
| current_ratio | ≥2.0 | ≥1.5 | ≥1.2 | ≥1.0 |
| quick_ratio | ≥1.5 | ≥1.0 | ≥0.8 | ≥0.5 |
| net_debt_ebitda | ≤1.0 | ≤2.0 | ≤3.0 | ≤4.0 |
| interest_coverage | ≥8.0 | ≥5.0 | ≥3.0 | ≥1.5 |
#### API Endpoints
```
GET /api/admin/umbrales - Listar umbrales
POST /api/admin/umbrales - Crear umbral
PUT /api/admin/umbrales/{id} - Actualizar umbral
DELETE /api/admin/umbrales/{id} - Eliminar umbral
```
#### Ejemplo: Umbral específico por giro
```bash
# Crear umbral de margen bruto específico para Hotelería
curl -X POST /api/admin/umbrales \
-H "Authorization: Bearer {token}" \
-d '{
"metrica": "margen_bruto",
"muy_positivo": 0.50,
"positivo": 0.40,
"neutral": 0.30,
"negativo": 0.20,
"giro_id": 12
}'
```
---
### 4. Reglas de Mapeo
**Ruta**: `/admin/reglas-mapeo`
Reglas para clasificar cuentas automáticamente según el sistema contable.
| Campo | Descripción |
|-------|-------------|
| sistema_origen | contpaqi, aspel, sap, etc. |
| cuenta_padre_codigo | Código de cuenta padre |
| rango_inicio | Inicio del rango de códigos |
| rango_fin | Fin del rango |
| patron_regex | Patrón regex alternativo |
| reporte_contable_id | Balance General o Estado de Resultados |
| categoria_contable_id | Categoría destino |
| prioridad | Mayor número = mayor prioridad |
| activo | Estado de la regla |
#### Reglas CONTPAQi predeterminadas
| Cuenta Padre | Rango | Categoría |
|--------------|-------|-----------|
| 001-100-000 | 101-000-000 a 154-999-999 | Activos Circulantes |
| 001-200-000 | 155-000-000 a 199-999-999 | Activos No Circulantes |
| 002-100-000 | 200-000-000 a 209-999-999 | Pasivo Circulante |
| 002-200-000 | 210-000-000 a 220-999-999 | Pasivo No Circulante |
| - | 30X-XXX-XXX | Capital Social |
| - | 310-XXX-XXX | Pérdidas Anteriores |
| - | 311-XXX-XXX | Utilidades Anteriores |
| - | 40X-XXX-XXX | Ingresos |
| - | 5XX-XXX-XXX | Gastos Operativos |
| - | 6XX-XXX-XXX | Otros Gastos |
| - | 7XX-XXX-XXX | Gastos Financieros |
#### API Endpoints
```
GET /api/admin/reglas-mapeo - Listar reglas
POST /api/admin/reglas-mapeo - Crear regla
PUT /api/admin/reglas-mapeo/{id} - Actualizar regla
DELETE /api/admin/reglas-mapeo/{id} - Eliminar regla
```
#### Ejemplo: Agregar regla para Aspel
```bash
curl -X POST /api/admin/reglas-mapeo \
-H "Authorization: Bearer {token}" \
-d '{
"sistema_origen": "aspel",
"patron_regex": "^1[0-4]\\d{2}",
"reporte_contable_id": 1,
"categoria_contable_id": 1,
"prioridad": 10,
"activo": true
}'
```
---
## Interfaz de Usuario
### Layout Admin
```tsx
// src/pages/Admin/Layout.tsx
export default function AdminLayout({ children }) {
const menuItems = [
{ path: '/admin/usuarios', label: 'Usuarios', icon: UsersIcon },
{ path: '/admin/giros', label: 'Giros', icon: BuildingIcon },
{ path: '/admin/umbrales', label: 'Umbrales', icon: ChartIcon },
{ path: '/admin/reglas-mapeo', label: 'Reglas Mapeo', icon: MapIcon },
];
return (
<div className="flex">
<aside className="w-64 bg-horux-dark min-h-screen p-4">
<h2 className="text-white text-xl font-bold mb-6">Administración</h2>
<nav>
{menuItems.map((item) => (
<NavLink
key={item.path}
to={item.path}
className={({ isActive }) =>
`flex items-center px-4 py-2 rounded ${
isActive ? 'bg-horux-primary text-white' : 'text-gray-300 hover:bg-gray-700'
}`
}
>
<item.icon className="w-5 h-5 mr-3" />
{item.label}
</NavLink>
))}
</nav>
</aside>
<main className="flex-1 p-8">{children}</main>
</div>
);
}
```
### Tabla CRUD genérica
```tsx
// src/components/admin/CrudTable.tsx
interface CrudTableProps<T> {
data: T[];
columns: Column<T>[];
onEdit: (item: T) => void;
onDelete: (item: T) => void;
onCreate: () => void;
title: string;
}
export default function CrudTable<T extends { id: number }>({
data,
columns,
onEdit,
onDelete,
onCreate,
title,
}: CrudTableProps<T>) {
return (
<div>
<div className="flex justify-between items-center mb-6">
<h1 className="text-2xl font-bold">{title}</h1>
<button
onClick={onCreate}
className="bg-horux-primary text-white px-4 py-2 rounded hover:bg-horux-secondary"
>
+ Nuevo
</button>
</div>
<table className="w-full border-collapse">
<thead>
<tr className="bg-gray-100">
{columns.map((col) => (
<th key={col.key} className="p-3 text-left">{col.label}</th>
))}
<th className="p-3 text-right">Acciones</th>
</tr>
</thead>
<tbody>
{data.map((item) => (
<tr key={item.id} className="border-b hover:bg-gray-50">
{columns.map((col) => (
<td key={col.key} className="p-3">
{col.render ? col.render(item) : item[col.key]}
</td>
))}
<td className="p-3 text-right">
<button
onClick={() => onEdit(item)}
className="text-blue-600 hover:text-blue-800 mr-3"
>
Editar
</button>
<button
onClick={() => onDelete(item)}
className="text-red-600 hover:text-red-800"
>
Eliminar
</button>
</td>
</tr>
))}
</tbody>
</table>
</div>
);
}
```
---
## Auditoría
Todas las acciones administrativas se registran en el log:
```php
// Ejemplo en AdminController
Log::channel('admin')->info('Usuario creado', [
'admin_id' => auth()->id(),
'user_id' => $user->id,
'email' => $user->email,
'ip' => request()->ip(),
]);
```
### Configuración de logging
```php
// config/logging.php
'channels' => [
'admin' => [
'driver' => 'daily',
'path' => storage_path('logs/admin.log'),
'level' => 'info',
'days' => 90,
],
],
```
---
## Permisos por Rol
| Acción | Admin | Analista | Cliente | Empleado |
|--------|-------|----------|---------|----------|
| Gestionar usuarios | ✓ | ✗ | ✗ | ✗ |
| Gestionar giros | ✓ | ✗ | ✗ | ✗ |
| Gestionar umbrales | ✓ | ✗ | ✗ | ✗ |
| Gestionar reglas mapeo | ✓ | ✗ | ✗ | ✗ |
| Ver todos los clientes | ✓ | ✓ | ✗ | ✗ |
| Crear clientes | ✓ | ✓ | ✗ | ✗ |
| Subir balanzas | ✓ | ✓ | ✗ | ✗ |
| Generar reportes | ✓ | ✓ | ✗ | ✗ |
| Ver dashboard propio | ✓ | ✓ | ✓ | * |
| Descargar PDF | ✓ | ✓ | ✓ | * |
\* Según permisos configurados

35
docs/README.md Normal file
View File

@@ -0,0 +1,35 @@
# Documentación - Horux Strategy Platform
## Índice
1. [Descripción General](./01-descripcion-general.md)
2. [Arquitectura del Sistema](./02-arquitectura.md)
3. [Instalación y Configuración](./03-instalacion.md)
4. [API Reference](./04-api-reference.md)
5. [Guía del Frontend](./05-frontend.md)
6. [Base de Datos](./06-base-de-datos.md)
7. [Parsers de Balanzas](./07-parsers.md)
8. [Métricas Financieras](./08-metricas.md)
9. [Generación de PDF](./09-pdf.md)
10. [Administración](./10-administracion.md)
## Inicio Rápido
```bash
# Backend
cd backend
composer install
cp .env.example .env
php artisan key:generate
php artisan migrate --seed
php artisan serve
# Frontend (otra terminal)
cd frontend
npm install
npm run dev
```
Accede a http://localhost:5173 con:
- Email: admin@horux360.com
- Password: password

View File

@@ -0,0 +1,384 @@
# Horux Strategy Platform - Diseño de Sistema
**Fecha:** 2025-01-31
**Proyecto:** Plataforma de Reportes Financieros
**Cliente:** Horux 360
---
## 1. Resumen Ejecutivo
Plataforma web para generar reportes financieros automatizados a partir de balanzas de comprobación. Permite a empresas subir sus datos contables de múltiples sistemas (CONTPAQi, Aspel, SAP, etc.) y obtener dashboards interactivos con métricas financieras y exportación a PDF profesional.
---
## 2. Stack Tecnológico
| Componente | Tecnología |
|------------|------------|
| Backend | Laravel 11 (API REST) |
| Autenticación | Laravel Sanctum |
| Frontend | React 18 + TypeScript |
| Base de datos | MySQL / PostgreSQL |
| Gráficas | Recharts |
| Generación PDF | Puppeteer / Browsershot |
| Parsing PDFs | spatie/pdf-to-text + regex |
---
## 3. Roles de Usuario
| Rol | Permisos |
|-----|----------|
| **Administrador** | Acceso total, configuración global, gestión de umbrales |
| **Analista** | Gestionar clientes asignados, procesar balanzas, generar reportes |
| **Cliente** | Ver dashboard propio, descargar PDFs, gestionar empleados |
| **Empleado** | Permisos configurables por el cliente |
---
## 4. Sistemas Contables Soportados
- CONTPAQi (inicial, con ejemplos)
- Aspel
- Alegra
- SAP
- Odoo
- Parser genérico (CSV/Excel configurable)
### 4.1 Arquitectura de Parsers
```
Upload archivo → Detector de formato → Parser específico → Formato normalizado
```
Cada parser normaliza los datos a una estructura estándar interna, permitiendo agregar nuevos sistemas sin modificar el resto del código.
---
## 5. Modelo de Datos
### 5.1 Usuarios y Acceso
```sql
-- users
id, nombre, email, password, role, cliente_id (nullable)
-- clientes
id, nombre_empresa, logo, giro_id, moneda, configuracion (JSON)
-- permisos_empleado
user_id, cliente_id, permisos (JSON)
```
### 5.2 Catálogos
```sql
-- giros
id, nombre, activo
-- umbrales
id, metrica, muy_positivo, positivo, neutral, negativo, muy_negativo, giro_id
-- reportes_contables
id, nombre ("Balance General", "Estado de Resultados")
-- categorias_contables
id, reporte_contable_id, nombre, orden
```
### 5.3 Categorías Contables
**Balance General:**
| ID | Categoría |
|----|-----------|
| 1 | Activos Circulantes |
| 2 | Activos No Circulantes |
| 3 | Pasivo Circulante |
| 4 | Pasivo No Circulante |
| 5 | Capital Social |
| 6 | Pérdidas Ejercicios Anteriores |
| 7 | Utilidades Ejercicios Anteriores |
**Estado de Resultados:**
| ID | Categoría |
|----|-----------|
| 8 | Ingresos |
| 9 | Costo de Venta |
| 10 | Gastos Operativos |
| 11 | Otros Gastos |
| 12 | Gastos Financieros |
### 5.4 Balanzas y Cuentas
```sql
-- balanzas
id, cliente_id, periodo_inicio, periodo_fin, sistema_origen, archivo_original, status
-- cuentas
id, balanza_id, codigo, nombre, nivel,
reporte_contable_id, categoria_contable_id, cuenta_padre_id,
saldo_inicial_deudor, saldo_inicial_acreedor,
cargos, abonos,
saldo_final_deudor, saldo_final_acreedor,
excluida (boolean)
-- reglas_mapeo
id, sistema_origen, cuenta_padre_codigo,
rango_hijo_inicio, rango_hijo_fin,
reporte_contable_id, categoria_contable_id, prioridad
-- mapeo_cuentas (excepciones por cliente)
cliente_id, codigo_patron, categoria_destino, notas
```
### 5.5 Reportes
```sql
-- reportes
id, cliente_id, nombre, periodo_tipo, fecha_generacion, data_calculada (JSON), pdf_path
```
---
## 6. Reglas de Mapeo Contable (CONTPAQi)
| Cuenta Padre | Rango Hijos | Reporte | Categoría |
|--------------|-------------|---------|-----------|
| 001-100-000 | 101-000-000 a 154-999-999 | Balance | Activos Circulantes |
| 001-200-000 | 155-000-000 a 199-999-999 | Balance | Activos No Circulantes |
| 002-100-000 | 200-000-000 a 209-999-999 | Balance | Pasivo Circulante |
| 002-200-000 | 210-000-000 a 220-999-999 | Balance | Pasivo No Circulante |
| 300-000-000 | - | Balance | Capital Social |
| 310-000-000 | - | Balance | Pérdidas Ejercicios Anteriores |
| 311-000-000 | - | Balance | Utilidades Ejercicios Anteriores |
| 40X-000-000 | 401 a 409 | Edo. Resultados | Ingresos |
| 5XX-000-000 | 500 a 599 | Edo. Resultados | Gastos Operativos |
| 6XX-000-000 | 600 a 699 | Edo. Resultados | Otros Gastos |
| 70X-000-000 | 700 a 799 | Edo. Resultados | Gastos Financieros |
---
## 7. Flujo de Usuario
1. **Crear/seleccionar cliente** - Nombre, logo, giro, moneda
2. **Subir balanzas** - 2+ archivos PDF/Excel/CSV
3. **Detección automática** - Sistema identifica origen (CONTPAQi, etc.)
4. **Clasificación automática** - Mapeo a categorías contables
5. **Revisión de anomalías** - Corregir cuentas mal clasificadas
6. **Limpieza de cuentas** - Desmarcar cuentas a excluir
7. **Procesamiento** - Cálculo de métricas
8. **Dashboard** - Visualización interactiva
9. **Exportar PDF** - Descarga de reporte
---
## 8. Métricas Financieras
### 8.1 Estados Financieros Calculados
- Balance General
- Estado de Resultados
- Flujo de Efectivo (método indirecto)
### 8.2 Métricas por Categoría
**Márgenes:**
- Margen Bruto = Utilidad Bruta / Ingresos
- Margen EBITDA = EBITDA / Ingresos
- Margen Operativo = EBIT / Ingresos
- Margen Neto = Utilidad Neta / Ingresos
- Margen NOPAT = NOPAT / Ingresos
- Margen OCF = Flujo Operación / Ingresos
- Margen FCF = Flujo Libre / Ingresos
**Retorno:**
- ROIC = NOPAT / Capital Invertido
- ROE = Utilidad Neta / Capital
- ROA = Utilidad Neta / Activo Total
- ROCE = EBIT / Capital Empleado
**Eficiencia:**
- Asset Turnover = Ingresos / Activo Total
- Inventory Turnover = Costo Venta / Inventario
- Días Clientes = (Clientes / Ingresos) × 365
- Días Proveedores = (Proveedores / Costo) × 365
- Días Inventario = (Inventario / Costo) × 365
- Ciclo Conversión = Días Clientes + Días Inv. - Días Prov.
**Liquidez:**
- Current Ratio = Activo Circ. / Pasivo Circ.
- Quick Ratio = (Activo Circ. - Inventario) / Pasivo Circ.
- Cash Ratio = Efectivo / Pasivo Circ.
**Solvencia:**
- Net Debt / EBITDA = (Deuda Total - Efectivo) / EBITDA
- Interest Coverage = EBITDA / Gastos Financieros
- Debt Ratio = Deuda Total / Activo Total
**Gestión:**
- Revenue Growth = (Ingreso Actual - Anterior) / Anterior
- Key Score = Crecimiento Ingreso 12m + Margen EBITDA 12m
- CapEx / Revenue = CAPEX / Ingresos
- Effective Tax Rate = Impuestos / EBT
### 8.3 Comparativos
Para cada métrica:
- Valor actual
- Promedio 3 periodos
- Periodo anterior
- Mismo periodo año anterior
- Variación absoluta y porcentual
- Tendencia (Muy positiva → Muy negativa)
---
## 9. Dashboard
### 9.1 Secciones
1. Mensajes Destacados (KPIs + insights)
2. Resumen Mensual
3. Resumen 12m
4. Márgenes
5. Márgenes Deep Dive
6. Resultados
7. Balance
8. Capital de Trabajo
9. Flujo de Efectivo
10. Métricas
11. Indicadores
12. Negocios (por unidad)
13. Estados Financieros
### 9.2 Componentes React
```
components/
├── charts/
│ ├── BarChart.tsx
│ ├── LineChart.tsx
│ ├── StackedBarChart.tsx
│ ├── WaterfallChart.tsx
│ └── ComboChart.tsx
├── cards/
│ ├── KPICard.tsx
│ ├── InsightCard.tsx
│ └── MetricTable.tsx
├── tables/
│ ├── FinancialStatement.tsx
│ └── MetricsGrid.tsx
└── layout/
├── DashboardNav.tsx
├── PeriodSelector.tsx
└── ExportButton.tsx
```
---
## 10. Panel Administrativo
### 10.1 Módulos
1. Dashboard admin (estadísticas)
2. Gestión de usuarios
3. Gestión de clientes
4. Catálogo de giros
5. Configuración de umbrales
6. Reglas de mapeo contable
7. Parsers de sistemas
8. Configuración general
### 10.2 Gestión de Empleados (Cliente)
El cliente puede:
- Agregar empleados
- Configurar permisos granulares por empleado
- Permisos disponibles: ver dashboard, ver estados financieros, exportar PDF, etc.
---
## 11. Generación de PDF
### 11.1 Enfoque
Usar Puppeteer/Browsershot para renderizar el dashboard de React a PDF, manteniendo el mismo diseño pixel-perfect.
### 11.2 Estructura (32 páginas)
1. Portada
2. Mensajes Destacados
3. Separador "Resumen"
4. Resumen Mensual
5. Resumen 12m
6. Márgenes
7. Márgenes Deep Dive
8. Separador "Resultados"
9. Resultados
10. Separador "Balance"
11. Balance
12. Capital de Trabajo
13. Separador "Flujo"
14. Flujo de Efectivo
15. Separador "Métricas"
16-17. Métricas
18. Separador "Indicadores"
19. Indicadores
20. Separador "Negocios"
21-22. Negocios por unidad
23. Separador "Estados Financieros"
24-25. Tabla de Métricas
26-27. Estado de Resultados
28-29. Subcategorías Costo/Gasto
30. Balance General
31. Flujo de Efectivo
32. Contraportada
---
## 12. Estructura del Proyecto
```
monthly-platform/
├── backend/ # Laravel
│ ├── app/
│ │ ├── Http/Controllers/
│ │ ├── Models/
│ │ ├── Services/
│ │ │ ├── Parsers/
│ │ │ │ ├── ParserInterface.php
│ │ │ │ ├── ContpaqiParser.php
│ │ │ │ ├── AspelParser.php
│ │ │ │ └── GenericoParser.php
│ │ │ ├── DetectorFormato.php
│ │ │ ├── ClasificadorCuentas.php
│ │ │ ├── CalculadorMetricas.php
│ │ │ └── GeneradorPdf.php
│ │ └── ...
│ ├── database/migrations/
│ └── routes/api.php
└── frontend/ # React
├── src/
│ ├── components/
│ ├── pages/
│ │ ├── Dashboard/
│ │ ├── Admin/
│ │ ├── Cliente/
│ │ └── PdfView/
│ ├── hooks/
│ ├── services/
│ └── utils/
└── ...
```
---
## 13. Consideraciones Futuras
- Integración directa con APIs de sistemas contables
- Generación de insights con IA
- Comparativas con benchmarks de industria (datos reales)
- App móvil para consulta de reportes
- Alertas automáticas por email cuando métricas salen de rango

View File

@@ -0,0 +1,355 @@
# Horux Strategy Platform - Plan de Implementación
**Fecha:** 2025-01-31
**Documento de diseño:** 2025-01-31-horux-strategy-design.md
---
## Fases de Implementación
### FASE 1: Fundamentos (Backend)
#### 1.1 Configuración del proyecto Laravel
- [ ] Crear proyecto Laravel 11
- [ ] Configurar base de datos (MySQL/PostgreSQL)
- [ ] Instalar y configurar Laravel Sanctum
- [ ] Configurar CORS para React
#### 1.2 Migraciones de base de datos
- [ ] Tabla `users` (con campo role)
- [ ] Tabla `clientes`
- [ ] Tabla `giros`
- [ ] Tabla `permisos_empleado`
- [ ] Tabla `reportes_contables`
- [ ] Tabla `categorias_contables`
- [ ] Tabla `umbrales`
- [ ] Tabla `balanzas`
- [ ] Tabla `cuentas`
- [ ] Tabla `reglas_mapeo`
- [ ] Tabla `mapeo_cuentas`
- [ ] Tabla `reportes`
- [ ] Seeders para catálogos iniciales (giros, categorías, reglas CONTPAQi)
#### 1.3 Modelos y relaciones
- [ ] User (con roles)
- [ ] Cliente
- [ ] Giro
- [ ] PermisoEmpleado
- [ ] Umbral
- [ ] Balanza
- [ ] Cuenta
- [ ] ReglaMappeo
- [ ] Reporte
#### 1.4 Sistema de autenticación
- [ ] Login / Logout
- [ ] Registro (solo admin puede crear usuarios)
- [ ] Middleware por rol
- [ ] Policies para autorización
---
### FASE 2: Parser de Balanzas
#### 2.1 Arquitectura de parsers
- [ ] Crear `ParserInterface.php`
- [ ] Crear `DetectorFormato.php`
- [ ] Implementar `ContpaqiParser.php`
- [ ] Crear `ParserGenerico.php` (CSV/Excel)
#### 2.2 Procesamiento de archivos
- [ ] Endpoint para upload de archivos
- [ ] Extracción de texto de PDF
- [ ] Parsing de estructura CONTPAQi
- [ ] Normalización a formato interno
- [ ] Almacenamiento en tabla `cuentas`
#### 2.3 Clasificación automática
- [ ] Crear `ClasificadorCuentas.php`
- [ ] Aplicar reglas de mapeo
- [ ] Detectar anomalías
- [ ] Marcar cuentas que requieren revisión
---
### FASE 3: Motor de Cálculo
#### 3.1 Calculador de estados financieros
- [ ] Crear `CalculadorMetricas.php`
- [ ] Calcular Balance General
- [ ] Calcular Estado de Resultados
- [ ] Calcular Flujo de Efectivo (método indirecto)
#### 3.2 Cálculo de métricas
- [ ] Métricas de márgenes (7 métricas)
- [ ] Métricas de retorno (4 métricas)
- [ ] Métricas de eficiencia (6 métricas)
- [ ] Métricas de liquidez (3 métricas)
- [ ] Métricas de solvencia (3 métricas)
- [ ] Métricas de gestión (4 métricas)
#### 3.3 Comparativos
- [ ] Calcular promedio 3 periodos
- [ ] Comparar con periodo anterior
- [ ] Comparar con año anterior
- [ ] Calcular variaciones
- [ ] Determinar tendencia según umbrales
---
### FASE 4: API REST
#### 4.1 Endpoints de autenticación
- [ ] POST /api/login
- [ ] POST /api/logout
- [ ] GET /api/user
#### 4.2 Endpoints de clientes
- [ ] GET /api/clientes
- [ ] POST /api/clientes
- [ ] GET /api/clientes/{id}
- [ ] PUT /api/clientes/{id}
- [ ] DELETE /api/clientes/{id}
#### 4.3 Endpoints de balanzas
- [ ] POST /api/clientes/{id}/balanzas (upload)
- [ ] GET /api/clientes/{id}/balanzas
- [ ] GET /api/balanzas/{id}/cuentas
- [ ] PUT /api/balanzas/{id}/cuentas (actualizar exclusiones)
- [ ] PUT /api/cuentas/{id}/clasificacion (corregir anomalía)
#### 4.4 Endpoints de reportes
- [ ] POST /api/clientes/{id}/reportes (generar)
- [ ] GET /api/clientes/{id}/reportes
- [ ] GET /api/reportes/{id}
- [ ] GET /api/reportes/{id}/pdf
#### 4.5 Endpoints administrativos
- [ ] CRUD /api/admin/usuarios
- [ ] CRUD /api/admin/giros
- [ ] CRUD /api/admin/umbrales
- [ ] CRUD /api/admin/reglas-mapeo
---
### FASE 5: Frontend - Fundamentos
#### 5.1 Configuración del proyecto React
- [ ] Crear proyecto con Vite + TypeScript
- [ ] Configurar React Router
- [ ] Configurar Axios para API
- [ ] Configurar Recharts
- [ ] Configurar Tailwind CSS
#### 5.2 Autenticación
- [ ] Página de Login
- [ ] Context de autenticación
- [ ] Rutas protegidas por rol
- [ ] Interceptor para tokens
#### 5.3 Layout base
- [ ] Sidebar de navegación
- [ ] Header con usuario
- [ ] Layout para admin
- [ ] Layout para cliente
---
### FASE 6: Frontend - Flujo Principal
#### 6.1 Gestión de clientes
- [ ] Lista de clientes
- [ ] Formulario crear/editar cliente
- [ ] Subida de logo
#### 6.2 Subida de balanzas
- [ ] Componente de upload (drag & drop)
- [ ] Preview de archivos
- [ ] Indicador de progreso
- [ ] Detección de sistema origen
#### 6.3 Revisión y limpieza
- [ ] Vista de anomalías con corrección
- [ ] Lista de cuentas con checkboxes
- [ ] Filtros y búsqueda
- [ ] Guardar exclusiones
---
### FASE 7: Frontend - Dashboard
#### 7.1 Componentes de gráficas
- [ ] BarChart
- [ ] LineChart
- [ ] StackedBarChart
- [ ] WaterfallChart
- [ ] ComboChart
#### 7.2 Componentes de cards
- [ ] KPICard (con semáforo)
- [ ] InsightCard
- [ ] MetricTable
#### 7.3 Secciones del dashboard
- [ ] Mensajes Destacados
- [ ] Resumen Mensual
- [ ] Resumen 12m
- [ ] Márgenes
- [ ] Márgenes Deep Dive
- [ ] Resultados
- [ ] Balance
- [ ] Capital de Trabajo
- [ ] Flujo de Efectivo
- [ ] Métricas
- [ ] Indicadores
- [ ] Negocios
- [ ] Estados Financieros
---
### FASE 8: Generación de PDF
#### 8.1 Backend
- [ ] Instalar Browsershot
- [ ] Crear `GeneradorPdf.php`
- [ ] Endpoint GET /api/reportes/{id}/pdf
#### 8.2 Frontend
- [ ] Vista `PdfView` con todas las páginas
- [ ] Estilos específicos para impresión
- [ ] Separadores de sección
- [ ] Portada y contraportada
---
### FASE 9: Panel Administrativo
#### 9.1 Dashboard admin
- [ ] Estadísticas generales
- [ ] Alertas pendientes
#### 9.2 Gestión de usuarios
- [ ] CRUD de usuarios
- [ ] Asignación de roles
#### 9.3 Configuración
- [ ] Editor de umbrales
- [ ] Editor de reglas de mapeo
- [ ] Editor de giros
---
### FASE 10: Funcionalidades de Cliente
#### 10.1 Gestión de empleados
- [ ] Lista de empleados
- [ ] Crear empleado
- [ ] Configurar permisos
#### 10.2 Configuración
- [ ] Exclusiones guardadas
- [ ] Preferencias de reporte
---
### FASE 11: Testing y Refinamiento
#### 11.1 Testing
- [ ] Tests unitarios del motor de cálculo
- [ ] Tests de parsers
- [ ] Tests de API
- [ ] Tests E2E del flujo principal
#### 11.2 Refinamiento
- [ ] Optimización de rendimiento
- [ ] Manejo de errores
- [ ] Validaciones
- [ ] UX/UI polish
---
## Prioridad de Implementación
1. **MVP (Fases 1-4, 5-7):** Sistema funcional con CONTPAQi, dashboard básico
2. **PDF (Fase 8):** Exportación de reportes
3. **Admin (Fase 9):** Panel de configuración
4. **Multi-usuario (Fase 10):** Funcionalidades de cliente
5. **Calidad (Fase 11):** Testing y refinamiento
---
## Archivos Clave a Crear
### Backend (Laravel)
```
app/
├── Http/Controllers/
│ ├── AuthController.php
│ ├── ClienteController.php
│ ├── BalanzaController.php
│ ├── CuentaController.php
│ ├── ReporteController.php
│ └── Admin/
│ ├── UsuarioController.php
│ ├── UmbralController.php
│ └── ReglaMappeoController.php
├── Models/
│ ├── User.php
│ ├── Cliente.php
│ ├── Balanza.php
│ ├── Cuenta.php
│ ├── Reporte.php
│ └── ...
├── Services/
│ ├── Parsers/
│ │ ├── ParserInterface.php
│ │ ├── ContpaqiParser.php
│ │ └── DetectorFormato.php
│ ├── ClasificadorCuentas.php
│ ├── CalculadorMetricas.php
│ └── GeneradorPdf.php
└── ...
```
### Frontend (React)
```
src/
├── components/
│ ├── charts/
│ │ ├── BarChart.tsx
│ │ ├── LineChart.tsx
│ │ ├── StackedBarChart.tsx
│ │ ├── WaterfallChart.tsx
│ │ └── ComboChart.tsx
│ ├── cards/
│ │ ├── KPICard.tsx
│ │ └── InsightCard.tsx
│ ├── forms/
│ │ ├── ClienteForm.tsx
│ │ └── UploadBalanza.tsx
│ └── layout/
│ ├── Sidebar.tsx
│ └── Header.tsx
├── pages/
│ ├── Login.tsx
│ ├── Dashboard/
│ │ ├── index.tsx
│ │ ├── Resumen.tsx
│ │ ├── Margenes.tsx
│ │ └── ...
│ ├── Admin/
│ │ ├── Usuarios.tsx
│ │ └── Umbrales.tsx
│ └── PdfView/
│ └── index.tsx
├── hooks/
│ ├── useAuth.ts
│ ├── useCliente.ts
│ └── useReporte.ts
├── services/
│ └── api.ts
└── types/
└── index.ts
```