From 906299ac108fbf64d1f30b58f7648fe8e23dd2c3 Mon Sep 17 00:00:00 2001 From: Juan Felipe Zapata Moreno Date: Thu, 30 Oct 2025 17:33:05 -0600 Subject: [PATCH] ADD: Nueva tabla catalogo, seeders catalog y modulos --- app/Http/Controllers/Admin/UserController.php | 4 +- .../Repuve/CatalogNameImgController.php | 76 ++++++ .../Repuve/InscriptionController.php | 249 +++++++++++++----- .../Controllers/Repuve/RecordController.php | 89 ++++++- .../Repuve/CatalogNameImgStoreRequest.php | 26 ++ .../Repuve/CatalogNameImgUpdateRequest.php | 26 ++ app/Models/CatalogNameImg.php | 28 ++ app/Models/File.php | 7 +- app/Models/Owner.php | 12 +- app/Models/Vehicle.php | 39 ++- database/factories/DeviceFactory.php | 67 ----- database/factories/ErrorFactory.php | 64 ----- database/factories/FileFactory.php | 128 --------- database/factories/ModuleFactory.php | 77 ------ database/factories/OwnerFactory.php | 116 -------- database/factories/PackageFactory.php | 76 ------ database/factories/RecordFactory.php | 93 ------- database/factories/TagFactory.php | 112 -------- database/factories/VehicleFactory.php | 153 ----------- .../2025_10_18_140200_create_owners_table.php | 12 +- ...2025_10_18_140600_create_vehicle_table.php | 36 +-- .../2025_10_18_141000_create_files_table.php | 1 - ...0_153423_create_catalog_name_img_table.php | 29 ++ ...0_30_164633_add_name_id_to_files_table.php | 23 ++ database/seeders/CatalogNameImgSeeder.php | 51 ++++ database/seeders/DevSeeder.php | 16 +- database/seeders/DeviceSeeder.php | 77 ------ database/seeders/ErrorSeeder.php | 38 --- database/seeders/FileSeeder.php | 50 ---- database/seeders/ModuleSeeder.php | 74 +++--- database/seeders/OwnerSeeder.php | 18 -- database/seeders/PackageSeeder.php | 31 --- database/seeders/RecordSeeder.php | 55 ---- database/seeders/TagSeeder.php | 93 ------- database/seeders/VehicleSeeder.php | 39 --- routes/api.php | 6 +- 36 files changed, 626 insertions(+), 1465 deletions(-) create mode 100644 app/Http/Controllers/Repuve/CatalogNameImgController.php create mode 100644 app/Http/Requests/Repuve/CatalogNameImgStoreRequest.php create mode 100644 app/Http/Requests/Repuve/CatalogNameImgUpdateRequest.php create mode 100644 app/Models/CatalogNameImg.php delete mode 100644 database/factories/DeviceFactory.php delete mode 100644 database/factories/ErrorFactory.php delete mode 100644 database/factories/FileFactory.php delete mode 100644 database/factories/ModuleFactory.php delete mode 100644 database/factories/OwnerFactory.php delete mode 100644 database/factories/PackageFactory.php delete mode 100644 database/factories/RecordFactory.php delete mode 100644 database/factories/TagFactory.php delete mode 100644 database/factories/VehicleFactory.php create mode 100644 database/migrations/2025_10_30_153423_create_catalog_name_img_table.php create mode 100644 database/migrations/2025_10_30_164633_add_name_id_to_files_table.php create mode 100644 database/seeders/CatalogNameImgSeeder.php delete mode 100644 database/seeders/DeviceSeeder.php delete mode 100644 database/seeders/ErrorSeeder.php delete mode 100644 database/seeders/FileSeeder.php delete mode 100644 database/seeders/OwnerSeeder.php delete mode 100644 database/seeders/PackageSeeder.php delete mode 100644 database/seeders/RecordSeeder.php delete mode 100644 database/seeders/TagSeeder.php delete mode 100644 database/seeders/VehicleSeeder.php diff --git a/app/Http/Controllers/Admin/UserController.php b/app/Http/Controllers/Admin/UserController.php index 8f79c55..f958af0 100644 --- a/app/Http/Controllers/Admin/UserController.php +++ b/app/Http/Controllers/Admin/UserController.php @@ -34,8 +34,8 @@ public function index() QuerySupport::queryByKeys($users, ['name', 'email']); return ApiResponse::OK->response([ - 'models' => $users->paginate(config('app.pagination')), - 'data' => $users->paginate(config('app.pagination'))->map(function($user) { + /* 'models' => $users->paginate(config('app.pagination')), */ + 'users' => $users->paginate(config('app.pagination'))->map(function($user) { return [ 'id' => $user->id, 'name' => $user->full_name, diff --git a/app/Http/Controllers/Repuve/CatalogNameImgController.php b/app/Http/Controllers/Repuve/CatalogNameImgController.php new file mode 100644 index 0000000..521286d --- /dev/null +++ b/app/Http/Controllers/Repuve/CatalogNameImgController.php @@ -0,0 +1,76 @@ +get(); + + return ApiResponse::OK->response([ + 'names' => $names, + ]); + } + + /** + * Crear + */ + public function store(CatalogNameImgStoreRequest $request) + { + $validated = $request->validated(); + + $catalogNameImg = CatalogNameImg::create($validated); + + return ApiResponse::CREATED->response([ + 'name' => $catalogNameImg, + ]); + } + + /** + * Actualizar + */ + public function update(CatalogNameImgUpdateRequest $request, $id) + { + $catalogName = CatalogNameImg::findOrFail($id); + + $validated = $request->validated([ + 'name' => 'required|string|max:255|unique:catalog_name_img,name,' . $id, + ]); + + $catalogName->update($validated); + + return ApiResponse::OK->response([ + 'name' => $catalogName, + ]); + } + + /** + * Eliminar + */ + public function destroy($id) + { + try { + $catalogName = CatalogNameImg::findOrFail($id); + $catalogName->delete(); + + return ApiResponse::OK->response([ + 'message' => 'Nombre del catálogo eliminado correctamente.', + ]); + } catch (\Exception $e) { + return ApiResponse::INTERNAL_ERROR->response([ + 'message' => 'Error al eliminar el nombre del catálogo.', + 'error' => $e->getMessage(), + ]); + } + } +} diff --git a/app/Http/Controllers/Repuve/InscriptionController.php b/app/Http/Controllers/Repuve/InscriptionController.php index 7a4154c..be1fc12 100644 --- a/app/Http/Controllers/Repuve/InscriptionController.php +++ b/app/Http/Controllers/Repuve/InscriptionController.php @@ -6,6 +6,7 @@ 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; @@ -76,39 +77,40 @@ public function vehicleInscription(VehicleStoreRequest $request) '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'], ] ); // 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'], + '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'], + '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'], + 'tipo_mov' => $vehicleData['tipo_mov'], 'owner_id' => $owner->id, ]); @@ -131,13 +133,14 @@ public function vehicleInscription(VehicleStoreRequest $request) foreach ($files as $index => $file) { $customName = $fileNames[$index] ?? "archivo_" . ($index + 1); $customName = str_replace(' ', '_', $customName); + $catalogName = CatalogNameImg::firstOrCreate(['name' => $customName]); $extension = $file->getClientOriginalExtension(); - $fileName = $customName . '_' . time() . '.' . $extension; + $fileName = $customName . '_' . date('dmY_His') . '.' . $extension; $path = $file->storeAs('records', $fileName, 'public'); $md5 = md5_file($file->getRealPath()); $fileRecord = File::create([ - 'name' => $customName, + 'name_id' => $catalogName->id, 'path' => $path, 'md5' => $md5, 'record_id' => $record->id, @@ -145,7 +148,7 @@ public function vehicleInscription(VehicleStoreRequest $request) $uploadedFiles[] = [ 'id' => $fileRecord->id, - 'name' => $fileRecord->name, + 'name' => $catalogName->name, 'path' => $fileRecord->path, 'url' => $fileRecord->url, ]; @@ -227,7 +230,7 @@ public function vehicleInscription(VehicleStoreRequest $request) 'vehicle' => [ 'id' => $vehicle->id, 'placa' => $vehicle->placa, - 'numero_serie' => $vehicle->numero_serie, + 'niv' => $vehicle->niv, 'marca' => $vehicle->marca, 'modelo' => $vehicle->modelo, 'color' => $vehicle->color, @@ -367,7 +370,7 @@ public function searchRecord(Request $request) }); } elseif ($request->filled('vin')) { $query->whereHas('vehicle', function ($q) use ($request) { - $q->where('numero_serie', 'LIKE', '%' . $request->input('vin') . '%'); + $q->where('niv', 'LIKE', '%' . $request->input('vin') . '%'); }); } @@ -396,11 +399,11 @@ public function searchRecord(Request $request) 'vehicle' => [ 'id' => $record->vehicle->id, 'placa' => $record->vehicle->placa, - 'numero_serie' => $record->vehicle->numero_serie, + 'niv' => $record->vehicle->niv, 'marca' => $record->vehicle->marca, 'modelo' => $record->vehicle->modelo, 'color' => $record->vehicle->color, - 'tipo' => $record->vehicle->tipo, + 'clase_veh' => $record->vehicle->clase_veh, ], 'owner' => [ 'id' => $record->vehicle->owner->id, @@ -435,48 +438,154 @@ public function searchRecord(Request $request) private function getVehicle(): array { + + $apiResponse = [ + "error" => 0, + "datos" => [[ + "entidadfederativa" => null, + "ofcexp" => "INTERNET", + "fechaexp" => "04/01/2022", + "placa" => "WNU700B", + "tarjetacir" => "2020-WNU700B", + "marca" => "CHEVROLET G.M.C.", + "submarca" => "AVEO", + "version" => "PAQ. \"A\" LS", + "clase_veh" => "AUTOMOVIL", + "tipo_veh" => "SEDAN", + "tipo_uso" => "PARTICULAR", + "modelo" => "2022", + "color" => "BLANCO", + "motor" => "H. EN WUHANLL,SGM", + "niv" => "LSGHD52H0ND032457", + "rfv" => null, + "numptas" => "4", + "observac" => null, + "tipopers" => 1, + "curp" => null, + "rfc" => "GME111116GJA", + "pasaporte" => null, + "licencia" => null, + "nombre" => "GOLSYSTEMS DE MEXICO S DE RL DE CV", + "ap_paterno" => null, + "ap_materno" => null, + "ent_fed" => "27", + "munic" => "04", + "callep" => "C BUGAMBILIAS ", + "num_ext" => "118", + "num_int" => null, + "colonia" => "FRACC. BLANCAS MARIPOSAS", + "cp" => "86179", + "cve_vehi" => "0037804", + "nrpv" => "5BK9MDO0", + "fe_act" => "10/01/2025", + "tipo_mov" => "1" + ]] + ]; + + $data = $apiResponse['datos'][0]; + + // Retornar datos mapeados para el vehículo return [ - "ANIO_PLACA" => "2023", - "PLACA" => "WXY-789-Z", - "NO_SERIE" => "9KLMNP8R7ST234567", - "RFC" => "SDE010203XYZ", - "FOLIO" => "54321", - "VIGENCIA" => "2026", - "FECHA_IMPRESION" => "15-03-2024", - "QR_HASH" => "Abc123Def456Ghi789Jkl0MnOpQrStUvWxYzZaBcDeFgHiJkLmNoPqRsTuVwXyZ", - "VALIDO" => true, - "FOLIOTEMP" => false, - "NOMBRE" => "SERVICIOS INFORMATICOS DEL GOLFO SA DE CV", - "NOMBRE2" => "SERVI*IOS I*TICOSLFO SA*CV", - "MUNICIPIO" => "CARDENAS", - "LOCALIDAD" => "HEROICA CARDENAS", - "CALLE" => "AV. LAZARO CARDENAS 200", - "CALLE2" => "AV. LA*RO CA*NAS 2*0", - "TIPO" => "SUV", - "TIPO_SERVICIO" => "PARTICULAR", - "MARCA" => "NISSAN", - "LINEA" => "KICKS", - "SUBLINEA" => "ADVANCE", - "MODELO" => 2023, - "NUMERO_SERIE" => "9KLMNP8R7ST234567", - "NUMERO_MOTOR" => "HR16DE123456Z", - "DESCRIPCION_ORIGEN" => "NACIONAL", - "COLOR" => "GRIS OXFORD", - "CODIGO_POSTAL" => "86500", - "SERIE_FOLIO" => "E8765432", - "SFOLIO" => "8765432" + 'placa' => $data['placa'], + 'niv' => $data['niv'], + 'marca' => $data['marca'], + 'linea' => $data['submarca'], + 'sublinea' => $data['version'], + 'modelo' => $data['modelo'], + 'color' => $data['color'], + 'numero_motor' => $data['motor'], + 'clase_veh' => $data['clase_veh'], + 'tipo_servicio' => $data['tipo_uso'], + 'rfv' => $data['rfv'], + 'rfc' => $data['rfc'], + 'ofcexpedicion' => $data['ofcexp'], + 'fechaexpedicion' => $data['fechaexp'], + 'tipo_veh' => $data['tipo_veh'], + 'numptas' => $data['numptas'], + 'observac' => $data['observac'], + 'cve_vehi' => $data['cve_vehi'], + 'tipo_mov' => $data['tipo_mov'], ]; } private function getOwner(): array { + $apiResponse = [ + "error" => 0, + "datos" => [[ + "entidadfederativa" => null, + "ofcexp" => "INTERNET", + "fechaexp" => "04/01/2022", + "placa" => "WNU700B", + "tarjetacir" => "2020-WNU700B", + "marca" => "CHEVROLET G.M.C.", + "submarca" => "AVEO", + "version" => "PAQ. \"A\" LS", + "clase_veh" => "AUTOMOVIL", + "tipo_veh" => "SEDAN", + "tipo_uso" => "PARTICULAR", + "modelo" => "2022", + "color" => "BLANCO", + "motor" => "H. EN WUHANLL,SGM", + "niv" => "LSGHD52H0ND032457", + "rfv" => null, + "numptas" => "4", + "observac" => null, + "tipopers" => 1, + "curp" => null, + "rfc" => "GME111116GJA", + "pasaporte" => null, + "licencia" => null, + "nombre" => "GOLSYSTEMS DE MEXICO S DE RL DE CV", + "ap_paterno" => null, + "ap_materno" => null, + "ent_fed" => "27", + "munic" => "04", + "callep" => "C BUGAMBILIAS ", + "num_ext" => "118", + "num_int" => null, + "colonia" => "FRACC. BLANCAS MARIPOSAS", + "cp" => "86179", + "cve_vehi" => "0037804", + "nrpv" => "5BK9MDO0", + "fe_act" => "10/01/2025", + "tipo_mov" => "1" + ]] + ]; + + $data = $apiResponse['datos'][0]; + + // Construir dirección completa + $addressParts = array_filter([ + $data['callep'], + $data['num_ext'] ? "Num {$data['num_ext']}" : null, + $data['num_int'] ? "Int {$data['num_int']}" : null, + $data['colonia'], + $data['cp'] ? "CP {$data['cp']}" : null, + $data['munic'] ? "Mun {$data['munic']}" : null, + $data['ent_fed'] ? "Edo {$data['ent_fed']}" : null, + ]); + + $address = implode(', ', $addressParts); + + // Retornar datos mapeados para el propietario return [ - 'name' => 'Nicolas', - 'paternal' => 'Hernandez', - 'maternal' => 'Castillo', - 'rfc' => 'HECN660509HTCRSC01', - 'curp' => 'HECN660509HTCRSC01', - 'address' => 'Fracc Pomoca, Calle Armadillo MZ9 LT28', + 'name' => $data['nombre'], + 'paternal' => $data['ap_paterno'], + 'maternal' => $data['ap_materno'], + 'rfc' => $data['rfc'], + 'curp' => $data['curp'], + 'address' => $address, + 'tipopers' => $data['tipopers'], + 'pasaporte' => $data['pasaporte'], + 'licencia' => $data['licencia'], + 'ent_fed' => $data['ent_fed'], + 'munic' => $data['munic'], + 'callep' => $data['callep'], + 'num_ext' => $data['num_ext'], + 'num_int' => $data['num_int'], + 'colonia' => $data['colonia'], + 'cp' => $data['cp'], ]; } } diff --git a/app/Http/Controllers/Repuve/RecordController.php b/app/Http/Controllers/Repuve/RecordController.php index c097c07..864afb2 100644 --- a/app/Http/Controllers/Repuve/RecordController.php +++ b/app/Http/Controllers/Repuve/RecordController.php @@ -8,6 +8,7 @@ use Illuminate\Support\Facades\Storage; use Notsoweb\ApiResponse\Enums\ApiResponse; use Codedge\Fpdf\Fpdf\Fpdf; +use Illuminate\Http\Request; class RecordController extends Controller { @@ -154,7 +155,6 @@ public function generatePdfImages($id) // Limpiar archivo temporal unlink($tempPath); - } // Verificar que se agregaron páginas @@ -171,7 +171,6 @@ public function generatePdfImages($id) return response($pdfContent, 200) ->header('Content-Type', 'application/pdf') ->header('Content-Disposition', 'inline; filename="expediente-imagenes-' . $record->folio . '.pdf"'); - } catch (\Exception $e) { return ApiResponse::INTERNAL_ERROR->response([ 'message' => 'Error al generar el PDF de imágenes', @@ -180,4 +179,90 @@ public function generatePdfImages($id) } } + public function errors(Request $request) + { + $request->validate([ + 'folio' => 'nullable|string', + 'placa' => 'nullable|string', + 'vin' => 'nullable|string', + ]); + + $query = Record::with(['vehicle.owner', 'vehicle.tag', 'files', 'user', 'error']) + ->whereNotNull('api_response') + ->whereRaw("JSON_EXTRACT(api_response, '$.has_error') = true") + ->orderBy('error_occurred_at', 'DESC'); + + if ($request->filled('folio')) { + $query->where('folio', 'LIKE', '%' . $request->input('folio') . '%'); + } + + if ($request->filled('placa')) { + $query->whereHas('vehicle', function ($q) use ($request) { + $q->where('placa', 'LIKE', '%' . $request->input('placa') . '%'); + }); + } + + if ($request->filled('vin')) { + $query->whereHas('vehicle', function ($q) use ($request) { + $q->where('niv', 'LIKE', '%' . $request->input('vin') . '%'); + }); + } + + $perPage = $request->input('per_page', 20); + $records = $query->paginate($perPage); + + if ($records->isEmpty()) { + return ApiResponse::NOT_FOUND->response([ + 'message' => 'No se encontraron expedientes con errores.', + 'records' => [], + 'pagination' => [ + 'current_page' => 1, + 'total_pages' => 0, + 'total_records' => 0, + 'per_page' => $perPage, + ], + ]); + } + + return ApiResponse::OK->response([ + 'message' => 'Expedientes con errores encontrados exitosamente', + 'records' => $records->map(function ($record) { + return [ + 'id' => $record->id, + 'folio' => $record->folio, + 'created_at' => $record->created_at->toDateTimeString(), + 'error_occurred_at' => $record->error_occurred_at?->toDateTimeString(), + + // Información del vehículo + 'vehicle' => [ + 'id' => $record->vehicle->id, + 'placa' => $record->vehicle->placa, + 'niv' => $record->vehicle->niv, + 'marca' => $record->vehicle->marca, + 'modelo' => $record->vehicle->modelo, + 'color' => $record->vehicle->color, + 'clase_veh' => $record->vehicle->clase_veh, + ], + + // Error del catálogo + 'error' => $record->error ? [ + 'id' => $record->error->id, + 'code' => $record->error->code, + 'description' => $record->error->description, + ] : null, + + // Respuesta completa de la API con el error + 'api_response' => $record->api_response, + ]; + }), + 'pagination' => [ + 'current_page' => $records->currentPage(), + 'total_pages' => $records->lastPage(), + 'total_records' => $records->total(), + 'per_page' => $records->perPage(), + 'from' => $records->firstItem(), + 'to' => $records->lastItem(), + ], + ]); + } } diff --git a/app/Http/Requests/Repuve/CatalogNameImgStoreRequest.php b/app/Http/Requests/Repuve/CatalogNameImgStoreRequest.php new file mode 100644 index 0000000..a4d2c56 --- /dev/null +++ b/app/Http/Requests/Repuve/CatalogNameImgStoreRequest.php @@ -0,0 +1,26 @@ + ['required'], + ]; + } + + public function messages(): array + { + return [ + 'name.required' => 'El nombre es requerido', + ]; + } +} diff --git a/app/Http/Requests/Repuve/CatalogNameImgUpdateRequest.php b/app/Http/Requests/Repuve/CatalogNameImgUpdateRequest.php new file mode 100644 index 0000000..26d5f60 --- /dev/null +++ b/app/Http/Requests/Repuve/CatalogNameImgUpdateRequest.php @@ -0,0 +1,26 @@ + ['required'], + ]; + } + + public function messages(): array + { + return [ + 'names.required' => 'El nombre es requerido', + ]; + } +} diff --git a/app/Models/CatalogNameImg.php b/app/Models/CatalogNameImg.php new file mode 100644 index 0000000..379a25e --- /dev/null +++ b/app/Models/CatalogNameImg.php @@ -0,0 +1,28 @@ + + * + * @version 1.0.0 + */ +class CatalogNameImg extends Model +{ + protected $table = 'catalog_name_img'; + + protected $fillable = [ + 'name', + ]; + + public function files() + { + return $this->hasMany(File::class, 'name_id'); + } +} diff --git a/app/Models/File.php b/app/Models/File.php index 62f7adb..0b5b1be 100644 --- a/app/Models/File.php +++ b/app/Models/File.php @@ -12,7 +12,7 @@ class File extends Model use HasFactory; protected $fillable = [ - 'name', + 'name_id', 'path', 'md5', 'record_id', @@ -28,6 +28,11 @@ public function record() return $this->belongsTo(Record::class); } + public function catalogName() + { + return $this->belongsTo(CatalogNameImg::class, 'name_id'); + } + public function url(): Attribute { return Attribute::make( diff --git a/app/Models/Owner.php b/app/Models/Owner.php index 6044200..e372750 100644 --- a/app/Models/Owner.php +++ b/app/Models/Owner.php @@ -10,13 +10,23 @@ class Owner extends Model { use HasFactory; - protected $fillable = [ + protected $fillable = [ 'name', 'paternal', 'maternal', 'rfc', 'curp', 'address', + 'tipopers', + 'pasaporte', + 'licencia', + 'ent_fed', + 'munic', + 'callep', + 'num_ext', + 'num_int', + 'colonia', + 'cp', ]; protected $appends = [ diff --git a/app/Models/Vehicle.php b/app/Models/Vehicle.php index a038508..2b44173 100644 --- a/app/Models/Vehicle.php +++ b/app/Models/Vehicle.php @@ -12,37 +12,32 @@ class Vehicle extends Model protected $table = 'vehicle'; protected $fillable = [ - 'anio_placa', 'placa', - 'numero_serie', - 'rfc', - 'folio', - 'vigencia', - 'fecha_impresion', - 'qr_hash', - 'valido', - 'nombre', - 'nombre2', - 'municipio', - 'localidad', - 'calle', - 'calle2', - 'tipo', - 'tipo_servicio', + 'niv', 'marca', 'linea', 'sublinea', 'modelo', - 'numero_motor', - 'descripcion_origen', 'color', - 'codigo_postal', - 'serie_folio', - 'sfolio', - 'nrpv', + 'numero_motor', + 'clase_veh', + 'tipo_servicio', + 'rfv', + 'rfc', + 'ofcexpedicion', + 'fechaexpedicion', + 'tipo_veh', + 'numptas', + 'observac', + 'cve_vehi', + 'tipo_mov', 'owner_id', ]; + protected $casts = [ + 'fechaexpedicion' => 'date', + ]; + public function owner() { return $this->belongsTo(Owner::class); diff --git a/database/factories/DeviceFactory.php b/database/factories/DeviceFactory.php deleted file mode 100644 index 3ef85c2..0000000 --- a/database/factories/DeviceFactory.php +++ /dev/null @@ -1,67 +0,0 @@ - - */ -class DeviceFactory extends Factory -{ - protected $model = Device::class; - - /** - * Define the model's default state. - * - * @return array - */ - public function definition(): array - { - $brands = [ - 'estatal', - 'nacional', - ]; - - $year = fake()->numberBetween(2020, 2025); - $randomNumber = fake()->unique()->numerify('######'); - - return [ - 'brand' => fake()->randomElement($brands), - 'serie' => strtoupper(fake()->bothify('??##')) . '-' . $year . '-' . $randomNumber, - 'mac_address' => fake()->macAddress(), - 'status' => fake()->boolean(85), // 85% activos - ]; - } - - /** - * Indicate that the device is inactive. - */ - public function inactive(): static - { - return $this->state(fn (array $attributes) => [ - 'status' => false, - ]); - } - - /** - * Indicate that the device is active. - */ - public function active(): static - { - return $this->state(fn (array $attributes) => [ - 'status' => true, - ]); - } - - /** - * Indicate that the device is of a specific brand. - */ - public function brand(string $brand): static - { - return $this->state(fn (array $attributes) => [ - 'brand' => $brand, - ]); - } -} diff --git a/database/factories/ErrorFactory.php b/database/factories/ErrorFactory.php deleted file mode 100644 index e033343..0000000 --- a/database/factories/ErrorFactory.php +++ /dev/null @@ -1,64 +0,0 @@ - - */ -class ErrorFactory extends Factory -{ - protected $model = Error::class; - - /** - * Define the model's default state. - * - * @return array - */ - public function definition(): array - { - $errorTypes = [ - ['code' => 'E001', 'description' => 'Vehículo reportado como robado'], - ['code' => 'E002', 'description' => 'Número de serie no válido o no coincide'], - ['code' => 'E003', 'description' => 'Documentos incompletos o ilegibles'], - ['code' => 'E004', 'description' => 'Propietario no coincide con documentos'], - ['code' => 'E005', 'description' => 'Placas no corresponden al vehículo'], - ['code' => 'E006', 'description' => 'Vehículo presenta adulteración'], - ['code' => 'E007', 'description' => 'RFC o CURP inválido'], - ['code' => 'E008', 'description' => 'Factura apócrifa o alterada'], - ['code' => 'E009', 'description' => 'Vehículo importado sin documentación legal'], - ['code' => 'E010', 'description' => 'Error en sistema REPUVE externo'], - ]; - - $error = fake()->randomElement($errorTypes); - - return [ - 'code' => $error['code'] . '-' . fake()->unique()->numberBetween(1000, 9999), - 'description' => $error['description'], - ]; - } - - /** - * State for stolen vehicle error - */ - public function stolen(): static - { - return $this->state(fn (array $attributes) => [ - 'code' => 'E001-' . fake()->unique()->numberBetween(1000, 9999), - 'description' => 'Vehículo reportado como robado', - ]); - } - - /** - * State for invalid VIN error - */ - public function invalidVin(): static - { - return $this->state(fn (array $attributes) => [ - 'code' => 'E002-' . fake()->unique()->numberBetween(1000, 9999), - 'description' => 'Número de serie no válido o no coincide', - ]); - } -} diff --git a/database/factories/FileFactory.php b/database/factories/FileFactory.php deleted file mode 100644 index 165e103..0000000 --- a/database/factories/FileFactory.php +++ /dev/null @@ -1,128 +0,0 @@ - - */ -class FileFactory extends Factory -{ - protected $model = File::class; - - /** - * Define the model's default state. - * - * @return array - */ - public function definition(): array - { - $fileTypes = [ - ['name' => 'Foto frontal del vehículo', 'ext' => 'jpg'], - ['name' => 'Foto lateral derecha del vehículo', 'ext' => 'jpg'], - ['name' => 'Foto lateral izquierda del vehículo', 'ext' => 'jpg'], - ['name' => 'Foto trasera del vehículo', 'ext' => 'jpg'], - ['name' => 'Foto del NIV/VIN', 'ext' => 'jpg'], - ['name' => 'Tarjeta de circulación', 'ext' => 'pdf'], - ['name' => 'Factura original', 'ext' => 'pdf'], - ['name' => 'Comprobante de domicilio', 'ext' => 'pdf'], - ['name' => 'Identificación oficial del propietario', 'ext' => 'pdf'], - ['name' => 'Constancia de inscripción', 'ext' => 'pdf'], - ]; - - $fileType = fake()->randomElement($fileTypes); - $timestamp = now()->timestamp . '_' . fake()->numberBetween(1000, 9999); - $fileName = $timestamp . '.' . $fileType['ext']; - - return [ - 'name' => $fileType['name'], - 'path' => 'records/' . $fileName, - 'md5' => md5(fake()->uuid()), - 'record_id' => Record::factory(), - ]; - } - - /** - * Indicate that the file is an image - */ - public function image(): static - { - $imageTypes = [ - 'Foto frontal del vehículo', - 'Foto lateral derecha del vehículo', - 'Foto lateral izquierda del vehículo', - 'Foto trasera del vehículo', - 'Foto del NIV/VIN', - ]; - - return $this->state(function (array $attributes) use ($imageTypes) { - $name = fake()->randomElement($imageTypes); - $timestamp = now()->timestamp . '_' . fake()->numberBetween(1000, 9999); - - return [ - 'name' => $name, - 'path' => 'records/' . $timestamp . '.jpg', - ]; - }); - } - - /** - * Indicate that the file is a PDF document - */ - public function pdf(): static - { - $pdfTypes = [ - 'Tarjeta de circulación', - 'Factura original', - 'Comprobante de domicilio', - 'Identificación oficial del propietario', - 'Constancia de inscripción', - ]; - - return $this->state(function (array $attributes) use ($pdfTypes) { - $name = fake()->randomElement($pdfTypes); - $timestamp = now()->timestamp . '_' . fake()->numberBetween(1000, 9999); - - return [ - 'name' => $name, - 'path' => 'records/' . $timestamp . '.pdf', - ]; - }); - } - - /** - * Indicate that the file belongs to a specific record - */ - public function forRecord(int $recordId): static - { - return $this->state(fn (array $attributes) => [ - 'record_id' => $recordId, - ]); - } - - /** - * Create a vehicle photo file - */ - public function vehiclePhoto(): static - { - $photoTypes = [ - 'Foto frontal del vehículo', - 'Foto lateral derecha del vehículo', - 'Foto lateral izquierda del vehículo', - 'Foto trasera del vehículo', - ]; - - return $this->state(function (array $attributes) use ($photoTypes) { - $name = fake()->randomElement($photoTypes); - $timestamp = now()->timestamp . '_' . fake()->numberBetween(1000, 9999); - - return [ - 'name' => $name, - 'path' => 'records/' . $timestamp . '.jpg', - ]; - }); - } -} diff --git a/database/factories/ModuleFactory.php b/database/factories/ModuleFactory.php deleted file mode 100644 index af95d14..0000000 --- a/database/factories/ModuleFactory.php +++ /dev/null @@ -1,77 +0,0 @@ - - */ -class ModuleFactory extends Factory -{ - protected $model = Module::class; - - /** - * Define the model's default state. - * - * @return array - */ - public function definition(): array - { - $municipalities = [ - 'Centro', - 'Cárdenas', - 'Comalcalco', - 'Cunduacán', - 'Huimanguillo', - 'Macuspana', - 'Paraíso', - 'Tacotalpa', - 'Teapa', - 'Tenosique', - ]; - - $colonies = [ - 'Centro', - 'Tierra Colorada', - 'Atasta de Serra', - 'José Colomo', - 'La Manga', - 'Tamulté de las Barrancas', - 'Gaviotas Norte', - 'Carrizal', - ]; - - return [ - 'name' => fake()->company() . ' - ' . fake()->randomElement($municipalities), - 'municipality' => fake()->randomElement($municipalities), - 'address' => fake()->streetAddress(), - 'colony' => fake()->randomElement($colonies), - 'cp' => fake()->postcode('86###'), - 'longitude' => fake()->longitude(-93.5, -92.5), // Tabasco longitude range - 'latitude' => fake()->latitude(17.5, 18.5), // Tabasco latitude range - 'status' => fake()->boolean(90), // 90% activos - ]; - } - - /** - * Indicate that the module is inactive. - */ - public function inactive(): static - { - return $this->state(fn (array $attributes) => [ - 'status' => false, - ]); - } - - /** - * Indicate that the module is in Centro municipality. - */ - public function centro(): static - { - return $this->state(fn (array $attributes) => [ - 'municipality' => 'Centro', - ]); - } -} diff --git a/database/factories/OwnerFactory.php b/database/factories/OwnerFactory.php deleted file mode 100644 index 0df8125..0000000 --- a/database/factories/OwnerFactory.php +++ /dev/null @@ -1,116 +0,0 @@ - - */ -class OwnerFactory extends Factory -{ - protected $model = Owner::class; - - /** - * Define the model's default state. - * - * @return array - */ - public function definition(): array - { - $name = fake()->firstName(); - $paternal = fake()->lastName(); - $maternal = fake()->lastName(); - - return [ - 'name' => strtoupper($name), - 'paternal' => strtoupper($paternal), - 'maternal' => strtoupper($maternal), - 'rfc' => $this->generateRFC($paternal, $maternal, $name), - 'curp' => $this->generateCURP($paternal, $maternal, $name), - 'address' => strtoupper(fake()->address()), - ]; - } - - /** - * Generate a realistic RFC (13 characters) - */ - private function generateRFC(string $paternal, string $maternal, string $name): string - { - $firstPaternal = substr($paternal, 0, 1); - $firstVowelPaternal = $this->getFirstVowel(substr($paternal, 1)); - $firstMaternal = substr($maternal, 0, 1); - $firstName = substr($name, 0, 1); - - $year = fake()->numberBetween(50, 99); - $month = str_pad(fake()->numberBetween(1, 12), 2, '0', STR_PAD_LEFT); - $day = str_pad(fake()->numberBetween(1, 28), 2, '0', STR_PAD_LEFT); - - $homoclave = strtoupper(fake()->bothify('???')); - - return strtoupper($firstPaternal . $firstVowelPaternal . $firstMaternal . $firstName . $year . $month . $day . $homoclave); - } - - /** - * Generate a realistic CURP (18 characters) - */ - private function generateCURP(string $paternal, string $maternal, string $name): string - { - $firstPaternal = substr($paternal, 0, 1); - $firstVowelPaternal = $this->getFirstVowel(substr($paternal, 1)); - $firstMaternal = substr($maternal, 0, 1); - $firstName = substr($name, 0, 1); - - $year = str_pad(fake()->numberBetween(50, 99), 2, '0', STR_PAD_LEFT); - $month = str_pad(fake()->numberBetween(1, 12), 2, '0', STR_PAD_LEFT); - $day = str_pad(fake()->numberBetween(1, 28), 2, '0', STR_PAD_LEFT); - - $gender = fake()->randomElement(['H', 'M']); - $state = 'TC'; // Tabasco - - $consonants = strtoupper( - $this->getFirstConsonant(substr($paternal, 1)) . - $this->getFirstConsonant(substr($maternal, 1)) . - $this->getFirstConsonant(substr($name, 1)) - ); - - $homoclave = strtoupper(fake()->bothify('??')); - - return strtoupper($firstPaternal . $firstVowelPaternal . $firstMaternal . $firstName . $year . $month . $day . $gender . $state . $consonants . $homoclave); - } - - /** - * Get first vowel from string - */ - private function getFirstVowel(string $str): string - { - $vowels = ['A', 'E', 'I', 'O', 'U']; - $str = strtoupper($str); - - for ($i = 0; $i < strlen($str); $i++) { - if (in_array($str[$i], $vowels)) { - return $str[$i]; - } - } - - return 'X'; - } - - /** - * Get first consonant from string - */ - private function getFirstConsonant(string $str): string - { - $vowels = ['A', 'E', 'I', 'O', 'U']; - $str = strtoupper($str); - - for ($i = 0; $i < strlen($str); $i++) { - if (!in_array($str[$i], $vowels) && ctype_alpha($str[$i])) { - return $str[$i]; - } - } - - return 'X'; - } -} diff --git a/database/factories/PackageFactory.php b/database/factories/PackageFactory.php deleted file mode 100644 index 1495d75..0000000 --- a/database/factories/PackageFactory.php +++ /dev/null @@ -1,76 +0,0 @@ - - */ -class PackageFactory extends Factory -{ - protected $model = Package::class; - - /** - * Define the model's default state. - * - * @return array - */ - public function definition(): array - { - $year = fake()->numberBetween(2020, 2025); - $lot = 'LOTE-' . $year . '-' . fake()->numberBetween(1, 99); - $boxNumber = 'CAJA-' . strtoupper(fake()->bothify('??##')); - - $startingPage = fake()->numberBetween(1, 100) * 100; - $endingPage = $startingPage + fake()->numberBetween(50, 200); - - return [ - 'lot' => $lot, - 'box_number' => $boxNumber, - 'starting_page' => $startingPage, - 'ending_page' => $endingPage, - 'module_id' => Module::factory(), - ]; - } - - /** - * Indicate that the package belongs to a specific module. - */ - public function forModule(int $moduleId): static - { - return $this->state(fn (array $attributes) => [ - 'module_id' => $moduleId, - ]); - } - - /** - * Create a small package (50-100 pages) - */ - public function small(): static - { - return $this->state(function (array $attributes) { - $startingPage = fake()->numberBetween(1, 50) * 100; - return [ - 'starting_page' => $startingPage, - 'ending_page' => $startingPage + fake()->numberBetween(50, 100), - ]; - }); - } - - /** - * Create a large package (200-500 pages) - */ - public function large(): static - { - return $this->state(function (array $attributes) { - $startingPage = fake()->numberBetween(1, 100) * 100; - return [ - 'starting_page' => $startingPage, - 'ending_page' => $startingPage + fake()->numberBetween(200, 500), - ]; - }); - } -} diff --git a/database/factories/RecordFactory.php b/database/factories/RecordFactory.php deleted file mode 100644 index 20817c2..0000000 --- a/database/factories/RecordFactory.php +++ /dev/null @@ -1,93 +0,0 @@ - - */ -class RecordFactory extends Factory -{ - protected $model = Record::class; - - /** - * Define the model's default state. - * - * @return array - */ - public function definition(): array - { - return [ - 'folio' => $this->generateFolio(), - 'vehicle_id' => Vehicle::factory(), - 'user_id' => User::inRandomOrder()->first()?->id ?? User::factory(), - 'error_id' => fake()->boolean(10) ? Error::factory() : null, // 10% con error - ]; - } - - /** - * Generate a unique record folio - */ - private function generateFolio(): string - { - $year = now()->year; - $number = fake()->unique()->numerify('######'); - - return 'EXP-' . $year . '-' . $number; - } - - /** - * Indicate that the record has an error - */ - public function withError(): static - { - return $this->state(fn (array $attributes) => [ - 'error_id' => Error::factory(), - ]); - } - - /** - * Indicate that the record has no error - */ - public function withoutError(): static - { - return $this->state(fn (array $attributes) => [ - 'error_id' => null, - ]); - } - - /** - * Indicate that the record belongs to a specific vehicle - */ - public function forVehicle(int $vehicleId): static - { - return $this->state(fn (array $attributes) => [ - 'vehicle_id' => $vehicleId, - ]); - } - - /** - * Indicate that the record belongs to a specific user - */ - public function forUser(int $userId): static - { - return $this->state(fn (array $attributes) => [ - 'user_id' => $userId, - ]); - } - - /** - * Indicate that the record has a specific error - */ - public function withSpecificError(int $errorId): static - { - return $this->state(fn (array $attributes) => [ - 'error_id' => $errorId, - ]); - } -} diff --git a/database/factories/TagFactory.php b/database/factories/TagFactory.php deleted file mode 100644 index fbfa09c..0000000 --- a/database/factories/TagFactory.php +++ /dev/null @@ -1,112 +0,0 @@ - - */ -class TagFactory extends Factory -{ - protected $model = Tag::class; - - /** - * Define the model's default state. - * - * @return array - */ - public function definition(): array - { - $statuses = ['available', 'assigned', 'cancelled', 'lost']; - $weights = [40, 50, 7, 3]; // Probabilidades: 40% available, 50% assigned, 7% cancelled, 3% lost - - return [ - 'folio' => $this->generateFolio(), - 'tag_number' => strtoupper(fake()->bothify('TAG-########')), - 'vehicle_id' => fake()->boolean(60) ? Vehicle::factory() : null, // 60% asignados - 'package_id' => Package::factory(), - 'status' => fake()->randomElement(array_combine($statuses, $weights)) ?? 'available', - ]; - } - - /** - * Generate a unique tag folio - */ - private function generateFolio(): string - { - $year = fake()->numberBetween(2020, 2025); - $series = strtoupper(fake()->bothify('??')); - $number = fake()->unique()->numerify('##########'); - - return $year . '-' . $series . '-' . $number; - } - - /** - * Indicate that the tag is available (not assigned) - */ - public function available(): static - { - return $this->state(fn (array $attributes) => [ - 'vehicle_id' => null, - 'status' => 'available', - ]); - } - - /** - * Indicate that the tag is assigned to a vehicle - */ - public function assigned(): static - { - return $this->state(fn (array $attributes) => [ - 'vehicle_id' => Vehicle::factory(), - 'status' => 'assigned', - ]); - } - - /** - * Indicate that the tag is cancelled - */ - public function cancelled(): static - { - return $this->state(fn (array $attributes) => [ - 'vehicle_id' => null, - 'status' => 'cancelled', - ]); - } - - /** - * Indicate that the tag is lost - */ - public function lost(): static - { - return $this->state(fn (array $attributes) => [ - 'vehicle_id' => null, - 'status' => 'lost', - ]); - } - - /** - * Indicate that the tag belongs to a specific package - */ - public function forPackage(int $packageId): static - { - return $this->state(fn (array $attributes) => [ - 'package_id' => $packageId, - ]); - } - - /** - * Indicate that the tag is assigned to a specific vehicle - */ - public function forVehicle(int $vehicleId): static - { - return $this->state(fn (array $attributes) => [ - 'vehicle_id' => $vehicleId, - 'status' => 'assigned', - ]); - } -} diff --git a/database/factories/VehicleFactory.php b/database/factories/VehicleFactory.php deleted file mode 100644 index 359f3c9..0000000 --- a/database/factories/VehicleFactory.php +++ /dev/null @@ -1,153 +0,0 @@ - - */ -class VehicleFactory extends Factory -{ - protected $model = Vehicle::class; - - /** - * Configure the model factory. - */ - public function configure(): static - { - return $this->afterCreating(function (Vehicle $vehicle) { - // Crear un Tag automáticamente después de crear el vehículo - Tag::factory()->create([ - 'vehicle_id' => $vehicle->id, - 'folio' => $vehicle->folio, - 'status' => 'assigned', - ]); - }); - } - - /** - * Define the model's default state. - * - * @return array - */ - public function definition(): array - { - $brands = [ - 'CHEVROLET G.M.C.', - 'NISSAN MEXICANA', - 'VOLKSWAGEN', - 'FORD MOTOR COMPANY', - 'TOYOTA', - 'HONDA', - 'MAZDA', - 'KIA MOTORS', - 'HYUNDAI', - ]; - - $types = ['SEDAN', 'SUV', 'PICKUP', 'HATCHBACK', 'VAN']; - $colors = ['BLANCO', 'NEGRO', 'GRIS', 'ROJO', 'AZUL', 'PLATA']; - $municipalities = ['CENTRO', 'CÁRDENAS', 'COMALCALCO', 'CUNDUACÁN', 'HUIMANGUILLO']; - - $year = fake()->numberBetween(2015, 2025); - $vin = $this->generateVIN(); - $placa = $this->generatePlaca(); - - return [ - 'anio_placa' => (string) $year, - 'placa' => $placa . fake()->unique(), - 'numero_serie' => $vin . fake()->unique(), - 'rfc' => 'GME' . fake()->numerify('######') . 'GJA', - 'folio' => fake()->unique()->numerify('#######'), - 'vigencia' => (string) ($year + 1), - 'fecha_impresion' => fake()->date('d-m-Y'), - 'qr_hash' => fake()->sha256(), - 'valido' => fake()->boolean(95), // 95% válidos - 'nombre' => strtoupper(fake()->company()), - 'nombre2' => strtoupper(fake()->lexify('????*????')), - 'municipio' => fake()->randomElement($municipalities), - 'localidad' => 'VILLAHERMOSA', - 'calle' => strtoupper(fake()->streetAddress()), - 'calle2' => strtoupper(fake()->lexify('? ??*????')), - 'tipo' => fake()->randomElement($types), - 'tipo_servicio' => fake()->randomElement(['PARTICULAR', 'PUBLICO', 'OFICIAL']), - 'marca' => fake()->randomElement($brands), - 'linea' => strtoupper(fake()->word()), - 'sublinea' => 'PAQ. "' . strtoupper(fake()->randomLetter()) . '" ' . strtoupper(fake()->word()), - 'modelo' => $year, - 'numero_motor' => strtoupper(fake()->bothify('??####??##')), - 'descripcion_origen' => fake()->randomElement(['NACIONAL', 'IMPORTADO']), - 'color' => fake()->randomElement($colors), - 'codigo_postal' => fake()->numerify('86###'), - 'serie_folio' => 'D' . fake()->unique()->numerify('#######'), - 'sfolio' => fake()->unique()->numerify('#######'), - 'nrpv' => $vin, - 'owner_id' => Owner::factory(), - ]; - } - - /** - * Generate a realistic VIN - */ - private function generateVIN(): string - { - $wmi = strtoupper(fake()->bothify('???')); - $vds = strtoupper(fake()->bothify('??????')); - $check = fake()->randomDigit(); - $year = strtoupper(fake()->randomLetter()); - $plant = fake()->randomDigit(); - $serial = fake()->numerify('######'); - - return $wmi . $vds . $check . $year . $plant . $serial; - } - - /** - * Generate a Tabasco plate - */ - private function generatePlaca(): string - { - return strtoupper(fake()->bothify('???###?')); - } - - /** - * Indicate that the vehicle belongs to a specific owner. - */ - public function forOwner(int $ownerId): static - { - return $this->state(fn (array $attributes) => [ - 'owner_id' => $ownerId, - ]); - } - - /** - * Create an imported vehicle - */ - public function imported(): static - { - return $this->state(fn (array $attributes) => [ - 'descripcion_origen' => 'IMPORTADO', - ]); - } - - /** - * Create a national vehicle - */ - public function national(): static - { - return $this->state(fn (array $attributes) => [ - 'descripcion_origen' => 'NACIONAL', - ]); - } - - /** - * Create a vehicle without automatically creating a tag - */ - public function withoutTag(): static - { - return $this->afterCreating(function (Vehicle $vehicle) { - }); - } -} diff --git a/database/migrations/2025_10_18_140200_create_owners_table.php b/database/migrations/2025_10_18_140200_create_owners_table.php index bf091e5..d140ecf 100644 --- a/database/migrations/2025_10_18_140200_create_owners_table.php +++ b/database/migrations/2025_10_18_140200_create_owners_table.php @@ -14,11 +14,21 @@ public function up(): void Schema::create('owners', function (Blueprint $table) { $table->id(); $table->string('name'); - $table->string('paternal'); + $table->string('paternal')->nullable(); $table->string('maternal')->nullable(); $table->string('rfc')->unique()->nullable(); $table->string('curp')->unique()->nullable(); $table->text('address')->nullable(); + $table->boolean('tipopers')->nullable(); + $table->string('pasaporte')->unique()->nullable(); + $table->string('licencia')->unique()->nullable(); + $table->string('ent_fed')->nullable(); + $table->string('munic')->nullable(); + $table->string('callep')->nullable(); + $table->string('num_ext')->nullable(); + $table->string('num_int')->nullable(); + $table->string('colonia')->nullable(); + $table->string('cp')->nullable(); $table->timestamps(); }); } diff --git a/database/migrations/2025_10_18_140600_create_vehicle_table.php b/database/migrations/2025_10_18_140600_create_vehicle_table.php index 82eeabc..a9092b2 100644 --- a/database/migrations/2025_10_18_140600_create_vehicle_table.php +++ b/database/migrations/2025_10_18_140600_create_vehicle_table.php @@ -13,35 +13,25 @@ public function up(): void { Schema::create('vehicle', function (Blueprint $table) { $table->id(); - $table->string('anio_placa')->nullable(); $table->string('placa')->unique()->nullable(); - $table->string('numero_serie')->unique()->nullable(); - $table->string('rfc')->nullable(); - $table->string('folio')->nullable(); - $table->string('vigencia')->nullable(); - $table->string('fecha_impresion')->nullable(); - $table->string('qr_hash')->nullable(); - $table->boolean('valido')->nullable(); - $table->boolean('foliotemp')->nullable(); - $table->string('nombre')->nullable(); - $table->string('nombre2')->nullable(); - $table->string('municipio')->nullable(); - $table->string('localidad')->nullable(); - $table->string('calle')->nullable(); - $table->string('calle2')->nullable(); - $table->string('tipo')->nullable(); - $table->string('tipo_servicio')->nullable(); + $table->string('niv')->unique()->nullable(); $table->string('marca')->nullable(); $table->string('linea')->nullable(); $table->string('sublinea')->nullable(); $table->string('modelo')->nullable(); - $table->string('numero_motor')->nullable(); - $table->string('descripcion_origen')->nullable(); $table->string('color')->nullable(); - $table->string('codigo_postal')->nullable(); - $table->string('serie_folio')->unique()->nullable(); - $table->string('sfolio')->unique()->nullable(); - $table->string('nrpv')->unique()->nullable(); + $table->string('numero_motor')->nullable(); + $table->string('clase_veh')->nullable(); + $table->string('tipo_servicio')->nullable(); + $table->string('rfv')->unique()->nullable(); + $table->string('rfc')->nullable(); + $table->string('ofcexpedicion')->nullable(); + $table->date('fechaexpedicion')->nullable(); + $table->string('tipo_veh')->nullable(); + $table->string('numptas')->nullable(); + $table->string('observac')->nullable(); + $table->string('cve_vehi')->nullable(); + $table->string('tipo_mov')->nullable(); $table->foreignId('owner_id')->nullable()->constrained('owners')->nullOnDelete(); $table->timestamps(); }); diff --git a/database/migrations/2025_10_18_141000_create_files_table.php b/database/migrations/2025_10_18_141000_create_files_table.php index 5271345..c2eef85 100644 --- a/database/migrations/2025_10_18_141000_create_files_table.php +++ b/database/migrations/2025_10_18_141000_create_files_table.php @@ -13,7 +13,6 @@ public function up(): void { Schema::create('files', function (Blueprint $table) { $table->id(); - $table->string('name'); $table->string('path'); $table->string('md5')->nullable(); $table->foreignId('record_id')->constrained('records')->cascadeOnDelete(); diff --git a/database/migrations/2025_10_30_153423_create_catalog_name_img_table.php b/database/migrations/2025_10_30_153423_create_catalog_name_img_table.php new file mode 100644 index 0000000..5572fcf --- /dev/null +++ b/database/migrations/2025_10_30_153423_create_catalog_name_img_table.php @@ -0,0 +1,29 @@ +id(); + $table->string('name'); + $table->softDeletes(); + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::dropIfExists('catalog_name_img'); + } +}; diff --git a/database/migrations/2025_10_30_164633_add_name_id_to_files_table.php b/database/migrations/2025_10_30_164633_add_name_id_to_files_table.php new file mode 100644 index 0000000..efbf9c4 --- /dev/null +++ b/database/migrations/2025_10_30_164633_add_name_id_to_files_table.php @@ -0,0 +1,23 @@ +foreignId('name_id')->after('id')->constrained('catalog_name_img')->cascadeOnDelete(); + }); + } + + public function down(): void + { + Schema::table('files', function (Blueprint $table) { + $table->dropForeign(['name_id']); + $table->dropColumn('name_id'); + }); + } +}; diff --git a/database/seeders/CatalogNameImgSeeder.php b/database/seeders/CatalogNameImgSeeder.php new file mode 100644 index 0000000..ddc8b0b --- /dev/null +++ b/database/seeders/CatalogNameImgSeeder.php @@ -0,0 +1,51 @@ + + * + * @version 1.0.0 + */ +class CatalogNameImgSeeder extends Seeder +{ + /** + * Ejecutar sembrado de base de datos + */ + public function run(): void + { + $names = [ + 'FRENTE', + 'TRASERA', + 'LATERAL', + 'RECEPCION', + 'CONSTANCIA', + 'VERIFICA', + 'FACTURA/CERTIFICADO FRONTAL', + 'FACTURA/CERTIFICADO TRASERA', + 'PEDIMENTO FRONTAL', + 'PEDIMENTO TRASERO', + 'PODER NOTARIAL', + 'CEDULA DE IDENTIFICACION FISCAL', + 'CARTA PODER', + 'ACTA CIRCUNSTANCIADA DE HECHOS', + 'IDENTIFICACIÓN OFICIAL FRENTE', + 'IDENTIFICACIÓN OFICIAL TRASERA', + 'TARJETA DE CIRCULACIÓN', + 'FOTO VIN', + ]; + + foreach ($names as $name) { + CatalogNameImg::create([ + 'name' => $name, + ]); + } + } +} diff --git a/database/seeders/DevSeeder.php b/database/seeders/DevSeeder.php index 5b00da6..8eed7db 100644 --- a/database/seeders/DevSeeder.php +++ b/database/seeders/DevSeeder.php @@ -23,21 +23,7 @@ public function run(): void $this->call(UserSeeder::class); $this->call(SettingSeeder::class); - // Nivel 1 - Sin dependencias $this->call(ModuleSeeder::class); - $this->call(OwnerSeeder::class); - //$this->call(ErrorSeeder::class); - - // Nivel 2 - Dependen de Nivel 1 - $this->call(PackageSeeder::class); - $this->call(VehicleSeeder::class); - - // Nivel 3 - Dependen de Nivel 2 - $this->call(TagSeeder::class); - $this->call(RecordSeeder::class); - - // Nivel 4 - Dependen de Nivel 3 - $this->call(FileSeeder::class); - $this->call(DeviceSeeder::class); + $this->call(CatalogNameImgSeeder::class); } } diff --git a/database/seeders/DeviceSeeder.php b/database/seeders/DeviceSeeder.php deleted file mode 100644 index 02f9c28..0000000 --- a/database/seeders/DeviceSeeder.php +++ /dev/null @@ -1,77 +0,0 @@ - 'estatal', - 'serie' => 'ZB01-2024-001234', - 'mac_address' => '00:1B:44:11:3A:B7', - 'status' => true, - ], - [ - 'brand' => 'estatal', - 'serie' => 'ZB01-2024-001235', - 'mac_address' => '00:1B:44:11:3A:B8', - 'status' => true, - ], - [ - 'brand' => 'estatal', - 'serie' => 'HW02-2024-002456', - 'mac_address' => '00:1B:44:11:3A:B9', - 'status' => true, - ], - [ - 'brand' => 'estatal', - 'serie' => 'HW02-2024-002457', - 'mac_address' => '00:1B:44:11:3A:BA', - 'status' => true, - ], - [ - 'brand' => 'nacional', - 'serie' => 'DL03-2023-003678', - 'mac_address' => '00:1B:44:11:3A:BB', - 'status' => true, - ], - [ - 'brand' => 'nacional', - 'serie' => 'IP04-2024-004890', - 'mac_address' => '00:1B:44:11:3A:BC', - 'status' => true, - ], - [ - 'brand' => 'nacional', - 'serie' => 'MT05-2023-005123', - 'mac_address' => '00:1B:44:11:3A:BD', - 'status' => true, - ], - [ - 'brand' => 'nacional', - 'serie' => 'TM06-2024-006345', - 'mac_address' => '00:1B:44:11:3A:BE', - 'status' => false, // Dispositivo inactivo - ], - ]; - - foreach ($devices as $device) { - Device::create($device); - } - - // Crear dispositivos adicionales con factory para pruebas - Device::factory(10)->create(); - - // Crear algunos dispositivos inactivos adicionales - Device::factory(3)->inactive()->create(); - } -} diff --git a/database/seeders/ErrorSeeder.php b/database/seeders/ErrorSeeder.php deleted file mode 100644 index 894f9c4..0000000 --- a/database/seeders/ErrorSeeder.php +++ /dev/null @@ -1,38 +0,0 @@ - 'E001', 'description' => 'Vehículo reportado como robado'], - ['code' => 'E002', 'description' => 'Número de serie (NIV/VIN) no válido o no coincide'], - ['code' => 'E003', 'description' => 'Documentos incompletos o ilegibles'], - ['code' => 'E004', 'description' => 'Datos del propietario no coinciden con documentos oficiales'], - ['code' => 'E005', 'description' => 'Placas de circulación no corresponden al vehículo'], - ['code' => 'E006', 'description' => 'Vehículo presenta evidencia de adulteración en NIV'], - ['code' => 'E007', 'description' => 'RFC o CURP inválido o no coincide'], - ['code' => 'E008', 'description' => 'Factura apócrifa o presenta alteraciones'], - ['code' => 'E009', 'description' => 'Vehículo importado sin documentación legal'], - ['code' => 'E010', 'description' => 'Error en consulta al sistema REPUVE externo'], - ['code' => 'E011', 'description' => 'Vehículo tiene adeudos de tenencia o infracciones'], - ['code' => 'E012', 'description' => 'Tarjeta de circulación no válida o vencida'], - ['code' => 'E013', 'description' => 'Comprobante de domicilio no válido'], - ['code' => 'E014', 'description' => 'Verificación física del vehículo no aprobada'], - ['code' => 'E015', 'description' => 'Modelo y año del vehículo no coinciden'], - ]; - - foreach ($errors as $error) { - Error::create($error); - } - } -} diff --git a/database/seeders/FileSeeder.php b/database/seeders/FileSeeder.php deleted file mode 100644 index 0c721a7..0000000 --- a/database/seeders/FileSeeder.php +++ /dev/null @@ -1,50 +0,0 @@ -forRecord($record->id) - ->vehiclePhoto() - ->create(); - $imageCount++; - } - - // El resto son PDFs (documentos) - $pdfFiles = $filesPerRecord - $vehiclePhotos; - for ($i = 0; $i < $pdfFiles; $i++) { - File::factory() - ->forRecord($record->id) - ->pdf() - ->create(); - $pdfCount++; - } - - $totalFiles += $filesPerRecord; - } - } -} diff --git a/database/seeders/ModuleSeeder.php b/database/seeders/ModuleSeeder.php index 7c5e96b..85ebfb9 100644 --- a/database/seeders/ModuleSeeder.php +++ b/database/seeders/ModuleSeeder.php @@ -15,63 +15,59 @@ public function run(): void // Crear módulos reales de Tabasco $modules = [ [ - 'name' => 'Módulo Centro Villahermosa', - 'municipality' => 'Centro', - 'address' => 'Av. Paseo Tabasco 1203', - 'colony' => 'Tabasco 2000', - 'cp' => '86000', - 'longitude' => -92.9376, - 'latitude' => 17.9892, + 'name' => 'MODULO PARQUE LA CHOCA', + 'municipality' => '4', + 'address' => 'CIRCUITO CARLOS PELLICER S/N JUNTO A PLAZA MALLORCA ESTACIONAMIENTO DEL PARQUE LA CHOCA', + 'colony' => 'CENTRO', + 'cp' => null, + 'longitude' => -92.954605, + 'latitude' => 18.004537, 'status' => true, ], [ - 'name' => 'Módulo Cárdenas', - 'municipality' => 'Cárdenas', - 'address' => 'Calle Benito Juárez No. 305', - 'colony' => 'Centro', - 'cp' => '86000', - 'longitude' => -93.3808, - 'latitude' => 18.0011, + 'name' => 'MODULO FINANZAS BASE 4', + 'municipality' => '4', + 'address' => 'AV. RUIZ CORTINES S/N', + 'colony' => 'CASA BLANCA', + 'cp' => null, + 'longitude' => -92.923486, + 'latitude' => 18.001417, 'status' => true, ], [ - 'name' => 'Módulo Comalcalco', - 'municipality' => 'Comalcalco', - 'address' => 'Av. Gregorio Méndez Magaña', - 'colony' => 'Centro', - 'cp' => '86000', - 'longitude' => -93.2042, - 'latitude' => 18.2667, + 'name' => 'MODULO CARDENAS', + 'municipality' => '2', + 'address' => 'ANILLO PERIFERICO CARLOS MOLINA S/N', + 'colony' => 'SANTA MARIA DE GUADALUPE', + 'cp' => null, + 'longitude' => -93.362824, + 'latitude' => 17.996747, 'status' => true, ], [ - 'name' => 'Módulo Cunduacán', - 'municipality' => 'Cunduacán', - 'address' => 'Calle Carlos Pellicer Cámara', - 'colony' => 'Centro', - 'cp' => '86000', - 'longitude' => -93.1608, - 'latitude' => 18.0667, + 'name' => 'MODULO PASEO DE LA SIERRA', + 'municipality' => '4', + 'address' => ' AV. PASEO DE LA SIERRA #435 COL. REFORMA, C.P. 86080 VILLAHERMOSA, TABASCO,', + 'colony' => 'REFORMA', + 'cp' => null, + 'longitude' => -92.929378, + 'latitude' => 17.981033, 'status' => true, ], [ - 'name' => 'Módulo Huimanguillo', - 'municipality' => 'Huimanguillo', - 'address' => 'Av. Constitución s/n', - 'colony' => 'Centro', - 'cp' => '86000', - 'longitude' => -93.3908, - 'latitude' => 17.8422, + 'name' => 'CENTRO DE ACTIVACION COMALCALCO', + 'municipality' => '5', + 'address' => 'MONSERRAT #5', + 'colony' => 'SANTO DOMINGO', + 'cp' => null, + 'longitude' => -93.218679, + 'latitude' => 18.264577, 'status' => true, ], ]; - foreach ($modules as $module) { Module::create($module); } - // Crear módulos adicionales con factory para pruebas - Module::factory(5)->create(); - } } diff --git a/database/seeders/OwnerSeeder.php b/database/seeders/OwnerSeeder.php deleted file mode 100644 index 526410f..0000000 --- a/database/seeders/OwnerSeeder.php +++ /dev/null @@ -1,18 +0,0 @@ -create(); - } -} diff --git a/database/seeders/PackageSeeder.php b/database/seeders/PackageSeeder.php deleted file mode 100644 index 0b580fc..0000000 --- a/database/seeders/PackageSeeder.php +++ /dev/null @@ -1,31 +0,0 @@ -forModule($module->id) - ->create(); - - $totalPackages += $packagesCount; - } - } -} diff --git a/database/seeders/RecordSeeder.php b/database/seeders/RecordSeeder.php deleted file mode 100644 index 97f9701..0000000 --- a/database/seeders/RecordSeeder.php +++ /dev/null @@ -1,55 +0,0 @@ -random(); - - // 10% de probabilidad de tener error - $hasError = rand(1, 100) <= 10; - - if ($hasError && $errors->isNotEmpty()) { - $randomError = $errors->random(); - Record::factory() - ->forVehicle($vehicle->id) - ->forUser($randomUser->id) - ->withSpecificError($randomError->id) - ->create(); - $recordsWithError++; - } else { - Record::factory() - ->forVehicle($vehicle->id) - ->forUser($randomUser->id) - ->withoutError() - ->create(); - $recordsWithoutError++; - } - } - } - - } -} diff --git a/database/seeders/TagSeeder.php b/database/seeders/TagSeeder.php deleted file mode 100644 index 6e39cdb..0000000 --- a/database/seeders/TagSeeder.php +++ /dev/null @@ -1,93 +0,0 @@ - 0, - 'assigned' => 0, - 'cancelled' => 0, - 'lost' => 0, - ]; - - // Obtener IDs de vehículos que YA tienen un tag asignado (creado por VehicleFactory) - $vehiclesWithTag = Tag::whereNotNull('vehicle_id')->pluck('vehicle_id')->toArray(); - - // Crear tags para cada paquete - foreach ($packages as $package) { - // Cada paquete tiene entre 20-50 tags - $tagsPerPackage = rand(20, 50); - - // 40% disponibles - $availableCount = (int)($tagsPerPackage * 0.4); - Tag::factory($availableCount) - ->forPackage($package->id) - ->available() - ->create(); - $statusCounts['available'] += $availableCount; - - // 50% asignados (si hay vehículos disponibles sin tag) - $assignedCount = (int)($tagsPerPackage * 0.5); - if ($vehicles->isNotEmpty()) { - // Filtrar vehículos que NO tienen tag asignado - $availableVehicles = $vehicles->filter(function($vehicle) use ($vehiclesWithTag) { - return !in_array($vehicle->id, $vehiclesWithTag); - }); - - // Limitar la cantidad de tags asignados a los vehículos disponibles - $actualAssignedCount = min($assignedCount, $availableVehicles->count()); - - for ($i = 0; $i < $actualAssignedCount; $i++) { - $randomVehicle = $availableVehicles->random(); - Tag::factory() - ->forPackage($package->id) - ->forVehicle($randomVehicle->id) - ->create(); - - // Marcar el vehículo como que ya tiene tag - $vehiclesWithTag[] = $randomVehicle->id; - - // Remover del pool de vehículos disponibles - $availableVehicles = $availableVehicles->reject(function($vehicle) use ($randomVehicle) { - return $vehicle->id === $randomVehicle->id; - }); - } - $statusCounts['assigned'] += $actualAssignedCount; - } - - // 7% cancelados - $cancelledCount = (int)($tagsPerPackage * 0.07); - Tag::factory($cancelledCount) - ->forPackage($package->id) - ->cancelled() - ->create(); - $statusCounts['cancelled'] += $cancelledCount; - - // 3% perdidos - $lostCount = max(1, (int)($tagsPerPackage * 0.03)); - Tag::factory($lostCount) - ->forPackage($package->id) - ->lost() - ->create(); - $statusCounts['lost'] += $lostCount; - - $totalTags += $tagsPerPackage; - } - } -} diff --git a/database/seeders/VehicleSeeder.php b/database/seeders/VehicleSeeder.php deleted file mode 100644 index e3cacfa..0000000 --- a/database/seeders/VehicleSeeder.php +++ /dev/null @@ -1,39 +0,0 @@ -= $vehiclesCount) { - break; - } - - $toCreate = min($vehiclesForOwner, $vehiclesCount - $vehiclesCreated); - - Vehicle::factory($toCreate) - ->forOwner($owner->id) - ->create(); - - $vehiclesCreated += $toCreate; - } - } -} diff --git a/routes/api.php b/routes/api.php index bf0cbd2..d43172d 100644 --- a/routes/api.php +++ b/routes/api.php @@ -5,7 +5,7 @@ use App\Http\Controllers\Repuve\CancellationController; use App\Http\Controllers\Repuve\InscriptionController; use App\Http\Controllers\Repuve\UpdateController; -use App\Http\Controllers\Admin\RoleController; +use App\Http\Controllers\Repuve\CatalogNameImgController; use App\Http\Controllers\Repuve\DeviceController; use App\Http\Controllers\Repuve\PackageController; use App\Http\Controllers\Repuve\TagsController; @@ -29,6 +29,7 @@ // Rutas de inscripción de vehículos Route::post('inscripcion', [InscriptionController::class, 'vehicleInscription']); Route::get('consultaV', [InscriptionController::class, 'searchRecord']); + Route::get('RecordErrors', [RecordController::class, 'errors']); // Rutas de expedientes y documentos Route::get('expediente/{id}/pdf', [RecordController::class, 'generatePdf']); @@ -61,6 +62,9 @@ //Ruta CRUD Tags Route::resource('tags', TagsController::class); + //Rutas de nombres de archivos en catálogo + Route::resource('catalog-name-imgs', CatalogNameImgController::class); + }); /** Rutas públicas */