withCount(['packages']); // Validar que se envíe al menos un parámetro de búsqueda if (!$request->filled('name') && !$request->filled('municipality')) { return ApiResponse::BAD_REQUEST->response([ 'message' => 'Debe proporcionar al menos uno de los siguientes parámetros: nombre o municipio.' ]); } // Filtro por nombre if ($request->filled('name')) { $query->where('name', 'like', '%' . $request->input('name') . '%'); } // Filtro por municipio if ($request->filled('municipality')) { $query->where('municipality', 'like', '%' . $request->input('municipality') . '%'); } // Cargar relaciones para contar $query->withCount(['packages']); // Ordenar $sortBy = $request->input('sort_by', 'created_at'); $sortOrder = $request->input('sort_order', 'desc'); $query->orderBy($sortBy, $sortOrder); // Paginación $perPage = $request->input('per_page', 20); $modules = $query->paginate($perPage); return ApiResponse::OK->response([ 'modules' => $modules->map(function ($module) { return [ 'id' => $module->id, 'name' => $module->name, 'responsible' => $module->responsible ? [ 'id' => $module->responsible->id, 'name' => $module->responsible->full_name, 'email' => $module->responsible->email, ] : null, 'municipality' => $module->municipality, 'address' => $module->address, 'colony' => $module->colony, 'cp' => $module->cp, 'longitude' => $module->longitude, 'latitude' => $module->latitude, 'status' => $module->status, 'status_text' => $module->status ? 'Activo' : 'Inactivo', 'packages_count' => $module->packages_count ?? 0, 'created_at' => $module->created_at->format('Y-m-d H:i:s'), 'updated_at' => $module->updated_at->format('Y-m-d H:i:s'), ]; }), 'pagination' => [ 'current_page' => $modules->currentPage(), 'total_pages' => $modules->lastPage(), 'per_page' => $modules->perPage(), 'total' => $modules->total(), 'from' => $modules->firstItem(), 'to' => $modules->lastItem(), ], ]); } catch (\Exception $e) { return ApiResponse::INTERNAL_ERROR->response([ 'message' => 'Error al listar módulos', 'error' => $e->getMessage(), ]); } } /** * Crear un nuevo módulo */ public function store(ModuleStoreRequest $request) { try { DB::beginTransaction(); // Crear el módulo $module = Module::create([ 'name' => $request->input('name'), 'responsible_id' => $request->input('responsible_id'), 'municipality' => $request->input('municipality'), 'address' => $request->input('address'), 'colony' => $request->input('colony'), 'cp' => $request->input('cp'), 'longitude' => $request->input('longitude'), 'latitude' => $request->input('latitude'), 'status' => $request->input('status', true), // Por defecto activo ]); DB::commit(); return ApiResponse::CREATED->response([ 'message' => 'Módulo creado exitosamente', 'module' => [ 'id' => $module->id, 'name' => $module->name, 'municipality' => $module->municipality, 'responsible_id' => $module->responsible_id, 'address' => $module->address, 'colony' => $module->colony, 'cp' => $module->cp, 'longitude' => $module->longitude, 'latitude' => $module->latitude, 'status' => $module->status, 'status_text' => $module->status ? 'Activo' : 'Inactivo', 'created_at' => $module->created_at->format('Y-m-d H:i:s'), ], ]); } catch (\Exception $e) { DB::rollBack(); return ApiResponse::INTERNAL_ERROR->response([ 'message' => 'Error al crear módulo', 'error' => $e->getMessage(), ]); } } /** * Actualizar un módulo existente */ public function update(ModuleUpdateRequest $request, int $id) { try { $module = Module::findOrFail($id); DB::beginTransaction(); // Actualizar solo los campos que vienen en el request $module->update($request->only([ 'name', 'responsible_id', 'municipality', 'address', 'colony', 'cp', 'longitude', 'latitude', 'status', ])); DB::commit(); return ApiResponse::OK->response([ 'message' => 'Módulo actualizado exitosamente', 'module' => [ 'id' => $module->id, 'name' => $module->name, 'responsible_id' => $module->responsible_id, 'municipality' => $module->municipality, 'address' => $module->address, 'colony' => $module->colony, 'cp' => $module->cp, 'longitude' => $module->longitude, 'latitude' => $module->latitude, 'status' => $module->status, 'status_text' => $module->status ? 'Activo' : 'Inactivo', 'updated_at' => $module->updated_at->format('Y-m-d H:i:s'), ], ]); } catch (\Illuminate\Database\Eloquent\ModelNotFoundException $e) { return ApiResponse::NOT_FOUND->response([ 'message' => 'Módulo no encontrado', ]); } catch (\Exception $e) { DB::rollBack(); Log::error('Error al actualizar módulo: ' . $e->getMessage(), [ 'module_id' => $id, 'request' => $request->all(), 'trace' => $e->getTraceAsString() ]); return ApiResponse::INTERNAL_ERROR->response([ 'message' => 'Error al actualizar módulo', 'error' => $e->getMessage(), ]); } } /** * Cambiar solo el status de un módulo */ public function toggleStatus(int $id) { try { $module = Module::findOrFail($id); DB::beginTransaction(); // Cambiar el status al valor opuesto $module->update([ 'status' => !$module->status, ]); DB::commit(); return ApiResponse::OK->response([ 'message' => $module->status ? 'Módulo activado exitosamente' : 'Módulo desactivado exitosamente', 'module' => [ 'id' => $module->id, 'name' => $module->name, 'status' => $module->status, 'status_text' => $module->status ? 'Activo' : 'Inactivo', 'updated_at' => $module->updated_at->format('Y-m-d H:i:s'), ], ]); } catch (ModelNotFoundException $e) { return ApiResponse::NOT_FOUND->response([ 'message' => 'Módulo no encontrado', ]); } catch (\Exception $e) { DB::rollBack(); Log::error('Error al cambiar status del módulo: ' . $e->getMessage(), [ 'module_id' => $id, 'trace' => $e->getTraceAsString() ]); return ApiResponse::INTERNAL_ERROR->response([ 'message' => 'Error al cambiar status del módulo', 'error' => $e->getMessage(), ]); } } public function getAvailableUsers() { try { $users = User::select('id', 'name', 'paternal', 'maternal', 'email') ->orderBy('name') ->get(); return ApiResponse::OK->response([ 'users' => $users->map(function ($user) { return [ 'id' => $user->id, 'name' => $user->full_name, 'email' => $user->email, ]; }), ]); } catch (\Exception $e) { Log::error('Error al obtener usuarios: ' . $e->getMessage()); return ApiResponse::INTERNAL_ERROR->response([ 'message' => 'Error al obtener lista de usuarios', 'error' => $e->getMessage(), ]); } } /** * Obtener lista simplificada de módulos para dropdown */ public function listForDropdown() { try { $modules = Module::where('status', true) // Solo activos ->orderBy('name') ->get(['id', 'name', 'municipality']); return ApiResponse::OK->response([ 'modules' => $modules->map(fn($m) => [ 'id' => $m->id, 'name' => $m->name, 'municipality' => $m->municipality, 'label' => "{$m->name} - {$m->municipality}", // Para mostrar en dropdown ]), ]); } catch (\Exception $e) { return ApiResponse::INTERNAL_ERROR->response([ 'message' => 'Error al obtener módulos', ]); } } }