repuve-backend-v1/app/Services/RepuveService.php

395 lines
14 KiB
PHP

<?php
namespace App\Services;
use Exception;
use App\Models\Error;
class RepuveService
{
private string $baseUrl;
private string $roboEndpoint;
private string $inscripcionEndpoint;
private string $username;
private string $password;
public function __construct()
{
$this->baseUrl = config('services.repuve_federal.base_url');
$this->roboEndpoint = config('services.repuve_federal.robo_endpoint');
$this->inscripcionEndpoint = config('services.repuve_federal.inscripcion_endpoint');
$this->username = config('services.repuve_federal.username');
$this->password = config('services.repuve_federal.password');
}
public function consultarPadron(string $niv)
{
$url = $this->baseUrl . $this->roboEndpoint;
$arg2 = $niv . '|||||||';
$soapBody = <<<XML
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:wsdl="http://consultaRpv.org/wsdl">
<soapenv:Header/>
<soapenv:Body>
<wsdl:doConsPadron>
<arg0>{$this->username}</arg0>
<arg1>{$this->password}</arg1>
<arg2>{$arg2}</arg2>
</wsdl:doConsPadron>
</soapenv:Body>
</soapenv:Envelope>
XML;
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, $soapBody);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
'Content-Type: text/xml; charset=utf-8',
'SOAPAction: "doConsPadron"',
'Content-Length: ' . strlen($soapBody),
]);
// Ejecutar la solicitud
$response = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
$error = curl_error($ch);
curl_close($ch);
if ($error) {
throw new Exception("Error en la petición SOAP: {$error}");
}
if ($httpCode !== 200) {
throw new Exception("Error al consultar REPUVE: Código HTTP {$httpCode}");
}
return $this->parseVehicleResponse($response, $niv);
}
private function parseVehicleResponse(string $soapResponse, string $niv)
{
preg_match('/<return>(.*?)<\/return>/s', $soapResponse, $matches);
if (!isset($matches[1])) {
$errorFromDb = Error::where('code', '108')->first();
return [
'has_error' => true,
'error_code' => '108',
'error_name' => $errorFromDb?->name,
'error_message' => $errorFromDb?->description ?? 'Error al parsear respuesta',
'timestamp' => now()->toDateTimeString(),
'niv' => $niv,
'repuve_response' => null,
];
}
$contenido = trim($matches[1]);
// Verificar si hay error de REPUVE Nacional (cualquier formato con ERR o ERROR)
if (preg_match('/(ERR|ERROR|err|error):(-?\d+)/i', $contenido, $errorMatch)) {
$errorCode = $errorMatch[2];
// Buscar el error completo en la base de datos
$errorFromDb = Error::where('code', $errorCode)->first();
return [
'has_error' => true,
'error_code' => $errorCode,
'error_name' => $errorFromDb?->name,
'error_message' => $errorFromDb?->description ?? "Error código {$errorCode} - no catalogado",
'timestamp' => now()->toDateTimeString(),
'niv' => $niv,
'repuve_response' => $contenido,
];
}
// Si empieza con OK:, parsear los datos
if (str_starts_with($contenido, 'OK:')) {
$datos = str_replace('OK:', '', $contenido);
$valores = explode('|', $datos);
$campos = [
'marca',
'submarca',
'tipo_vehiculo',
'fecha_expedicion',
'oficina',
'niv',
'placa',
'motor',
'modelo',
'color',
'version',
'entidad',
'marca_padron',
'submarca_padron',
'tipo_uso_padron',
'tipo_vehiculo_padron',
'estatus_registro',
'aduana',
'nombre_aduana',
'patente',
'pedimento',
'fecha_pedimento',
'clave_importador',
'folio_ci',
'identificador_ci',
'observaciones'
];
$jsonResponse = [];
foreach ($campos as $i => $campo) {
$jsonResponse[$campo] = $valores[$i] ?? null;
}
return [
'has_error' => false,
'error_code' => null,
'error_message' => null,
'timestamp' => now()->toDateTimeString(),
'niv' => $niv,
'repuve_response' => $jsonResponse,
];
}
$errorFromDb = Error::where('code', '108')->first();
return [
'has_error' => true,
'error_code' => '108',
'error_name' => $errorFromDb?->name,
'error_message' => $errorFromDb?->description ?? 'Error al parsear respuesta',
'timestamp' => now()->toDateTimeString(),
'niv' => $niv,
'repuve_response' => null,
];
}
/**
* Verifica si un vehículo está reportado como robado
*/
public function verificarRobo(string $niv)
{
try {
$resultado = $this->consultarPadron($niv);
if ($resultado['has_error']) {
return false;
}
$estatus = $resultado['repuve_response']['estatus_registro'] ?? null;
return in_array(strtoupper($estatus), ['ROBADO', 'ROBO']);
} catch (Exception $e) {
logger()->error("Error al verificar robo en REPUVE: " . $e->getMessage());
return false;
}
}
public function inscribirVehiculo(array $datos)
{
$url = $this->baseUrl . $this->inscripcionEndpoint;
// DATOS HARDCODEADOS
$arg2 = implode('|', [
$datos['ent_fed'] ?? '', // 1. Entidad federativa
$datos['ofcexp'] ?? '', // 2. Oficina expedición
$datos['fechaexp'] ?? '', // 3. Fecha expedición
$datos['placa'] ?? '', // 4. Placa
$datos['tarjetacir'] ?? '', // 5. Tarjeta circulación
$datos['marca'] ?? '', // 6. Marca
$datos['submarca'] ?? '', // 7. Submarca
$datos['version'] ?? '', // 8. Versión
$datos['clase_veh'] ?? '', // 9. Clase vehículo
$datos['tipo_veh'] ?? '', // 10. Tipo vehículo
$datos['tipo_uso'] ?? '', // 11. Tipo uso
$datos['modelo'] ?? '', // 12. Modelo (año)
$datos['color'] ?? '', // 13. Color
$datos['motor'] ?? '', // 14. Número motor
$datos['niv'] ?? '', // 15. NIV
$datos['rfv'] ?? '', // 16. RFV
$datos['numptas'] ?? '', // 17. Número puertas
$datos['observac'] ?? '', // 18. Observaciones
$datos['tipopers'] ?? '', // 19. Tipo persona
$datos['curp'] ?? '', // 20. CURP
$datos['rfc'] ?? '', // 21. RFC
$datos['pasaporte'] ?? '', // 22. Pasaporte
$datos['licencia'] ?? '', // 23. Licencia
$datos['nombre'] ?? '', // 24. Nombre
$datos['ap_paterno'] ?? '', // 25. Apellido paterno
$datos['ap_materno'] ?? '', // 26. Apellido materno
$datos['ent_fed'] ?? '', // 27. Entidad federativa propietario (repetido?)
$datos['munic'] ?? '', // 28. Municipio
$datos['callep'] ?? '', // 29. Calle principal
$datos['num_ext'] ?? '', // 30. Número exterior
$datos['num_int'] ?? '', // 31. Número interior
$datos['colonia'] ?? '', // 32. Colonia
$datos['cp'] ?? '', // 33. Código postal
$datos['cve_vehi'] ?? '', // 34. Clave vehículo
$datos['nrpv'] ?? '', // 35. NRPV
$datos['fe_act'] ?? '', // 36. Fecha actualización
$datos['tipo_mov'] ?? '', // 37. Tipo movimiento
]);
// Construir el cuerpo SOAP
$soapBody = <<<XML
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:wsdl="http://inscripcion.org/wsdl">
<soapenv:Header/>
<soapenv:Body>
<wsdl:inscribe>
<arg0>{$this->username}</arg0>
<arg1>{$this->password}</arg1>
<arg2>{$arg2}</arg2>
</wsdl:inscribe>
</soapenv:Body>
</soapenv:Envelope>
XML;
// Configurar cURL
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, $soapBody);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
'Content-Type: text/xml; charset=utf-8',
'SOAPAction: "inscribe"',
'Content-Length: ' . strlen($soapBody),
]);
// Ejecutar la petición
$response = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
$curlError = curl_error($ch);
curl_close($ch);
// Loguear para debug
logger()->info('REPUVE Inscripción Request', [
'url' => $url,
'soap_body' => $soapBody
]);
logger()->info('REPUVE Inscripción Response', [
'http_code' => $httpCode,
'curl_error' => $curlError,
'response' => $response
]);
if ($curlError) {
$errorFromDb = Error::where('code', '103')->first();
return [
'has_error' => true,
'error_code' => '103',
'error_name' => $errorFromDb?->name,
'error_message' => $errorFromDb?->description ?? "Error de conexión: {$curlError}",
'timestamp' => now()->toDateTimeString(),
'http_code' => $httpCode,
'raw_response' => $response,
];
}
if ($httpCode !== 200) {
$errorFromDb = Error::where('code', '-1')->first();
return [
'has_error' => true,
'error_code' => '-1',
'error_name' => $errorFromDb?->name,
'error_message' => $errorFromDb?->description ?? "Error interno HTTP {$httpCode}",
'timestamp' => now()->toDateTimeString(),
'http_code' => $httpCode,
'raw_response' => $response,
];
}
// Parsear la respuesta
return $this->parsearRespuestaInscripcion($response);
}
/**
* Parsea la respuesta
*/
private function parsearRespuestaInscripcion(string $soapResponse)
{
preg_match('/<return>(.*?)<\/return>/s', $soapResponse, $matches);
if (!isset($matches[1])) {
$errorFromDb = Error::where('code', '108')->first();
return [
'has_error' => true,
'error_code' => '108',
'error_name' => $errorFromDb?->name,
'error_message' => $errorFromDb?->description ?? 'Error al parsear respuesta',
'timestamp' => now()->toDateTimeString(),
'raw_response' => $soapResponse,
'repuve_response' => null,
];
}
$contenido = trim($matches[1]);
// Buscar patrones de error: ERR:, ERROR:, err:, error:
if (preg_match('/(ERR|ERROR|err|error):(-?\d+)/i', $contenido, $errorMatch)) {
$errorCode = $errorMatch[2];
// Buscar el error completo en la base de datos
$errorFromDb = Error::where('code', $errorCode)->first();
if ($errorFromDb) {
// Retornar nombre y descripción de la BD
return [
'has_error' => true,
'error_code' => $errorCode,
'error_name' => $errorFromDb->name,
'error_message' => $errorFromDb->description,
'timestamp' => now()->toDateTimeString(),
'raw_response' => $soapResponse,
'repuve_response' => $contenido,
];
}
// Si no existe en BD, retornar el código sin descripción
return [
'has_error' => true,
'error_code' => $errorCode,
'error_name' => null,
'error_message' => "Error código {$errorCode} - no catalogado",
'timestamp' => now()->toDateTimeString(),
'raw_response' => $soapResponse,
'repuve_response' => $contenido,
];
}
// Si empieza con OK: es éxito
if (preg_match('/^OK:/i', $contenido)) {
$datos = preg_replace('/^OK:/i', '', $contenido);
return [
'has_error' => false,
'error_code' => null,
'error_message' => null,
'timestamp' => now()->toDateTimeString(),
'raw_response' => $soapResponse,
'repuve_response' => [
'status' => 'OK',
'data' => $datos,
],
];
}
// Si no hay ERR/ERROR y no es OK, asumir que es respuesta exitosa
return [
'has_error' => false,
'error_code' => null,
'error_name' => null,
'error_message' => null,
'timestamp' => now()->toDateTimeString(),
'raw_response' => $soapResponse,
'repuve_response' => [
'status' => 'OK',
'data' => $contenido,
],
];
}
}