$request->method(), 'all_data' => $request->all(), 'only_email' => $request->only(['email']), 'email_value' => $request->input('email'), 'has_email' => $request->has('email'), 'filled_email' => $request->filled('email'), ]); // Validasi dengan pesan error yang jelas $validated = $request->validate([ 'email' => [ 'required', 'string', 'email:rfc,dns', 'max:255' ], 'password' => [ 'required', 'string', 'min:6' ], ], [ 'email.required' => 'Email wajib diisi', 'email.string' => 'Email harus berupa teks', 'email.email' => 'Format email tidak valid', 'email.max' => 'Email terlalu panjang', 'password.required' => 'Password wajib diisi', 'password.string' => 'Password harus berupa teks', 'password.min' => 'Password minimal 6 karakter', ]); // Debug: Log validated data Log::info('Validated data', $validated); $credentials = [ 'email' => $validated['email'], 'password' => $validated['password'] ]; // Cek apakah user dengan email ini ada $user = User::where('email', $credentials['email'])->first(); if (!$user) { Log::warning('User not found', ['email' => $credentials['email']]); return back()->withErrors([ 'email' => 'Akun admin dengan email ini tidak ditemukan', ])->withInput($request->only('email')); } // Coba login if (Auth::attempt($credentials, $request->boolean('remember'))) { $request->session()->regenerate(); Log::info('Login successful', ['user_id' => Auth::id()]); return redirect() ->intended(route('admin.dashboard')) ->with('success', 'Selamat datang, ' . Auth::user()->name . '!'); } Log::warning('Login failed - wrong credentials', ['email' => $credentials['email']]); return back()->withErrors([ 'email' => 'Email atau password salah. Silakan coba lagi.', ])->withInput($request->only('email')); } /** * Show the admin dashboard. */ public function dashboard() { $this->syncProductLabels(); // Total bibit terjual dari tabel transaksi_details $totalSold = \App\Models\TransaksiDetail::whereHas('transaksi', function($q) { $q->whereIn('payment_status', ['paid', 'lunas', 'success']); })->sum('quantity'); // Jika masih 0, ambil semua tanpa filter payment_status if ($totalSold == 0) { $totalSold = \App\Models\TransaksiDetail::sum('quantity'); } // Stok menipis = produk dengan stok > 0 dan stok < 1000 $lowStock = Product::where('stock', '>', 0) ->where('stock', '<', 1000) ->count(); $stats = [ 'total_products' => Product::count(), 'active_products' => Product::where('status', 'aktif')->count(), 'total_sold' => number_format($totalSold, 0, ',', '.'), 'low_stock' => $lowStock, ]; $recent_products = Product::latest()->take(5)->get(); // Grafik pendapatan per hari (30 hari terakhir) - semua transaksi $salesChart = \App\Models\Transaksi::selectRaw('DATE(created_at) as date, SUM(total_amount) as total') ->where('created_at', '>=', now()->subDays(30)) ->groupBy('date') ->orderBy('date', 'asc') ->get(); $chartLabels = $salesChart->pluck('date') ->map(fn($d) => \Carbon\Carbon::parse($d)->format('d M')) ->toArray(); $chartData = $salesChart->pluck('total')->toArray(); return view('admin.dashboard', compact('stats', 'recent_products', 'chartLabels', 'chartData')); } /** * Show orders management. */ public function orders() { $orders = \App\Models\Transaksi::with(['details.product']) ->orderBy('created_at', 'desc') ->paginate(15); return view('admin.orders', compact('orders')); } /** * Show users management. */ public function users() { $users = User::orderBy('id', 'desc')->paginate(15); $totalUsers = User::count(); $totalAdmins = User::where('is_admin', 1)->count(); $verifiedUsers = User::whereNotNull('email_verified_at')->count(); $activeUsers = User::where('created_at', '>=', now()->subDays(30))->count(); return view('admin.users', compact( 'users', 'totalUsers', 'totalAdmins', 'verifiedUsers', 'activeUsers' )); } /** * Show reports. */ public function reports() { return view('admin.reports'); } /** * Show settings. */ public function settings() { return view('admin.settings'); } /** * Logout admin. */ public function logout(Request $request) { Log::info('Admin logout', ['user_id' => Auth::id()]); Auth::logout(); $request->session()->invalidate(); $request->session()->regenerateToken(); return redirect('/') ->with('success', 'Anda telah berhasil logout'); } /** * Show reports / laporan penjualan. * Ganti method laporan() yang ada di AdminController dengan ini. */ public function laporan(Request $request) { $startDate = $request->input('start_date', now()->startOfMonth()->toDateString()); $endDate = $request->input('end_date', now()->toDateString()); // ── Query transaksi ─────────────────────────────────────────────── $query = \App\Models\Transaksi::with(['details.product']) ->whereBetween('created_at', [$startDate . ' 00:00:00', $endDate . ' 23:59:59']); // Filter order_status (bukan payment_status) if ($request->filled('status')) { $query->where('order_status', $request->status); } // Filter berdasarkan produk (lewat relasi details) if ($request->filled('product_id')) { $query->whereHas('details', function ($q) use ($request) { $q->where('product_id', $request->product_id); }); } $orders = $query->orderBy('created_at', 'desc')->paginate(15); // ── Ringkasan ───────────────────────────────────────────────────── $summaryQuery = \App\Models\Transaksi::whereBetween('created_at', [$startDate . ' 00:00:00', $endDate . ' 23:59:59']); if ($request->filled('status')) { $summaryQuery->where('order_status', $request->status); } if ($request->filled('product_id')) { $summaryQuery->whereHas('details', fn($q) => $q->where('product_id', $request->product_id)); } $totalPendapatan = $summaryQuery->sum('total_amount'); $totalTransaksi = $summaryQuery->count(); $totalProdukKeluar = \App\Models\TransaksiDetail::whereHas('transaksi', function ($q) use ($startDate, $endDate, $request) { $q->whereBetween('created_at', [$startDate . ' 00:00:00', $endDate . ' 23:59:59']); if ($request->filled('status')) { $q->where('order_status', $request->status); } }) ->when($request->filled('product_id'), fn($q) => $q->where('product_id', $request->product_id)) ->sum('transaksi_details.quantity'); $summary = [ 'total_pendapatan' => $totalPendapatan, 'total_transaksi' => $totalTransaksi, 'total_produk_keluar' => $totalProdukKeluar, 'rata_per_transaksi' => $totalTransaksi > 0 ? round($totalPendapatan / $totalTransaksi) : 0, ]; // ── Produk terlaris ─────────────────────────────────────────────── $productSales = \App\Models\TransaksiDetail::selectRaw(' transaksi_details.product_id, products.name as product_name, SUM(transaksi_details.quantity) as total_qty, SUM(transaksi_details.subtotal) as total_revenue ') ->join('products', 'transaksi_details.product_id', '=', 'products.id') ->whereHas('transaksi', function ($q) use ($startDate, $endDate, $request) { $q->whereBetween('created_at', [$startDate . ' 00:00:00', $endDate . ' 23:59:59']); if ($request->filled('status')) { $q->where('order_status', $request->status); } }) ->when($request->filled('product_id'), fn($q) => $q->where('transaksi_details.product_id', $request->product_id)) ->groupBy('transaksi_details.product_id', 'products.name') ->orderByDesc('total_qty') ->get(); $topProducts = $productSales->take(7); // ── Grafik harian ───────────────────────────────────────────────── $salesChart = \App\Models\Transaksi::selectRaw('DATE(created_at) as date, SUM(total_amount) as total') ->whereBetween('created_at', [$startDate . ' 00:00:00', $endDate . ' 23:59:59']) ->when($request->filled('status'), fn($q) => $q->where('order_status', $request->status)) ->when($request->filled('product_id'), fn($q) => $q->whereHas('details', fn($d) => $d->where('product_id', $request->product_id))) ->groupBy('date') ->orderBy('date', 'asc') ->get(); $chartLabels = $salesChart->pluck('date')->map(fn($d) => \Carbon\Carbon::parse($d)->format('d M'))->toArray(); $chartData = $salesChart->pluck('total')->toArray(); $products = \App\Models\Product::orderBy('name')->get(); return view('admin.laporan', compact( 'orders', 'summary', 'productSales', 'topProducts', 'chartLabels', 'chartData', 'products' )); } /** * Sync label produk berdasarkan total terjual dari transaksi nyata */ private function syncProductLabels() { // Ambil top 10 produk terlaris berdasarkan transaksi nyata $bestSellingIds = \Illuminate\Support\Facades\DB::table('transaksi_details') ->select('product_id', \Illuminate\Support\Facades\DB::raw('SUM(quantity) as total_sold')) ->groupBy('product_id') ->orderByDesc('total_sold') ->take(10) ->pluck('product_id') ->toArray(); // Reset semua label dulu Product::where('stock', '>', 0) ->whereNotIn('id', $bestSellingIds) ->update(['label' => 'tersedia']); Product::where('stock', '<=', 0) ->update(['label' => 'habis']); // Set label terlaris untuk top 10 if (!empty($bestSellingIds)) { Product::whereIn('id', $bestSellingIds) ->where('stock', '>', 0) ->update(['label' => 'terlaris']); } } }