diff --git a/app/Exports/TechnicianReportExport.php b/app/Exports/TechnicianReportExport.php index 67fe940..6d0b920 100644 --- a/app/Exports/TechnicianReportExport.php +++ b/app/Exports/TechnicianReportExport.php @@ -83,7 +83,26 @@ class TechnicianReportExport implements FromCollection, WithHeadings, WithStyles $dealerName = $dealer ? $dealer->name : 'Unknown Dealer'; $this->filterInfo[] = "Dealer: {$dealerName}"; } else { - $this->filterInfo[] = "Dealer: Semua Dealer"; + // Check user access for "Semua Dealer" + $user = auth()->user(); + if ($user && $user->role_id) { + $role = \App\Models\Role::with('dealers')->find($user->role_id); + if ($role) { + $technicianReportService = new \App\Services\TechnicianReportService(); + if ($technicianReportService->isAdminRole($role)) { + $this->filterInfo[] = "Dealer: Semua Dealer (Admin)"; + } else if ($role->dealers->count() > 0) { + $dealerNames = $role->dealers->pluck('name')->implode(', '); + $this->filterInfo[] = "Dealer: Semua Dealer (Pivot: {$dealerNames})"; + } else { + $this->filterInfo[] = "Dealer: Semua Dealer"; + } + } else { + $this->filterInfo[] = "Dealer: Semua Dealer"; + } + } else { + $this->filterInfo[] = "Dealer: Semua Dealer"; + } } // Date range filter @@ -300,7 +319,12 @@ class TechnicianReportExport implements FromCollection, WithHeadings, WithStyles // Auto-size columns foreach (range('A', $lastColumn) as $column) { - $sheet->getColumnDimension($column)->setAutoSize(true); + if ($column === 'A') { + // Set specific width for column A (No) - don't auto-size + $sheet->getColumnDimension($column)->setWidth(5); + } else { + $sheet->getColumnDimension($column)->setAutoSize(true); + } } } catch (\Exception $e) { @@ -311,7 +335,7 @@ class TechnicianReportExport implements FromCollection, WithHeadings, WithStyles public function columnWidths(): array { $widths = [ - 'A' => 8, // No + 'A' => 5, // No - reduced from 8 to 5 'B' => 30, // Nama Pekerjaan 'C' => 15, // Kode Pekerjaan 'D' => 20, // Kategori diff --git a/app/Http/Controllers/Auth/LoginController.php b/app/Http/Controllers/Auth/LoginController.php index 31e5d7f..5462b68 100755 --- a/app/Http/Controllers/Auth/LoginController.php +++ b/app/Http/Controllers/Auth/LoginController.php @@ -4,6 +4,7 @@ namespace App\Http\Controllers\Auth; use App\Http\Controllers\Controller; use App\Models\Privilege; +use App\Models\User; use App\Providers\RouteServiceProvider; use Illuminate\Http\Request; use Illuminate\Foundation\Auth\AuthenticatesUsers; @@ -50,11 +51,39 @@ class LoginController extends Controller */ protected function authenticated(Request $request, $user) { - $user = Privilege::where('menu_id', 10)->where('role_id', Auth::user()->role_id)->where('view', 1)->first(); + // Get user's role_id + $roleId = Auth::user()->role_id; + + if (!$roleId) { + // User has no role, redirect to default + return redirect(RouteServiceProvider::HOME); + } - if ($user != null) { - return redirect()->route('dashboard'); - }else{ + // Check if user has access to adminarea menu + if (!User::roleCanAccessMenu($roleId, 'adminarea')) { + // User doesn't have admin area access, redirect to default home + return redirect(RouteServiceProvider::HOME); + } + + // User has admin area access, get first accessible menu (excluding adminarea and mechanicarea) + $firstMenu = Privilege::join('menus', 'privileges.menu_id', '=', 'menus.id') + ->where('privileges.role_id', $roleId) + ->where('privileges.view', 1) + ->whereNotIn('menus.link', ['adminarea', 'mechanicarea']) + ->select('menus.*', 'privileges.view', 'privileges.create', 'privileges.update', 'privileges.delete') + ->orderBy('menus.id') + ->first(); + + if (!$firstMenu) { + // User has no accessible menus (excluding adminarea/mechanicarea), redirect to default + return redirect(RouteServiceProvider::HOME); + } + + try { + // Try to redirect to the first accessible menu + return redirect()->route($firstMenu->link); + } catch (\Exception $e) { + // Route doesn't exist, fallback to default home return redirect(RouteServiceProvider::HOME); } } diff --git a/app/Http/Controllers/Reports/ReportTechniciansController.php b/app/Http/Controllers/Reports/ReportTechniciansController.php index 6a7d362..0acc44e 100644 --- a/app/Http/Controllers/Reports/ReportTechniciansController.php +++ b/app/Http/Controllers/Reports/ReportTechniciansController.php @@ -5,11 +5,14 @@ namespace App\Http\Controllers\Reports; use App\Http\Controllers\Controller; use Illuminate\Http\Request; use App\Models\Menu; +use App\Models\Role; use App\Services\TechnicianReportService; use App\Exports\TechnicianReportExport; use Illuminate\Support\Facades\Gate; use Illuminate\Support\Facades\Log; use Maatwebsite\Excel\Facades\Excel; +use Illuminate\Support\Facades\DB; // Added DB facade +use App\Models\Dealer; // Added Dealer model class ReportTechniciansController extends Controller { @@ -34,18 +37,66 @@ class ReportTechniciansController extends Controller public function getDealers() { try { + // Get current authenticated user + $user = auth()->user(); + + if (!$user) { + Log::info('Controller: No authenticated user found'); + return response()->json([ + 'status' => 'error', + 'message' => 'User tidak terautentikasi' + ], 401); + } + + Log::info('Controller: Getting dealers for user:', [ + 'user_id' => $user->id, + 'user_name' => $user->name, + 'user_role_id' => $user->role_id, + 'user_dealer_id' => $user->dealer_id + ]); + $dealers = $this->technicianReportService->getDealers(); - // Default ke "Semua Dealer" (tidak ada dealer yang terselect) + $defaultDealer = $this->technicianReportService->getDefaultDealer(); + + Log::info('Controller: Service returned dealers:', [ + 'dealers_count' => $dealers->count(), + 'dealers' => $dealers->toArray(), + 'default_dealer' => $defaultDealer ? $defaultDealer->toArray() : null, + 'default_dealer_id' => $defaultDealer ? $defaultDealer->id : null + ]); + + // Check if default dealer exists in dealers list + if ($defaultDealer && $dealers->count() > 0) { + $defaultDealerExists = $dealers->contains('id', $defaultDealer->id); + Log::info('Controller: Default dealer validation:', [ + 'default_dealer_id' => $defaultDealer->id, + 'default_dealer_exists_in_list' => $defaultDealerExists, + 'available_dealer_ids' => $dealers->pluck('id')->toArray() + ]); + + // If default dealer doesn't exist in list, use first dealer from list + if (!$defaultDealerExists) { + Log::info('Controller: Default dealer not in list, using first dealer from list'); + $defaultDealer = $dealers->first(); + Log::info('Controller: New default dealer:', $defaultDealer ? $defaultDealer->toArray() : null); + } + } else if ($defaultDealer === null && $dealers->count() > 0) { + // Admin without default dealer - no need to set default + Log::info('Controller: Admin without default dealer, no default will be set'); + } + return response()->json([ 'status' => 'success', 'data' => $dealers, - 'default_dealer' => null + 'default_dealer' => $defaultDealer ? $defaultDealer->id : null ]); } catch (\Exception $e) { - Log::error('Error getting dealers: ' . $e->getMessage()); + Log::error('Controller: Error getting dealers: ' . $e->getMessage(), [ + 'trace' => $e->getTraceAsString() + ]); return response()->json([ 'status' => 'error', - 'message' => 'Gagal mengambil data dealer' + 'message' => 'Gagal mengambil data dealer: ' . $e->getMessage() ], 500); } } @@ -60,10 +111,23 @@ class ReportTechniciansController extends Controller $startDate = $request->input('start_date'); $endDate = $request->input('end_date'); + // Get current authenticated user + $user = auth()->user(); + + if (!$user) { + return response()->json([ + 'status' => 'error', + 'message' => 'User tidak terautentikasi' + ], 401); + } + Log::info('Requesting technician report data:', [ 'dealer_id' => $dealerId, 'start_date' => $startDate, - 'end_date' => $endDate + 'end_date' => $endDate, + 'user_id' => $user->id, + 'user_role_id' => $user->role_id, + 'user_dealer_id' => $user->dealer_id ]); $reportData = $this->technicianReportService->getTechnicianReportData( @@ -116,10 +180,22 @@ class ReportTechniciansController extends Controller $startDate = $request->input('start_date'); $endDate = $request->input('end_date'); + // Get current authenticated user + $user = auth()->user(); + + if (!$user) { + return response()->json([ + 'error' => 'User tidak terautentikasi' + ], 401); + } + Log::info('Requesting technician report data for DataTable:', [ 'dealer_id' => $dealerId, 'start_date' => $startDate, - 'end_date' => $endDate + 'end_date' => $endDate, + 'user_id' => $user->id, + 'user_role_id' => $user->role_id, + 'user_dealer_id' => $user->dealer_id ]); $reportData = $this->technicianReportService->getTechnicianReportDataForDataTable( @@ -153,12 +229,87 @@ class ReportTechniciansController extends Controller $startDate = $request->input('start_date'); $endDate = $request->input('end_date'); + // Get current authenticated user + $user = auth()->user(); + + if (!$user) { + return response()->json([ + 'status' => 'error', + 'message' => 'User tidak terautentikasi' + ], 401); + } + Log::info('Exporting technician report', [ 'dealer_id' => $dealerId, 'start_date' => $startDate, - 'end_date' => $endDate + 'end_date' => $endDate, + 'user_id' => $user->id, + 'user_role_id' => $user->role_id, + 'user_dealer_id' => $user->dealer_id ]); + // Validate dealer access for export + if ($dealerId) { + // User is trying to export specific dealer + if ($user->dealer_id) { + // User has specific dealer_id, check if they can access the requested dealer + if ($user->dealer_id != $dealerId) { + if ($user->role_id) { + $role = \App\Models\Role::with('dealers')->find($user->role_id); + if (!$role || !$role->hasDealer($dealerId)) { + return response()->json([ + 'status' => 'error', + 'message' => 'Anda tidak memiliki akses untuk export data dealer ini' + ], 403); + } + } else { + return response()->json([ + 'status' => 'error', + 'message' => 'Anda tidak memiliki akses untuk export data dealer ini' + ], 403); + } + } + } else if ($user->role_id) { + // User has role, check if they can access the requested dealer + $role = \App\Models\Role::with('dealers')->find($user->role_id); + if (!$role || !$role->hasDealer($dealerId)) { + return response()->json([ + 'status' => 'error', + 'message' => 'Anda tidak memiliki akses untuk export data dealer ini' + ], 403); + } + } + } else { + // User is trying to export "Semua Dealer" - check if they have permission + if ($user->role_id) { + $role = \App\Models\Role::with('dealers')->find($user->role_id); + if ($role) { + // Check if role is admin type + $technicianReportService = new \App\Services\TechnicianReportService(); + if ($technicianReportService->isAdminRole($role)) { + // Admin can export all dealers + Log::info('Admin user exporting all dealers'); + } else { + // Non-admin with pivot dealers - can only export pivot dealers + if ($role->dealers->count() > 0) { + Log::info('User with pivot dealers exporting pivot dealers only'); + } else { + return response()->json([ + 'status' => 'error', + 'message' => 'Anda tidak memiliki akses untuk export data semua dealer' + ], 403); + } + } + } + } else if ($user->dealer_id) { + // User with specific dealer_id cannot export all dealers + return response()->json([ + 'status' => 'error', + 'message' => 'Anda hanya dapat export data dealer Anda sendiri' + ], 403); + } + } + return Excel::download(new TechnicianReportExport($dealerId, $startDate, $endDate), 'laporan_teknisi_' . date('Y-m-d') . '.xlsx'); } catch (\Exception $e) { @@ -175,5 +326,4 @@ class ReportTechniciansController extends Controller } } - } diff --git a/app/Http/Controllers/RolePrivilegeController.php b/app/Http/Controllers/RolePrivilegeController.php index c5b6d5b..5721a29 100755 --- a/app/Http/Controllers/RolePrivilegeController.php +++ b/app/Http/Controllers/RolePrivilegeController.php @@ -6,6 +6,7 @@ use App\Models\Menu; use App\Models\Privilege; use App\Models\Role; use App\Models\User; +use App\Models\Dealer; use Illuminate\Http\Request; use Illuminate\Support\Facades\Gate; @@ -14,10 +15,11 @@ class RolePrivilegeController extends Controller public function index() { $menu = Menu::where('link', 'roleprivileges.index')->first(); abort_if(Gate::denies('view', $menu), 403, 'Unauthorized User'); - $roles = Role::all(); + $roles = Role::with('dealers')->get(); $menus = Menu::all(); $users = User::all(); - return view('back.roleprivileges', compact('roles', 'users', 'menus')); + $dealers = Dealer::all(); + return view('back.roleprivileges', compact('roles', 'users', 'menus', 'dealers')); } public function store(Request $request) { @@ -117,4 +119,36 @@ class RolePrivilegeController extends Controller User::where('role_id', $id)->update(['role_id' => 0]); return redirect()->back()->with('success', 'Berhasil Hapus Role'); } + + public function assignDealer(Request $request, $id) { + $menu = Menu::where('link', 'roleprivileges.index')->first(); + abort_if(Gate::denies('create', $menu), 403, 'Unauthorized User'); + + $request->validate([ + 'dealers' => 'required|array', + 'dealers.*' => 'exists:dealers,id' + ]); + + $role = Role::findOrFail($id); + + // Sync dealers (this will replace existing assignments) + $role->dealers()->sync($request->dealers); + + return response()->json([ + 'success' => true, + 'message' => 'Berhasil assign dealer ke role' + ]); + } + + public function getAssignedDealers($id) { + $menu = Menu::where('link', 'roleprivileges.index')->first(); + abort_if(Gate::denies('view', $menu), 403, 'Unauthorized User'); + + $role = Role::findOrFail($id); + $assignedDealers = $role->dealers()->pluck('dealers.id')->toArray(); + + return response()->json([ + 'assignedDealers' => $assignedDealers + ]); + } } diff --git a/app/Models/Dealer.php b/app/Models/Dealer.php index 084a9b3..f241c5e 100755 --- a/app/Models/Dealer.php +++ b/app/Models/Dealer.php @@ -82,4 +82,9 @@ class Dealer extends Model { return $this->hasMany(WorkDealerPrice::class)->active(); } + + public function roles() + { + return $this->belongsToMany(Role::class, 'role_dealer'); + } } diff --git a/app/Models/Role.php b/app/Models/Role.php index bfba968..59de317 100755 --- a/app/Models/Role.php +++ b/app/Models/Role.php @@ -4,6 +4,7 @@ namespace App\Models; use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\Model; +use Illuminate\Support\Facades\Log; class Role extends Model { @@ -11,4 +12,19 @@ class Role extends Model protected $fillable = [ 'name' ]; + + public function dealers() + { + return $this->belongsToMany(Dealer::class, 'role_dealer'); + } + + public function users() + { + return $this->hasMany(User::class); + } + + public function hasDealer($dealerId) + { + return $this->dealers()->where('dealers.id', $dealerId)->whereNull('dealers.deleted_at')->exists(); + } } diff --git a/app/Models/User.php b/app/Models/User.php index 1b9b941..b957ad7 100755 --- a/app/Models/User.php +++ b/app/Models/User.php @@ -192,4 +192,113 @@ class User extends Authenticatable ->where('month', $month) ->first(); } + + public function accessibleDealers() + { + if (!$this->role_id) { + return collect(); + } + + // Load role with dealers + if (!$this->relationLoaded('role')) { + $this->load('role.dealers'); + } + + // If user has specific dealer_id, check if role allows access + if ($this->dealer_id) { + if ($this->role && $this->role->hasDealer($this->dealer_id)) { + return Dealer::where('id', $this->dealer_id)->get(); + } + return collect(); + } + + // If no specific dealer_id, return all dealers accessible by role + return $this->role ? $this->role->dealers : collect(); + } + + public function canAccessDealer($dealerId) + { + if (!$this->role_id) { + return false; + } + + // Load role with dealers + if (!$this->relationLoaded('role')) { + $this->load('role.dealers'); + } + + return $this->role && $this->role->hasDealer($dealerId); + } + + public function getPrimaryDealer() + { + if ($this->dealer_id && $this->canAccessDealer($this->dealer_id)) { + return $this->dealer; + } + return null; + } + + /** + * Get all accessible menus for a specific role + * + * @param int $roleId + * @return \Illuminate\Database\Eloquent\Collection + */ + public static function getAccessibleMenus($roleId) + { + return \App\Models\Privilege::join('menus', 'privileges.menu_id', '=', 'menus.id') + ->where('privileges.role_id', $roleId) + ->where('privileges.view', 1) + ->select('menus.*', 'privileges.view', 'privileges.create', 'privileges.update', 'privileges.delete') + ->orderBy('menus.id') + ->get(); + } + + /** + * Get accessible menus for current user + * + * @return \Illuminate\Database\Eloquent\Collection + */ + public function getMyAccessibleMenus() + { + if (!$this->role_id) { + return collect(); + } + return self::getAccessibleMenus($this->role_id); + } + + /** + * Check if user can access specific menu + * + * @param string $menuLink + * @return bool + */ + public function canAccessMenu($menuLink) + { + if (!$this->role_id) { + return false; + } + + return \App\Models\Privilege::join('menus', 'privileges.menu_id', '=', 'menus.id') + ->where('privileges.role_id', $this->role_id) + ->where('menus.link', $menuLink) + ->where('privileges.view', 1) + ->exists(); + } + + /** + * Check if role can access specific menu (static method) + * + * @param int $roleId + * @param string $menuLink + * @return bool + */ + public static function roleCanAccessMenu($roleId, $menuLink) + { + return \App\Models\Privilege::join('menus', 'privileges.menu_id', '=', 'menus.id') + ->where('privileges.role_id', $roleId) + ->where('menus.link', $menuLink) + ->where('privileges.view', 1) + ->exists(); + } } diff --git a/app/Services/TechnicianReportService.php b/app/Services/TechnicianReportService.php index 6b9427b..c284f1f 100644 --- a/app/Services/TechnicianReportService.php +++ b/app/Services/TechnicianReportService.php @@ -6,6 +6,7 @@ use App\Models\Work; use App\Models\User; use App\Models\Transaction; use App\Models\Dealer; +use App\Models\Role; use Carbon\Carbon; use Illuminate\Support\Facades\DB; use Illuminate\Support\Facades\Log; @@ -18,23 +19,60 @@ class TechnicianReportService public function getTechnicianReportData($dealerId = null, $startDate = null, $endDate = null) { try { - // Debug: Check all users and roles - $allUsers = User::with('role')->get(); - Log::info('All users in database:', [ - 'total_users' => $allUsers->count(), - 'users_with_roles' => $allUsers->map(function($user) { - $roleName = 'No role'; - if ($user->role) { - $roleName = is_string($user->role) ? $user->role : $user->role->name; + // Get current authenticated user + $user = auth()->user(); + + if (!$user) { + return [ + 'data' => [], + 'mechanics' => collect(), + 'works' => collect() + ]; + } + + // Validate dealer access + if ($dealerId) { + if ($user->dealer_id) { + // User has specific dealer_id, check if they can access the requested dealer + if ($user->dealer_id != $dealerId) { + if ($user->role_id) { + $role = Role::with('dealers')->find($user->role_id); + if (!$role || !$role->hasDealer($dealerId)) { + // User doesn't have access to this dealer + return [ + 'data' => [], + 'mechanics' => collect(), + 'works' => collect() + ]; + } + } else { + // User has dealer_id but no role, can only access their dealer + return [ + 'data' => [], + 'mechanics' => collect(), + 'works' => collect() + ]; + } } - return [ - 'id' => $user->id, - 'name' => $user->name, - 'role_id' => $user->role_id, - 'role_name' => $roleName, - 'dealer_id' => $user->dealer_id - ]; - }) + } else if ($user->role_id) { + // User has role, check if they can access the requested dealer + $role = Role::with('dealers')->find($user->role_id); + if (!$role || !$role->hasDealer($dealerId)) { + // User doesn't have access to this dealer + return [ + 'data' => [], + 'mechanics' => collect(), + 'works' => collect() + ]; + } + } + } + + Log::info('Getting technician report data', [ + 'user_id' => $user->id, + 'dealer_id' => $dealerId, + 'start_date' => $startDate, + 'end_date' => $endDate ]); // Get all works with category in single query @@ -42,29 +80,10 @@ class TechnicianReportService ->orderBy('name') ->get(); - // Get all mechanics (users with role name = 'mechanic') - $mechanics = User::with('role')->whereHas('role', function($query) { - $query->where('name', 'mechanic'); - }) - ->when($dealerId, function($query) use ($dealerId) { - return $query->where('dealer_id', $dealerId); - }) - ->orderBy('name') - ->get(['id', 'name', 'role_id', 'dealer_id']); + // Get mechanics based on dealer and role access + $mechanics = $this->getMechanicsByDealer($dealerId); - // Fallback: If no mechanics found, get all users with dealer_id - if ($mechanics->isEmpty()) { - Log::info('No users with role "mechanic" found, using fallback: all users with dealer_id'); - $mechanics = User::with('role')->whereNotNull('dealer_id') - ->whereNotNull('role_id') - ->when($dealerId, function($query) use ($dealerId) { - return $query->where('dealer_id', $dealerId); - }) - ->orderBy('name') - ->get(['id', 'name', 'role_id', 'dealer_id']); - } - - Log::info('Mechanics found:', [ + Log::info('Mechanics found for report:', [ 'count' => $mechanics->count(), 'dealer_id_filter' => $dealerId, 'mechanics' => $mechanics->map(function($mechanic) { @@ -87,7 +106,12 @@ class TechnicianReportService Log::info('Transaction data:', [ 'transaction_count' => count($transactions), - 'sample_transactions' => array_slice($transactions, 0, 5, true) + 'sample_transactions' => array_slice($transactions, 0, 5, true), + 'dealer_id_filter' => $dealerId, + 'is_admin_with_pivot' => $user->role_id ? (function() use ($user) { + $role = Role::with('dealers')->find($user->role_id); + return $role && $this->isAdminRole($role) && $role->dealers->count() > 0; + })() : false ]); $data = []; @@ -148,6 +172,46 @@ class TechnicianReportService */ private function getOptimizedTransactionData($dealerId = null, $startDate = null, $endDate = null, $mechanicIds = null, $workIds = null) { + // Get current authenticated user + $user = auth()->user(); + + if (!$user) { + return []; + } + + // Validate dealer access + if ($dealerId) { + if ($user->dealer_id) { + // User has specific dealer_id, check if they can access the requested dealer + if ($user->dealer_id != $dealerId) { + if ($user->role_id) { + $role = Role::with('dealers')->find($user->role_id); + if (!$role || !$role->hasDealer($dealerId)) { + // User doesn't have access to this dealer + return []; + } + } else { + // User has dealer_id but no role, can only access their dealer + return []; + } + } + } else if ($user->role_id) { + // User has role, check if they can access the requested dealer + $role = Role::with('dealers')->find($user->role_id); + if (!$role || !$role->hasDealer($dealerId)) { + // User doesn't have access to this dealer + return []; + } + } + } + + Log::info('Getting optimized transaction data', [ + 'user_id' => $user->id, + 'dealer_id' => $dealerId, + 'start_date' => $startDate, + 'end_date' => $endDate + ]); + $query = Transaction::select( 'work_id', 'user_id', @@ -158,6 +222,15 @@ class TechnicianReportService if ($dealerId) { $query->where('dealer_id', $dealerId); + } else if ($user->role_id) { + // Check if admin with pivot dealers and "Semua Dealer" selected + $role = Role::with('dealers')->find($user->role_id); + if ($role && $this->isAdminRole($role) && $role->dealers->count() > 0) { + // Admin with pivot dealers and "Semua Dealer" selected - filter by pivot dealers + $accessibleDealerIds = $role->dealers->pluck('id'); + $query->whereIn('dealer_id', $accessibleDealerIds); + Log::info('Admin with pivot dealers, filtering transactions by pivot dealer IDs:', $accessibleDealerIds->toArray()); + } } if ($startDate) { @@ -179,6 +252,10 @@ class TechnicianReportService // Remove index hint that doesn't exist $results = $query->get(); + Log::info('Transaction query results', [ + 'results_count' => $results->count() + ]); + // Organize data by work_id_user_id key $organizedData = []; @@ -281,16 +358,200 @@ class TechnicianReportService */ public function getDealers() { - return Dealer::orderBy('name')->get(['id', 'name', 'dealer_code']); + // Get current authenticated user + $user = auth()->user(); + + if (!$user) { + Log::info('No authenticated user found'); + return collect(); + } + + Log::info('Getting dealers for user:', [ + 'user_id' => $user->id, + 'user_name' => $user->name, + 'user_role_id' => $user->role_id, + 'user_dealer_id' => $user->dealer_id + ]); + + // If user has role, check role type and dealer access + if ($user->role_id) { + $role = Role::with(['dealers' => function($query) { + $query->whereNull('dealers.deleted_at'); // Only active dealers + }])->find($user->role_id); + + Log::info('Role details:', [ + 'role_id' => $role ? $role->id : null, + 'role_name' => $role ? $role->name : null, + 'role_dealers_count' => $role ? $role->dealers->count() : 0, + 'role_dealers' => $role ? $role->dealers->pluck('id', 'name')->toArray() : [] + ]); + + if ($role) { + // Check if role is admin type + if ($this->isAdminRole($role)) { + // Admin role - check if has pivot dealers + if ($role->dealers->count() > 0) { + // Admin with pivot dealers - return pivot dealers (for "Semua Dealer" option) + Log::info('Admin role with pivot dealers, returning pivot dealers'); + $dealers = $role->dealers()->whereNull('dealers.deleted_at')->orderBy('name')->get(['dealers.id', 'dealers.name', 'dealers.dealer_code']); + Log::info('Returning pivot dealers for admin:', $dealers->toArray()); + return $dealers; + } else { + // Admin without pivot dealers - return all dealers + Log::info('Admin role without pivot dealers, returning all dealers'); + $allDealers = Dealer::whereNull('deleted_at')->orderBy('name')->get(['id', 'name', 'dealer_code']); + Log::info('Returning all dealers for admin:', $allDealers->toArray()); + return $allDealers; + } + } + + // Role has dealer relationship (tampilkan dealer berdasarkan pivot) + if ($role->dealers->count() > 0) { + Log::info('Role has dealers relationship, returning role dealers'); + $dealers = $role->dealers()->whereNull('dealers.deleted_at')->orderBy('name')->get(['dealers.id', 'dealers.name', 'dealers.dealer_code']); + Log::info('Returning dealers from role:', $dealers->toArray()); + return $dealers; + } + } + } + + // If user has specific dealer_id but no role dealers, check if they can access their dealer_id + if ($user->dealer_id) { + Log::info('User has specific dealer_id:', ['dealer_id' => $user->dealer_id]); + if ($user->role_id) { + $role = Role::with(['dealers' => function($query) { + $query->whereNull('dealers.deleted_at'); // Only active dealers + }])->find($user->role_id); + + if ($role && $role->hasDealer($user->dealer_id)) { + Log::info('User can access their dealer_id, returning single dealer'); + $dealer = Dealer::where('id', $user->dealer_id)->whereNull('deleted_at')->orderBy('name')->get(['id', 'name', 'dealer_code']); + Log::info('Returning dealer:', $dealer->toArray()); + return $dealer; + } else { + Log::info('User cannot access their dealer_id'); + } + } + Log::info('User has dealer_id but no role or no access, returning empty'); + return collect(); + } + + // Fallback: return all dealers if no restrictions + Log::info('No restrictions found, returning all dealers'); + $allDealers = Dealer::whereNull('deleted_at')->orderBy('name')->get(['id', 'name', 'dealer_code']); + Log::info('Returning all dealers:', $allDealers->toArray()); + return $allDealers; } /** - * Get default dealer for filter (tidak perlu berbasis user) + * Check if role is admin type (should show all dealers) + */ + public function isAdminRole($role) + { + // Define admin role names that should have access to all dealers + $adminRoleNames = [ + 'admin', + 'super admin', + 'administrator', + 'sa', + 'superadmin' + ]; + + // Check if role name contains admin keywords (but not "area") + $roleName = strtolower(trim($role->name)); + foreach ($adminRoleNames as $adminName) { + if (strpos($roleName, $adminName) !== false && strpos($roleName, 'area') === false) { + Log::info('Role identified as admin type:', ['role_name' => $role->name]); + return true; + } + } + + // Check if role has no dealer restrictions (no pivot relationships) + // This means role can access all dealers + if ($role->dealers->count() === 0) { + Log::info('Role has no dealer restrictions, treating as admin type:', ['role_name' => $role->name]); + return true; + } + + // Role with "area" in name should use pivot dealers, not all dealers + if (strpos($roleName, 'area') !== false) { + Log::info('Role contains "area", treating as area role (use pivot dealers):', ['role_name' => $role->name]); + return false; + } + + Log::info('Role is not admin type:', ['role_name' => $role->name]); + return false; + } + + /** + * Get default dealer for filter (berbasis user role) */ public function getDefaultDealer() { - // Dealer pertama saja jika ada - return Dealer::orderBy('name')->first(); + // Get current authenticated user + $user = auth()->user(); + + if (!$user) { + return null; + } + + Log::info('Getting default dealer for user:', [ + 'user_id' => $user->id, + 'user_role_id' => $user->role_id, + 'user_dealer_id' => $user->dealer_id + ]); + + // If user has role, check role type and dealer access + if ($user->role_id) { + $role = Role::with(['dealers' => function($query) { + $query->whereNull('dealers.deleted_at'); // Only active dealers + }])->find($user->role_id); + + if ($role) { + // Check if role is admin type + if ($this->isAdminRole($role)) { + // Admin role - check if has pivot dealers + if ($role->dealers->count() > 0) { + // Admin with pivot dealers - return first dealer from pivot + Log::info('Admin role with pivot dealers, returning first dealer from pivot'); + $defaultDealer = $role->dealers()->whereNull('dealers.deleted_at')->orderBy('name')->first(); + Log::info('Default dealer for admin with pivot:', $defaultDealer ? $defaultDealer->toArray() : null); + return $defaultDealer; + } else { + // Admin without pivot dealers - no default dealer (show all dealers without selection) + Log::info('Admin role without pivot dealers, no default dealer'); + return null; + } + } + + // Role has dealer relationship (return first dealer from role dealers) + if ($role->dealers->count() > 0) { + Log::info('Role has dealers relationship, returning first dealer from role dealers'); + $defaultDealer = $role->dealers()->whereNull('dealers.deleted_at')->orderBy('name')->first(); + Log::info('Default dealer from role dealers:', $defaultDealer ? $defaultDealer->toArray() : null); + return $defaultDealer; + } + } + } + + // If user has specific dealer_id, check if they can access it + if ($user->dealer_id) { + if ($user->role_id) { + $role = Role::with(['dealers' => function($query) { + $query->whereNull('dealers.deleted_at'); // Only active dealers + }])->find($user->role_id); + if ($role && $role->hasDealer($user->dealer_id)) { + $defaultDealer = Dealer::where('id', $user->dealer_id)->whereNull('deleted_at')->first(); + Log::info('User dealer found:', $defaultDealer ? $defaultDealer->toArray() : null); + return $defaultDealer; + } + } + return null; + } + + // Fallback: no default dealer + Log::info('No default dealer found'); + return null; } /** @@ -298,15 +559,94 @@ class TechnicianReportService */ public function getMechanicsByDealer($dealerId = null) { + // Get current authenticated user + $user = auth()->user(); + + if (!$user) { + return collect(); + } + + Log::info('Getting mechanics by dealer:', [ + 'user_id' => $user->id, + 'user_role_id' => $user->role_id, + 'user_dealer_id' => $user->dealer_id, + 'requested_dealer_id' => $dealerId + ]); + $query = User::with('role')->whereHas('role', function($query) { $query->where('name', 'mechanic'); }); - if ($dealerId) { + // If user has role, check role type and dealer access + if ($user->role_id) { + $role = Role::with(['dealers' => function($query) { + $query->whereNull('dealers.deleted_at'); // Only active dealers + }])->find($user->role_id); + + if ($role) { + // Check if role is admin type + if ($this->isAdminRole($role)) { + // Admin role - check if has pivot dealers + if ($role->dealers->count() > 0) { + // Admin with pivot dealers + if ($dealerId) { + // Specific dealer selected - get mechanics from that dealer + Log::info('Admin with pivot dealers, specific dealer selected:', ['dealer_id' => $dealerId]); + $query->where('dealer_id', $dealerId); + } else { + // "Semua Dealer" selected - get mechanics from all pivot dealers + Log::info('Admin with pivot dealers, "Semua Dealer" selected, getting mechanics from all pivot dealers'); + $accessibleDealerIds = $role->dealers->pluck('id'); + $query->whereIn('dealer_id', $accessibleDealerIds); + Log::info('Accessible dealer IDs for admin:', $accessibleDealerIds->toArray()); + } + } else { + // Admin without pivot dealers - can access all dealers + Log::info('Admin without pivot dealers, can access mechanics from all dealers'); + if ($dealerId) { + $query->where('dealer_id', $dealerId); + } + // If no dealer_id, show all mechanics (no additional filtering) + } + } else { + // Role has dealer relationship (filter by accessible dealers) + if ($role->dealers->count() > 0) { + Log::info('Role has dealers relationship, filtering mechanics by accessible dealers'); + $accessibleDealerIds = $role->dealers->pluck('id'); + $query->whereIn('dealer_id', $accessibleDealerIds); + Log::info('Accessible dealer IDs:', $accessibleDealerIds->toArray()); + } else { + Log::info('Role has no dealers, returning empty'); + return collect(); + } + } + } + } else if ($user->dealer_id) { + // User has specific dealer_id but no role, can only access their dealer + Log::info('User has dealer_id but no role, can only access their dealer'); + $query->where('dealer_id', $user->dealer_id); + } + + // Apply dealer filter if provided (for non-admin roles) + if ($dealerId && !$this->isAdminRole($role ?? null)) { + Log::info('Applying dealer filter for non-admin role:', ['dealer_id' => $dealerId]); $query->where('dealer_id', $dealerId); } - return $query->orderBy('name')->get(['id', 'name', 'dealer_id']); + $mechanics = $query->orderBy('name')->get(['id', 'name', 'dealer_id']); + + Log::info('Mechanics found:', [ + 'count' => $mechanics->count(), + 'mechanics' => $mechanics->map(function($mechanic) { + return [ + 'id' => $mechanic->id, + 'name' => $mechanic->name, + 'dealer_id' => $mechanic->dealer_id + ]; + })->toArray() + ]); + + return $mechanics; } /** @@ -315,36 +655,94 @@ class TechnicianReportService public function getTechnicianReportDataForDataTable($dealerId = null, $startDate = null, $endDate = null) { try { + // Get current authenticated user + $user = auth()->user(); + + if (!$user) { + return response()->json([ + 'draw' => request()->input('draw', 1), + 'recordsTotal' => 0, + 'recordsFiltered' => 0, + 'data' => [], + 'mechanics' => collect(), + 'works' => collect() + ]); + } + + // Validate dealer access + if ($dealerId) { + if ($user->dealer_id) { + // User has specific dealer_id, check if they can access the requested dealer + if ($user->dealer_id != $dealerId) { + if ($user->role_id) { + $role = Role::with('dealers')->find($user->role_id); + if (!$role || !$role->hasDealer($dealerId)) { + // User doesn't have access to this dealer + return response()->json([ + 'draw' => request()->input('draw', 1), + 'recordsTotal' => 0, + 'recordsFiltered' => 0, + 'data' => [], + 'mechanics' => collect(), + 'works' => collect() + ]); + } + } else { + // User has dealer_id but no role, can only access their dealer + return response()->json([ + 'draw' => request()->input('draw', 1), + 'recordsTotal' => 0, + 'recordsFiltered' => 0, + 'data' => [], + 'mechanics' => collect(), + 'works' => collect() + ]); + } + } + } else if ($user->role_id) { + // User has role, check if they can access the requested dealer + $role = Role::with('dealers')->find($user->role_id); + if (!$role || !$role->hasDealer($dealerId)) { + // User doesn't have access to this dealer + return response()->json([ + 'draw' => request()->input('draw', 1), + 'recordsTotal' => 0, + 'recordsFiltered' => 0, + 'data' => [], + 'mechanics' => collect(), + 'works' => collect() + ]); + } + } + } + + Log::info('Getting technician report data for DataTable', [ + 'user_id' => $user->id, + 'dealer_id' => $dealerId, + 'start_date' => $startDate, + 'end_date' => $endDate + ]); + // Get all works with category $works = Work::with(['category']) ->orderBy('name') ->get(); - // Get all mechanics - $mechanics = User::with('role')->whereHas('role', function($query) { - $query->where('name', 'mechanic'); - }) - ->when($dealerId, function($query) use ($dealerId) { - return $query->where('dealer_id', $dealerId); - }) - ->orderBy('name') - ->get(['id', 'name', 'role_id', 'dealer_id']); - - // Fallback: If no mechanics found, get all users with dealer_id - if ($mechanics->isEmpty()) { - Log::info('No users with role "mechanic" found, using fallback: all users with dealer_id'); - $mechanics = User::with('role')->whereNotNull('dealer_id') - ->whereNotNull('role_id') - ->when($dealerId, function($query) use ($dealerId) { - return $query->where('dealer_id', $dealerId); - }) - ->orderBy('name') - ->get(['id', 'name', 'role_id', 'dealer_id']); - } + // Get mechanics based on dealer and role access + $mechanics = $this->getMechanicsByDealer($dealerId); // Get transaction data $transactions = $this->getOptimizedTransactionData($dealerId, $startDate, $endDate, $mechanics->pluck('id'), $works->pluck('id')); + Log::info('Transaction data for DataTable:', [ + 'transaction_count' => count($transactions), + 'dealer_id_filter' => $dealerId, + 'is_admin_with_pivot' => $user->role_id ? (function() use ($user) { + $role = Role::with('dealers')->find($user->role_id); + return $role && $this->isAdminRole($role) && $role->dealers->count() > 0; + })() : false + ]); + $data = []; foreach ($works as $work) { @@ -366,6 +764,12 @@ class TechnicianReportService $data[] = $row; } + Log::info('DataTable response prepared', [ + 'data_count' => count($data), + 'mechanics_count' => $mechanics->count(), + 'works_count' => $works->count() + ]); + // Create DataTable response return response()->json([ 'draw' => request()->input('draw', 1), diff --git a/database/migrations/2025_07_09_120017_create_role_dealer_table.php b/database/migrations/2025_07_09_120017_create_role_dealer_table.php new file mode 100644 index 0000000..29ae609 --- /dev/null +++ b/database/migrations/2025_07_09_120017_create_role_dealer_table.php @@ -0,0 +1,35 @@ +id(); + $table->foreignId('role_id')->constrained()->onDelete('cascade'); + $table->foreignId('dealer_id')->constrained()->onDelete('cascade'); + $table->timestamps(); + + $table->unique(['role_id', 'dealer_id']); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::dropIfExists('role_dealer'); + } +} diff --git a/database/seeders/MenuSeeder.php b/database/seeders/MenuSeeder.php index e502504..275ae87 100755 --- a/database/seeders/MenuSeeder.php +++ b/database/seeders/MenuSeeder.php @@ -59,5 +59,7 @@ class MenuSeeder extends Seeder ] ); } + + Menu::whereIn('link', ['targets.index','product-categories.index'])->delete(); } } diff --git a/resources/views/auth/login.blade.php b/resources/views/auth/login.blade.php index 4b8680d..0744150 100755 --- a/resources/views/auth/login.blade.php +++ b/resources/views/auth/login.blade.php @@ -81,7 +81,7 @@ POS | Login - + diff --git a/resources/views/back/roleprivileges.blade.php b/resources/views/back/roleprivileges.blade.php index f3a4001..bb8cc5d 100755 --- a/resources/views/back/roleprivileges.blade.php +++ b/resources/views/back/roleprivileges.blade.php @@ -39,6 +39,7 @@ No Nama Role + Dealer Tambahan Aksi @@ -47,13 +48,30 @@ {{ $loop->iteration }} {{ $role->name }} + + @if($role->dealers->count() > 0) +
+ @foreach($role->dealers->take(3) as $dealer) + {{ $dealer->name }} + @endforeach + @if($role->dealers->count() > 3) + +{{ $role->dealers->count() - 3 }} more + @endif +
+ @else + Tidak ada dealer tambahan untuk role ini + @endif +
@can('update', $menus['roleprivileges.index']) @endcan @can('delete', $menus['roleprivileges.index']) - + + @endcan + @can('create', $menus['roleprivileges.index']) + @endcan
@@ -183,6 +201,141 @@ + +@endsection + +@section('styles') + @endsection @section('javascripts') @@ -296,17 +449,145 @@ } }) } + + function assignDealer(roleId) { + // Set form action + let url = '{{ route("roleprivileges.assignDealer", ":id") }}'.replace(':id', roleId); + $("#assignDealerForm").attr("action", url); + + // Reset checkboxes and counter + $('.dealer-checkbox').prop('checked', false); + updateSelectedCount(); + + // Load existing assigned dealers + $.ajax({ + url: '{{ route("roleprivileges.getAssignedDealers", ":id") }}'.replace(':id', roleId), + type: 'GET', + success: function(response) { + if (response.assignedDealers) { + response.assignedDealers.forEach(function(dealerId) { + $(`#dealer_${dealerId}`).prop('checked', true); + }); + } + updateSelectedCount(); + }, + error: function() { + console.log('Error loading assigned dealers'); + updateSelectedCount(); + } + }); + + $("#assignDealerModal").modal("show"); + } + + function selectAllDealers() { + $('.dealer-checkbox').prop('checked', true); + updateSelectedCount(); + } + + function deselectAllDealers() { + $('.dealer-checkbox').prop('checked', false); + updateSelectedCount(); + } + + function updateSelectedCount() { + const selectedCount = $('.dealer-checkbox:checked').length; + $('#selectedCount').text(selectedCount); + + // Update submit button state + if (selectedCount > 0) { + $('#submitBtn').prop('disabled', false).removeClass('btn-secondary').addClass('btn-primary'); + } else { + $('#submitBtn').prop('disabled', true).removeClass('btn-primary').addClass('btn-secondary'); + } + } + $(document).ready(function () { // Add event handlers for modal close buttons $('.close, [data-dismiss="modal"]').on("click", function () { $("#roleModal").modal("hide"); $("#roleEditModal").modal("hide"); + $("#assignDealerModal").modal("hide"); }); // Also handle the "Close" button $('.btn-secondary[data-dismiss="modal"]').on("click", function () { $("#roleModal").modal("hide"); $("#roleEditModal").modal("hide"); + $("#assignDealerModal").modal("hide"); + }); + + // Event listener for dealer checkboxes + $(document).on('change', '.dealer-checkbox', function() { + updateSelectedCount(); + }); + + // Handle form submission for assign dealer + $("#assignDealerForm").on("submit", function(e) { + e.preventDefault(); + + // Validate if at least one dealer is selected + const selectedDealers = $('.dealer-checkbox:checked').length; + if (selectedDealers === 0) { + Swal.fire({ + title: 'Peringatan!', + text: 'Silakan pilih minimal satu dealer', + icon: 'warning', + confirmButtonText: 'OK' + }); + return; + } + + // Disable submit button and show loading + const submitBtn = $('#submitBtn'); + const originalText = submitBtn.html(); + submitBtn.prop('disabled', true).html('Menyimpan...'); + + let formData = new FormData(this); + let url = $(this).attr("action"); + + $.ajax({ + url: url, + type: 'POST', + data: formData, + processData: false, + contentType: false, + success: function(response) { + if (response.success) { + Swal.fire({ + title: 'Berhasil!', + text: response.message, + icon: 'success', + confirmButtonText: 'OK' + }).then(() => { + location.reload(); + }); + } else { + Swal.fire({ + title: 'Error!', + text: response.message || 'Terjadi kesalahan', + icon: 'error', + confirmButtonText: 'OK' + }); + } + }, + error: function(xhr) { + let message = 'Terjadi kesalahan'; + if (xhr.responseJSON && xhr.responseJSON.message) { + message = xhr.responseJSON.message; + } + Swal.fire({ + title: 'Error!', + text: message, + icon: 'error', + confirmButtonText: 'OK' + }); + }, + complete: function() { + // Re-enable submit button + submitBtn.prop('disabled', false).html(originalText); + } + }); }); }); diff --git a/resources/views/reports/technician.blade.php b/resources/views/reports/technician.blade.php index be22333..86d71d9 100644 --- a/resources/views/reports/technician.blade.php +++ b/resources/views/reports/technician.blade.php @@ -153,7 +153,7 @@
- Pilih dealer untuk memfilter data atau biarkan "Semua Dealer" untuk melihat data lengkap. + Filter diset ke "Semua Dealer" untuk melihat data lengkap. Pilih dealer untuk memfilter data.
@@ -283,14 +283,45 @@ $(document).ready(function() { // Initialize Select2 after populating options initializeSelect2(); - // Default ke "Semua Dealer" (tidak ada dealer yang terselect) - console.log('Default set to "Semua Dealer"'); - $('#default-dealer-info').text('Pilih dealer untuk memfilter data atau biarkan "Semua Dealer" untuk melihat data lengkap.'); + // Set default dealer if provided + if (response.default_dealer && response.data.length > 0) { + // Don't set default dealer - always show "Semua Dealer" on initial load + $('#default-dealer-info').text('Filter diset ke "Semua Dealer" untuk melihat data lengkap. Pilih dealer untuk memfilter data.'); + + // Load initial data without dealer filter (show all dealers) + if (!isInitialized) { + console.log('Default dealer available but loading with "Semua Dealer" filter'); + loadInitialMechanics(); + } + } else if (response.default_dealer === null && response.data.length > 0) { + // Admin without default dealer - show all dealers without selection + $('#default-dealer-info').text('Filter diset ke "Semua Dealer" untuk melihat data lengkap. Pilih dealer untuk memfilter data.'); + + // Load initial data without dealer filter + if (!isInitialized) { + console.log('Admin without default dealer, loading initial data'); + loadInitialMechanics(); + } + } else if (response.data.length > 0) { + $('#default-dealer-info').text('Filter diset ke "Semua Dealer" untuk melihat data lengkap. Pilih dealer untuk memfilter data.'); + + // Load initial data without dealer filter + if (!isInitialized) { + console.log('No default dealer, loading initial data'); + loadInitialMechanics(); + } + } else { + // No dealers available + $('#default-dealer-info').text('Tidak ada dealer yang tersedia untuk Anda.'); + hideLoadingOverlay(); + } - // Load initial mechanics and then initialize DataTable - if (!isInitialized) { - console.log('Dealers loaded, loading initial mechanics...'); - loadInitialMechanics(); + // Check if user has access to any dealers + if (response.data.length === 0) { + toastr.warning('Anda tidak memiliki akses ke dealer manapun. Silakan hubungi administrator.'); + $('#default-dealer-info').text('Anda tidak memiliki akses ke dealer manapun.'); + hideLoadingOverlay(); + return; } } else { toastr.error('Gagal memuat data dealer'); @@ -304,14 +335,14 @@ $(document).ready(function() { }); } - function loadInitialMechanics() { - // Get initial filter values (empty dealer, default dates) - let dealerId = ''; + function loadDataWithDealer(dealerId) { + // Show loading overlay + showLoadingOverlay("Memuat data laporan teknisi..."); + const startDate = $('#filter-start-date').val(); const endDate = $('#filter-end-date').val(); - // Show loading overlay - showLoadingOverlay("Memuat data laporan teknisi..."); + console.log('Loading data with dealer:', dealerId, 'date range:', { startDate, endDate }); // Get mechanics first, then initialize DataTable $.ajax({ @@ -319,9 +350,21 @@ $(document).ready(function() { type: 'GET', data: { dealer_id: dealerId, start_date: startDate, end_date: endDate }, success: function(response) { + console.log('Data response:', response); + if (response.status === 'success' && Array.isArray(response.mechanics)) { mechanics = response.mechanics; - console.log('Initial mechanics loaded:', mechanics.length); + console.log('Data loaded with dealer:', dealerId, 'mechanics:', mechanics.length); + + // Check if user has access to any data + if (response.data.length === 0 && response.mechanics.length === 0) { + console.log('No data available for dealer:', dealerId); + toastr.info('Tidak ada data yang tersedia untuk dealer yang dipilih. Silakan pilih dealer lain.'); + $('#default-dealer-info').text('Tidak ada data yang tersedia untuk dealer yang dipilih.'); + hideLoadingOverlay(); + return; + } + // Now initialize DataTable with mechanics ready updateTableStructureWithMechanics(); isInitialized = true; @@ -332,7 +375,70 @@ $(document).ready(function() { isInitialized = true; } }, - error: function() { + error: function(xhr, status, error) { + console.error('Error loading data with dealer:', error); + console.error('Response:', xhr.responseText); + + toastr.error('Gagal memuat data untuk dealer yang dipilih. Silakan coba lagi.'); + hideLoadingOverlay(); + + // Don't try fallback to avoid multiple notifications + mechanics = []; + updateTableStructureWithMechanics(); + isInitialized = true; + } + }); + } + + function loadInitialMechanics() { + // Get initial filter values (empty dealer, default dates) + let dealerId = ''; + const startDate = $('#filter-start-date').val(); + const endDate = $('#filter-end-date').val(); + + console.log('Loading initial mechanics without dealer filter, date range:', { startDate, endDate }); + + // Show loading overlay + showLoadingOverlay("Memuat data laporan teknisi..."); + + // Get mechanics first, then initialize DataTable + $.ajax({ + url: '{{ route("reports.technician.data") }}', + type: 'GET', + data: { dealer_id: dealerId, start_date: startDate, end_date: endDate }, + success: function(response) { + console.log('Initial data response:', response); + + if (response.status === 'success' && Array.isArray(response.mechanics)) { + mechanics = response.mechanics; + console.log('Initial mechanics loaded:', mechanics.length); + + // Check if user has access to any data + if (response.data.length === 0 && response.mechanics.length === 0) { + console.log('No data available without dealer filter'); + // Don't show notification for initial load without dealer filter + $('#default-dealer-info').text('Tidak ada data yang tersedia. Silakan pilih dealer untuk memfilter data.'); + hideLoadingOverlay(); + return; + } + + // Now initialize DataTable with mechanics ready + updateTableStructureWithMechanics(); + isInitialized = true; + } else { + console.warn('Invalid mechanics data, using fallback'); + mechanics = []; + updateTableStructureWithMechanics(); + isInitialized = true; + } + }, + error: function(xhr, status, error) { + console.error('Error loading initial mechanics:', error); + console.error('Response:', xhr.responseText); + + toastr.error('Gagal memuat data laporan teknisi. Silakan coba lagi.'); + hideLoadingOverlay(); + console.warn('Error loading initial mechanics, using fallback'); mechanics = []; updateTableStructureWithMechanics(); @@ -382,6 +488,12 @@ $(document).ready(function() { mechanics = []; } + // Check if user has access to any data + if (response.data.length === 0 && response.mechanics.length === 0) { + toastr.info('Tidak ada data yang tersedia untuk filter yang dipilih atau Anda tidak memiliki akses ke data tersebut.'); + $('#default-dealer-info').text('Tidak ada data yang tersedia untuk filter yang dipilih.'); + } + } else { console.error('Server returned error status:', response); toastr.error('Gagal memuat data laporan teknisi'); @@ -401,7 +513,7 @@ $(document).ready(function() { } else if (xhr.status === 404) { errorMessage = 'Endpoint tidak ditemukan'; } else if (xhr.status === 403) { - errorMessage = 'Akses ditolak'; + errorMessage = 'Akses ditolak - Anda tidak memiliki izin untuk mengakses data ini'; } toastr.error(errorMessage); @@ -500,6 +612,13 @@ $(document).ready(function() { dataSrc: function(json) { console.log('DataTable response:', json); + // Check for error response + if (json.error) { + console.error('DataTable error:', json.error); + toastr.error('Error loading data: ' + json.error); + return []; + } + // Update mechanics from response if (json.mechanics && Array.isArray(json.mechanics)) { mechanics = json.mechanics; @@ -512,6 +631,27 @@ $(document).ready(function() { } return json.data || []; + }, + error: function(xhr, error, thrown) { + console.error('DataTable AJAX error:', { + xhr: xhr, + error: error, + thrown: thrown + }); + + let errorMessage = 'Gagal memuat data'; + if (xhr.responseJSON && xhr.responseJSON.error) { + errorMessage = xhr.responseJSON.error; + } else if (xhr.status === 500) { + errorMessage = 'Server error: ' + (xhr.responseText || 'Unknown error'); + } else if (xhr.status === 404) { + errorMessage = 'Endpoint tidak ditemukan'; + } else if (xhr.status === 403) { + errorMessage = 'Akses ditolak'; + } + + toastr.error(errorMessage); + hideLoadingOverlay(); } }, columns: [ @@ -754,12 +894,40 @@ $(document).ready(function() { dataSrc: function(json) { console.log('DataTable response:', json); + // Check for error response + if (json.error) { + console.error('DataTable error:', json.error); + toastr.error('Error loading data: ' + json.error); + return []; + } + // Don't update mechanics from datatable response - use existing mechanics // if (json.mechanics && Array.isArray(json.mechanics)) { // mechanics = json.mechanics; // } return json.data || []; + }, + error: function(xhr, error, thrown) { + console.error('DataTable AJAX error:', { + xhr: xhr, + error: error, + thrown: thrown + }); + + let errorMessage = 'Gagal memuat data'; + if (xhr.responseJSON && xhr.responseJSON.error) { + errorMessage = xhr.responseJSON.error; + } else if (xhr.status === 500) { + errorMessage = 'Server error: ' + (xhr.responseText || 'Unknown error'); + } else if (xhr.status === 404) { + errorMessage = 'Endpoint tidak ditemukan'; + } else if (xhr.status === 403) { + errorMessage = 'Akses ditolak'; + } + + toastr.error(errorMessage); + hideLoadingOverlay(); } }, columns: columns, @@ -1105,7 +1273,7 @@ $(document).ready(function() { $('#btn-reset').on('click', function() { console.log('Reset button clicked'); - // Reset dealer selection + // Reset dealer selection to "Semua Dealer" if (typeof $.fn.select2 !== 'undefined' && $('#filter-dealer').data('select2')) { $('#filter-dealer').val('').trigger('change'); } else { @@ -1116,7 +1284,7 @@ $(document).ready(function() { $('#filter-start-date').val('{{ date('Y-m-d', strtotime('-30 days')) }}'); $('#filter-end-date').val('{{ date('Y-m-d') }}'); - console.log('Filters reset, reloading DataTable...'); + console.log('Filters reset to "Semua Dealer", reloading DataTable...'); // Reset initialization flag isInitialized = false; diff --git a/routes/web.php b/routes/web.php index 669aa1a..defb1f5 100755 --- a/routes/web.php +++ b/routes/web.php @@ -230,6 +230,8 @@ Route::group(['middleware' => 'auth'], function() { Route::get('/roleprivileges/{id}/edit', [RolePrivilegeController::class, 'edit'])->name('roleprivileges.edit'); Route::put('/roleprivileges/{id}/update', [RolePrivilegeController::class, 'update'])->name('roleprivileges.update'); Route::delete('/roleprivileges/{id}/delete', [RolePrivilegeController::class, 'delete'])->name('roleprivileges.delete'); + Route::post('/roleprivileges/{id}/assign-dealer', [RolePrivilegeController::class, 'assignDealer'])->name('roleprivileges.assignDealer'); + Route::get('/roleprivileges/{id}/assigned-dealers', [RolePrivilegeController::class, 'getAssignedDealers'])->name('roleprivileges.getAssignedDealers'); Route::get('/report/transaction', [ReportController::class, 'transaction'])->name('report.transaction'); Route::post('/report/transaction/data', [ReportController::class, 'transaction_data'])->name('report.transaction_data');