Correciones a Actualizar y Cancelar

This commit is contained in:
Juan Felipe Zapata Moreno 2025-11-21 20:17:26 -06:00
parent 4c6dccf056
commit ef864c4753
3 changed files with 291 additions and 115 deletions

View File

@ -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,

View File

@ -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']) {

View File

@ -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);
}
}