diff --git a/app/Http/Controllers/UserController.php b/app/Http/Controllers/UserController.php index dfe957f0..052ffa9e 100644 --- a/app/Http/Controllers/UserController.php +++ b/app/Http/Controllers/UserController.php @@ -2,10 +2,11 @@ namespace App\Http\Controllers; -use Illuminate\Routing\Controller; -use App\Models\Plantel; use App\Models\User; +use App\Models\Plantel; use Illuminate\Http\Request; +use Illuminate\Routing\Controller; +use Illuminate\Support\Facades\DB; use Spatie\Permission\Models\Role; class UserController extends Controller @@ -29,11 +30,11 @@ class UserController extends Controller public function create() { $plantels = Plantel::where('status','=','1')->get(); + $codigos = DB::table('area_code')->get(); $roles= Role::all(); - return view('user.create',compact('roles','plantels')); + return view('user.create',compact('roles','plantels','codigos')); } - public function store(Request $request,User $user) { $user= User::create($request->except(['plantels'])); @@ -44,18 +45,17 @@ class UserController extends Controller return redirect()->route('user.edit',compact('user'))->with('info','Se creó el usuario correctamente'); } - public function show(User $user) { return view('user.show',compact('user')); } - public function edit(User $user) { $plantels=Plantel::all(); + $codigos = DB::table('area_code')->get(); $roles= Role::all(); - return view('user.edit',compact('user','roles','plantels')); + return view('user.edit',compact('user','roles','plantels','codigos')); } public function update(Request $request, User $user) diff --git a/app/Livewire/CodeScanner.php b/app/Livewire/CodeScanner.php index 7872d5f4..19eda09e 100644 --- a/app/Livewire/CodeScanner.php +++ b/app/Livewire/CodeScanner.php @@ -2,8 +2,13 @@ namespace App\Livewire; +use Carbon\Carbon; +use App\Models\Code; +use App\Models\User; use Livewire\Component; use Livewire\Attributes\On; +use Illuminate\Support\Facades\DB; +use Illuminate\Support\Facades\Auth; class CodeScanner extends Component { @@ -12,15 +17,233 @@ class CodeScanner extends Component public function qrLeido($texto, $lat, $lng) { + $dia = now()->translatedFormat('l'); + dd($dia); - $this->dispatch('swal', - icon: 'success', - title: 'Asistencia registrada!', - text: $lat, - timer: 2000, - confirm: false, - closeModal: true - ); + $codigo = DB::table('area_code') + ->where('name', $texto) + ->first(); + + $corporativo = DB::table('area_code') + ->where('name','like', '%COR%') + ->first(); + + $user = Auth::user(); + + if($user->code == $corporativo->id){ + + if($codigo){ + + $planteles = $user->plantelUsuarios; + + $match=0; + + foreach($planteles as $plantel){ + + $latCentro = $plantel->latitud; + $lngCentro = $plantel->longitud; + $radioPermitido = 100; // metros + + $distancia = $this->calcularDistancia($lat,$lng,$latCentro,$lngCentro); + + if($distancia > $radioPermitido){ + $match=1; + }else{ + $match = 0; + break; + } + + } + + if($match == 1){ + $this->dispatch('swal', + icon: 'error', + title: 'Error!', + text: 'Fuera del area permitida', + confirm: false, + closeModal: true + ); + return; + } + + + $hoy = Carbon::today(); + + $asistenciasHoy = Code::where('user_id',$user->id) + ->whereDate('registro',$hoy) + ->orderBy('registro','desc') + ->get(); + + if($asistenciasHoy->count() >= 4){ + $this->dispatch('swal', + icon: 'warning', + title: 'Chequeos completos!', + text: 'Límite de registros alcanzados', + confirm: false, + closeModal: true, + ); + return; + } + + + if($asistenciasHoy->count() > 0){ + $ultima = Code::where('user_id',$user->id) + ->whereDate('registro', today()) + ->latest('registro') + ->first(); + + if($ultima->registro->diffInMinutes(now()) < 40){ + $this->dispatch('swal', + icon: 'warning', + title: 'Espera!', + text: 'podrás checar 40 minutos despues de tu ultimo registro', + confirm: false, + closeModal: true, + ); + return; + } + } + + Code::create([ + 'user_id' => $user->id, + 'codigo' => $texto, + 'registro' => Carbon::now('America/Mexico_City')->format('d-m-Y H:i:s'), + 'latitud' => $lat, + 'longitud' => $lng, + ]); + + $this->dispatch('swal', + icon: 'success', + title: 'Excelente!', + text: 'asistencia registrada', + confirm: false, + closeModal: true, + reload:true + ); + + }else{ + $this->dispatch('swal', + icon: 'error', + title: 'Código inexistente', + text: 'Este codigo no es institucional', + confirm: false, + closeModal: true + ); + return; + } + + }else{ + + if($codigo->id != $user->code){ + $this->dispatch('swal', + icon: 'error', + title: 'Error!', + text: 'Este codigo no corresponde a tu area', + confirm: false, + closeModal: true + ); + return; + } + + $planteles = $user->plantelUsuarios; + + $match=0; + + foreach($planteles as $plantel){ + + $latCentro = $plantel->latitud; + $lngCentro = $plantel->longitud; + $radioPermitido = 100; // metros + + $distancia = $this->calcularDistancia($lat,$lng,$latCentro,$lngCentro); + + if($distancia > $radioPermitido){ + $match=1; + }else{ + $match = 0; + break; + } + + } + + if($match == 1){ + $this->dispatch('swal', + icon: 'error', + title: 'Error!', + text: 'Fuera del area permitida', + confirm: false, + closeModal: true + ); + return; + } + + + $hoy = Carbon::today(); + + $asistenciasHoy = Code::where('user_id',$user->id) + ->whereDate('registro',$hoy) + ->orderBy('registro','desc') + ->get(); + + if($asistenciasHoy->count() >= 4){ + $this->dispatch('swal', + icon: 'warning', + title: 'Chequeos completos!', + text: 'Límite de registros alcanzados', + confirm: false, + closeModal: true, + ); + return; + } + + if($asistenciasHoy->count() > 0){ + $ultima = $asistenciasHoy->first(); + + if($ultima->registro->diffInMinutes(now()) < 40){ + $this->dispatch('swal', + icon:'info', + title:'Aún no pasan 40 minutos' + ); + return; + } + } + + Code::create([ + 'user_id' => $user->id, + 'codigo' => $texto, + 'registro' => Carbon::now('America/Mexico_City')->format('d-m-Y H:i:s'), + 'latitud' => $lat, + 'longitud' => $lng, + ]); + + $this->dispatch('swal', + icon: 'success', + title: 'Excelente!', + text: 'asistencia registrada', + confirm: false, + closeModal: true, + reload:true + ); + + } + + } + + private function calcularDistancia($lat1,$lon1,$lat2,$lon2) + { + $radioTierra = 6371000; + + $dLat = deg2rad($lat2 - $lat1); + $dLon = deg2rad($lon2 - $lon1); + + $a = sin($dLat/2) * sin($dLat/2) + + cos(deg2rad($lat1)) * + cos(deg2rad($lat2)) * + sin($dLon/2) * sin($dLon/2); + + $c = 2 * atan2(sqrt($a), sqrt(1-$a)); + + return $radioTierra * $c; } public function render() diff --git a/app/Models/User.php b/app/Models/User.php index 33f8a179..ed117a73 100644 --- a/app/Models/User.php +++ b/app/Models/User.php @@ -11,7 +11,6 @@ use Laravel\Fortify\TwoFactorAuthenticatable; use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\Relations\BelongsToMany; use Illuminate\Database\Eloquent\Relations\HasMany; -use Illuminate\Database\Eloquent\Relations\HasOne; use Illuminate\Foundation\Auth\User as Authenticatable; class User extends Authenticatable @@ -25,11 +24,6 @@ class User extends Authenticatable use TwoFactorAuthenticatable; use HasRoles; - /** - * The attributes that are mass assignable. - * - * @var array - */ protected $fillable = [ 'name', 'email', @@ -50,16 +44,10 @@ class User extends Authenticatable 'status', ]; - protected $appends = [ 'profile_photo_url', ]; - /** - * Get the attributes that should be cast. - * - * @return array - */ protected function casts(): array { return [ diff --git a/config/app.php b/config/app.php index 8b7804d2..f5e9537c 100644 --- a/config/app.php +++ b/config/app.php @@ -65,7 +65,7 @@ return [ | */ - 'timezone' => 'UTC', + 'timezone' => 'America/Mexico_City', /* |-------------------------------------------------------------------------- diff --git a/database/migrations/2025_12_25_204533_create_plantels_table.php b/database/migrations/2025_12_25_204533_create_plantels_table.php index 637df474..5990fb34 100644 --- a/database/migrations/2025_12_25_204533_create_plantels_table.php +++ b/database/migrations/2025_12_25_204533_create_plantels_table.php @@ -15,7 +15,10 @@ return new class extends Migration $table->id(); $table->string('name'); $table->string('razon'); - $table->string('ubicacion'); + $table->string('ubicacion')->nullable();; + $table->string('nomenclatura')->nullable(); + $table->string('latitud')->nullable(); + $table->string('longitud')->nullable(); $table->bigInteger('telefono'); $table->boolean('status'); $table->timestamps(); diff --git a/database/migrations/2026_02_05_194540_create_codes_table.php b/database/migrations/2026_02_05_194540_create_codes_table.php index 2815df23..2aa895ee 100644 --- a/database/migrations/2026_02_05_194540_create_codes_table.php +++ b/database/migrations/2026_02_05_194540_create_codes_table.php @@ -6,14 +6,13 @@ use Illuminate\Support\Facades\Schema; return new class extends Migration { - /** - * Run the migrations. - */ + public function up(): void { Schema::create('codes', function (Blueprint $table) { $table->id(); $table->unsignedBigInteger('user_id'); + $table->string('codigo'); $table->dateTime('registro')->nullable(); $table->string('latitud'); $table->string('longitud'); @@ -21,9 +20,6 @@ return new class extends Migration }); } - /** - * Reverse the migrations. - */ public function down(): void { Schema::dropIfExists('codes'); diff --git a/database/seeders/DatabaseSeeder.php b/database/seeders/DatabaseSeeder.php index 9df21622..2dd8e48d 100644 --- a/database/seeders/DatabaseSeeder.php +++ b/database/seeders/DatabaseSeeder.php @@ -10,9 +10,6 @@ class DatabaseSeeder extends Seeder { use WithoutModelEvents; - /** - * Seed the application's database. - */ public function run(): void { $this->call(RoleSeeder::class); diff --git a/database/seeders/PlantelSeeder.php b/database/seeders/PlantelSeeder.php index 487ebdf2..54131ca0 100644 --- a/database/seeders/PlantelSeeder.php +++ b/database/seeders/PlantelSeeder.php @@ -3,7 +3,6 @@ namespace Database\Seeders; use App\Models\Plantel; -use Illuminate\Database\Console\Seeds\WithoutModelEvents; use Illuminate\Database\Seeder; class PlantelSeeder extends Seeder @@ -18,6 +17,9 @@ class PlantelSeeder extends Seeder 'razon'=>'123456789', 'ubicacion'=>'Carretera Aculco-Amealco S/N, 50360 Aculco de Espinoza, Méx.', 'telefono'=>7181240287, + 'nomenclatura'=>'ACU', + 'latitud'=>'20.095675599841005', + 'longitud'=>'-99.83370646050189', 'status'=>1 ]); @@ -26,6 +28,9 @@ class PlantelSeeder extends Seeder 'razon'=>'123456789', 'ubicacion'=>'5 de Mayo 26, Centro, 76800 San Juan del Río, Qro.', 'telefono'=>4272774826, + 'nomenclatura'=>'SJR', + 'latitud'=>'20.38996649108517,20.384703934068455', + 'longitud'=>'-99.99204858595175,-99.99729277268392', 'status'=>1 ]); @@ -34,6 +39,9 @@ class PlantelSeeder extends Seeder 'razon'=>'123456789', 'ubicacion'=>'Carr. México - Pachuca Km. 38.5, Tecámac Centro, Tecamac, 55740 Tecámac de Felipe Villanueva, Méx.', 'telefono'=>5533552116, + 'nomenclatura'=>'TEC', + 'latitud'=>'19.71385878202753', + 'longitud'=>'-98.97363138918948', 'status'=>1 ]); @@ -42,6 +50,9 @@ class PlantelSeeder extends Seeder 'razon'=>'123456789', 'ubicacion'=>'C. Nigromante #85, San Francisco 1ra, 42854 Tepeji del Río de Ocampo, Hgo.', 'telefono'=>7736826093, + 'nomenclatura'=>'TEP', + 'latitud'=>'19.89967939304829', + 'longitud'=>'-99.34733192966145', 'status'=>1 ]); @@ -50,6 +61,9 @@ class PlantelSeeder extends Seeder 'razon'=>'123456789', 'ubicacion'=>'Legislatura 56, 50450 Atlacomulco de Fabela, Méx.', 'telefono'=>7122174727, + 'nomenclatura'=>'ATL', + 'latitud'=>'19.79552485274741', + 'longitud'=>'-99.87546357384377', 'status'=>1 ]); @@ -58,6 +72,20 @@ class PlantelSeeder extends Seeder 'razon'=>'123456789', 'ubicacion'=>'Prof. Benjamín García Uribe 8, Centro, 42470 Nopala de Villagrán, Hgo.', 'telefono'=>7731328198, + 'nomenclatura'=>'NOP', + 'latitud'=>'20.251432945100376', + 'longitud'=>'-99.64692423068954', + 'status'=>1 + ]); + + Plantel::create([ + 'name'=>'En línea', + 'razon'=>'123456789', + 'ubicacion'=>'', + 'telefono'=>7731328198, + 'nomenclatura'=>'LIN', + 'latitud'=>'19.71385878202753', + 'longitud'=>'-98.97363138918948', 'status'=>1 ]); } diff --git a/database/seeders/UserSeeder.php b/database/seeders/UserSeeder.php index 24156e66..9ac40d1c 100644 --- a/database/seeders/UserSeeder.php +++ b/database/seeders/UserSeeder.php @@ -31,6 +31,7 @@ class UserSeeder extends Seeder 'direccion'=>'Zacatenco mz 21 lt 2 san francisco cuautliquixca', 'telefono'=>'5636287758', 'password' => bcrypt('2000'), + 'code'=>1, 'status'=>1 ])->assignRole('Promotor'); $user2->plantelUsuarios()->sync([1,2,3]); diff --git a/resources/views/livewire/code-scanner.blade.php b/resources/views/livewire/code-scanner.blade.php index 031aecac..d69ca3f4 100644 --- a/resources/views/livewire/code-scanner.blade.php +++ b/resources/views/livewire/code-scanner.blade.php @@ -24,25 +24,37 @@ function iniciarScanner(){ scanner = new Html5Qrcode("reader"); scanner.start( - { facingMode: "environment" }, - { fps: 10, qrbox: 250 }, - (mensaje) => { + { facingMode: "environment" }, + { fps: 10, qrbox: 250 }, + (mensaje) => { + + if(!gpsListo){ + Swal.fire("GPS","Esperando ubicación...","warning"); + return; + } + + if(yaEscaneado) return; + yaEscaneado = true; + + Livewire.dispatch('qrLeido', { + texto: mensaje, + lat: latitud, + lng: longitud + }); - if(!gpsListo){ - Swal.fire("GPS","Esperando ubicación...","warning"); - return; } + ).catch(err => { - if(yaEscaneado) return; - yaEscaneado = true; + console.error("Error cámara:", err); - Livewire.dispatch('qrLeido', { - texto: mensaje, - lat: latitud, - lng: longitud - }); + Swal.fire( + "Cámara bloqueada", + "Debes permitir el acceso a la cámara para escanear el QR", + "error" + ); }); + } document.addEventListener('livewire:init', () => { @@ -97,7 +109,4 @@ document.addEventListener("visibilitychange", function() { - - - @endpush diff --git a/resources/views/plantel/create.blade.php b/resources/views/plantel/create.blade.php index e75c22b9..e255ae6f 100644 --- a/resources/views/plantel/create.blade.php +++ b/resources/views/plantel/create.blade.php @@ -28,6 +28,22 @@ + +
+ + +
+ +
+ + +
+ +
+ + +
+
diff --git a/resources/views/plantel/edit.blade.php b/resources/views/plantel/edit.blade.php index 48cfd54b..3cf2180c 100644 --- a/resources/views/plantel/edit.blade.php +++ b/resources/views/plantel/edit.blade.php @@ -34,6 +34,21 @@
+ +
+ + +
+ +
+ + +
+ +
+ + +
diff --git a/resources/views/user/create.blade.php b/resources/views/user/create.blade.php index 49ca40f1..bb03c921 100644 --- a/resources/views/user/create.blade.php +++ b/resources/views/user/create.blade.php @@ -72,6 +72,16 @@
+
+ + +
+
-
+
@foreach ($plantels as $plantel) @@ -56,10 +56,10 @@ {{ $plantel->name }}
- @endforeach -
+ @endforeach + -
+
@foreach ($roles as $role)
@@ -71,16 +71,27 @@ {{ $role->name }}
- @endforeach + @endforeach
+
+ + +
+ +
-
+