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,21 @@
<?php
namespace Database\Seeders;
use App\Models\User;
use Illuminate\Database\Seeder;
use Illuminate\Support\Facades\Hash;
class AdminUserSeeder extends Seeder
{
public function run(): void
{
User::create([
'nombre' => 'Administrador',
'email' => 'admin@horux360.com',
'password' => Hash::make('password'),
'role' => 'admin',
'cliente_id' => null,
]);
}
}

View File

@@ -0,0 +1,19 @@
<?php
namespace Database\Seeders;
use Illuminate\Database\Seeder;
class DatabaseSeeder extends Seeder
{
public function run(): void
{
$this->call([
GirosSeeder::class,
ReportesContablesSeeder::class,
ReglasMapeeoContpaqiSeeder::class,
UmbralesSeeder::class,
AdminUserSeeder::class,
]);
}
}

View File

@@ -0,0 +1,43 @@
<?php
namespace Database\Seeders;
use App\Models\Giro;
use Illuminate\Database\Seeder;
class GirosSeeder extends Seeder
{
public function run(): void
{
$giros = [
'Agricultura y Ganadería',
'Alimentos y Bebidas',
'Automotriz',
'Comercio al por Mayor',
'Comercio al por Menor',
'Construcción',
'Educación',
'Energía',
'Farmacéutica',
'Financiero',
'Hotelería',
'Inmobiliario',
'Logística y Transporte',
'Manufactura',
'Medios y Entretenimiento',
'Minería',
'Restaurantes',
'Salud',
'Servicios Profesionales',
'Tecnología',
'Telecomunicaciones',
'Textil y Moda',
'Turismo',
'Otro',
];
foreach ($giros as $nombre) {
Giro::create(['nombre' => $nombre, 'activo' => true]);
}
}
}

View File

@@ -0,0 +1,142 @@
<?php
namespace Database\Seeders;
use App\Models\ReglaMapeo;
use App\Models\ReporteContable;
use App\Models\CategoriaContable;
use Illuminate\Database\Seeder;
class ReglasMapeeoContpaqiSeeder extends Seeder
{
public function run(): void
{
$balanceGeneral = ReporteContable::where('nombre', 'Balance General')->first();
$estadoResultados = ReporteContable::where('nombre', 'Estado de Resultados')->first();
// Obtener categorías
$activosCirculantes = CategoriaContable::where('nombre', 'Activos Circulantes')->first();
$activosNoCirculantes = CategoriaContable::where('nombre', 'Activos No Circulantes')->first();
$pasivoCirculante = CategoriaContable::where('nombre', 'Pasivo Circulante')->first();
$pasivoNoCirculante = CategoriaContable::where('nombre', 'Pasivo No Circulante')->first();
$capitalSocial = CategoriaContable::where('nombre', 'Capital Social')->first();
$perdidasAnteriores = CategoriaContable::where('nombre', 'Pérdidas Ejercicios Anteriores')->first();
$utilidadesAnteriores = CategoriaContable::where('nombre', 'Utilidades Ejercicios Anteriores')->first();
$ingresos = CategoriaContable::where('nombre', 'Ingresos')->first();
$costoVenta = CategoriaContable::where('nombre', 'Costo de Venta')->first();
$gastosOperativos = CategoriaContable::where('nombre', 'Gastos Operativos')->first();
$otrosGastos = CategoriaContable::where('nombre', 'Otros Gastos')->first();
$gastosFinancieros = CategoriaContable::where('nombre', 'Gastos Financieros')->first();
$reglas = [
// Activos Circulantes: 001-100-000, hijos 101-000-000 a 154-999-999
[
'sistema_origen' => 'contpaqi',
'cuenta_padre_codigo' => '001-100-000',
'rango_inicio' => '101-000-000',
'rango_fin' => '154-999-999',
'reporte_contable_id' => $balanceGeneral->id,
'categoria_contable_id' => $activosCirculantes->id,
'prioridad' => 10,
],
// Activos No Circulantes: 001-200-000, hijos 155-000-000 a 199-999-999
[
'sistema_origen' => 'contpaqi',
'cuenta_padre_codigo' => '001-200-000',
'rango_inicio' => '155-000-000',
'rango_fin' => '199-999-999',
'reporte_contable_id' => $balanceGeneral->id,
'categoria_contable_id' => $activosNoCirculantes->id,
'prioridad' => 10,
],
// Pasivo Circulante: 002-100-000, hijos 200-000-000 a 209-999-999
[
'sistema_origen' => 'contpaqi',
'cuenta_padre_codigo' => '002-100-000',
'rango_inicio' => '200-000-000',
'rango_fin' => '209-999-999',
'reporte_contable_id' => $balanceGeneral->id,
'categoria_contable_id' => $pasivoCirculante->id,
'prioridad' => 10,
],
// Pasivo No Circulante: 002-200-000, hijos 210-000-000 a 220-999-999
[
'sistema_origen' => 'contpaqi',
'cuenta_padre_codigo' => '002-200-000',
'rango_inicio' => '210-000-000',
'rango_fin' => '220-999-999',
'reporte_contable_id' => $balanceGeneral->id,
'categoria_contable_id' => $pasivoNoCirculante->id,
'prioridad' => 10,
],
// Capital Social: 300-XXX-XXX
[
'sistema_origen' => 'contpaqi',
'patron_regex' => '/^30[0-9]-/',
'reporte_contable_id' => $balanceGeneral->id,
'categoria_contable_id' => $capitalSocial->id,
'prioridad' => 10,
],
// Pérdidas Ejercicios Anteriores: 310-XXX-XXX
[
'sistema_origen' => 'contpaqi',
'patron_regex' => '/^310-/',
'reporte_contable_id' => $balanceGeneral->id,
'categoria_contable_id' => $perdidasAnteriores->id,
'prioridad' => 15,
],
// Utilidades Ejercicios Anteriores: 311-XXX-XXX
[
'sistema_origen' => 'contpaqi',
'patron_regex' => '/^311-/',
'reporte_contable_id' => $balanceGeneral->id,
'categoria_contable_id' => $utilidadesAnteriores->id,
'prioridad' => 15,
],
// Ingresos: 40X-XXX-XXX
[
'sistema_origen' => 'contpaqi',
'patron_regex' => '/^40[0-9]-/',
'reporte_contable_id' => $estadoResultados->id,
'categoria_contable_id' => $ingresos->id,
'prioridad' => 10,
],
// Costo de Venta: podría ser 410-XXX o 50X en algunos casos
[
'sistema_origen' => 'contpaqi',
'patron_regex' => '/^41[0-9]-/',
'reporte_contable_id' => $estadoResultados->id,
'categoria_contable_id' => $costoVenta->id,
'prioridad' => 10,
],
// Gastos Operativos: 5XX-XXX-XXX
[
'sistema_origen' => 'contpaqi',
'patron_regex' => '/^5[0-9]{2}-/',
'reporte_contable_id' => $estadoResultados->id,
'categoria_contable_id' => $gastosOperativos->id,
'prioridad' => 10,
],
// Otros Gastos: 6XX-XXX-XXX
[
'sistema_origen' => 'contpaqi',
'patron_regex' => '/^6[0-9]{2}-/',
'reporte_contable_id' => $estadoResultados->id,
'categoria_contable_id' => $otrosGastos->id,
'prioridad' => 10,
],
// Gastos Financieros: 7XX-XXX-XXX
[
'sistema_origen' => 'contpaqi',
'patron_regex' => '/^7[0-9]{2}-/',
'reporte_contable_id' => $estadoResultados->id,
'categoria_contable_id' => $gastosFinancieros->id,
'prioridad' => 10,
],
];
foreach ($reglas as $regla) {
ReglaMapeo::create(array_merge($regla, ['activo' => true]));
}
}
}

