483 lines
18 KiB
PHP
483 lines
18 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\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'],
|
|
]
|
|
);
|
|
|
|
// Crear vehículo
|
|
$vehicle = Vehicle::create([
|
|
'anio_placa' => $vehicleData['ANIO_PLACA'],
|
|
'placa' => $vehicleData['PLACA'],
|
|
'numero_serie' => $vin,
|
|
'rfc' => $vehicleData['RFC'],
|
|
'folio' => $folio,
|
|
'vigencia' => $vehicleData['VIGENCIA'],
|
|
'fecha_impresion' => $vehicleData['FECHA_IMPRESION'],
|
|
'qr_hash' => $vehicleData['QR_HASH'],
|
|
'valido' => $vehicleData['VALIDO'],
|
|
'nombre' => $vehicleData['NOMBRE'],
|
|
'nombre2' => $vehicleData['NOMBRE2'],
|
|
'municipio' => $vehicleData['MUNICIPIO'],
|
|
'localidad' => $vehicleData['LOCALIDAD'],
|
|
'calle' => $vehicleData['CALLE'],
|
|
'calle2' => $vehicleData['CALLE2'],
|
|
'tipo' => $vehicleData['TIPO'],
|
|
'tipo_servicio' => $vehicleData['TIPO_SERVICIO'],
|
|
'marca' => $vehicleData['MARCA'],
|
|
'linea' => $vehicleData['LINEA'],
|
|
'sublinea' => $vehicleData['SUBLINEA'],
|
|
'modelo' => $vehicleData['MODELO'],
|
|
'numero_motor' => $vehicleData['NUMERO_MOTOR'],
|
|
'descripcion_origen' => $vehicleData['DESCRIPCION_ORIGEN'],
|
|
'color' => $vehicleData['COLOR'],
|
|
'codigo_postal' => $vehicleData['CODIGO_POSTAL'],
|
|
'serie_folio' => $vehicleData['SERIE_FOLIO'],
|
|
'sfolio' => $vehicleData['SFOLIO'],
|
|
'nrpv' => $vehicleData['NUMERO_SERIE'],
|
|
'owner_id' => $owner->id,
|
|
]);
|
|
|
|
// Asignar Tag al vehículo
|
|
$tag->update([
|
|
'vehicle_id' => $vehicle->id,
|
|
'folio' => $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) {
|
|
$fileName = uniqid() . '_' . time() . '_' . $file->getClientOriginalName();
|
|
$path = $file->storeAs('/', $fileName, 'records');
|
|
$md5 = md5_file($file->getRealPath());
|
|
|
|
$fileRecord = File::create([
|
|
'name' => $fileNames[$index] ?? "Archivo " . ($index + 1),
|
|
'path' => $path,
|
|
'md5' => $md5,
|
|
'record_id' => $record->id,
|
|
]);
|
|
|
|
$uploadedFiles[] = [
|
|
'id' => $fileRecord->id,
|
|
'name' => $fileRecord->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,
|
|
'numero_serie' => $vehicle->numero_serie,
|
|
'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,
|
|
],
|
|
'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
";
|
|
|
|
// 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',
|
|
'niv' => 'nullable|string',
|
|
], [
|
|
'required_without_all' => 'Debe proporcionar al menos uno de los siguientes: folio, placa o NIV.'
|
|
]);
|
|
|
|
$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('niv')) {
|
|
$query->whereHas('vehicle', function ($q) use ($request) {
|
|
$q->where('numero_serie', 'LIKE', '%' . $request->input('niv') . '%');
|
|
});
|
|
}
|
|
|
|
$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,
|
|
'numero_serie' => $record->vehicle->numero_serie,
|
|
'marca' => $record->vehicle->marca,
|
|
'modelo' => $record->vehicle->modelo,
|
|
'color' => $record->vehicle->color,
|
|
'tipo' => $record->vehicle->tipo,
|
|
],
|
|
'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,
|
|
'md5' => $file->md5,
|
|
];
|
|
}),
|
|
];
|
|
}),
|
|
'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
|
|
{
|
|
return [
|
|
"ANIO_PLACA" => "2021",
|
|
"PLACA" => "WNU700A",
|
|
"NO_SERIE" => "LSGHD52H0ND032458",
|
|
"RFC" => "GME111116GJA",
|
|
"FOLIO" => "EXP-2025-201030",
|
|
"VIGENCIA" => "2025",
|
|
"FECHA_IMPRESION" => "10-01-2025",
|
|
"QR_HASH" => "Vu5TF4kYsbbltzjDdGQyenKfZoIk2wro34a5Gkh9JVh0CFxfPlrd92YEWK21JF.nLjQNyzKmqRvWYuPiS.kU7A--",
|
|
"VALIDO" => true,
|
|
"FOLIOTEMP" => false,
|
|
"NOMBRE" => "GOLSYSTEMS DE MEXICO S DE RL DE CV",
|
|
"NOMBRE2" => "GOLS*MS DXICOE RL*CV",
|
|
"MUNICIPIO" => "CENTRO",
|
|
"LOCALIDAD" => "VILLAHERMOSA",
|
|
"CALLE" => "C BUGAMBILIAS 118 ",
|
|
"CALLE2" => "C BU*ILIA*18 ",
|
|
"TIPO" => "SEDAN",
|
|
"TIPO_SERVICIO" => "PARTICULAR",
|
|
"MARCA" => "CHEVROLET G.M.C.",
|
|
"LINEA" => "AVEO",
|
|
"SUBLINEA" => "PAQ. \"A\" LS",
|
|
"MODELO" => 2022,
|
|
"NUMERO_SERIE" => "LSGHD52H0ND032458",
|
|
"NUMERO_MOTOR" => "H. EN WUHANLL,SGM",
|
|
"DESCRIPCION_ORIGEN" => "NACIONAL",
|
|
"COLOR" => "BLANCO",
|
|
"CODIGO_POSTAL" => "86179",
|
|
"SERIE_FOLIO" => "D3962242",
|
|
"SFOLIO" => "3962242"
|
|
];
|
|
}
|
|
|
|
private function getOwner(): array
|
|
{
|
|
return [
|
|
'name' => 'Nicolas',
|
|
'paternal' => 'Hernandez',
|
|
'maternal' => 'Castillo',
|
|
'rfc' => 'HECN660509HTCRSC01',
|
|
'curp' => 'HECN660509HTCRSC01',
|
|
'address' => 'Fracc Pomoca, Calle Armadillo MZ9 LT28',
|
|
];
|
|
}
|
|
}
|