Saltar a contenido

Fix: Requerimiento dPaisExt de TheFactoryHKA para Clientes Extranjeros

Problema Identificado

Al emitir facturas de operación interna a clientes extranjeros usando el PAC TheFactoryHKA, se presentaba el error:

Error validación: El campo paisExtranjero es requerido.

Análisis del Problema

Contexto Técnico

  • PAC: TheFactoryHKA
  • Operación: Interna (iDest = 1) a cliente extranjero (iTipoRec = 4)
  • Error: Campo paisExtranjero no presente en estructura gIdExt

Investigación en HKAService

Archivo: app/Services/HKAService.php línea 109

$cliente->paisExtranjero = $this->getNestedValue($doc, 'dGen.gDatRec.gIdExt.dPaisExt');

Hallazgo: TheFactoryHKA mapea el campo dPaisExt desde gIdExt para determinar la nacionalidad del cliente extranjero.

Problema en getUnifiedForeignReceiverData()

Archivo: app/Http/Livewire/Admin/Einvoice/Create.php

Lógica anterior (líneas 837-839):

// B4062 - País extranjero (OPCIONAL, solo para pasaportes)
if ($paisExtranjero) {
    $oficialData['dPaisExt'] = $paisExtranjero;
}

Problema: Solo incluía dPaisExt si $paisExtranjero tenía valor, pero TheFactoryHKA lo requiere para todos los clientes extranjeros.

Solución Implementada

1. Lógica Mejorada en getUnifiedForeignReceiverData()

Ubicación: app/Http/Livewire/Admin/Einvoice/Create.php líneas ~837-853

// B4062 - País extranjero: TheFactoryHKA requiere este campo para clientes extranjeros
if ($paisExtranjero) {
    $oficialData['dPaisExt'] = $paisExtranjero;
} elseif ($this->receptor_tipo === '3' || $this->receptor_tipo === 3) {
    // Cliente extranjero: TheFactoryHKA requiere dPaisExt obligatorio
    if ($this->destinoOperacion == '1') {
        // Operación interna: usar país de nacionalidad del cliente
        $paisNacionalidadCode = $this->getPaisCodeFromNacionalidad();
        $oficialData['dPaisExt'] = $paisNacionalidadCode ?: 'PA';
    } else {
        // Operación de exportación: usar código del país receptor
        $oficialData['dPaisExt'] = $codigoPaisReceptor ?: 'US';
    }
}

2. Nueva Función getPaisCodeFromNacionalidad()

Ubicación: app/Http/Livewire/Admin/Einvoice/Create.php líneas ~880-895

private function getPaisCodeFromNacionalidad()
{
    if (!$this->receptor_paisNacionalidad) {
        return null;
    }

    // Si ya es un código de 2 caracteres, devolverlo directamente
    if (is_string($this->receptor_paisNacionalidad) && strlen($this->receptor_paisNacionalidad) === 2) {
        return strtoupper($this->receptor_paisNacionalidad);
    }

    // Si es un ID, buscar en la tabla para obtener el código
    $paisNacionalidad = Destinationcountryoperation::find($this->receptor_paisNacionalidad);
    return $paisNacionalidad ? strtoupper($paisNacionalidad->code) : null;
}

Reglas de Negocio Aplicadas

Para Clientes Extranjeros (receptor_tipo = '3')

Operación Interna (destinoOperacion = '1')

  • dPaisExt: País de nacionalidad del cliente
  • Ejemplo: Cliente chileno → dPaisExt = 'CL'
  • Fallback: Si no hay nacionalidad específica → dPaisExt = 'PA'

Operación de Exportación (destinoOperacion = '2')

  • dPaisExt: País de destino de la exportación
  • Ejemplo: Exportación a USA → dPaisExt = 'US'
  • Fallback: Si no hay país específico → dPaisExt = 'US'

Para Clientes Nacionales (receptor_tipo ≠ '3')

  • dPaisExt: No incluido (correcto según especificación)

Estructura de Datos Resultante

Antes del Fix (causaba error)

{
  "gIdExt": {
    "tipoIdentificacion": "01",
    "dIdExt": "XYZABC123"
    // ❌ dPaisExt faltante
  }
}

Después del Fix (TheFactoryHKA compatible)

