diff --git a/app/Http/Controllers/admin/AdminController.php b/app/Http/Controllers/admin/AdminController.php index dfd6079..a96fba0 100644 --- a/app/Http/Controllers/admin/AdminController.php +++ b/app/Http/Controllers/admin/AdminController.php @@ -8,12 +8,35 @@ use App\Models\Table; use App\Models\Booking; use Carbon\Carbon; +use Illuminate\Support\Facades\DB; +use Illuminate\Support\Facades\Auth; class AdminController extends Controller { public function index() { - $venue = Venue::find(auth()->user()->venue_id); + // Get current admin's venue ID + $user = Auth::user(); + $adminVenueId = $user->venue_id; + $isSuperAdmin = $user->hasRole('superadmin') || $adminVenueId === null; + + // For super admin, get the first venue or allow selection + if ($isSuperAdmin) { + $venue = request()->has('venue_id') + ? Venue::find(request('venue_id')) + : Venue::first(); + + // Get all venues for dropdown selection + $venues = Venue::all(); + } else { + $venue = Venue::find($adminVenueId); + $venues = collect([$venue]); + } + + // Jika tidak ada venue, tampilkan halaman khusus + if (!$venue) { + return view('admin.no_venue_dashboard'); + } // Menghitung booking hari ini $todayBookings = Booking::whereDate('created_at', now()) @@ -32,7 +55,7 @@ public function index() ->whereHas('table', function ($query) use ($venue) { $query->where('venue_id', $venue->id); }) - ->where('status', 'paid') + ->where('bookings.status', 'paid') ->sum('total_amount'); // Menghitung pendapatan bulan ini @@ -41,20 +64,20 @@ public function index() ->whereHas('table', function ($query) use ($venue) { $query->where('venue_id', $venue->id); }) - ->where('status', 'paid') + ->where('bookings.status', 'paid') ->sum('total_amount'); // Menghitung jumlah booking berdasarkan status $pendingBookings = Booking::whereHas('table', function ($query) use ($venue) { $query->where('venue_id', $venue->id); }) - ->where('status', 'pending') + ->where('bookings.status', 'pending') ->count(); $paidBookings = Booking::whereHas('table', function ($query) use ($venue) { $query->where('venue_id', $venue->id); }) - ->where('status', 'paid') + ->where('bookings.status', 'paid') ->count(); // Ambil booking terbaru @@ -66,7 +89,7 @@ public function index() ->with(['user', 'table']) ->get(); - // Menghitung data analitik untuk diagram + // Menghitung data analitik untuk diagram booking 7 hari terakhir $lastWeekBookings = []; for ($i = 6; $i >= 0; $i--) { $date = now()->subDays($i); @@ -81,8 +104,118 @@ public function index() ]; } + // NEW: MONTHLY REVENUE FOR LAST 6 MONTHS + $lastSixMonthsRevenue = []; + for ($i = 5; $i >= 0; $i--) { + $month = now()->subMonths($i); + $revenue = Booking::whereMonth('created_at', $month->month) + ->whereYear('created_at', $month->year) + ->whereHas('table', function ($query) use ($venue) { + $query->where('venue_id', $venue->id); + }) + ->where('bookings.status', 'paid') + ->sum('total_amount'); + + $lastSixMonthsRevenue[] = [ + 'month' => $month->format('M Y'), + 'revenue' => $revenue + ]; + } + + // FIXED: REVENUE PER TABLE - AMBIL DATA LEBIH FLEKSIBEL + // Ubah untuk mengambil data dari 6 bulan terakhir jika bulan ini tidak ada data + $tableRevenue = Booking::where(function($query) { + // Coba ambil dari bulan ini dulu + $query->whereMonth('bookings.created_at', now()->month) + ->whereYear('bookings.created_at', now()->year); + }) + ->whereHas('table', function ($query) use ($venue) { + $query->where('venue_id', $venue->id); + }) + ->where('bookings.status', 'paid') + ->select( + 'table_id', + DB::raw('tables.name as table_name'), + DB::raw('COUNT(*) as booking_count'), + DB::raw('SUM(bookings.total_amount) as table_revenue') + ) + ->join('tables', 'bookings.table_id', '=', 'tables.id') + ->groupBy('table_id', 'tables.name') + ->orderBy('table_revenue', 'desc') + ->take(10) + ->get(); + + // Jika tidak ada data bulan ini, coba ambil dari 6 bulan terakhir + if ($tableRevenue->isEmpty()) { + $tableRevenue = Booking::where(function($query) { + // Ambil dari 6 bulan terakhir + $query->where('bookings.created_at', '>=', now()->subMonths(6)); + }) + ->whereHas('table', function ($query) use ($venue) { + $query->where('venue_id', $venue->id); + }) + ->where('bookings.status', 'paid') + ->select( + 'table_id', + DB::raw('tables.name as table_name'), + DB::raw('COUNT(*) as booking_count'), + DB::raw('SUM(bookings.total_amount) as table_revenue') + ) + ->join('tables', 'bookings.table_id', '=', 'tables.id') + ->groupBy('table_id', 'tables.name') + ->orderBy('table_revenue', 'desc') + ->take(10) + ->get(); + } + + // Jika masih tidak ada data, buat dummy data supaya chart tetap muncul + if ($tableRevenue->isEmpty()) { + // Ambil 5 meja dari venue ini + $tables = Table::where('venue_id', $venue->id) + ->take(5) + ->get(); + + foreach ($tables as $table) { + $tableRevenue->push([ + 'table_id' => $table->id, + 'table_name' => $table->name, + 'booking_count' => 0, + 'table_revenue' => 0 + ]); + } + + // Jika tidak ada meja sama sekali, buat data dummy + if ($tableRevenue->isEmpty()) { + $tableRevenue = collect([ + [ + 'table_id' => 1, + 'table_name' => 'Meja 1', + 'booking_count' => 0, + 'table_revenue' => 0 + ], + [ + 'table_id' => 2, + 'table_name' => 'Meja 2', + 'booking_count' => 0, + 'table_revenue' => 0 + ], + [ + 'table_id' => 3, + 'table_name' => 'Meja 3', + 'booking_count' => 0, + 'table_revenue' => 0 + ] + ]); + } + } + + // NEW: REMOVE REVENUE BY DAY OF WEEK + // Hapus bagian revenueByDay karena tidak diperlukan lagi + return view('admin.dashboard', compact( 'venue', + 'venues', + 'isSuperAdmin', 'todayBookings', 'totalTables', 'usedTables', @@ -92,7 +225,10 @@ public function index() 'monthlyRevenue', 'pendingBookings', 'paidBookings', - 'lastWeekBookings' + 'lastWeekBookings', + 'lastSixMonthsRevenue', + 'tableRevenue' + // Hapus 'revenueByDay' dari compact )); } } \ No newline at end of file diff --git a/app/Http/Controllers/admin/RevenueController.php b/app/Http/Controllers/admin/RevenueController.php new file mode 100644 index 0000000..f65d083 --- /dev/null +++ b/app/Http/Controllers/admin/RevenueController.php @@ -0,0 +1,261 @@ +input('start_date', Carbon::now()->startOfMonth()->format('Y-m-d')); + $endDate = $request->input('end_date', Carbon::now()->format('Y-m-d')); + + // Get current admin's venue ID + $user = Auth::user(); + $adminVenueId = $user->venue_id; // Asumsi: Admin memiliki venue_id yang menunjukkan venue yang mereka kelola + + // Jika admin adalah super admin (bisa melihat semua venue) + $isSuperAdmin = $user->hasRole('superadmin') || $adminVenueId === null; // Asumsi: Super admin tidak memiliki venue_id spesifik atau memiliki role khusus + + // Query untuk mengambil data venue untuk filter (hanya venue yang dikelola oleh admin atau semua venue untuk super admin) + if ($isSuperAdmin) { + $venues = Venue::all(); + $venueId = $request->input('venue_id'); + } else { + $venues = Venue::where('id', $adminVenueId)->get(); + $venueId = $adminVenueId; // Force venue id ke venue yang dikelola admin + } + + // Base query untuk pendapatan + $revenueQuery = Booking::with('table.venue') + ->where('bookings.status', 'paid') + ->whereBetween(DB::raw('DATE(bookings.start_time)'), [$startDate, $endDate]); + + // Filter berdasarkan venue yang dikelola admin atau yang dipilih oleh super admin + if (!$isSuperAdmin) { + // Admin venue biasa hanya bisa melihat venuenya sendiri + $revenueQuery->whereHas('table', function($query) use ($adminVenueId) { + $query->where('venue_id', $adminVenueId); + }); + } elseif ($venueId) { + // Super admin bisa memilih venue tertentu + $revenueQuery->whereHas('table', function($query) use ($venueId) { + $query->where('venue_id', $venueId); + }); + } + + // Get summary total pendapatan + $totalRevenue = $revenueQuery->sum('total_amount'); + + // Get total bookings + $totalBookings = $revenueQuery->count(); + + // Get revenue per venue - dengan filter sesuai akses admin + $revenuePerVenueQuery = Booking::with('table.venue') + ->where('bookings.status', 'paid') + ->whereBetween(DB::raw('DATE(bookings.start_time)'), [$startDate, $endDate]); + + if (!$isSuperAdmin) { + $revenuePerVenueQuery->whereHas('table', function($query) use ($adminVenueId) { + $query->where('venue_id', $adminVenueId); + }); + } + + $revenuePerVenue = $revenuePerVenueQuery + ->select( + 'tables.venue_id', + DB::raw('venues.name as venue_name'), + DB::raw('COUNT(*) as total_bookings'), + DB::raw('SUM(bookings.total_amount) as total_revenue') + ) + ->join('tables', 'bookings.table_id', '=', 'tables.id') + ->join('venues', 'tables.venue_id', '=', 'venues.id') + ->groupBy('tables.venue_id', 'venues.name') + ->get(); + + // Get revenue per table (Untuk admin biasa, selalu tampilkan detail meja venuenya) + // Untuk super admin, detail meja hanya muncul jika venue tertentu dipilih + $revenuePerTable = null; + if (!$isSuperAdmin || $venueId) { + $venueIdForTable = $isSuperAdmin ? $venueId : $adminVenueId; + + $revenuePerTable = Booking::with('table') + ->where('bookings.status', 'paid') + ->whereBetween(DB::raw('DATE(bookings.start_time)'), [$startDate, $endDate]) + ->whereHas('table', function($query) use ($venueIdForTable) { + $query->where('venue_id', $venueIdForTable); + }) + ->select( + 'table_id', + DB::raw('tables.name as table_name'), + DB::raw('COUNT(*) as booking_count'), + DB::raw('SUM(bookings.total_amount) as table_revenue') + ) + ->join('tables', 'bookings.table_id', '=', 'tables.id') + ->groupBy('table_id', 'tables.name') + ->get(); + } + + // Get data untuk chart pendapatan harian dalam periode + $dailyRevenueQuery = Booking::with('table.venue') + ->where('bookings.status', 'paid') + ->whereBetween(DB::raw('DATE(bookings.start_time)'), [$startDate, $endDate]); + + if (!$isSuperAdmin) { + $dailyRevenueQuery->whereHas('table', function($query) use ($adminVenueId) { + $query->where('venue_id', $adminVenueId); + }); + } elseif ($venueId) { + $dailyRevenueQuery->whereHas('table', function($query) use ($venueId) { + $query->where('venue_id', $venueId); + }); + } + + $dailyRevenue = $dailyRevenueQuery + ->select( + DB::raw('DATE(bookings.start_time) as date'), + DB::raw('SUM(bookings.total_amount) as revenue') + ) + ->groupBy(DB::raw('DATE(bookings.start_time)')) + ->orderBy('date', 'asc') + ->get(); + + return view('admin.revenues.index', compact( + 'venues', + 'venueId', + 'totalRevenue', + 'totalBookings', + 'revenuePerVenue', + 'revenuePerTable', + 'dailyRevenue', + 'startDate', + 'endDate', + 'isSuperAdmin' + )); + } + + public function detail(Request $request, $tableId) + { + // Default filter periode (bulan ini) + $startDate = $request->input('start_date', Carbon::now()->startOfMonth()->format('Y-m-d')); + $endDate = $request->input('end_date', Carbon::now()->format('Y-m-d')); + + // Get table detail + $table = Table::with('venue')->findOrFail($tableId); + + // Cek apakah admin memiliki akses ke meja ini + $user = Auth::user(); + $adminVenueId = $user->venue_id; + $isSuperAdmin = $user->hasRole('superadmin') || $adminVenueId === null; + + // Jika bukan super admin dan meja bukan dari venue yang dikelola, tolak akses + if (!$isSuperAdmin && $table->venue_id != $adminVenueId) { + abort(403, 'Tidak memiliki akses ke meja ini'); + } + + // Query untuk detail booking meja tersebut + $bookings = Booking::where('table_id', $tableId) + ->where('bookings.status', 'paid') + ->whereBetween(DB::raw('DATE(bookings.start_time)'), [$startDate, $endDate]) + ->with('user') + ->orderBy('start_time', 'desc') + ->get(); + + // Hitung total pendapatan untuk meja ini di periode + $totalRevenue = $bookings->sum('total_amount'); + + // Hitung total jam penggunaan + $totalHours = $bookings->sum(function($booking) { + $start = Carbon::parse($booking->start_time); + $end = Carbon::parse($booking->end_time); + return $end->diffInHours($start); + }); + + return view('admin.revenues.detail', compact( + 'table', + 'bookings', + 'totalRevenue', + 'totalHours', + 'startDate', + 'endDate' + )); + } + + public function export(Request $request) + { + // Get current admin's venue ID + $user = Auth::user(); + $adminVenueId = $user->venue_id; + $isSuperAdmin = $user->hasRole('superadmin') || $adminVenueId === null; + + $startDate = $request->input('start_date', Carbon::now()->startOfMonth()->format('Y-m-d')); + $endDate = $request->input('end_date', Carbon::now()->format('Y-m-d')); + $venueId = $isSuperAdmin ? $request->input('venue_id') : $adminVenueId; + + // Base query untuk pendapatan + $bookingsQuery = Booking::with(['table.venue', 'user']) + ->where('bookings.status', 'paid') + ->whereBetween(DB::raw('DATE(bookings.start_time)'), [$startDate, $endDate]); + + // Filter berdasarkan venue sesuai hak akses admin + if (!$isSuperAdmin) { + $bookingsQuery->whereHas('table', function($query) use ($adminVenueId) { + $query->where('venue_id', $adminVenueId); + }); + } elseif ($venueId) { + $bookingsQuery->whereHas('table', function($query) use ($venueId) { + $query->where('venue_id', $venueId); + }); + } + + $bookings = $bookingsQuery->get(); + + // Export logic using Laravel Excel or simple CSV download + // For now we'll return a simple array that could be converted to CSV/Excel + $exportData = []; + + foreach ($bookings as $booking) { + $exportData[] = [ + 'id' => $booking->id, + 'user' => $booking->user->name, + 'venue' => $booking->table->venue->name, + 'table' => $booking->table->name, + 'start_time' => $booking->start_time->format('Y-m-d H:i'), + 'end_time' => $booking->end_time->format('Y-m-d H:i'), + 'duration_hours' => $booking->end_time->diffInHours($booking->start_time), + 'payment_method' => $booking->payment_method, + 'total_amount' => $booking->total_amount, + ]; + } + + // Return CSV response (simplified example) + $headers = [ + 'Content-Type' => 'text/csv', + 'Content-Disposition' => 'attachment; filename="venue-revenue-report.csv"', + ]; + + // Convert array to CSV string + $callback = function() use ($exportData) { + $file = fopen('php://output', 'w'); + // Header row + fputcsv($file, array_keys($exportData[0] ?? [])); + + // Data rows + foreach ($exportData as $row) { + fputcsv($file, $row); + } + fclose($file); + }; + + return response()->stream($callback, 200, $headers); + } +} \ No newline at end of file diff --git a/app/Models/User.php b/app/Models/User.php index 17931a2..bc9e162 100644 --- a/app/Models/User.php +++ b/app/Models/User.php @@ -55,6 +55,17 @@ public function isAdmin() return $this->role === 'admin'; } + /** + * Check if the user has a specific role. + * + * @param string $role + * @return bool + */ + public function hasRole($role) + { + return $this->role === $role; + } + /** * Get the venue that the admin belongs to. */ diff --git a/config/app.php b/config/app.php index 9207160..c303137 100644 --- a/config/app.php +++ b/config/app.php @@ -70,7 +70,7 @@ | */ - 'timezone' => 'UTC', + 'timezone' => 'Asia/Jakarta', /* |-------------------------------------------------------------------------- diff --git a/resources/views/admin/bookings/index.blade.php b/resources/views/admin/bookings/index.blade.php index 9145aae..50495ad 100644 --- a/resources/views/admin/bookings/index.blade.php +++ b/resources/views/admin/bookings/index.blade.php @@ -24,7 +24,7 @@
-
@@ -35,24 +35,26 @@ class="form-input w-full rounded-md border-gray-300 focus:border-blue-500 focus:
- - +
-
-
@@ -82,8 +84,10 @@ class="form-input w-full rounded-md border-gray-300 focus:border-blue-500 focus: - - - - - - --}} + {{-- + --}} @@ -143,7 +156,9 @@ class="form-input w-full rounded-md border-gray-300 focus:border-blue-500 focus: - - --}} + {{-- + --}} @empty @@ -226,7 +253,8 @@ class="form-input w-full rounded-md border-gray-300 focus:border-blue-500 focus:
- Menampilkan {{ $bookings->firstItem() ?? 0 }} - {{ $bookings->lastItem() ?? 0 }} dari {{ $bookings->total() }} data + Menampilkan {{ $bookings->firstItem() ?? 0 }} - {{ $bookings->lastItem() ?? 0 }} dari + {{ $bookings->total() }} data
{{ $bookings->appends(request()->query())->links() }} @@ -278,17 +306,17 @@ class="form-input w-full rounded-md border-gray-300 focus:border-blue-500 focus: @push('scripts') @endpush diff --git a/resources/views/admin/revenues/detail.blade.php b/resources/views/admin/revenues/detail.blade.php new file mode 100644 index 0000000..c615fc9 --- /dev/null +++ b/resources/views/admin/revenues/detail.blade.php @@ -0,0 +1,234 @@ +@extends('layouts.admin') + +@section('content') +
+
+
+
+

