self::canAccessLead($user, $entity), $entity instanceof Company => self::canAccessCompany($user, $entity), $entity instanceof Deal => self::canAccessDeal($user, $entity), $entity instanceof Contact => self::canAccessContact($user, $entity), $entity instanceof Product => self::canAccessProduct($user), $entity instanceof Call => self::canAccessCall($user, $entity), $entity instanceof Campaign => self::canAccessCampaign($user, $entity), default => false, }; } public static function canAccessLead(User $user, Lead $lead, bool $allowUnassignedClaim = false): bool { if ($user->hasRole('admin')) { return true; } if ($user->hasRole('agent')) { return $lead->assigned_to === $user->id || ($allowUnassignedClaim && is_null($lead->assigned_to) && (bool) $lead->is_unassigned); } if ($user->hasRole('supervisor')) { return $lead->assigned_to === $user->id || in_array($lead->team_id, self::teamIds($user), true) || (is_null($lead->team_id) && is_null($lead->assigned_to)); } return false; } public static function canAccessCall(User $user, Call $call): bool { if ($user->hasRole('admin')) { return true; } if ($user->hasRole('agent')) { return $call->user_id === $user->id; } if ($user->hasRole('supervisor')) { return in_array($call->user_id, self::teamMemberIds($user), true) || ($call->lead && self::canAccessLead($user, $call->lead)); } return false; } public static function canAccessFollowUp(User $user, FollowUp $followUp): bool { if ($user->hasRole('admin')) { return true; } if ($user->hasRole('agent')) { return $followUp->user_id === $user->id; } if ($user->hasRole('supervisor')) { return in_array($followUp->user_id, self::teamMemberIds($user), true) || ($followUp->lead && self::canAccessLead($user, $followUp->lead)); } return false; } public static function canAccessCampaign(User $user, Campaign $campaign): bool { if ($user->hasRole('admin')) { return true; } if ($user->hasRole('agent')) { return $campaign->assignedAgents()->whereKey($user->id)->exists() || $campaign->leads()->where('assigned_to', $user->id)->exists(); } if ($user->hasRole('supervisor')) { $teamIds = self::teamIds($user); return $campaign->assignedSupervisors()->whereKey($user->id)->exists() || $campaign->leads()->whereIn('team_id', $teamIds)->exists(); } return false; } public static function canAccessCompany(User $user, Company $company): bool { if ($user->hasRole('admin')) { return true; } if ($company->owner_id === $user->id) { return true; } if ($user->hasRole('agent')) { return $company->leads()->where('assigned_to', $user->id)->exists(); } if ($user->hasRole('supervisor')) { return in_array($company->owner_id, self::teamMemberIds($user), true) || $company->leads()->where(function (Builder $query) use ($user): void { self::scopeLeads($query, $user, false); })->exists(); } return false; } public static function canAccessDeal(User $user, Deal $deal): bool { if ($user->hasRole('admin') || $deal->owner_id === $user->id) { return true; } if ($deal->lead && self::canAccessLead($user, $deal->lead)) { return true; } return $user->hasRole('supervisor') && in_array($deal->owner_id, self::teamMemberIds($user), true); } public static function canAccessContact(User $user, Contact $contact): bool { if ($user->hasRole('admin') || $contact->created_by === $user->id) { return true; } return ($contact->lead && self::canAccessLead($user, $contact->lead)) || ($contact->company && self::canAccessCompany($user, $contact->company)) || ($contact->deal && self::canAccessDeal($user, $contact->deal)); } public static function canAccessProduct(User $user): bool { return $user->hasRole('admin') || $user->can('view_products'); } public static function canAssignUser(User $user, ?int $ownerId): bool { if ($ownerId === null || $user->hasRole('admin')) { return true; } if ($ownerId === $user->id) { return true; } return $user->hasRole('supervisor') && in_array($ownerId, self::teamMemberIds($user), true); } public static function canAccessTask(User $user, Task $task): bool { if ($user->can('view_all_tasks')) { return true; } if ($task->assigned_to === $user->id || $task->created_by === $user->id) { return $user->can('view_own_tasks') || $user->can('view_team_tasks'); } if (! $user->can('view_team_tasks') || $task->visibility->value === 'private') { return false; } $teamUserIds = self::teamMemberIds($user); return in_array($task->assigned_to, $teamUserIds, true) || in_array($task->created_by, $teamUserIds, true); } public static function scopeTasks(Builder $query, User $user): Builder { if ($user->can('view_all_tasks')) { return $query; } if ($user->can('view_team_tasks')) { $teamUserIds = self::teamMemberIds($user); return $query->where(function (Builder $scope) use ($user, $teamUserIds): void { $scope->where('assigned_to', $user->id) ->orWhere('created_by', $user->id) ->orWhere(function (Builder $teamScope) use ($teamUserIds): void { $teamScope->where('visibility', '<>', 'private') ->where(function (Builder $members) use ($teamUserIds): void { $members->whereIn('assigned_to', $teamUserIds) ->orWhereIn('created_by', $teamUserIds); }); }); }); } if ($user->can('view_own_tasks')) { return $query->where(fn (Builder $scope) => $scope ->where('assigned_to', $user->id) ->orWhere('created_by', $user->id)); } return $query->whereRaw('1 = 0'); } public static function scopeLeads(Builder $query, User $user, bool $allowUnassignedForSupervisor = true): Builder { if ($user->hasRole('admin')) { return $query; } if ($user->hasRole('agent')) { return $query->where('assigned_to', $user->id); } if ($user->hasRole('supervisor')) { $teamIds = self::teamIds($user); return $query->where(function (Builder $q) use ($user, $teamIds, $allowUnassignedForSupervisor): void { $q->whereIn('team_id', $teamIds) ->orWhere('assigned_to', $user->id); if ($allowUnassignedForSupervisor) { $q->orWhere(function (Builder $unassigned): void { $unassigned->whereNull('team_id')->whereNull('assigned_to'); }); } }); } return $query->whereRaw('1 = 0'); } public static function scopeCalls(Builder $query, User $user): Builder { if ($user->hasRole('admin')) { return $query; } if ($user->hasRole('agent')) { return $query->where('user_id', $user->id); } if ($user->hasRole('supervisor')) { return $query->where(function (Builder $q) use ($user): void { $q->whereIn('user_id', self::teamMemberIds($user)) ->orWhereHas('lead', fn (Builder $leadQuery) => self::scopeLeads($leadQuery, $user)); }); } return $query->whereRaw('1 = 0'); } public static function scopeFollowUps(Builder $query, User $user): Builder { if ($user->hasRole('admin')) { return $query; } if ($user->hasRole('agent')) { return $query->where('user_id', $user->id); } if ($user->hasRole('supervisor')) { return $query->where(function (Builder $q) use ($user): void { $q->whereIn('user_id', self::teamMemberIds($user)) ->orWhereHas('lead', fn (Builder $leadQuery) => self::scopeLeads($leadQuery, $user)); }); } return $query->whereRaw('1 = 0'); } public static function scopeCampaigns(Builder $query, User $user): Builder { if ($user->hasRole('admin')) { return $query; } if ($user->hasRole('agent')) { return $query->where(function (Builder $q) use ($user): void { $q->whereHas('assignedAgents', fn (Builder $agentQuery) => $agentQuery->whereKey($user->id)) ->orWhereHas('leads', fn (Builder $leadQuery) => $leadQuery->where('assigned_to', $user->id)); }); } if ($user->hasRole('supervisor')) { $teamIds = self::teamIds($user); return $query->where(function (Builder $q) use ($user, $teamIds): void { $q->whereHas('assignedSupervisors', fn (Builder $supervisorQuery) => $supervisorQuery->whereKey($user->id)) ->orWhereHas('leads', fn (Builder $leadQuery) => $leadQuery->whereIn('team_id', $teamIds)); }); } return $query->whereRaw('1 = 0'); } public static function scopeCompanies(Builder $query, User $user): Builder { if ($user->hasRole('admin')) { return $query; } if ($user->hasRole('agent')) { return $query->where(function (Builder $companyQuery) use ($user): void { $companyQuery->where('owner_id', $user->id) ->orWhereHas('leads', fn (Builder $leadQuery) => $leadQuery->where('assigned_to', $user->id)); }); } if ($user->hasRole('supervisor')) { $ownerIds = array_values(array_unique(array_merge([$user->id], self::teamMemberIds($user)))); return $query->where(function (Builder $companyQuery) use ($user, $ownerIds): void { $companyQuery->whereIn('owner_id', $ownerIds) ->orWhereHas('leads', fn (Builder $leadQuery) => self::scopeLeads($leadQuery, $user, false)); }); } return $query->whereRaw('1 = 0'); } public static function scopeDeals(Builder $query, User $user): Builder { if ($user->hasRole('admin')) { return $query; } if ($user->hasRole('agent')) { return $query->where(function (Builder $dealQuery) use ($user): void { $dealQuery->where('owner_id', $user->id) ->orWhereHas('lead', fn (Builder $leadQuery) => $leadQuery->where('assigned_to', $user->id)); }); } if ($user->hasRole('supervisor')) { $ownerIds = array_values(array_unique(array_merge([$user->id], self::teamMemberIds($user)))); return $query->where(function (Builder $dealQuery) use ($user, $ownerIds): void { $dealQuery->whereIn('owner_id', $ownerIds) ->orWhereHas('lead', fn (Builder $leadQuery) => self::scopeLeads($leadQuery, $user, false)); }); } return $query->whereRaw('1 = 0'); } public static function scopeContacts(Builder $query, User $user): Builder { if ($user->hasRole('admin')) { return $query; } return $query->where(function (Builder $contactQuery) use ($user): void { $contactQuery->where('created_by', $user->id) ->orWhereHas('lead', fn (Builder $leadQuery) => self::scopeLeads($leadQuery, $user, false)) ->orWhereHas('company', fn (Builder $companyQuery) => self::scopeCompanies($companyQuery, $user)) ->orWhereHas('deal', fn (Builder $dealQuery) => self::scopeDeals($dealQuery, $user)); }); } public static function teamIds(User $user): array { return $user->teams()->pluck('teams.id')->all(); } public static function teamMemberIds(User $user): array { $teamIds = self::teamIds($user); if (! $teamIds) { return []; } return Team::whereIn('id', $teamIds) ->with('members:id') ->get() ->pluck('members.*.id') ->flatten() ->unique() ->values() ->all(); } }