{
  "gIdExt": {
    "tipoIdentificacion": "01", 
    "dIdExt": "XYZABC123",
    "dPaisExt": "PA"  // ✅ Incluido automáticamente
  }
}

Mapeo en HKAService

Archivo: app/Services/HKAService.php

// Línea 107: Número identificación extranjero
$cliente->nroIdentificacionExtranjero = $this->getNestedValue($doc, 'dGen.gDatRec.gIdExt.dIdExt');

// Línea 109: País extranjero (AHORA INCLUIDO)
$cliente->paisExtranjero = $this->getNestedValue($doc, 'dGen.gDatRec.gIdExt.dPaisExt');

Resultado: HKAService ahora puede mapear correctamente paisExtranjero para TheFactoryHKA.

Casos de Uso Resueltos

Caso 1: Operación Interna + Cliente Extranjero Real

$datos = [
    'receptor_tipo' => '3',
    'destinoOperacion' => '1',
    'receptor_paisNacionalidad' => 'CL', // Cliente chileno
    'numeroIdentificacionExtranjero' => 'CL12345678'
];
// Resultado: dPaisExt = 'CL'

Caso 2: Operación Interna + Cliente Extranjero sin Nacionalidad Específica

$datos = [
    'receptor_tipo' => '3', 
    'destinoOperacion' => '1',
    'receptor_paisNacionalidad' => 'PA', // Fallback
    'numeroIdentificacionExtranjero' => 'XYZABC123'
];
// Resultado: dPaisExt = 'PA'

Caso 3: Exportación + Cliente Extranjero

$datos = [
    'receptor_tipo' => '3',
    'destinoOperacion' => '2',
    'codigoPaisReceptor' => 'US',
    'numeroIdentificacionExtranjero' => 'US87654321'
];
// Resultado: dPaisExt = 'US'

Caso 4: Cliente Nacional (no afectado)

$datos = [
    'receptor_tipo' => '2', // Nacional
    'destinoOperacion' => '1'
];
// Resultado: dPaisExt NO incluido (correcto)

Testing y Verificación

Test Automatizado

Archivo: docs/testing/test-thefactoryhka-dpaisext-fix.php

Ejecución:

cd /home/weirdolabs/code/docucenter
docker exec -it docucenter_laravel.test php docs/testing/test-thefactoryhka-dpaisext-fix.php

Resultados del Test:

 Campo dPaisExt incluido para extranjeros: PASS
 Caso Chile operación interna: PASS  
 Caso exportación: PASS
 Caso nacional (no debe incluir): PASS
 HKAService podrá procesar: PASS

🎯 RESULTADO GENERAL: 5/5 tests pasados

Verificación Manual

  1. Crear factura: Operación interna a cliente extranjero
  2. Verificar logs: HKAService debe mostrar paisExtranjero poblado
  3. Confirmar envío: PAC TheFactoryHKA debe procesar sin error

Archivos Modificados

Archivos Principales

  • app/Http/Livewire/Admin/Einvoice/Create.php
  • Función getUnifiedForeignReceiverData() (líneas ~837-853)
  • Nueva función getPaisCodeFromNacionalidad() (líneas ~880-895)

Archivos de Testing

  • docs/testing/test-thefactoryhka-dpaisext-fix.php (nuevo)

Compatibilidad PAC

TheFactoryHKA ✅

  • Requiere: dPaisExt para clientes extranjeros
  • Status: Completamente compatible

Otros PACs

  • Alanube: No requiere dPaisExt, ignora si está presente ✅
  • MEYPAR: No requiere dPaisExt, ignora si está presente ✅

Normativas DGI

  • B4061: Número identificación extranjero (obligatorio) ✅
  • B4062: País extranjero (opcional según DGI, requerido por TheFactoryHKA) ✅
  • Grupo gIdExt: Estructura oficial para clientes extranjeros ✅

Commit

commit: fix: resolver requerimiento dPaisExt de TheFactoryHKA para clientes extranjeros

Fecha de Implementación

20 de Octubre, 2025

Resolución Confirmada

Error resuelto: "El campo paisExtranjero es requerido"
PAC compatible: TheFactoryHKA puede procesar clientes extranjeros
Operación interna: Funciona correctamente para iTipoRec=4, iDest=1
Backward compatible: No afecta otros PACs ni clientes nacionales