Files
horux-strategy-platform/docs/10-administracion.md
Torch2196 4c3dc94ff2 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>
2026-01-31 22:24:00 -06:00

9.7 KiB

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

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

# 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

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

// 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

// 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:

// 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

// 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