187 خطوط
5.9 KiB
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;
|
|
}
|
|
}
|