631 lines
24 KiB
PHP
631 lines
24 KiB
PHP
<?php
|
|
|
|
namespace App\Http\Controllers\Repuve;
|
|
|
|
use App\Http\Controllers\Controller;
|
|
use Illuminate\Http\Request;
|
|
use App\Http\Requests\Repuve\VehicleUpdateRequest;
|
|
use Notsoweb\ApiResponse\Enums\ApiResponse;
|
|
use Illuminate\Support\Facades\DB;
|
|
use Illuminate\Support\Facades\Storage;
|
|
use Illuminate\Support\Facades\Cache;
|
|
use App\Models\Record;
|
|
use App\Models\File;
|
|
use App\Models\Owner;
|
|
use App\Models\Error;
|
|
use App\Models\CatalogNameImg;
|
|
use App\Models\VehicleTagLog;
|
|
use App\Services\RepuveService;
|
|
use App\Services\PadronEstatalService;
|
|
use Exception;
|
|
use Illuminate\Support\Facades\Auth;
|
|
|
|
class UpdateController extends Controller
|
|
{
|
|
private RepuveService $repuveService;
|
|
private PadronEstatalService $padronEstatalService;
|
|
|
|
public function __construct(
|
|
RepuveService $repuveService,
|
|
PadronEstatalService $padronEstatalService
|
|
) {
|
|
$this->repuveService = $repuveService;
|
|
$this->padronEstatalService = $padronEstatalService;
|
|
}
|
|
|
|
public function vehicleData(Request $request)
|
|
{
|
|
try {
|
|
$request->validate([
|
|
'folio' => 'required|string|exists:records,folio',
|
|
'tag_number' => 'required|string|exists:tags,tag_number',
|
|
'niv' => 'required|string|exists:vehicle,niv'
|
|
]);
|
|
|
|
$folio = $request->input('folio');
|
|
$tagNumber = $request->input('tag_number');
|
|
$niv = $request->input('niv');
|
|
|
|
$isStolen = $this->checkIfStolen($niv);
|
|
|
|
if ($isStolen) {
|
|
return ApiResponse::FORBIDDEN->response([
|
|
'message' => 'El vehículo reporta robo. No se puede continuar con la actualización.',
|
|
]);
|
|
}
|
|
|
|
$record = 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',
|
|
'files:id,record_id,name_id,path,md5',
|
|
'files.catalogName:id,name',
|
|
'user:id,name,email',
|
|
'error:id,code,description'
|
|
])
|
|
->select([
|
|
'id',
|
|
'folio',
|
|
'vehicle_id',
|
|
'user_id',
|
|
'error_id',
|
|
'created_at',
|
|
'updated_at'
|
|
])->where('folio', $folio)
|
|
->first();
|
|
|
|
if (!$record) {
|
|
return ApiResponse::NOT_FOUND->response([
|
|
'message' => 'No se encontró el expediente',
|
|
]);
|
|
}
|
|
|
|
$vehicle = $record->vehicle;
|
|
$tag = $vehicle->tag;
|
|
|
|
if (!$tag || $tag->tag_number !== $tagNumber) {
|
|
return ApiResponse::BAD_REQUEST->response([
|
|
'message' => 'El tag_number no coincide con el registrado en el expediente',
|
|
]);
|
|
}
|
|
|
|
if ($vehicle->niv !== $niv) {
|
|
return ApiResponse::BAD_REQUEST->response([
|
|
'message' => 'El NIV no coincide con el registrado en el expediente',
|
|
]);
|
|
}
|
|
|
|
// Consultar REPUVE Estatal para obtener datos actualizados
|
|
$vehicleDataEstatal = $this->getVehicle($niv);
|
|
$ownerDataEstatal = $this->getOwner($niv);
|
|
|
|
// Guardar en caché por 30 minutos
|
|
Cache::put("update_vehicle_{$niv}", $vehicleDataEstatal, 1800);
|
|
Cache::put("update_owner_{$niv}", $ownerDataEstatal, 1800);
|
|
|
|
// Detectar si hay cambios entre BD y padrón estatal
|
|
$hasVehicleChanges = $this->detectVehicleChanges($vehicle, $vehicleDataEstatal);
|
|
$hasOwnerChanges = $this->detectOwnerChanges($vehicle->owner, $ownerDataEstatal);
|
|
|
|
return ApiResponse::OK->response([
|
|
'message' => 'Datos del vehículo obtenidos exitosamente',
|
|
'current_data' => $record,
|
|
'estatal_data' => [
|
|
'vehicle' => $vehicleDataEstatal,
|
|
'owner' => $ownerDataEstatal,
|
|
],
|
|
'has_changes' => $hasVehicleChanges || $hasOwnerChanges,
|
|
'changes_detail' => [
|
|
'vehicle' => $hasVehicleChanges,
|
|
'owner' => $hasOwnerChanges,
|
|
],
|
|
]);
|
|
} catch (Exception $e) {
|
|
return ApiResponse::BAD_REQUEST->response([
|
|
'message' => 'Error de validación',
|
|
'error' => $e->getMessage(),
|
|
]);
|
|
}
|
|
}
|
|
|
|
public function vehicleUpdate(VehicleUpdateRequest $request)
|
|
{
|
|
try {
|
|
$folio = $request->input('folio');
|
|
$tagNumber = $request->input('tag_number');
|
|
$niv = $request->input('niv');
|
|
|
|
$isStolen = $this->checkIfStolen($niv);
|
|
|
|
if ($isStolen) {
|
|
return ApiResponse::FORBIDDEN->response([
|
|
'niv' => $niv,
|
|
'stolen' => true,
|
|
'message' => 'El vehículo reporta robo. No se puede continuar con la actualización.',
|
|
]);
|
|
}
|
|
|
|
$record = Record::with(['vehicle.owner', 'vehicle.tag', 'files', 'error'])
|
|
->where('folio', $folio)
|
|
->first();
|
|
|
|
if (!$record) {
|
|
return ApiResponse::NOT_FOUND->response([
|
|
'message' => 'No se encontró el expediente',
|
|
'folio' => $folio,
|
|
]);
|
|
}
|
|
|
|
$vehicle = $record->vehicle;
|
|
$tag = $vehicle->tag;
|
|
|
|
if (!$tag) {
|
|
return ApiResponse::NOT_FOUND->response([
|
|
'message' => 'El TAG no coincide con el registrado en el expediente',
|
|
'tag_number' => $tagNumber,
|
|
]);
|
|
}
|
|
|
|
if ($vehicle->niv !== $niv) {
|
|
return ApiResponse::BAD_REQUEST->response([
|
|
'message' => 'El NIV no coincide con el registrado en el expediente',
|
|
]);
|
|
}
|
|
|
|
DB::beginTransaction();
|
|
|
|
$isManualUpdate = $request->has('vehicle') || $request->has('owner');
|
|
$hasVehicleChanges = false;
|
|
$hasOwnerChanges = false;
|
|
$owner = $vehicle->owner;
|
|
|
|
if ($isManualUpdate) {
|
|
if ($request->has('vehicle')) {
|
|
$vehicleData = $request->input('vehicle', []);
|
|
|
|
$allowedVehicleFields = [
|
|
'placa',
|
|
'marca',
|
|
'linea',
|
|
'sublinea',
|
|
'modelo',
|
|
'color',
|
|
'numero_motor',
|
|
'clase_veh',
|
|
'tipo_servicio',
|
|
'rfv',
|
|
'ofcexpedicion',
|
|
'fechaexpedicion',
|
|
'tipo_veh',
|
|
'numptas',
|
|
'observac',
|
|
'cve_vehi',
|
|
'nrpv',
|
|
'tipo_mov'
|
|
];
|
|
|
|
$vehicleData = array_filter(
|
|
array_intersect_key($vehicleData, array_flip($allowedVehicleFields)),
|
|
fn($value) => $value !== null && $value !== ''
|
|
);
|
|
|
|
if (!empty($vehicleData)) {
|
|
$vehicle->update($vehicleData);
|
|
$hasVehicleChanges = true;
|
|
}
|
|
}
|
|
|
|
if ($request->has('owner')) {
|
|
$ownerInput = $request->input('owner', []);
|
|
|
|
$allowedOwnerFields = [
|
|
'name',
|
|
'paternal',
|
|
'maternal',
|
|
'rfc',
|
|
'curp',
|
|
'address',
|
|
'tipopers',
|
|
'pasaporte',
|
|
'licencia',
|
|
'ent_fed',
|
|
'munic',
|
|
'callep',
|
|
'num_ext',
|
|
'num_int',
|
|
'colonia',
|
|
'cp',
|
|
'telefono'
|
|
];
|
|
|
|
$ownerData = array_filter(
|
|
array_intersect_key($ownerInput, array_flip($allowedOwnerFields)),
|
|
fn($value) => $value !== null && $value !== ''
|
|
);
|
|
|
|
if (!empty($ownerData)) {
|
|
// Si se cambió el RFC, buscar/crear otro propietario
|
|
if (isset($ownerData['rfc']) && $ownerData['rfc'] !== $owner->rfc) {
|
|
$owner = Owner::updateOrCreate(
|
|
['rfc' => $ownerData['rfc']],
|
|
$ownerData
|
|
);
|
|
$vehicle->update(['owner_id' => $owner->id]);
|
|
} else {
|
|
// Actualizar propietario existente
|
|
$owner->update($ownerData);
|
|
}
|
|
$hasOwnerChanges = true;
|
|
}
|
|
}
|
|
} else {
|
|
|
|
// Intentar obtener datos del caché primero
|
|
$vehicleDataEstatal = Cache::get("update_vehicle_{$niv}");
|
|
$ownerDataEstatal = Cache::get("update_owner_{$niv}");
|
|
|
|
// Si no hay
|
|
if (!$vehicleDataEstatal || !$ownerDataEstatal) {
|
|
$vehicleDataEstatal = $this->getVehicle($niv);
|
|
$ownerDataEstatal = $this->getOwner($niv);
|
|
}
|
|
|
|
// Limpiar caché
|
|
Cache::forget("update_vehicle_{$niv}");
|
|
Cache::forget("update_owner_{$niv}");
|
|
|
|
// Detectar si hay cambios
|
|
$hasVehicleChanges = $this->detectVehicleChanges($vehicle, $vehicleDataEstatal);
|
|
$hasOwnerChanges = $this->detectOwnerChanges($vehicle->owner, $ownerDataEstatal);
|
|
|
|
// Actualizar vehículo solo si hay cambios
|
|
if ($hasVehicleChanges) {
|
|
$vehicle->update($vehicleDataEstatal);
|
|
}
|
|
|
|
// Actualizar propietario solo si hay cambios
|
|
$owner = $vehicle->owner;
|
|
if ($hasOwnerChanges) {
|
|
$owner = Owner::updateOrCreate(
|
|
['rfc' => $ownerDataEstatal['rfc']],
|
|
$ownerDataEstatal
|
|
);
|
|
$vehicle->update(['owner_id' => $owner->id]);
|
|
}
|
|
}
|
|
|
|
|
|
$uploadedFiles = [];
|
|
$replacedFiles = [];
|
|
|
|
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::BAD_REQUEST->response([
|
|
'message' => 'Algunos ids del catálogo de nombres no son válidos',
|
|
'provided_id' => $nameIds,
|
|
'valid_id' => $validIds,
|
|
]);
|
|
}
|
|
}
|
|
|
|
foreach ($files as $indx => $file) {
|
|
$nameId = $nameIds[$indx] ?? null;
|
|
|
|
if ($nameId === null) {
|
|
DB::rollBack();
|
|
return ApiResponse::BAD_REQUEST->response([
|
|
'message' => "Falta el nombre para el archivo, busca en el catálogo de nombres",
|
|
]);
|
|
}
|
|
|
|
$existingFile = File::where('record_id', $record->id)
|
|
->where('name_id', $nameId)
|
|
->first();
|
|
|
|
if ($existingFile) {
|
|
Storage::disk('public')->delete($existingFile->path);
|
|
|
|
$replacedFiles[] = [
|
|
'id' => $existingFile->id,
|
|
'name_id' => $nameId,
|
|
'old_path' => $existingFile->path,
|
|
];
|
|
|
|
$existingFile->delete();
|
|
}
|
|
|
|
// 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,
|
|
'replaced' => $existingFile !== null,
|
|
];
|
|
}
|
|
}
|
|
|
|
if ($hasVehicleChanges || $hasOwnerChanges || count($uploadedFiles) > 0) {
|
|
VehicleTagLog::create([
|
|
'vehicle_id' => $vehicle->id,
|
|
'tag_id' => $tag->id,
|
|
'action_type' => 'actualizacion',
|
|
'performed_by' => Auth::id()
|
|
]);
|
|
}
|
|
|
|
// Solo enviar a REPUVE Nacional si hay cambios
|
|
if ($hasVehicleChanges || $hasOwnerChanges || count($uploadedFiles) > 0) {
|
|
//Envio de datos
|
|
$apiResponse = $this->sendToRepuveNacional($niv);
|
|
$apiResponse["repuve_response"]["folio_ci"] = $record->folio;
|
|
$apiResponse["repuve_response"]["identificador_ci"] = $tag->tag_number;
|
|
|
|
if (isset($apiResponse['has_error']) && $apiResponse['has_error']) {
|
|
$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
|
|
$error = Error::where('code', '-1')->first();
|
|
|
|
if (!$error) {
|
|
// Si ni siquiera existe el error genérico
|
|
$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',
|
|
]);
|
|
}
|
|
}
|
|
|
|
$record->update([
|
|
'error_id' => $error->id,
|
|
'api_response' => $apiResponse,
|
|
'error_occurred_at' => now(),
|
|
]);
|
|
|
|
DB::commit();
|
|
|
|
return ApiResponse::NOT_ACCEPTABLE->response([
|
|
'message' => 'Datos guardados con error. Corrija y vuelva a enviar.',
|
|
'has_error' => true,
|
|
'can_retry' => true,
|
|
'error' => [
|
|
'code' => $error->code,
|
|
'description' => $error->description,
|
|
'occurred_at' => $record->error_occurred_at->toDateTimeString(),
|
|
],
|
|
'record' => [
|
|
'id' => $record->id,
|
|
'folio' => $record->folio,
|
|
],
|
|
]);
|
|
}
|
|
|
|
$record->update([
|
|
'error_id' => null,
|
|
'api_response' => $apiResponse,
|
|
'error_occurred_at' => null,
|
|
]);
|
|
}
|
|
|
|
DB::commit();
|
|
|
|
$sentToRepuve = $hasVehicleChanges || $hasOwnerChanges || count($uploadedFiles) > 0;
|
|
|
|
$message = 'Vehículo actualizado exitosamente';
|
|
if (!$hasVehicleChanges && !$hasOwnerChanges && empty($uploadedFiles)) {
|
|
$message = 'No se detectaron cambios. Los datos ya estaban actualizados.';
|
|
} elseif (!$hasVehicleChanges && !$hasOwnerChanges && empty($uploadedFiles)) {
|
|
$message = 'Solo se actualizaron archivos. Los datos del vehículo/propietario no cambiaron.';
|
|
} elseif (($hasVehicleChanges || $hasOwnerChanges) && empty($uploadedFiles)) {
|
|
$message = 'Datos del vehículo/propietario actualizados exitosamente. No se subieron archivos.';
|
|
} elseif ((!$hasVehicleChanges && !$hasOwnerChanges) && !empty($uploadedFiles)) {
|
|
$message = 'Archivos subidos exitosamente. No hubo cambios en los datos del vehículo/propietario.';
|
|
}
|
|
|
|
return ApiResponse::OK->response([
|
|
'message' => $message,
|
|
'has_error' => false,
|
|
'sent_to_repuve' => $sentToRepuve,
|
|
'changes_made' => [
|
|
'vehicle_updated' => $hasVehicleChanges,
|
|
'owner_updated' => $hasOwnerChanges,
|
|
'files_uploaded' => count($uploadedFiles) > 0,
|
|
],
|
|
'record' => [
|
|
'id' => $record->id,
|
|
'folio' => $record->folio,
|
|
'updated_at' => $record->updated_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,
|
|
'tag_number' => $tag->tag_number,
|
|
'status' => $tag->status->name,
|
|
],
|
|
'uploaded_files' => $uploadedFiles,
|
|
'replaced_count' => count($replacedFiles),
|
|
'total_files' => File::where('record_id', $record->id)->count(),
|
|
]);
|
|
} catch (Exception $e) {
|
|
return ApiResponse::INTERNAL_ERROR->response([
|
|
'message' => 'Error al actualizar el vehículo',
|
|
'error' => $e->getMessage(),
|
|
]);
|
|
}
|
|
}
|
|
|
|
private function checkIfStolen(string $niv): bool
|
|
{
|
|
return $this->repuveService->verificarRobo($niv);
|
|
}
|
|
|
|
private function prepararDatosParaInscripcion(string $niv): array
|
|
{
|
|
$datos = $this->padronEstatalService->getVehiculoByNiv($niv);
|
|
|
|
return [
|
|
'ent_fed' => $datos['ent_fed'] ?? '',
|
|
'ofcexp' => $datos['ofcexp'] ?? '',
|
|
'fechaexp' => $datos['fechaexp'] ?? '',
|
|
'placa' => $datos['placa'] ?? '',
|
|
'tarjetacir' => $datos['tarjetacir'] ?? '',
|
|
'marca' => $datos['marca'] ?? '',
|
|
'submarca' => $datos['submarca'] ?? '',
|
|
'version' => $datos['version'] ?? '',
|
|
'clase_veh' => $datos['clase_veh'] ?? '',
|
|
'tipo_veh' => $datos['tipo_veh'] ?? '',
|
|
'tipo_uso' => $datos['tipo_uso'] ?? '',
|
|
'modelo' => $datos['modelo'] ?? '',
|
|
'color' => $datos['color'] ?? '',
|
|
'motor' => $datos['motor'] ?? '',
|
|
'niv' => $datos['niv'] ?? '',
|
|
'rfv' => $datos['rfv'] ?? '',
|
|
'numptas' => $datos['numptas'] ?? '',
|
|
'observac' => $datos['observac'] ?? '',
|
|
'tipopers' => $datos['tipopers'] ?? '',
|
|
'curp' => $datos['curp'] ?? '',
|
|
'rfc' => $datos['rfc'] ?? '',
|
|
'pasaporte' => $datos['pasaporte'] ?? '',
|
|
'licencia' => $datos['licencia'] ?? '',
|
|
'nombre' => $datos['nombre'] ?? '',
|
|
'ap_paterno' => $datos['ap_paterno'] ?? '',
|
|
'ap_materno' => $datos['ap_materno'] ?? '',
|
|
'munic' => $datos['munic'] ?? '',
|
|
'callep' => $datos['callep'] ?? '',
|
|
'num_ext' => $datos['num_ext'] ?? '',
|
|
'num_int' => $datos['num_int'] ?? '',
|
|
'colonia' => $datos['colonia'] ?? '',
|
|
'cp' => $datos['cp'] ?? '',
|
|
'cve_vehi' => $datos['cve_vehi'] ?? '',
|
|
'nrpv' => $datos['nrpv'] ?? '',
|
|
'tipo_mov' => $datos['tipo_mov'] ?? '',
|
|
];
|
|
}
|
|
|
|
private function sendToRepuveNacional(string $niv): array
|
|
{
|
|
$datosCompletos = $this->prepararDatosParaInscripcion($niv);
|
|
return $this->repuveService->inscribirVehiculo($datosCompletos);
|
|
}
|
|
|
|
private function detectVehicleChanges($vehicle, array $vehicleDataEstatal): bool
|
|
{
|
|
$fieldsToCompare = [
|
|
'placa',
|
|
'marca',
|
|
'linea',
|
|
'sublinea',
|
|
'modelo',
|
|
'color',
|
|
'numero_motor',
|
|
'clase_veh',
|
|
'tipo_servicio',
|
|
'rfv',
|
|
'ofcexpedicion',
|
|
'tipo_veh',
|
|
'numptas',
|
|
'observac',
|
|
'cve_vehi',
|
|
'nrpv',
|
|
'tipo_mov'
|
|
];
|
|
|
|
foreach ($fieldsToCompare as $field) {
|
|
$bdValue = $vehicle->$field ?? null;
|
|
$estatalValue = $vehicleDataEstatal[$field] ?? null;
|
|
|
|
if (strval($bdValue) !== strval($estatalValue)) {
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
private function detectOwnerChanges($owner, array $ownerDataEstatal): bool
|
|
{
|
|
$fieldsToCompare = [
|
|
'name',
|
|
'paternal',
|
|
'maternal',
|
|
'rfc',
|
|
'curp',
|
|
'address',
|
|
'tipopers',
|
|
'pasaporte',
|
|
'licencia',
|
|
'ent_fed',
|
|
'munic',
|
|
'callep',
|
|
'num_ext',
|
|
'num_int',
|
|
'colonia',
|
|
'cp'
|
|
];
|
|
|
|
foreach ($fieldsToCompare as $field) {
|
|
$bdValue = $owner->$field ?? null;
|
|
$estatalValue = $ownerDataEstatal[$field] ?? null;
|
|
|
|
if (strval($bdValue) !== strval($estatalValue)) {
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
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);
|
|
}
|
|
}
|