diff --git a/app/Http/Controllers/Repuve/CancellationController.php b/app/Http/Controllers/Repuve/CancellationController.php index 03e1fe9..ef5c554 100644 --- a/app/Http/Controllers/Repuve/CancellationController.php +++ b/app/Http/Controllers/Repuve/CancellationController.php @@ -40,7 +40,15 @@ public function cancelarConstancia(CancelConstanciaRequest $request) ]); } - // Crear registro en el log de cancelaciones (HISTORIAL) + // Validar que el registro no tenga errores previos + if ($record->error_id !== null) { + return ApiResponse::BAD_REQUEST->response([ + 'message' => 'No se puede cancelar un registro que tiene errores. El vehículo no fue inscrito.', + 'error_id' => $record->error_id + ]); + } + + // Crear registro en el log de cancelaciones $cancellationLog = VehicleTagLog::create([ 'vehicle_id' => $vehicle->id, 'tag_id' => $tag->id, @@ -50,9 +58,10 @@ public function cancelarConstancia(CancelConstanciaRequest $request) 'cancelled_by' => auth()->id(), ]); - // Actualizar estado del tag a 'cancelled' + // Actualizar estado del tag a 'cancelled' y desasignar vehículo $tag->update([ 'status' => 'cancelled', + 'vehicle_id' => null, ]); DB::commit(); @@ -64,7 +73,7 @@ public function cancelarConstancia(CancelConstanciaRequest $request) 'vehicle' => [ 'id' => $vehicle->id, 'placa' => $vehicle->placa, - 'numero_serie' => $vehicle->numero_serie, + 'niv' => $vehicle->niv, ], 'tag' => [ 'id' => $tag->id, diff --git a/app/Http/Controllers/Repuve/InscriptionController.php b/app/Http/Controllers/Repuve/InscriptionController.php index f12b9e0..2eb9486 100644 --- a/app/Http/Controllers/Repuve/InscriptionController.php +++ b/app/Http/Controllers/Repuve/InscriptionController.php @@ -191,8 +191,8 @@ public function vehicleInscription(VehicleStoreRequest $request) // Enviar a API Repuve Nacional $apiResponse = $this->sendToRepuveNacional($niv); - $apiResponse["repuve_response"]["folio_ci"] = $folio; - $apiResponse["repuve_response"]["identificador_ci"] = $tagNumber; + $apiResponse["repuve_response"]["folio_ci"] = $folio; //harcodeado cambiar despues + $apiResponse["repuve_response"]["identificador_ci"] = $tagNumber; //harcodeado cambiar despues // Procesar respuesta if (isset($apiResponse['has_error']) && $apiResponse['has_error']) { diff --git a/app/Http/Controllers/Repuve/UpdateController.php b/app/Http/Controllers/Repuve/UpdateController.php index 873faea..edfcb63 100644 --- a/app/Http/Controllers/Repuve/UpdateController.php +++ b/app/Http/Controllers/Repuve/UpdateController.php @@ -8,15 +8,28 @@ 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\Services\RepuveService; +use App\Services\PadronEstatalService; use Exception; 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) { @@ -31,7 +44,7 @@ public function vehicleData(Request $request) $tagNumber = $request->input('tag_number'); $niv = $request->input('niv'); - $isStolen = $this->checkIfStolen($folio); + $isStolen = $this->checkIfStolen($niv); if ($isStolen) { return ApiResponse::FORBIDDEN->response([ @@ -80,9 +93,30 @@ public function vehicleData(Request $request) ]); } + // 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', - 'records' => $record, + '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([ @@ -99,7 +133,7 @@ public function vehicleUpdate(VehicleUpdateRequest $request) $tagNumber = $request->input('tag_number'); $niv = $request->input('niv'); - $isStolen = $this->checkIfStolen($folio); + $isStolen = $this->checkIfStolen($niv); if ($isStolen) { return ApiResponse::FORBIDDEN->response([ @@ -137,20 +171,77 @@ public function vehicleUpdate(VehicleUpdateRequest $request) DB::beginTransaction(); - $ownerData = $this->getOwner(); + // Intentar obtener datos del caché primero + $vehicleData = Cache::get("update_vehicle_{$niv}"); + $ownerData = Cache::get("update_owner_{$niv}"); - $owner = Owner::updateOrCreate( - ['rfc' => $ownerData['rfc']], - [ - 'name' => $ownerData['name'], - 'paternal' => $ownerData['paternal'], - 'maternal' => $ownerData['maternal'], - 'curp' => $ownerData['curp'], - 'address' => $ownerData['address'], - ] - ); + // Si no hay + if (!$vehicleData || !$ownerData) { + $vehicleData = $this->getVehicle($niv); + $ownerData = $this->getOwner($niv); + } + + // Limpiar caché + Cache::forget("update_vehicle_{$niv}"); + Cache::forget("update_owner_{$niv}"); + + // Detectar si hay cambios + $hasVehicleChanges = $this->detectVehicleChanges($vehicle, $vehicleData); + $hasOwnerChanges = $this->detectOwnerChanges($vehicle->owner, $ownerData); + + // Actualizar propietario solo si hay cambios + $owner = $vehicle->owner; + if ($hasOwnerChanges) { + $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'], + ] + ); + } + + // Actualizar vehículo solo si hay cambios + if ($hasVehicleChanges) { + $vehicle->update([ + 'placa' => $vehicleData['placa'], + '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'], + 'nrpv' => $vehicleData['nrpv'], + 'tipo_mov' => $vehicleData['tipo_mov'], + 'owner_id' => $owner->id, + ]); + } $uploadedFiles = []; + $replacedFiles = []; if ($request->hasFile('files')) { $files = $request->file('files'); @@ -178,13 +269,11 @@ public function vehicleUpdate(VehicleUpdateRequest $request) ]); } - // Buscar si ya existe un archivo con este name_id para este record $existingFile = File::where('record_id', $record->id) ->where('name_id', $nameId) ->first(); if ($existingFile) { - // Eliminar el archivo físico anterior Storage::disk('public')->delete($existingFile->path); $replacedFiles[] = [ @@ -193,7 +282,6 @@ public function vehicleUpdate(VehicleUpdateRequest $request) 'old_path' => $existingFile->path, ]; - // Eliminar el registro de la BD $existingFile->delete(); } @@ -221,58 +309,76 @@ public function vehicleUpdate(VehicleUpdateRequest $request) } } - //Envio de datos - $apiResponse = $this->sendToRepuveNacional($niv); - $apiResponse["repuve_response"]["folio_ci"] = $record->folio; - $apiResponse["repuve_response"]["identificador_ci"] = $tag->tag_number; + // 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 (isset($apiResponse['has_error']) && $apiResponse['has_error']) { + $error = Error::where('code', $apiResponse['error_code'])->first(); - if (!$error) { - DB::rollBack(); - return ApiResponse::INTERNAL_ERROR->response([ - 'message' => 'Código de error no encontrado en el catálogo', - 'error_code' => $apiResponse['error_code'], - 'error_message' => $apiResponse['error_message'], + if (!$error) { + DB::rollBack(); + return ApiResponse::INTERNAL_ERROR->response([ + 'message' => 'Código de error no encontrado en el catálogo', + 'error_code' => $apiResponse['error_code'], + 'error_message' => $apiResponse['error_message'], + ]); + } + + $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' => $error->id, + 'error_id' => null, '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, - ], + 'error_occurred_at' => null, ]); } - $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) { + $message = 'Solo se actualizaron archivos. Los datos del vehículo/propietario no cambiaron.'; + } + return ApiResponse::OK->response([ - 'message' => 'Vehículo actualizado exitosamente', + '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, @@ -308,76 +414,137 @@ public function vehicleUpdate(VehicleUpdateRequest $request) } } - private function checkIfStolen(string $folio): bool + private function checkIfStolen(string $niv): bool { - // Aquí api servicio de REPUVE Nacional - // simulamos con random - return (bool) rand(0, 1); + 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 { - // Enviar datos a API Repuve Nacional - // Aquí se haría la llamada real a la API de Repuve Nacional - // Por ahora simulamos con mock igual que InscriptionController + $datosCompletos = $this->prepararDatosParaInscripcion($niv); + return $this->repuveService->inscribirVehiculo($datosCompletos); + } - // Respuesta exitosa mockup REPUVE - $mockResponse = "OK:SIN INFORMACION|OTROS|SIN INFORMACION|10/07/2023|CENTRO|$niv|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 usando los campos oficiales - $fields = [ - 'marca', - 'submarca', - 'tipo_vehiculo', - 'fecha_expedicion', - 'oficina', - 'niv', + private function detectVehicleChanges($vehicle, array $vehicleDataEstatal): bool + { + $fieldsToCompare = [ 'placa', - 'motor', + 'marca', + 'linea', + 'sublinea', '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' + 'numero_motor', + 'clase_veh', + 'tipo_servicio', + 'rfv', + 'rfc', + 'ofcexpedicion', + 'tipo_veh', + 'numptas', + 'observac', + 'cve_vehi', + 'nrpv', + 'tipo_mov' ]; - $values = explode('|', str_replace('OK:', '', $mockResponse)); - $jsonResponse = []; - foreach ($fields as $i => $field) { - $jsonResponse[$field] = $values[$i] ?? null; + + foreach ($fieldsToCompare as $field) { + $bdValue = $vehicle->$field ?? null; + $estatalValue = $vehicleDataEstatal[$field] ?? null; + + if (strval($bdValue) !== strval($estatalValue)) { + return true; + } } - return [ - 'has_error' => false, - 'error_code' => null, - 'error_message' => null, - 'timestamp' => now()->toDateTimeString(), - 'niv' => $niv, - 'repuve_response' => $jsonResponse, - ]; + return false; } - private function getOwner(): array + private function detectOwnerChanges($owner, array $ownerDataEstatal): bool { - return [ - 'name' => 'Nicolas', - 'paternal' => 'Hernandez', - 'maternal' => 'Castillo', - 'rfc' => 'HECN660509HTCRSC01', - 'curp' => 'HECN660509HTCRSC01', - 'address' => 'Fracc Pomoca, Calle Armadillo MZ9 LT28', + $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); } }