validate([ 'name' => 'required|string|max:255', 'email' => 'required|email|unique:users,email', 'password' => 'sometimes|string|min:8', 'language' => 'sometimes|string|in:es,pt-BR,en', 'currency' => 'sometimes|string|size:3', 'user_type' => 'sometimes|string|in:free,pro,admin', ]); // Generate random password if not provided $password = $validated['password'] ?? bin2hex(random_bytes(8)); $userType = $validated['user_type'] ?? 'free'; $user = User::create([ 'name' => $validated['name'], 'email' => $validated['email'], 'password' => Hash::make($password), 'language' => $validated['language'] ?? 'es', 'currency' => $validated['currency'] ?? 'EUR', 'email_verified_at' => now(), // Auto-verify admin-created users 'is_admin' => $userType === 'admin', ]); $subscriptionInfo = null; // Create Pro subscription if user_type is 'pro' or 'admin' if (in_array($userType, ['pro', 'admin'])) { $proPlan = Plan::where('slug', 'pro-annual')->first(); if ($proPlan) { $subscription = Subscription::create([ 'user_id' => $user->id, 'plan_id' => $proPlan->id, 'status' => Subscription::STATUS_ACTIVE, 'current_period_start' => now(), 'current_period_end' => now()->addYears(100), // "Lifetime" subscription 'paypal_subscription_id' => 'ADMIN_GRANTED_' . strtoupper(bin2hex(random_bytes(8))), 'paypal_status' => 'ACTIVE', 'price_paid' => 0, 'currency' => 'EUR', ]); $subscriptionInfo = [ 'plan' => $proPlan->name, 'status' => 'active', 'expires' => 'Nunca (otorgado por admin)', ]; } } return response()->json([ 'success' => true, 'message' => 'Usuario creado correctamente', 'data' => [ 'user' => [ 'id' => $user->id, 'name' => $user->name, 'email' => $user->email, 'is_admin' => $user->is_admin, ], 'user_type' => $userType, 'subscription' => $subscriptionInfo, 'temporary_password' => isset($validated['password']) ? null : $password, ], ], 201); } /** * List all users with their subscription info */ public function index(Request $request) { $query = User::with(['subscription.plan']) ->withCount(['accounts', 'categories', 'budgets', 'transactions']); // Search if ($request->has('search') && $request->search) { $search = $request->search; $query->where(function ($q) use ($search) { $q->where('name', 'like', "%{$search}%") ->orWhere('email', 'like', "%{$search}%"); }); } // Filter by subscription status if ($request->has('subscription_status')) { if ($request->subscription_status === 'active') { $query->whereHas('subscription'); } elseif ($request->subscription_status === 'free') { $query->whereDoesntHave('subscription'); } } // Pagination $perPage = $request->get('per_page', 20); $users = $query->orderBy('created_at', 'desc')->paginate($perPage); // Transform data $users->getCollection()->transform(function ($user) { return [ 'id' => $user->id, 'name' => $user->name, 'email' => $user->email, 'created_at' => $user->created_at, 'last_login_at' => $user->last_login_at, 'email_verified_at' => $user->email_verified_at, 'subscription' => $user->subscription ? [ 'plan_name' => $user->subscription->plan->name ?? 'Unknown', 'plan_slug' => $user->subscription->plan->slug ?? 'unknown', 'status' => $user->subscription->status, 'current_period_end' => $user->subscription->current_period_end, ] : null, 'usage' => [ 'accounts' => $user->accounts_count, 'categories' => $user->categories_count, 'budgets' => $user->budgets_count, 'transactions' => $user->transactions_count, ], ]; }); return response()->json([ 'success' => true, 'data' => $users->items(), 'pagination' => [ 'current_page' => $users->currentPage(), 'last_page' => $users->lastPage(), 'per_page' => $users->perPage(), 'total' => $users->total(), ], ]); } /** * Get single user details */ public function show($id) { $user = User::with(['subscription.plan', 'subscriptions.plan']) ->withCount(['accounts', 'categories', 'budgets', 'transactions', 'goals']) ->findOrFail($id); return response()->json([ 'success' => true, 'data' => [ 'id' => $user->id, 'name' => $user->name, 'email' => $user->email, 'language' => $user->language, 'currency' => $user->currency, 'created_at' => $user->created_at, 'last_login_at' => $user->last_login_at, 'email_verified_at' => $user->email_verified_at, 'subscription' => $user->subscription ? [ 'id' => $user->subscription->id, 'plan' => $user->subscription->plan, 'status' => $user->subscription->status, 'paypal_subscription_id' => $user->subscription->paypal_subscription_id, 'current_period_start' => $user->subscription->current_period_start, 'current_period_end' => $user->subscription->current_period_end, 'canceled_at' => $user->subscription->canceled_at, ] : null, 'subscription_history' => $user->subscriptions->map(function ($sub) { return [ 'plan_name' => $sub->plan->name ?? 'Unknown', 'status' => $sub->status, 'created_at' => $sub->created_at, 'canceled_at' => $sub->canceled_at, ]; }), 'usage' => [ 'accounts' => $user->accounts_count, 'categories' => $user->categories_count, 'budgets' => $user->budgets_count, 'transactions' => $user->transactions_count, 'goals' => $user->goals_count, ], ], ]); } /** * Update user */ public function update(Request $request, $id) { $user = User::findOrFail($id); $validated = $request->validate([ 'name' => 'sometimes|string|max:255', 'email' => 'sometimes|email|unique:users,email,' . $id, 'language' => 'sometimes|string|in:es,pt-BR,en', 'currency' => 'sometimes|string|size:3', ]); $user->update($validated); return response()->json([ 'success' => true, 'message' => 'Usuario actualizado correctamente', 'data' => $user, ]); } /** * Reset user password (generate random) */ public function resetPassword($id) { $user = User::findOrFail($id); // Generate random password $newPassword = bin2hex(random_bytes(8)); // 16 chars $user->password = Hash::make($newPassword); $user->save(); return response()->json([ 'success' => true, 'message' => 'ContraseƱa restablecida correctamente', 'data' => [ 'temporary_password' => $newPassword, ], ]); } /** * Delete user and all their data */ public function destroy($id) { $user = User::findOrFail($id); // Don't allow deleting admin if ($user->email === 'marco@cnxifly.com') { return response()->json([ 'success' => false, 'message' => 'No se puede eliminar el usuario administrador', ], 403); } // Delete user (cascade will handle related data) $user->delete(); return response()->json([ 'success' => true, 'message' => 'Usuario eliminado correctamente', ]); } /** * Get summary statistics */ public function summary() { $totalUsers = User::count(); $activeSubscribers = Subscription::where('status', 'active')->count(); $freeUsers = $totalUsers - $activeSubscribers; $newUsersThisMonth = User::whereMonth('created_at', now()->month) ->whereYear('created_at', now()->year) ->count(); return response()->json([ 'success' => true, 'data' => [ 'total_users' => $totalUsers, 'active_subscribers' => $activeSubscribers, 'free_users' => $freeUsers, 'new_users_this_month' => $newUsersThisMonth, ], ]); } }