450 lines
17 KiB
PHP
450 lines
17 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 App\Models\VehicleTagLog;
|
|
use Illuminate\Support\Facades\DB;
|
|
use Illuminate\Support\Facades\Auth;
|
|
use App\Services\RepuveService;
|
|
use App\Services\PadronEstatalService;
|
|
|
|
class InscriptionController extends Controller
|
|
{
|
|
private RepuveService $repuveService;
|
|
private PadronEstatalService $padronEstatalService;
|
|
|
|
public function __construct(
|
|
RepuveService $repuveService,
|
|
PadronEstatalService $padronEstatalService
|
|
) {
|
|
$this->repuveService = $repuveService;
|
|
$this->padronEstatalService = $padronEstatalService;
|
|
}
|
|
|
|
/*
|
|
* Inscripción de vehículo al REPUVE
|
|
*/
|
|
public function vehicleInscription(VehicleStoreRequest $request)
|
|
{
|
|
try {
|
|
$folio = $request->input('folio');
|
|
$tagNumber = $request->input('tag_number');
|
|
$niv = $request->input('niv');
|
|
$telefono = $request->input('telefono');
|
|
|
|
// 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->isAvailable()) {
|
|
return ApiResponse::BAD_REQUEST->response([
|
|
'message' => 'El tag ya está asignado a un vehículo. Use actualizar en su lugar.',
|
|
'current_status' => $tag->status->name,
|
|
]);
|
|
}
|
|
|
|
// Verificar robo (API Repuve Nacional)
|
|
$isStolen = $this->checkIfStolen($niv);
|
|
|
|
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($niv);
|
|
$ownerData = $this->getOwner($niv);
|
|
|
|
// 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'],
|
|
'telefono' => $telefono
|
|
]
|
|
);
|
|
|
|
// 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'],
|
|
'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);
|
|
|
|
VehicleTagLog::create([
|
|
'vehicle_id' => $vehicle->id,
|
|
'tag_id' => $tag->id,
|
|
'action_type' => 'inscripcion',
|
|
'performed_by' => Auth::id(),
|
|
]);
|
|
|
|
// Crear registro
|
|
$record = Record::create([
|
|
'folio' => $folio,
|
|
'vehicle_id' => $vehicle->id,
|
|
'user_id' => Auth::id(),
|
|
'module_id' => Auth::user()->module_id,
|
|
]);
|
|
|
|
// Procesar archivos
|
|
$uploadedFiles = [];
|
|
if ($request->hasFile('files')) {
|
|
$files = $request->file('files');
|
|
$nameIds = $request->input('name_id', []);
|
|
|
|
if (!empty($nameIds)) {
|
|
$validIds = CatalogNameImg::whereIn('id', $nameIds)->pluck('id')->toArray();
|
|
if (count($validIds) !== count($nameIds)) {
|
|
DB::rollBack();
|
|
return ApiResponse::INTERNAL_ERROR->response([
|
|
'message' => 'Algunos IDs del catálogo de nombres no son válidos',
|
|
'provided_id' => $nameIds,
|
|
'valid_id' => $validIds,
|
|
]);
|
|
}
|
|
}
|
|
|
|
foreach ($files as $index => $file) {
|
|
// Obtener el name_id del request o usar null como fallback
|
|
$nameId = $nameIds[$index] ?? null;
|
|
|
|
if ($nameId === null) {
|
|
DB::rollBack();
|
|
return ApiResponse::INTERNAL_ERROR->response([
|
|
'message' => "Falta el name_id para el archivo en el índice {$index}",
|
|
'file_index' => $index,
|
|
]);
|
|
}
|
|
|
|
// Obtener el nombre del catálogo para el nombre del archivo
|
|
$catalogName = CatalogNameImg::find($nameId);
|
|
$extension = $file->getClientOriginalExtension();
|
|
$fileName = $catalogName->name . '_' . date('dmY_His') . '.' . $extension;
|
|
$path = $file->storeAs("records/{$record->folio}", $fileName, 'public');
|
|
$md5 = md5_file($file->getRealPath());
|
|
|
|
$fileRecord = File::create([
|
|
'name_id' => $nameId,
|
|
'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($niv);
|
|
|
|
if (isset($apiResponse['repuve_response']) && is_array($apiResponse['repuve_response'])) {
|
|
$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) {
|
|
// Usar error genérico si no se encuentra el código
|
|
logger()->warning('Código de error REPUVE no catalogado', [
|
|
'error_code' => $apiResponse['error_code'],
|
|
'error_message' => $apiResponse['error_message'],
|
|
'niv' => $niv,
|
|
]);
|
|
|
|
// Buscar error genérico -1 (Error Interno)
|
|
$error = Error::where('code', '-1')->first();
|
|
|
|
if (!$error) {
|
|
// Si ni siquiera existe el error genérico, crear uno temporal
|
|
$error = Error::create([
|
|
'code' => '-1',
|
|
'name' => 'Error Interno',
|
|
'description' => 'Error interno del web service. Problemas con la base de datos o en la red.',
|
|
'type' => 'Error de Conexión',
|
|
]);
|
|
}
|
|
}
|
|
|
|
// 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();
|
|
|
|
$record->load(['vehicle.owner', 'vehicle.tag', 'files', 'user']);
|
|
|
|
// 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' => $record->vehicle->id,
|
|
'placa' => $record->vehicle->placa,
|
|
'niv' => $record->vehicle->niv,
|
|
'marca' => $record->vehicle->marca,
|
|
'linea' => $record->vehicle->linea,
|
|
'modelo' => $record->vehicle->modelo,
|
|
'color' => $record->vehicle->color,
|
|
],
|
|
'owner' => [
|
|
'id' => $record->vehicle->owner->id,
|
|
'full_name' => $record->vehicle->owner->full_name,
|
|
'rfc' => $record->vehicle->owner->rfc,
|
|
],
|
|
'tag' => [
|
|
'id' => $record->vehicle->tag->id,
|
|
'folio' => $record->vehicle->tag->folio,
|
|
'status' => $record->vehicle->tag->status->name,
|
|
],
|
|
'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 $niv)
|
|
{
|
|
return $this->repuveService->verificarRobo($niv);
|
|
}
|
|
|
|
public function stolen(Request $request)
|
|
{
|
|
$request->validate([
|
|
'folio' => ['sometimes', 'string', 'max:50'],
|
|
'tag_number' => ['sometimes', 'string', 'exists:tags,tag_number'],
|
|
'vin' => ['sometimes', 'string', 'max:30'],
|
|
]);
|
|
|
|
$folio = $request->input('folio');
|
|
$tagNumber = $request->input('tag_number');
|
|
$vin = $request->input('vin');
|
|
|
|
// Validar que se proporcione al menos un criterio de búsqueda
|
|
if (!$folio && !$tagNumber && !$vin) {
|
|
return ApiResponse::BAD_REQUEST->response([
|
|
'message' => 'Debe proporcionar al menos un criterio de búsqueda: folio y tag_number, o vin',
|
|
]);
|
|
}
|
|
$query = Record::with(['vehicle.owner', 'vehicle.tag']);
|
|
|
|
// Búsqueda por folio ó tag_number
|
|
if ($folio && !$tagNumber) {
|
|
$query->where('folio', $folio);
|
|
} elseif (!$folio && $tagNumber) {
|
|
$query->whereHas('vehicle.tag', function ($q) use ($tagNumber) {
|
|
$q->where('tag_number', $tagNumber);
|
|
});
|
|
} // Búsqueda solo por VIN
|
|
elseif ($vin) {
|
|
$query->whereHas('vehicle', function ($q) use ($vin) {
|
|
$q->where('niv', $vin);
|
|
});
|
|
}
|
|
|
|
$record = $query->first();
|
|
|
|
if (!$record) {
|
|
return ApiResponse::NOT_FOUND->response([
|
|
'stolen' => false,
|
|
'message' => 'No se encontró ningún registro con los criterios proporcionados',
|
|
]);
|
|
}
|
|
|
|
return ApiResponse::OK->response([
|
|
'stolen' => true,
|
|
'vehicle' => [
|
|
'folio' => $record->folio,
|
|
'placa' => $record->vehicle->placa,
|
|
'tag_number' => $record->vehicle->tag?->tag_number,
|
|
'vin' => $record->vehicle->niv,
|
|
'marca' => $record->vehicle->marca,
|
|
'modelo' => $record->vehicle->linea,
|
|
'año' => $record->vehicle->modelo,
|
|
],
|
|
]);
|
|
}
|
|
|
|
private function sendToRepuveNacional(string $niv): array
|
|
{
|
|
// Obtener los datos completos del padrón estatal
|
|
$datosCompletos = $this->padronEstatalService->getVehiculoByNiv($niv);
|
|
// Enviar a inscripción de REPUVE Federal
|
|
return $this->repuveService->inscribirVehiculo($datosCompletos);
|
|
}
|
|
|
|
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.'
|
|
]);
|
|
|
|
$records = Record::with([
|
|
'vehicle:id,owner_id,placa,niv,marca,linea,modelo,color',
|
|
'vehicle.owner:id,name,paternal,maternal,rfc',
|
|
'vehicle.tag:id,vehicle_id,folio,tag_number,status_id',
|
|
'vehicle.tag.status:id,code,name',
|
|
'files:id,record_id,name_id,path,md5',
|
|
'files.catalogName:id,name',
|
|
'user:id,name,email',
|
|
'error:id,code,description'
|
|
])->orderBy('id', 'ASC');
|
|
|
|
if ($request->filled('folio')) {
|
|
$records->whereHas('vehicle.tag', function ($q) use ($request) {
|
|
$q->where('folio', 'LIKE', '%' . $request->input('folio') . '%');
|
|
});
|
|
} elseif ($request->filled('placa')) {
|
|
$records->whereHas('vehicle', function ($q) use ($request) {
|
|
$q->where('placa', 'LIKE', '%' . $request->input('placa') . '%');
|
|
});
|
|
} elseif ($request->filled('vin')) {
|
|
$records->whereHas('vehicle', function ($q) use ($request) {
|
|
$q->where('niv', 'LIKE', '%' . $request->input('vin') . '%');
|
|
});
|
|
}
|
|
|
|
return ApiResponse::OK->response([
|
|
'records' => $records->select([
|
|
'id',
|
|
'folio',
|
|
'vehicle_id',
|
|
'user_id',
|
|
'error_id',
|
|
'created_at'
|
|
])->paginate(config('app.pagination'))
|
|
]);
|
|
}
|
|
|
|
private function getVehicle(string $niv): array
|
|
{
|
|
$datos = $this->padronEstatalService->getVehiculoByNiv($niv);
|
|
return $this->padronEstatalService->extraerDatosVehiculo($datos);
|
|
}
|
|
|
|
private function getOwner(string $niv): array
|
|
{
|
|
$datos = $this->padronEstatalService->getVehiculoByNiv($niv);
|
|
return $this->padronEstatalService->extraerDatosPropietario($datos);
|
|
}
|
|
}
|