diff --git a/app/Http/Controllers/AuditoriaController.php b/app/Http/Controllers/AuditoriaController.php new file mode 100644 index 0000000000000000000000000000000000000000..c5c2815c31b40b99dc3757af97f2646230a1130d --- /dev/null +++ b/app/Http/Controllers/AuditoriaController.php @@ -0,0 +1,65 @@ +get(); return view('adminGen.contactos.index', compact('contactos')); } @@ -68,7 +71,7 @@ public function store(Request $request) $correosData = $request->only(['correo_electronico', 'tipo_correo_electronico']); $correosData = array_map(function ($item) { return array_map(function ($value) { - return ($value === '0' || $value === "null") ? null : $value; + return ($value === "null") ? null : $value; }, $item); }, $correosData); @@ -140,33 +143,216 @@ public function store(Request $request) /** * Display the specified resource. */ - public function show(Contacto $contacto) + public function show(string $id) { - // + $contacto = Contacto::with('profesion', 'cargo', 'pareja')->findOrFail($id); + return view('adminGen.contactos.show', compact('contacto')); } /** * Show the form for editing the specified resource. */ - public function edit(Contacto $contacto) + public function edit(string $id) { - // + $conyuges = Contacto::where('id', '!=' ,$id)->get(); + $profesiones = Profesion::get(); + $cargos = cargos::get(); + $caracteristicas = Caracteristicas::get(); + $subgrupos = Subgrupo::get(); + $contacto = Contacto::with(['telefonos', 'redes', 'correos'])->findOrFail($id); + //dd($contacto); + return view('adminGen.contactos.edit', compact('contacto', 'conyuges', 'profesiones', 'cargos', 'caracteristicas', 'subgrupos')); } /** * Update the specified resource in storage. + * TODO: Falta terminar de hacer pruebas a la funcionalidad de auditoria */ - public function update(Request $request, Contacto $contacto) + public function update(Request $request, string $id) { - // + // Validar los datos + $validatedData = $request->validate([ + 'nombre' => 'required|string|max:255', + 'foto_perfil' => 'image|mimes:jpeg,png,jpg,gif,svg|max:2048', + ]); + + $contacto = Contacto::findOrFail($id); + $user = auth()->user(); + + $fieldsToCheck = [ + 'conyuge_id', + 'profesion_id', + 'cargo_id', + 'caracteristica_id', + 'subgrupo_id', + 'mes_cump', + 'dia_cump', + //institucion_id + ]; + $requestData = $request->all(); + foreach ($fieldsToCheck as $field) { + if (isset($requestData[$field]) && $requestData[$field] === "null") { + unset($requestData[$field]); + } + } + + $request->replace($requestData); + + // Guardar auditoría de campos simples + $changes = []; + foreach ($requestData as $key => $value) { + if (!is_array($value) && $key !== '_token' && $contacto->$key != $value) { + $changes[] = [ + 'campo_editado' => $key, + 'valor_anterior' => $contacto->$key, + 'nuevo_valor' => $value, + 'contacto_id' => $contacto->id, + 'user_id' => $user->id, + 'created_at' => now(), + 'updated_at' => now(), + ]; + } + } + + // Guardar auditoría de teléfonos + $telefonosAnteriores = $contacto->telefonos->toArray(); + $telefonos = collect($request->input('prefijo'))->map(function($prefijo, $index) use ($request) { + return [ + 'prefijo' => $prefijo, + 'lada' => $request->input('lada')[$index], + 'numero' => $request->input('numero')[$index], + 'tipo' => $request->input('tipo')[$index], + 'estatus' => $request->input('estatus')[$index], + 'ext' => $request->input('ext')[$index], + 'id_radio' => $request->input('id_radio')[$index], + 'observaciones' => $request->input('observaciones')[$index], + ]; + })->toArray(); + + foreach ($telefonosAnteriores as $index => $telefonoAnterior) { + foreach ($telefonoAnterior as $key => $value) { + if (isset($telefonos[$index][$key]) && $value != $telefonos[$index][$key]) { + $changes[] = [ + 'campo_editado' => "telefono_{$index}_{$key}", + 'valor_anterior' => $value, + 'nuevo_valor' => $telefonos[$index][$key], + 'contacto_id' => $contacto->id, + 'user_id' => $user->id, + 'created_at' => now(), + 'updated_at' => now(), + ]; + } + } + } + + // Guardar auditoría de redes sociales + $redesAnteriores = $contacto->redes->toArray(); + $redes = collect($request->input('red_social'))->map(function($url, $index) use ($request) { + return [ + 'red_social' => $url, + 'tipo_red_social' => $request->input('tipo_red_social')[$index], + ]; + })->toArray(); + + foreach ($redesAnteriores as $index => $redAnterior) { + foreach ($redAnterior as $key => $value) { + if (isset($redes[$index][$key]) && $value != $redes[$index][$key]) { + $changes[] = [ + 'campo_editado' => "red_{$index}_{$key}", + 'valor_anterior' => $value, + 'nuevo_valor' => $redes[$index][$key], + 'contacto_id' => $contacto->id, + 'user_id' => $user->id, + 'created_at' => now(), + 'updated_at' => now(), + ]; + } + } + } + + // Guardar auditoría de correos + $correosAnteriores = $contacto->correos->toArray(); + $correos = collect($request->input('correo_electronico'))->map(function($email, $index) use ($request) { + return [ + 'correo_electronico' => $email, + 'tipo_correo_electronico' => $request->input('tipo_correo_electronico')[$index], + ]; + })->toArray(); + + foreach ($correosAnteriores as $index => $correoAnterior) { + foreach ($correoAnterior as $key => $value) { + if (isset($correos[$index][$key]) && $value != $correos[$index][$key]) { + $changes[] = [ + 'campo_editado' => "correo_{$index}_{$key}", + 'valor_anterior' => $value, + 'nuevo_valor' => $correos[$index][$key], + 'contacto_id' => $contacto->id, + 'user_id' => $user->id, + 'created_at' => now(), + 'updated_at' => now(), + ]; + } + } + } + + if (!empty($changes)) { + Auditoria::insert($changes); + } + + // Actualizar los datos del contacto + $contacto->conyuge_id = $request->input('conyuge_id') !== 'null' ? $request->input('conyuge_id') : null; + $contacto->profesion_id = $request->input('profesion_id') !== 'null' ? $request->input('profesion_id') : null; + $contacto->cargo_id = $request->input('cargo_id') !== 'null' ? $request->input('cargo_id') : null; + $contacto->cargo_desc = $request->input('cargo_desc'); + + $data = $request->all(); + + if ($request->hasFile('foto_perfil')) { + // Eliminar la foto de perfil anterior si existe + if ($contacto->foto_perfil) { + Storage::delete(STR::substr($contacto->foto_perfil, 8)); + } + + // Guardar la nueva foto de perfil + $path_file = $this->storeProfilePicture($request); + + if ($path_file) { + $data['foto_perfil'] = 'storage/' . $path_file; + } else { + $data['foto_perfil'] = 'assets/images/profile-icon.webp'; + } + } + + // Actualizar los datos del usuario + $contacto->update($data); + + // Guardar teléfonos + $contacto->telefonos()->delete(); + $contacto->telefonos()->createMany($telefonos); + + // Guardar redes sociales + $contacto->redes()->delete(); + $contacto->redes()->createMany($redes); + + // Guardar correos electrónicos + $contacto->correos()->delete(); + $contacto->correos()->createMany($correos); + + return redirect()->route('contacto.get')->with('success', 'Contacto actualizado correctamente'); } /** * Remove the specified resource from storage. */ - public function destroy(Contacto $contacto) + public function destroy(string $id) { - // + try{ + $contacto = Contacto::findOrFail($id); + $contacto->delete(); + return redirect()->route('contacto.get')->with('success', 'Contacto eliminado correctamente.'); + }catch(\Exception $e){ + return redirect()->route('contacto.get')->withErrors('Error al eliminar el contacto.'); + } } /** @@ -335,4 +521,109 @@ private function correoDataPresent($correosData) return false; } + + public function viewUpload() + { + return view('adminGen.contactos.upload'); + } + + public function upload(Request $request) + { + $request->validate([ + 'csv_file' => 'required|mimes:csv,txt', + ]); + + $path = $request->file('csv_file')->getRealPath(); + $content = file_get_contents($path); + $content = str_replace("\xEF\xBB\xBF", '', $content); + + $data = array_map('str_getcsv', explode("\n", $content)); + $header = array_shift($data); + + foreach ($data as $row) { + if (count($header) !== count($row)) { + continue; + } + $row = array_combine($header, $row); + + $contacto = Contacto::create([ + 'nombre' => $row['nombre'], + 'ap_paterno' => $row['ap_paterno'], + 'ap_materno' => $row['ap_materno'], + 'cargo_desc' => $row['cargo_desc'], + 'mes_cump' => $row['mes_cump'], + 'dia_cump' => $row['dia_cump'], + 'domicilio_oficial' => $row['domicilio_oficial'], + 'codigo_postal' => $row['codigo_postal'], + 'localidad_oficial' => $row['localidad_oficial'], + 'municipio_oficial' => $row['municipio_oficial'], + 'estado' => $row['estado'], + 'pais' => $row['pais'], + 'domicilio_par' => $row['domicilio_par'], + 'codigo_postal_par' => $row['codigo_postal_par'], + 'localidad_par' => $row['localidad_par'], + 'municipio_par' => $row['municipio_par'], + 'estado_par' => $row['estado_par'], + 'pais_par' => $row['pais_par'], + 'finado' => $row['finado'], + 'foto_perfil' => 'assets/images/profile-icon.webp' + ]); + + // Procesar teléfonos + $prefijos = explode(';', $row['prefijo']); + $ladas = explode(';', $row['lada']); + $numeros = explode(';', $row['numero']); + $tipos = explode(';', $row['tipo']); + $estatuses = explode(';', $row['estatus']); + $exts = explode(';', $row['ext']); + $id_radios = explode(';', $row['id_radio']); + $observaciones = explode(';', $row['observaciones']); + + for ($i = 0; $i < count($prefijos); $i++) { + if ($prefijos[$i] != 'null' || $ladas[$i] != 'null' || $numeros[$i] != 'null') { + Telefono::create([ + 'contacto_id' => $contacto->id, + 'prefijo' => $prefijos[$i], + 'lada' => $ladas[$i], + 'numero' => $numeros[$i], + 'tipo' => $tipos[$i], + 'estatus' => $estatuses[$i], + 'ext' => $exts[$i], + 'id_radio' => $id_radios[$i], + 'observaciones' => $observaciones[$i], + ]); + } + } + + // Procesar redes sociales + $redes_sociales = explode(';', $row['red_social']); + $tipos_redes_sociales = explode(';', $row['tipo_red_social']); + + for ($i = 0; $i < count($redes_sociales); $i++) { + if ($redes_sociales[$i] != 'null' || $tipos_redes_sociales[$i] != 'null') { + RedesSociales::create([ + 'contacto_id' => $contacto->id, + 'red_social' => $redes_sociales[$i], + 'tipo_red_social' => $tipos_redes_sociales[$i], + ]); + } + } + + // Procesar correos electrónicos + $correos = explode(';', $row['correo_electronico']); + $tipos_correos = explode(';', $row['tipo_correo_electronico']); + + for ($i = 0; $i < count($correos); $i++) { + if ($correos[$i] != 'null' || $tipos_correos[$i] != 'null') { + CorreoContactos::create([ + 'contacto_id' => $contacto->id, + 'correo_electronico' => $correos[$i], + 'tipo_correo_electronico' => $tipos_correos[$i], + ]); + } + } + } + + return redirect()->route('contacto.get')->with('success', 'Importación de contactos almacenada correctamente'); + } } diff --git a/app/Models/Auditoria.php b/app/Models/Auditoria.php new file mode 100644 index 0000000000000000000000000000000000000000..fd14a5602a147e81a1c730fef22a8831cad69d8a --- /dev/null +++ b/app/Models/Auditoria.php @@ -0,0 +1,29 @@ +belongsTo(Contacto::class); + } + + public function user() + { + return $this->belongsTo(User::class); + } +} diff --git a/app/Models/Contacto.php b/app/Models/Contacto.php index 459592d4ccc47e8d59c5865440ac1888a7803c50..675b3e8ac000b342ef1c6f149bc72983bd147834 100644 --- a/app/Models/Contacto.php +++ b/app/Models/Contacto.php @@ -4,6 +4,7 @@ use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\Model; +use Illuminate\Database\Eloquent\Relations\BelongsTo; class Contacto extends Model { @@ -39,4 +40,34 @@ class Contacto extends Model //'institucion_id', 'subgrupo_id', ]; + + public function profesion(): BelongsTo + { + return $this->belongsTo(Profesion::class); + } + + public function pareja(): BelongsTo + { + return $this->belongsTo(Contacto::class, 'conyuge_id'); + } + + public function cargo(): BelongsTo + { + return $this->belongsTo(cargos::class); + } + + public function telefonos() + { + return $this->hasMany(Telefono::class); + } + + public function redes() + { + return $this->hasMany(RedesSociales::class); + } + + public function correos() + { + return $this->hasMany(CorreoContactos::class); + } } diff --git a/composer.lock b/composer.lock index b5bb1d9bc6a3de8f31a438558dd0423eb584dc87..d0ca1ab2b354adc5ff64271a7ee9845a894fa1e9 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "ad53994e33fc40bc932315ca31084ff3", + "content-hash": "7b28faeac6b57475b878b6147632b657", "packages": [ { "name": "bacon/bacon-qr-code", diff --git a/database/migrations/2024_06_30_182925_create_telefonos_table.php b/database/migrations/2024_06_30_182925_create_telefonos_table.php index 78deb2c84ac90bd80cf1a49b0edaf55ad967ee3a..ad3a1a9650fe8f677e89f26b904039e22112ece5 100644 --- a/database/migrations/2024_06_30_182925_create_telefonos_table.php +++ b/database/migrations/2024_06_30_182925_create_telefonos_table.php @@ -15,7 +15,7 @@ public function up(): void $table->id(); $table->integer('prefijo')->nullable(); $table->integer('lada')->nullable(); - $table->integer('numero')->nullable(); + $table->bigInteger('numero')->nullable(); $table->string('tipo')->nullable(); $table->string('estatus')->nullable(); $table->integer('ext')->nullable(); diff --git a/database/migrations/2024_07_03_145858_create_auditorias_table.php b/database/migrations/2024_07_03_145858_create_auditorias_table.php new file mode 100644 index 0000000000000000000000000000000000000000..397c52b8c9b17146cb28451921500ce5f35882c3 --- /dev/null +++ b/database/migrations/2024_07_03_145858_create_auditorias_table.php @@ -0,0 +1,35 @@ +id(); + $table->string('campo_editado'); + $table->text('valor_anterior')->nullable(); + $table->text('nuevo_valor')->nullable(); + $table->unsignedBigInteger('contacto_id'); + $table->unsignedBigInteger('user_id'); + $table->timestamps(); + + $table->foreign('contacto_id')->references('id')->on('contactos')->onDelete('cascade'); + $table->foreign('user_id')->references('id')->on('users')->onDelete('cascade'); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::dropIfExists('auditorias'); + } +}; diff --git a/public/assets/formato/data.csv b/public/assets/formato/data.csv new file mode 100644 index 0000000000000000000000000000000000000000..bb9b28bba500167689f4d47d0239bd86b84afaac --- /dev/null +++ b/public/assets/formato/data.csv @@ -0,0 +1,4 @@ +nombre,ap_paterno,ap_materno,cargo_desc,mes_cump,dia_cump,domicilio_oficial,codigo_postal,localidad_oficial,municipio_oficial,estado,pais,domicilio_par,codigo_postal_par,localidad_par,municipio_par,estado_par,pais_par,finado,prefijo,lada,numero,tipo,estatus,ext,id_radio,observaciones,red_social,tipo_red_social,correo_electronico,tipo_correo_electronico +John,Doe,,Amigo del hijo del C. Gobernador,2,12,Conocido,98000,Zacatecas,Zacatecas,Zacatecas,México,Conocido,98000,Zacatecas,Zacatecas,Zacatecas,México,0,123;124,456;457,7890123456;1234567890,Celular;Fax,Público;Privado,123;124,123;124,Nota 1;Nota 2,http://facebook.com/johndoe;http://twitter.com/johndoe,Facebook;Twitter,johndoe@example.com;johndoe123@example.com,Oficial;Personal +Jane,Smith,,Amigo del hijo del C. Gobernador,10,10,Conocido,98612,Guadalupe,Guadalupe,Zacatecas,México,Conocido,98612,Guadalupe,Guadalupe,Zacatecas,México,1,321;322,654;655,9876543210;1122334455,Particular;Directo,Privado;Público,456;457,456;457,Otra nota 1;Otra nota 2,http://twitter.com/janesmith;http://linkedin.com/janesmith,Twitter;LinkedIn,janesmith@example.com;janesmith123@example.com,Personal;Oficial +Bob ,Johnson,,Amigo del hijo del C. Gobernador,12,2,Conocido,98640,Trancoso,Trancoso,Zacatecas,México,Conocido,98640,Trancoso,Trancoso,Zacatecas,México,0,555;556;557,123;124;125,1112223333;4445556666;7778889999,Radio;Celular;Fax,Público;Privado;Público,101;102;103,555;556;557,Observación 1;Observación 2;Observación 3,http://facebook.com/bobjohnson;http://instagram.com/bobjohnson,Facebook;Instagram,bobjohnson@example.com;bobjohnson123@example.com,Oficial;Personal diff --git a/resources/views/adminGen/contactos/edit.blade.php b/resources/views/adminGen/contactos/edit.blade.php new file mode 100644 index 0000000000000000000000000000000000000000..f9ee2a865a86ae22f0eb836436800ce85fd0630c --- /dev/null +++ b/resources/views/adminGen/contactos/edit.blade.php @@ -0,0 +1,742 @@ + + + + + + + Dashboard + + + Contactos + + + Editar contacto + + + + + Editar contacto + + + + + + + + + + + + + + + + + + + + Datos personales + + + + + + + + + + + + + Domicilio oficial + + + + + + + + + + + + + Domicilio particular + + + + + + + + + + + Teléfonos + + + + + + + + + + + + Redes sociales + + + + + + + + + + + + Correos electrónicos + + + + + + + + + + Guardar contacto + + + + + + @csrf + @method('PUT') + + + + + + Nombre + + + + + + Apellido paterno + + + + Apellido materno + + + + + + Mes cumpleaños + + mes_cump) == null ? 'selected' : '' }}>Selecciona un mes + mes_cump) == 1 ? 'selected' : '' }}>Enero + mes_cump) == 2 ? 'selected' : '' }}>Febrero + mes_cump) == 3 ? 'selected' : '' }}>Marzo + mes_cump) == 4 ? 'selected' : '' }}>Abril + mes_cump) == 5 ? 'selected' : '' }}>Mayo + mes_cump) == 6 ? 'selected' : '' }}>Junio + mes_cump) == 7 ? 'selected' : '' }}>Julio + mes_cump) == 8 ? 'selected' : '' }}>Agosto + mes_cump) == 9 ? 'selected' : '' }}>Septiembre + mes_cump) == 10 ? 'selected' : '' }}>Octubre + mes_cump) == 11 ? 'selected' : '' }}>Noviembre + mes_cump) == 12 ? 'selected' : '' }}>Diciembre + + + + Día cumpleaños + + dia_cump) == null ? 'selected' : '' }}>Selecciona una opción + + + + + + + Finado + + finado) ? 'checked' : '' }} /> + + + + + + + Conyuge + + conyuge_id) == null ? 'selected' : '' }}>Selecciona una opción + @foreach($conyuges as $conyuge) + conyuge_id) == $conyuge->id ? 'selected' : '' }}> + {{ $conyuge->nombre . ' ' . $conyuge->ap_paterno . ' ' . $conyuge->ap_materno }} + + @endforeach + + + + Profesión + + profesion_id) == null ? 'selected' : '' }}>Selecciona una opción + @foreach($profesiones as $profesion) + profesion_id) == $profesion->id ? 'selected' : '' }}> + {{ $profesion->nombre }} + + @endforeach + + + + Cargos + + cargo_id) == null ? 'selected' : '' }}>Selecciona una opción + @foreach($cargos as $cargo) + cargo_id) == $cargo->id ? 'selected' : '' }}> + {{ $cargo->nombre }} + + @endforeach + + + + Descripción del cargo + + + + + + Caracteristicas + + caracteristica_id) == null ? 'selected' : '' }}>Selecciona una opción + @foreach($caracteristicas as $caracteristica) + caracteristica_id) == $caracteristica->id ? 'selected' : '' }}> + {{ $caracteristica->nombre }} + + @endforeach + + + + Subgrupos + + subgrupo_id) == null ? 'selected' : '' }}>Selecciona una opción + @foreach($subgrupos as $subgrupo) + subgrupo_id) == $subgrupo->id ? 'selected' : '' }}> + {{ $subgrupo->nombre }} + + @endforeach + + + + + + + Foto de perfil + @if($contacto->foto_perfil) + + + + @endif + + + + + + + + + Domicilio oficial + + + + Código postal oficial + + + + Localidad oficial + + + + Municipio oficial + + + + Estado oficial + + + + País oficial + + + + + + + + + + Domicilio particular + + + + Código postal particular + + + + Localidad particular + + + + Municipio particular + + + + Estado particular + + + + País particular + + + + + + + + + @foreach($contacto->telefonos as $telefono) + + + Prefijo + + + + Lada + + + + Número + + + + Tipo + + tipo) == null ? 'selected' : '' }}>Selecciona una opción + tipo) == 'Celular' ? 'selected' : '' }}>Celular + tipo) == 'Fax' ? 'selected' : '' }}>Fax + tipo) == 'Directo' ? 'selected' : '' }}>Directo + tipo) == 'Radio' ? 'selected' : '' }}>Radio + tipo) == 'Particular' ? 'selected' : '' }}>Particular + tipo) == 'Conmutador' ? 'selected' : '' }}>Conmutador + + + + Estatus + + estatus) == null ? 'selected' : '' }}>Selecciona una opción + estatus) == 'Público' ? 'selected' : '' }}>Público + estatus) == 'Privado' ? 'selected' : '' }}>Privado + + + + Ext. + + + + Id radio + + + + Observaciones + + + + + + + + + + + + + @endforeach + + Agregar + + + + + + @foreach($contacto->redes as $red) + + + URL del la red social o página web + + + + Tipo + + tipo_red_social) == null ? 'selected' : '' }}>Selecciona una opción + tipo_red_social) == 'Facebook' ? 'selected' : '' }}>Facebook + tipo_red_social) == 'Instagram' ? 'selected' : '' }}>Instagram + tipo_red_social) == 'Twitter' ? 'selected' : '' }}>Twitter + tipo_red_social) == 'Página Web' ? 'selected' : '' }}>Página Web + tipo_red_social) == 'LinkedIn' ? 'selected' : '' }}>LinkedIn + + + + + + + + + + + + @endforeach + + Agregar + + + + + + @foreach($contacto->correos as $correo) + + + Correo electrónico + + + + Tipo + + tipo_correo_electronico) == null ? 'selected' : '' }}>Selecciona una opción + tipo_correo_electronico) == 'Oficial' ? 'selected' : '' }}>Oficial + tipo_correo_electronico) == 'Personal' ? 'selected' : '' }}>Personal + tipo_correo_electronico) == 'De respaldo' ? 'selected' : '' }}>De respaldo + + + + + + + + + + + + @endforeach + + Agregar + + + + + Enviar formulario + + Por favor, revise toda la información antes de enviar el formulario. + Si encuentra algún error, puede regresar y editar la información antes de enviar. + + + Guardar contacto + + + + + + Atras + Siguiente + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/resources/views/adminGen/contactos/index.blade.php b/resources/views/adminGen/contactos/index.blade.php index 8130fe66aea27599d53fb3171da10b2dd93b0392..8bbbaa6129f650744ac65926366e9d7c8a998fd0 100644 --- a/resources/views/adminGen/contactos/index.blade.php +++ b/resources/views/adminGen/contactos/index.blade.php @@ -40,32 +40,42 @@
Por favor, revise toda la información antes de enviar el formulario.
Si encuentra algún error, puede regresar y editar la información antes de enviar.