CRM/backend/app/Http/Controllers/Api/FollowUpController.php

187 خطوط
5.9 KiB
PHP

<?php
namespace App\Http\Controllers\Api;
use App\Http\Controllers\Controller;
use App\Models\FollowUp;
use App\Models\Lead;
use App\Services\ActivityLogger;
use App\Services\NotificationService;
use App\Support\AccessControl;
use App\Support\WorkingHours;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Gate;
class FollowUpController extends Controller
{
public function index(Request $request): JsonResponse
{
$user = auth()->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;
}
}