Files
horux-strategy-platform/backend/app/Services/ClasificadorCuentas.php
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

120 lines
3.8 KiB
PHP

<?php
namespace App\Services;
use App\Models\Balanza;
use App\Models\Cuenta;
use App\Models\ReglaMapeo;
use App\Models\MapeoCuenta;
class ClasificadorCuentas
{
/**
* Clasifica todas las cuentas de una balanza según las reglas de mapeo
*/
public function clasificar(Balanza $balanza): void
{
$cuentas = $balanza->cuentas()->get();
$sistemaOrigen = $balanza->sistema_origen;
$clienteId = $balanza->cliente_id;
// Obtener reglas ordenadas por prioridad
$reglas = ReglaMapeo::where('sistema_origen', $sistemaOrigen)
->where('activo', true)
->orderByDesc('prioridad')
->get();
// Obtener mapeos específicos del cliente
$mapeosCliente = MapeoCuenta::where('cliente_id', $clienteId)->get();
foreach ($cuentas as $cuenta) {
$this->clasificarCuenta($cuenta, $reglas, $mapeosCliente);
}
// Establecer relaciones padre-hijo en base de datos
$this->establecerRelacionesPadreHijo($balanza);
}
private function clasificarCuenta(Cuenta $cuenta, $reglas, $mapeosCliente): void
{
// Primero buscar en mapeos específicos del cliente
foreach ($mapeosCliente as $mapeo) {
if ($this->coincidePatron($cuenta->codigo, $mapeo->codigo_patron)) {
$cuenta->update([
'categoria_contable_id' => $mapeo->categoria_contable_id,
'reporte_contable_id' => $mapeo->categoriaContable->reporte_contable_id,
'requiere_revision' => false,
]);
return;
}
}
// Buscar en reglas del sistema
foreach ($reglas as $regla) {
if ($regla->coincideCon($cuenta->codigo)) {
$cuenta->update([
'categoria_contable_id' => $regla->categoria_contable_id,
'reporte_contable_id' => $regla->reporte_contable_id,
'requiere_revision' => false,
]);
return;
}
}
// No se encontró regla - marcar para revisión
$this->marcarParaRevision($cuenta);
}
private function coincidePatron(string $codigo, string $patron): bool
{
// El patrón puede ser exacto o con wildcards (*)
$regex = '/^' . str_replace(['*', '-'], ['.*', '\-'], $patron) . '$/';
return (bool) preg_match($regex, $codigo);
}
private function marcarParaRevision(Cuenta $cuenta): void
{
$nota = $this->generarNotaRevision($cuenta);
$cuenta->update([
'requiere_revision' => true,
'nota_revision' => $nota,
]);
}
private function generarNotaRevision(Cuenta $cuenta): string
{
$codigo = $cuenta->codigo;
$notas = [];
// Detectar posibles anomalías basadas en el código
if (preg_match('/^45[0-9]-/', $codigo)) {
$notas[] = 'Código 45X normalmente es pasivo pero podría ser gasto. Verificar clasificación.';
}
if (preg_match('/^[89][0-9]{2}-/', $codigo)) {
$notas[] = 'Cuenta de orden o especial. Verificar si debe incluirse en estados financieros.';
}
if (empty($notas)) {
$notas[] = 'No se encontró regla de mapeo para este código. Asignar clasificación manualmente.';
}
return implode(' ', $notas);
}
private function establecerRelacionesPadreHijo(Balanza $balanza): void
{
$cuentas = $balanza->cuentas()->get()->keyBy('codigo');
foreach ($cuentas as $cuenta) {
if (isset($cuenta->cuenta_padre_codigo)) {
$padre = $cuentas->get($cuenta->cuenta_padre_codigo);
if ($padre) {
$cuenta->update(['cuenta_padre_id' => $padre->id]);
}
}
}
}
}