repuve-backend-v1/app/Http/Controllers/Repuve/InscriptionController.php
2025-10-30 17:33:05 -06:00

592 lines
22 KiB
PHP

<?php
namespace App\Http\Controllers\Repuve;
use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
use Notsoweb\ApiResponse\Enums\ApiResponse;
use App\Http\Requests\Repuve\VehicleStoreRequest;
use App\Models\CatalogNameImg;
use App\Models\Vehicle;
use App\Models\Record;
use App\Models\Owner;
use App\Models\File;
use App\Models\Tag;
use App\Models\Error;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Auth;
class InscriptionController extends Controller
{
/* ===========================================================
* Inscripción de vehículo al REPUVE
* ===========================================================
*/
public function vehicleInscription(VehicleStoreRequest $request)
{
try {
$folio = $request->input('folio');
$tagNumber = $request->input('tag_number');
$vin = $request->input('vin');
// Buscar Tag y validar que NO tenga vehículo asignado
$tag = Tag::where('folio', $folio)->where('tag_number', $tagNumber)->first();
if (!$tag) {
return ApiResponse::NOT_FOUND->response([
'message' => 'No se encontró el tag con el folio y tag_number proporcionados.',
'folio' => $folio,
'tag_number' => $tagNumber,
]);
}
if ($tag->vehicle_id) {
return ApiResponse::BAD_REQUEST->response([
'message' => 'El tag ya está asignado a un vehículo. Use actualizar en su lugar.',
'tag_number' => $tagNumber,
'vehicle_id' => $tag->vehicle_id,
]);
}
// Verificar robo (API Repuve Nacional)
$isStolen = $this->checkIfStolen($folio);
if ($isStolen) {
return ApiResponse::FORBIDDEN->response([
'folio' => $folio,
'tag_number' => $tagNumber,
'stolen' => true,
'message' => 'El vehículo reporta robo. No se puede continuar con la inscripción.',
]);
}
// Iniciar transacción
DB::beginTransaction();
// Obtener 37 datos de API Estatal
$vehicleData = $this->getVehicle();
$ownerData = $this->getOwner();
// Crear propietario
$owner = Owner::updateOrCreate(
['rfc' => $ownerData['rfc']],
[
'name' => $ownerData['name'],
'paternal' => $ownerData['paternal'],
'maternal' => $ownerData['maternal'],
'curp' => $ownerData['curp'],
'address' => $ownerData['address'],
'tipopers' => $ownerData['tipopers'],
'pasaporte' => $ownerData['pasaporte'],
'licencia' => $ownerData['licencia'],
'ent_fed' => $ownerData['ent_fed'],
'munic' => $ownerData['munic'],
'callep' => $ownerData['callep'],
'num_ext' => $ownerData['num_ext'],
'num_int' => $ownerData['num_int'],
'colonia' => $ownerData['colonia'],
'cp' => $ownerData['cp'],
]
);
// Crear vehículo
$vehicle = Vehicle::create([
'placa' => $vehicleData['placa'],
'niv' => $vehicleData['niv'],
'marca' => $vehicleData['marca'],
'linea' => $vehicleData['linea'],
'sublinea' => $vehicleData['sublinea'],
'modelo' => $vehicleData['modelo'],
'color' => $vehicleData['color'],
'numero_motor' => $vehicleData['numero_motor'],
'clase_veh' => $vehicleData['clase_veh'],
'tipo_servicio' => $vehicleData['tipo_servicio'],
'rfv' => $vehicleData['rfv'],
'rfc' => $vehicleData['rfc'],
'ofcexpedicion' => $vehicleData['ofcexpedicion'],
'fechaexpedicion' => $vehicleData['fechaexpedicion'],
'tipo_veh' => $vehicleData['tipo_veh'],
'numptas' => $vehicleData['numptas'],
'observac' => $vehicleData['observac'],
'cve_vehi' => $vehicleData['cve_vehi'],
'tipo_mov' => $vehicleData['tipo_mov'],
'owner_id' => $owner->id,
]);
// Asignar Tag al vehículo
$tag->markAsAssigned($vehicle->id, $folio);
// Crear registro
$record = Record::create([
'folio' => $folio,
'vehicle_id' => $vehicle->id,
'user_id' => Auth::id(),
]);
// Procesar archivos
$uploadedFiles = [];
if ($request->hasFile('files')) {
$files = $request->file('files');
$fileNames = $request->input('names', []);
foreach ($files as $index => $file) {
$customName = $fileNames[$index] ?? "archivo_" . ($index + 1);
$customName = str_replace(' ', '_', $customName);
$catalogName = CatalogNameImg::firstOrCreate(['name' => $customName]);
$extension = $file->getClientOriginalExtension();
$fileName = $customName . '_' . date('dmY_His') . '.' . $extension;
$path = $file->storeAs('records', $fileName, 'public');
$md5 = md5_file($file->getRealPath());
$fileRecord = File::create([
'name_id' => $catalogName->id,
'path' => $path,
'md5' => $md5,
'record_id' => $record->id,
]);
$uploadedFiles[] = [
'id' => $fileRecord->id,
'name' => $catalogName->name,
'path' => $fileRecord->path,
'url' => $fileRecord->url,
];
}
}
// Enviar a API Repuve Nacional
$apiResponse = $this->sendToRepuveNacional($vin);
$apiResponse["repuve_response"]["folio_ci"] = $folio;
$apiResponse["repuve_response"]["identificador_ci"] = $tagNumber;
// Procesar respuesta
if (isset($apiResponse['has_error']) && $apiResponse['has_error']) {
// Si hay error, buscar el error en la BD
$error = Error::where('code', $apiResponse['error_code'])->first();
if (!$error) {
DB::rollBack();
return ApiResponse::BAD_REQUEST->response([
'message' => 'Código de error no encontrado en el catálogo',
'error_code' => $apiResponse['error_code'],
'error_message' => $apiResponse['error_message'],
]);
}
// Guardar error en Record
$record->update([
'error_id' => $error->id,
'api_response' => $apiResponse,
'error_occurred_at' => now(),
]);
DB::commit();
// Retornar con error
return ApiResponse::OK->response([
'message' => 'Vehículo inscrito con error. Corrija los datos usando la función de actualización.',
'has_error' => true,
'can_update' => true,
'record_id' => $record->id,
'error' => [
'code' => $error->code,
'description' => $error->description,
'occurred_at' => $record->error_occurred_at->toDateTimeString(),
],
'record' => [
'id' => $record->id,
'folio' => $record->folio,
],
'vehicle' => $vehicleData,
'owner' => $ownerData,
'files' => $uploadedFiles,
'total_files' => count($uploadedFiles),
]);
}
// Si NO hay error, guardar respuesta exitosa
$record->update([
'error_id' => null,
'api_response' => $apiResponse,
'error_occurred_at' => null,
]);
DB::commit();
// Responder con éxito
return ApiResponse::OK->response([
'message' => 'Vehículo inscrito exitosamente',
'has_error' => false,
'stolen' => false,
'record' => [
'id' => $record->id,
'folio' => $record->folio,
'vehicle_id' => $vehicle->id,
'user_id' => $record->user_id,
'created_at' => $record->created_at->toDateTimeString(),
],
'vehicle' => [
'id' => $vehicle->id,
'placa' => $vehicle->placa,
'niv' => $vehicle->niv,
'marca' => $vehicle->marca,
'modelo' => $vehicle->modelo,
'color' => $vehicle->color,
],
'owner' => [
'id' => $owner->id,
'full_name' => $owner->full_name,
'rfc' => $owner->rfc,
],
'tag' => [
'id' => $tag->id,
'folio' => $tag->folio,
'status' => $tag->status,
],
'files' => $uploadedFiles,
'total_files' => count($uploadedFiles),
]);
} catch (\Exception $e) {
DB::rollBack();
return ApiResponse::BAD_REQUEST->response([
'message' => 'Error al procesar la inscripción del vehículo',
'error' => $e->getMessage(),
]);
}
}
private function checkIfStolen(string $folio): bool
{
// Aquí api servicio de REPUVE Nacional
// simulamos con random
return (bool) rand(0, 1);
}
private function sendToRepuveNacional(string $vin): array
{
// Enviar datos a API Repuve Nacional
// Aquí se haría la llamada real a la API de Repuve Nacional
// Por ahora simulamos respuestas aleatorias usando la tabla errors
/* $hasError = (bool) rand(0, 1);
if ($hasError) {
// Obtener un error aleatorio de la tabla errors
$error = Error::inRandomOrder()->first();
if (!$error) {
// Si no hay errores en la tabla, retornar error genérico
return [
'has_error' => true,
'error_code' => 'ERR_UNKNOWN',
'error_message' => 'No hay errores registrados en el catálogo',
'timestamp' => now()->toDateTimeString(),
'vin' => $vin,
'response_data' => null,
];
}
return [
'has_error' => true,
'error_code' => $error->code,
'error_message' => $error->description,
'timestamp' => now()->toDateTimeString(),
'vin' => $vin,
'response_data' => null,
];
} */
// Respuesta exitosa mockup REPUVE
$mockResponse = "OK:SIN INFORMACION|OTROS|SIN INFORMACION|10/07/2023|CENTRO|$vin|WSA548B|HR16777934V|2023|BLANCO|ADVANCE|TABASCO|NISSAN|MARCH|PARTICULAR|AUTOMOVIL|ACTIVO|null||null|0|null|0|10337954|E2003412012BB0C130FAD04D|Sin observaciones&#xd;";
// Parsear la cadena a JSON
// Parsear la cadena a JSON usando los campos oficiales
$fields = [
'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'
];
$values = explode('|', str_replace('OK:', '', $mockResponse));
$jsonResponse = [];
foreach ($fields as $i => $field) {
$jsonResponse[$field] = $values[$i] ?? null;
}
return [
'has_error' => false,
'error_code' => null,
'error_message' => null,
'timestamp' => now()->toDateTimeString(),
'vin' => $vin,
'repuve_response' => $jsonResponse,
];
}
public function searchRecord(Request $request)
{
$request->validate([
'folio' => 'nullable|string',
'placa' => 'nullable|string',
'vin' => 'nullable|string',
], [
'required_without_all' => 'Debe proporcionar al menos uno de los siguientes: folio, placa o vin.'
]);
$query = Record::with(['vehicle.owner', 'vehicle.tag', 'files', 'user', 'error'])->orderBy('id', 'ASC');
if ($request->filled('folio')) {
$query->whereHas('vehicle.tag', function ($q) use ($request) {
$q->where('folio', 'LIKE', '%' . $request->input('folio') . '%');
});
} elseif ($request->filled('placa')) {
$query->whereHas('vehicle', function ($q) use ($request) {
$q->where('placa', 'LIKE', '%' . $request->input('placa') . '%');
});
} elseif ($request->filled('vin')) {
$query->whereHas('vehicle', function ($q) use ($request) {
$q->where('niv', 'LIKE', '%' . $request->input('vin') . '%');
});
}
$perPage = $request->input('per_page', 20);
$records = $query->paginate($perPage);
if ($records->isEmpty()) {
return ApiResponse::NOT_FOUND->response([
'message' => 'No se encontraron expedientes con los criterios proporcionados.',
'records' => [],
'pagination' => [
'current_page' => 1,
'total_pages' => 0,
'total_records' => 0,
'per_page' => $perPage,
],
]);
}
return ApiResponse::OK->response([
'message' => 'Expedientes encontrados exitosamente',
'records' => $records->map(function ($record) {
return [
'id' => $record->id,
'folio' => $record->folio,
'created_at' => $record->created_at->toDateTimeString(),
'vehicle' => [
'id' => $record->vehicle->id,
'placa' => $record->vehicle->placa,
'niv' => $record->vehicle->niv,
'marca' => $record->vehicle->marca,
'modelo' => $record->vehicle->modelo,
'color' => $record->vehicle->color,
'clase_veh' => $record->vehicle->clase_veh,
],
'owner' => [
'id' => $record->vehicle->owner->id,
'full_name' => $record->vehicle->owner->full_name,
'rfc' => $record->vehicle->owner->rfc,
],
'tag' => [
'id' => $record->vehicle->tag ? $record->vehicle->tag->id : null,
'folio' => $record->vehicle->tag ? $record->vehicle->tag->folio : null,
'status' => $record->vehicle->tag ? $record->vehicle->tag->status : null,
],
'files' => $record->files->map(function ($file) {
return [
'id' => $file->id,
'name' => $file->name,
'path' => $file->path,
'url' => $file->url,
];
}),
];
}),
'pagination' => [
'current_page' => $records->currentPage(),
'total_pages' => $records->lastPage(),
'total_records' => $records->total(),
'per_page' => $records->perPage(),
'from' => $records->firstItem(),
'to' => $records->lastItem(),
],
]);
}
private function getVehicle(): array
{
$apiResponse = [
"error" => 0,
"datos" => [[
"entidadfederativa" => null,
"ofcexp" => "INTERNET",
"fechaexp" => "04/01/2022",
"placa" => "WNU700B",
"tarjetacir" => "2020-WNU700B",
"marca" => "CHEVROLET G.M.C.",
"submarca" => "AVEO",
"version" => "PAQ. \"A\" LS",
"clase_veh" => "AUTOMOVIL",
"tipo_veh" => "SEDAN",
"tipo_uso" => "PARTICULAR",
"modelo" => "2022",
"color" => "BLANCO",
"motor" => "H. EN WUHANLL,SGM",
"niv" => "LSGHD52H0ND032457",
"rfv" => null,
"numptas" => "4",
"observac" => null,
"tipopers" => 1,
"curp" => null,
"rfc" => "GME111116GJA",
"pasaporte" => null,
"licencia" => null,
"nombre" => "GOLSYSTEMS DE MEXICO S DE RL DE CV",
"ap_paterno" => null,
"ap_materno" => null,
"ent_fed" => "27",
"munic" => "04",
"callep" => "C BUGAMBILIAS ",
"num_ext" => "118",
"num_int" => null,
"colonia" => "FRACC. BLANCAS MARIPOSAS",
"cp" => "86179",
"cve_vehi" => "0037804",
"nrpv" => "5BK9MDO0",
"fe_act" => "10/01/2025",
"tipo_mov" => "1"
]]
];
$data = $apiResponse['datos'][0];
// Retornar datos mapeados para el vehículo
return [
'placa' => $data['placa'],
'niv' => $data['niv'],
'marca' => $data['marca'],
'linea' => $data['submarca'],
'sublinea' => $data['version'],
'modelo' => $data['modelo'],
'color' => $data['color'],
'numero_motor' => $data['motor'],
'clase_veh' => $data['clase_veh'],
'tipo_servicio' => $data['tipo_uso'],
'rfv' => $data['rfv'],
'rfc' => $data['rfc'],
'ofcexpedicion' => $data['ofcexp'],
'fechaexpedicion' => $data['fechaexp'],
'tipo_veh' => $data['tipo_veh'],
'numptas' => $data['numptas'],
'observac' => $data['observac'],
'cve_vehi' => $data['cve_vehi'],
'tipo_mov' => $data['tipo_mov'],
];
}
private function getOwner(): array
{
$apiResponse = [
"error" => 0,
"datos" => [[
"entidadfederativa" => null,
"ofcexp" => "INTERNET",
"fechaexp" => "04/01/2022",
"placa" => "WNU700B",
"tarjetacir" => "2020-WNU700B",
"marca" => "CHEVROLET G.M.C.",
"submarca" => "AVEO",
"version" => "PAQ. \"A\" LS",
"clase_veh" => "AUTOMOVIL",
"tipo_veh" => "SEDAN",
"tipo_uso" => "PARTICULAR",
"modelo" => "2022",
"color" => "BLANCO",
"motor" => "H. EN WUHANLL,SGM",
"niv" => "LSGHD52H0ND032457",
"rfv" => null,
"numptas" => "4",
"observac" => null,
"tipopers" => 1,
"curp" => null,
"rfc" => "GME111116GJA",
"pasaporte" => null,
"licencia" => null,
"nombre" => "GOLSYSTEMS DE MEXICO S DE RL DE CV",
"ap_paterno" => null,
"ap_materno" => null,
"ent_fed" => "27",
"munic" => "04",
"callep" => "C BUGAMBILIAS ",
"num_ext" => "118",
"num_int" => null,
"colonia" => "FRACC. BLANCAS MARIPOSAS",
"cp" => "86179",
"cve_vehi" => "0037804",
"nrpv" => "5BK9MDO0",
"fe_act" => "10/01/2025",
"tipo_mov" => "1"
]]
];
$data = $apiResponse['datos'][0];
// Construir dirección completa
$addressParts = array_filter([
$data['callep'],
$data['num_ext'] ? "Num {$data['num_ext']}" : null,
$data['num_int'] ? "Int {$data['num_int']}" : null,
$data['colonia'],
$data['cp'] ? "CP {$data['cp']}" : null,
$data['munic'] ? "Mun {$data['munic']}" : null,
$data['ent_fed'] ? "Edo {$data['ent_fed']}" : null,
]);
$address = implode(', ', $addressParts);
// Retornar datos mapeados para el propietario
return [
'name' => $data['nombre'],
'paternal' => $data['ap_paterno'],
'maternal' => $data['ap_materno'],
'rfc' => $data['rfc'],
'curp' => $data['curp'],
'address' => $address,
'tipopers' => $data['tipopers'],
'pasaporte' => $data['pasaporte'],
'licencia' => $data['licencia'],
'ent_fed' => $data['ent_fed'],
'munic' => $data['munic'],
'callep' => $data['callep'],
'num_ext' => $data['num_ext'],
'num_int' => $data['num_int'],
'colonia' => $data['colonia'],
'cp' => $data['cp'],
];
}
}