Luego de varias pruebas en diferentes escenarios, me pude dar cuenta que las incidencias puede ser de varios tipos. Pueden de tipo remoto o local; sobre todo cuando es SoapFaul.
Al final mi clase para el proceso quedo definida así:
Esto es para php 8.1.
Código PHP:
<?php
/**
* Permite la gestión de los archivos xml, en el procesamiento WSDL mediante SOAP.
* Date: 27/02/2025
* Copyright:2025
* Author: José Hernández
*/
namespace ElectronicInvoice\Content\SoapService;
class ServiceVerifactu
{
public $Parameters;
private $response;
private $type_incedent;
private $correcto = false;
public function __construct()
{
$this->Parameters = (object) [
'http_service'=>'',
'http_port_test'=>'',
'http_port_prod'=>'',
'certificate'=>'',
'passw_cert'=>'',
'type_process'=>'',
'content_invoice'=>''
];
}
/**
* @return bool Si fue correcta la validación de la factura
*/
public function getCorrect():bool{
return $this->correcto;
}
/***
* @return string Devuelve el tipo de incidencia
*/
public function getTypeIncedent()
{
return $this->type_incedent;
}
/***
* Description: Permite definir los parametros
* Date: 27/02/2025
* Copyright: 2025
* Author: Ing. José Hernández
* @return object Retorna el objecto Parameter
*/
public function parameters()
{
return $this->Parameters;
}
/**
* Se emplea la conexión mediante SOAP, para los datos envueltos
* @return string return $response Devuelve la repuesta del servicio
*/
public function getResponseService():string
{
$this->response = ""; // declaración de la variable
try {
// Cargar el XML de la factura
// El valor de pase debe ser de tipo string, previamente con file_get_contents()
$factura = new \SimpleXMLElement($this->Parameters->content_invoice);
$client = new \SoapClient($this->Parameters->http_service, $this->ClientOptions());
// Llamada al servicio SOAP
$this->correcto = false;
$this->response = $client->__doRequest($factura->asXml(), $this->getPortWork(),'AltaFactuSistemaFacturacion', SOAP_1_1);
$this->processIncident();
} catch (\SoapFault $e) {
// Manejo de errores
$this->response = "Error en la llamada SOAPFaul(Local): " . $e->getMessage();
} catch (\Exception $e) {
// Manejo de errores
$this->response = "Error System: " . $e->getMessage();
}
return $this->response;
}
/**
* Permite determinar que incidencia se produjo en el proceso
* estan pueden : html, SoapFaul o Data Center errores de transcripción
* @return string Retorna el $response en forma esquematica
*/
private function processIncident()
{
$this->callMethodIncident();
}
private function callMethodIncident()
{
switch (true)
{
case str_contains($this->response, 'env:Fault'):
// Incidencia remota retorna SoapFaul
$this->IncidentRemoteSoapFaul();
$this->type_incedent = "SoapFaul";
break;
case str_contains($this->response, 'DOCTYPE html'):
// Incidencia remota retorna Sitio Web con error
$this->IncidentRemoteHtml();
$this->type_incedent = "HtmlDoc";
break;
case str_contains($this->response, 'tikR:RespuestaLinea'):
// Incidencia de transcripción de data, reporte factura.
$this->IncidentRemoteAnswerOnline();
$this->type_incedent = "RespLin";
break;
default:
// Proceso inesperado no se determino la incidencia
$this->response = "Error no determinado:".$this->response;
$this->type_incedent = "NoDet";
}
}
/**
* Client Options
* Description: Permite obtener las configuraciones para
* procesar el servicio SOAP.
* Date: 27/02/2025
* Nota: El certificado debe estar en extensión pem
* para convertir : openssl pkcs12 -in cert.pfx -out cert.pem -nodes
* @return array return parameters options.
*/
private function ClientOptions():array
{
return [
'soap_version' => SOAP_1_1,
'trace' => 1, // Habilita el seguimiento para depuración
'exceptions' => false,
'cache_wsdl' => WSDL_CACHE_NONE,
'local_cert' => $this->Parameters->certificate,
'passphrase' => $this->Parameters->passw_cert,
'stream_context' => stream_context_create(
[
'ssl' => [
'verify_peer' => false,
'verify_peer_name' => false,
'allow_self_signed' => true,
]
]
)
];
}
/**
* @return string Retorna el puerto a emplear
*/
public function getPortWork():string
{
return ($this->Parameters->type_process=='prodXml') ? $this->Parameters->http_port_test : $this->Parameters->http_port_prod;
}
private function IncidentRemoteSoapFaul()
{
$xml_resp = simplexml_load_string($this->response);
$this->response = "Response: \n" .$xml_resp->xpath('//env:Fault')[0]->faultcode ."\n\n". $xml_resp->xpath('//env:Fault')[0]->faultstring;
}
private function IncidentRemoteHtml()
{
// Tomar los datos mediante un sistema de expresión regular decidir modo de repuesta.
$html_data = $this->response;
$this->response = preg_replace('/(<body\s[\s\S\d\D\w\W]+<\/body>)/','$1',$html_data);
}
private function IncidentRemoteAnswerOnline()
{
// Cargar el XML en un objeto SimpleXML
$xml = simplexml_load_string($this->response);
// Registrar los namespaces para poder acceder a los elementos
$namespaces = $xml->getNamespaces(true);
// Registrar el namespace 'env' y 'tikR'
$xml->registerXPathNamespace('env', $namespaces['env']);
$xml->registerXPathNamespace('tikR', $namespaces['tikR']);
// Extraer los datos que necesitas
$estadoEnvio = $xml->xpath('//env:Body/tikR:RespuestaRegFactuSistemaFacturacion/tikR:EstadoEnvio')[0];
$estadoRegistro = $xml->xpath('//env:Body/tikR:RespuestaRegFactuSistemaFacturacion/tikR:RespuestaLinea/tikR:EstadoRegistro')[0];
if ($estadoEnvio!="Correcto" && $estadoRegistro!="Correcto" ){
$codigoErrorRegistro = $xml->xpath('//env:Body/tikR:RespuestaRegFactuSistemaFacturacion/tikR:RespuestaLinea/tikR:CodigoErrorRegistro')[0];
$descripcionErrorRegistro = $xml->xpath('//env:Body/tikR:RespuestaRegFactuSistemaFacturacion/tikR:RespuestaLinea/tikR:DescripcionErrorRegistro')[0];
} else {
$codigoErrorRegistro = "";
$descripcionErrorRegistro="Procesado Correctamente !!! ";
$this->correcto = True;
}
// Concatenar los datos en una variable
$resultado = "Estado del Envio: " . (string)$estadoEnvio . "\n" .
"Estado del Registro: " . (string)$estadoRegistro . "\n" .
"Código Registro: " . (string)$codigoErrorRegistro . "\n" .
"Descripción: " . (string)$descripcionErrorRegistro;
// Datos devueltos en cadena de string.
$this->response = $resultado;
}
}
?>
Este un ejemplo de cómo cargar los datos en los parámetros:
Código PHP:
<?php
$root_file_signature = $root_file . "/files/signxml/" . $name_file . "_sign.xml";
// Cargar el XML de la factura
$factura = file_get_contents($root_file_signature);
$this->soap_service->parameters()->content_invoice = $factura;
$this->soap_service->parameters()->http_service = $this->http_service;
$this->soap_service->parameters()->http_port_test = $this->http_test;
$this->soap_service->parameters()->http_port_prod = $this->http_prod;
$this->soap_service->parameters()->type_process = $this->http_ambiente;
$this->soap_service->parameters()->certificate = $certificate;
$this->soap_service->parameters()->passw_cert = $password;
?>

Si quieren algo así para su lenguaje de desarrollo pueden, hacer la conversión de la clase mediante IA.