user(); Gate::authorize('viewAny', FollowUp::class); $query = FollowUp::with('lead:id,first_name,last_name,phone', 'user:id,name'); AccessControl::scopeFollowUps($query, $user); if ($request->status) { $query->where('status', $request->status); } if ($request->lead_id) { $query->where('lead_id', $request->lead_id); } if ($request->date_from) { $query->whereDate('scheduled_at', '>=', $request->date_from); } if ($request->date_to) { $query->whereDate('scheduled_at', '<=', $request->date_to); } return response()->json($query->orderBy('scheduled_at')->paginate($request->per_page ?? 15)); } public function store(Request $request): JsonResponse { $validated = $request->validate([ 'lead_id' => 'required|exists:leads,id', 'scheduled_at' => 'required|date', 'notes' => 'nullable|string', ]); $lead = Lead::findOrFail($validated['lead_id']); Gate::authorize('create', [FollowUp::class, $lead]); if (!WorkingHours::followUpAllowed($validated['scheduled_at'])) { return response()->json(['message' => 'زمان پیگیری خارج از روز یا ساعت کاری مجاز است.'], 422); } $followUp = FollowUp::create([ 'lead_id' => $validated['lead_id'], 'user_id' => auth()->id(), 'scheduled_at' => $validated['scheduled_at'], 'notes' => $validated['notes'] ?? null, 'status' => 'pending', ]); ActivityLogger::log('follow_up_created', "Follow-up for lead {$validated['lead_id']} scheduled", $followUp); NotificationService::notifyFollowUpReminder($followUp->user_id, $lead->full_name ?: ($lead->company ?? "لید {$lead->id}")); return response()->json($followUp->load('lead'), 201); } public function update(Request $request, FollowUp $followUp): JsonResponse { Gate::authorize('update', $followUp); $validated = $request->validate([ 'scheduled_at' => 'sometimes|date', 'notes' => 'nullable|string', 'status' => 'sometimes|string|in:pending,completed,cancelled', ]); $followUp->update($validated); ActivityLogger::log('follow_up_updated', "Follow-up {$followUp->id} updated", $followUp); return response()->json($followUp->load('lead')); } public function markDone(FollowUp $followUp): JsonResponse { Gate::authorize('update', $followUp); $followUp->update([ 'status' => 'completed', 'completed_at' => now(), ]); ActivityLogger::log('follow_up_completed', "Follow-up {$followUp->id} completed", $followUp); return response()->json($followUp); } public function today(): JsonResponse { $user = auth()->user(); $query = FollowUp::with('lead:id,first_name,last_name,phone') ->whereDate('scheduled_at', now()->toDateString()) ->where('status', 'pending'); AccessControl::scopeFollowUps($query, $user); $followUps = $query->orderBy('scheduled_at')->get(); foreach ($followUps as $followUp) { NotificationService::sendOnce( $followUp->user_id, 'پیگیری عقب‌افتاده', 'پیگیری لید ' . ($followUp->lead?->full_name ?: ($followUp->lead?->company ?? "لید {$followUp->lead_id}")) . ' عقب افتاده است', 'overdue_follow_up', ['follow_up_id' => $followUp->id, 'lead_id' => $followUp->lead_id] ); } return response()->json($followUps); } public function overdue(): JsonResponse { $user = auth()->user(); $query = FollowUp::with('lead:id,first_name,last_name,phone') ->where('status', 'pending') ->where(function ($q) { $q->where('is_overdue', true) ->orWhere('scheduled_at', '<', now()); }); AccessControl::scopeFollowUps($query, $user); return response()->json($query->orderBy('scheduled_at')->get()); } private function canManageFollowUp(FollowUp $followUp): bool { $user = auth()->user(); if (!$user) { return false; } if ($user->hasRole('admin')) { return true; } if ($user->hasRole('agent')) { return $followUp->user_id === $user->id; } if ($user->hasRole('supervisor')) { $teamIds = $user->teams->pluck('id')->toArray(); $agentIds = \App\Models\Team::whereIn('id', $teamIds)->with('members')->get()->pluck('members.*.id')->flatten(); return $agentIds->contains($followUp->user_id); } return false; } private function canAccessLead(\App\Models\Lead $lead): bool { $user = auth()->user(); if (!$user) { return false; } if ($user->hasRole('admin')) { return true; } if ($user->hasRole('agent')) { return $lead->assigned_to === $user->id; } if ($user->hasRole('supervisor')) { $teamIds = $user->teams->pluck('id')->toArray(); return in_array($lead->team_id, $teamIds, true) || $lead->assigned_to === $user->id; } return false; } }