View File

@@ -0,0 +1,53 @@
<?php
namespace Database\Seeders;
use App\Models\ReporteContable;
use App\Models\CategoriaContable;
use Illuminate\Database\Seeder;
class ReportesContablesSeeder extends Seeder
{
public function run(): void
{
// Balance General
$balanceGeneral = ReporteContable::create(['nombre' => 'Balance General']);
$categoriasBalance = [
['nombre' => 'Activos Circulantes', 'orden' => 1],
['nombre' => 'Activos No Circulantes', 'orden' => 2],
['nombre' => 'Pasivo Circulante', 'orden' => 3],
['nombre' => 'Pasivo No Circulante', 'orden' => 4],
['nombre' => 'Capital Social', 'orden' => 5],
['nombre' => 'Pérdidas Ejercicios Anteriores', 'orden' => 6],
['nombre' => 'Utilidades Ejercicios Anteriores', 'orden' => 7],
];
foreach ($categoriasBalance as $categoria) {
CategoriaContable::create([
'reporte_contable_id' => $balanceGeneral->id,
'nombre' => $categoria['nombre'],
'orden' => $categoria['orden'],
]);
}
// Estado de Resultados
$estadoResultados = ReporteContable::create(['nombre' => 'Estado de Resultados']);
$categoriasResultados = [
['nombre' => 'Ingresos', 'orden' => 1],
['nombre' => 'Costo de Venta', 'orden' => 2],
['nombre' => 'Gastos Operativos', 'orden' => 3],
['nombre' => 'Otros Gastos', 'orden' => 4],
['nombre' => 'Gastos Financieros', 'orden' => 5],
];
foreach ($categoriasResultados as $categoria) {
CategoriaContable::create([
'reporte_contable_id' => $estadoResultados->id,
'nombre' => $categoria['nombre'],
'orden' => $categoria['orden'],
]);
}
}
}

View File