Detail Pendapatan Meja: {{ $table->name }}

+ + + + + Kembali + +
+
+ +
+
+

Venue

+

{{ $table->venue->name }}

+
+
+

Total Pendapatan

+

Rp {{ number_format($totalRevenue, 0, ',', '.') }}

+
+
+

Total Jam Terpakai

+

{{ $totalHours }} jam

+
+
+ + +
+
+
+ + +
+
+ + +
+
+ +
+
+ + + +
+
+
+

Daftar Booking

+
+
+
- + + User @if(request('sort') == 'user') @@ -92,8 +96,10 @@ class="form-input w-full rounded-md border-gray-300 focus:border-blue-500 focus: @endif - + + Meja @if(request('sort') == 'table') @@ -102,8 +108,10 @@ class="form-input w-full rounded-md border-gray-300 focus:border-blue-500 focus: @endif - + + Mulai @if(request('sort') == 'start_time') @@ -112,8 +120,10 @@ class="form-input w-full rounded-md border-gray-300 focus:border-blue-500 focus: @endif - + + Selesai @if(request('sort') == 'end_time') @@ -122,19 +132,22 @@ class="form-input w-full rounded-md border-gray-300 focus:border-blue-500 focus: @endif - + {{-- + Status @if(request('sort') == 'status') - + @else - + @endif - + Aksi -
- +
{{ $booking->user->name }}
@@ -153,60 +168,72 @@ class="form-input w-full rounded-md border-gray-300 focus:border-blue-500 focus:
{{ $booking->table->name }}
-
Kapasitas: {{ $booking->table->capacity }} orang
-
{{ \Carbon\Carbon::parse($booking->start_time)->format('H:i') }}
-
{{ \Carbon\Carbon::parse($booking->start_time)->format('d M Y') }}
+
+ {{ \Carbon\Carbon::parse($booking->start_time)->format('H:i') }}
+
+ {{ \Carbon\Carbon::parse($booking->start_time)->format('d M Y') }}
-
{{ \Carbon\Carbon::parse($booking->end_time)->format('H:i') }}
-
{{ \Carbon\Carbon::parse($booking->end_time)->format('d M Y') }}
+
+ {{ \Carbon\Carbon::parse($booking->end_time)->format('H:i') }}
+
+ {{ \Carbon\Carbon::parse($booking->end_time)->format('d M Y') }}
+ {{-- @if($booking->status === 'booked') - - Booked - + + Booked + @elseif($booking->status === 'selesai') - - Selesai - + + Selesai + @else - - Dibatalkan - + + Dibatalkan + @endif - +
- + @if($booking->status === 'booked') - + -
+ @csrf @method('PATCH') -
-
+ @csrf @method('PATCH') -
@endif
-
+ + + + + + + + + + + + + @forelse($bookings as $booking) + + + + + + + + + + @empty + + + + @endforelse + +
ID BookingPelangganWaktu MulaiWaktu SelesaiDurasi (Jam)Metode PembayaranTotal Pembayaran
{{ $booking->id }}{{ $booking->user->name }}{{ $booking->start_time->format('d M Y, H:i') }}{{ $booking->end_time->format('d M Y, H:i') }} + @php + $hours = $booking->start_time->diffInHours($booking->end_time); + $minutes = $booking->start_time->copy()->addHours($hours)->diffInMinutes($booking->end_time); + echo $hours . ($minutes > 0 ? '.' . $minutes : ''); + @endphp + + + {{ $booking->payment_method }} + + + Rp {{ number_format($booking->total_amount, 0, ',', '.') }} +
+ + + +

Tidak ada data booking untuk periode ini

+

Coba ubah filter tanggal untuk melihat data lainnya.

+
+
+
+
+ + +
+
+
+

Pola Penggunaan Meja

+
+
+ +
+
+
+ + + + +@endsection + +@section('scripts') + + +@endsection \ No newline at end of file diff --git a/resources/views/admin/revenues/index.blade.php b/resources/views/admin/revenues/index.blade.php new file mode 100644 index 0000000..bd11645 --- /dev/null +++ b/resources/views/admin/revenues/index.blade.php @@ -0,0 +1,267 @@ +@extends('layouts.admin') + +@section('content') +
+
+
+
+

Laporan Pendapatan

+
+
+ +
+
+
+ + +
+
+ + +
+
+ + +
+
+
+ + + + + + Export + +
+
+
+
+ + +
+
+
+

Total Pendapatan

+

Rp {{ number_format($totalRevenue, 0, ',', '.') }}

+
+
+
+
+

Total Booking

+

{{ $totalBookings }}

+
+
+
+ + +
+
+
+

Grafik Pendapatan Harian

+
+
+ +
+
+
+ + +
+
+
+

Pendapatan Per Venue

+
+
+
+ + + + + + + + + + @forelse($revenuePerVenue as $venueRevenue) + + + + + + @empty + + + + @endforelse + +
VenueTotal BookingTotal Pendapatan
{{ $venueRevenue->venue_name }}{{ $venueRevenue->total_bookings }} + Rp {{ number_format($venueRevenue->total_revenue, 0, ',', '.') }} +
Tidak ada data pendapatan
+
+
+
+
+ + + @if($revenuePerTable) +
+
+
+

Detail Pendapatan Per Meja

+
+
+
+ + + + + + + + + + + @forelse($revenuePerTable as $tableRevenue) + + + + + + + @empty + + + + @endforelse + +
MejaJumlah BookingTotal PendapatanAksi
{{ $tableRevenue->table_name }}{{ $tableRevenue->booking_count }} + Rp {{ number_format($tableRevenue->table_revenue, 0, ',', '.') }} + + + + + + + Detail + +
Tidak ada data pendapatan meja
+
+
+
+
+ @endif +
+
+
+
+@endsection + +@section('scripts') + + +@endsection \ No newline at end of file diff --git a/resources/views/admin/tables/index.blade.php b/resources/views/admin/tables/index.blade.php index 1b3290a..0ef2b39 100644 --- a/resources/views/admin/tables/index.blade.php +++ b/resources/views/admin/tables/index.blade.php @@ -1,125 +1,151 @@ @extends('layouts.admin') @section('content') -
- -
-

Kelola Meja

- - - - - Tambah Meja Baru - -
- - - @if(session('success')) -