- 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>
254 lines
6.0 KiB
Markdown
254 lines
6.0 KiB
Markdown
# 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."
|
|
```
|