@@ -0,0 +1,55 @@
<?php
namespace Database\Seeders;
use App\Models\Umbral;
use Illuminate\Database\Seeder;
class UmbralesSeeder extends Seeder
{
public function run(): void
{
// Umbrales por defecto (sin giro específico)
$umbrales = [
// Márgenes (valores en decimales, ej: 0.20 = 20%)
['metrica' => 'margen_bruto', 'muy_positivo' => 0.50, 'positivo' => 0.35, 'neutral' => 0.20, 'negativo' => 0.10, 'muy_negativo' => 0],
['metrica' => 'margen_ebitda', 'muy_positivo' => 0.30, 'positivo' => 0.20, 'neutral' => 0.10, 'negativo' => 0.05, 'muy_negativo' => 0],
['metrica' => 'margen_operativo', 'muy_positivo' => 0.25, 'positivo' => 0.15, 'neutral' => 0.08, 'negativo' => 0.03, 'muy_negativo' => 0],
['metrica' => 'margen_neto', 'muy_positivo' => 0.20, 'positivo' => 0.10, 'neutral' => 0.05, 'negativo' => 0.02, 'muy_negativo' => 0],
['metrica' => 'margen_nopat', 'muy_positivo' => 0.18, 'positivo' => 0.10, 'neutral' => 0.05, 'negativo' => 0.02, 'muy_negativo' => 0],
['metrica' => 'margen_ocf', 'muy_positivo' => 0.25, 'positivo' => 0.15, 'neutral' => 0.08, 'negativo' => 0.03, 'muy_negativo' => 0],
['metrica' => 'margen_fcf', 'muy_positivo' => 0.20, 'positivo' => 0.10, 'neutral' => 0.05, 'negativo' => 0, 'muy_negativo' => -0.10],
// Retorno
['metrica' => 'roic', 'muy_positivo' => 0.20, 'positivo' => 0.12, 'neutral' => 0.08, 'negativo' => 0.04, 'muy_negativo' => 0],
['metrica' => 'roe', 'muy_positivo' => 0.25, 'positivo' => 0.15, 'neutral' => 0.10, 'negativo' => 0.05, 'muy_negativo' => 0],
['metrica' => 'roa', 'muy_positivo' => 0.15, 'positivo' => 0.08, 'neutral' => 0.05, 'negativo' => 0.02, 'muy_negativo' => 0],
['metrica' => 'roce', 'muy_positivo' => 0.20, 'positivo' => 0.12, 'neutral' => 0.08, 'negativo' => 0.04, 'muy_negativo' => 0],
// Eficiencia (días)
['metrica' => 'dias_clientes', 'muy_positivo' => 30, 'positivo' => 45, 'neutral' => 60, 'negativo' => 90, 'muy_negativo' => 120],
['metrica' => 'dias_proveedores', 'muy_positivo' => 60, 'positivo' => 45, 'neutral' => 30, 'negativo' => 20, 'muy_negativo' => 15],
['metrica' => 'dias_inventario', 'muy_positivo' => 30, 'positivo' => 45, 'neutral' => 60, 'negativo' => 90, 'muy_negativo' => 120],
['metrica' => 'ciclo_conversion', 'muy_positivo' => 30, 'positivo' => 45, 'neutral' => 60, 'negativo' => 90, 'muy_negativo' => 120],
// Liquidez (ratios)
['metrica' => 'current_ratio', 'muy_positivo' => 2.5, 'positivo' => 2.0, 'neutral' => 1.5, 'negativo' => 1.0, 'muy_negativo' => 0.8],
['metrica' => 'quick_ratio', 'muy_positivo' => 1.5, 'positivo' => 1.2, 'neutral' => 1.0, 'negativo' => 0.8, 'muy_negativo' => 0.5],
['metrica' => 'cash_ratio', 'muy_positivo' => 0.5, 'positivo' => 0.3, 'neutral' => 0.2, 'negativo' => 0.1, 'muy_negativo' => 0.05],
// Solvencia
['metrica' => 'net_debt_ebitda', 'muy_positivo' => 1.0, 'positivo' => 2.0, 'neutral' => 3.0, 'negativo' => 4.0, 'muy_negativo' => 5.0],
['metrica' => 'interest_coverage', 'muy_positivo' => 10.0, 'positivo' => 5.0, 'neutral' => 3.0, 'negativo' => 2.0, 'muy_negativo' => 1.0],
['metrica' => 'debt_ratio', 'muy_positivo' => 0.30, 'positivo' => 0.40, 'neutral' => 0.50, 'negativo' => 0.60, 'muy_negativo' => 0.70],
// Gestión
['metrica' => 'revenue_growth', 'muy_positivo' => 0.20, 'positivo' => 0.10, 'neutral' => 0.05, 'negativo' => 0, 'muy_negativo' => -0.05],
['metrica' => 'capex_revenue', 'muy_positivo' => 0.05, 'positivo' => 0.08, 'neutral' => 0.12, 'negativo' => 0.15, 'muy_negativo' => 0.20],
['metrica' => 'effective_tax_rate', 'muy_positivo' => 0.25, 'positivo' => 0.28, 'neutral' => 0.30, 'negativo' => 0.33, 'muy_negativo' => 0.35],
];
foreach ($umbrales as $umbral) {
Umbral::create(array_merge($umbral, ['giro_id' => null]));
}
}
}