172 خطوط
6.5 KiB
PHP
172 خطوط
6.5 KiB
PHP
<?php
|
|
|
|
namespace App\Http\Controllers\Api;
|
|
|
|
use App\Http\Controllers\Controller;
|
|
use App\Models\Lead;
|
|
use App\Models\User;
|
|
use App\Services\ActivityLogger;
|
|
use App\Services\AssignmentService;
|
|
use App\Support\AccessControl;
|
|
use Illuminate\Http\JsonResponse;
|
|
use Illuminate\Http\Request;
|
|
use Illuminate\Support\Facades\Gate;
|
|
|
|
class AssignmentController extends Controller
|
|
{
|
|
public function __construct(private AssignmentService $assignmentService) {}
|
|
|
|
public function assign(Request $request): JsonResponse
|
|
{
|
|
$validated = $request->validate([
|
|
'lead_id' => 'required|exists:leads,id',
|
|
'agent_id' => 'required|exists:users,id',
|
|
]);
|
|
$lead = Lead::findOrFail($validated['lead_id']);
|
|
$agent = User::findOrFail($validated['agent_id']);
|
|
if (! $this->canAssignToAgent($lead, $agent)) {
|
|
return response()->json(['message' => 'دسترسی غیرمجاز'], 403);
|
|
}
|
|
|
|
$lead = $this->assignmentService->assignToAgent(
|
|
$validated['lead_id'],
|
|
$validated['agent_id'],
|
|
auth()->id()
|
|
);
|
|
ActivityLogger::log('lead_owner_changed', "Lead {$lead->id} assigned to user {$agent->id}", $lead);
|
|
|
|
return response()->json($lead->load('assignedAgent'));
|
|
}
|
|
|
|
public function bulkAssign(Request $request): JsonResponse
|
|
{
|
|
$validated = $request->validate([
|
|
'lead_ids' => 'required|array|min:1',
|
|
'lead_ids.*' => 'exists:leads,id',
|
|
'agent_id' => 'required|exists:users,id',
|
|
]);
|
|
$agent = User::findOrFail($validated['agent_id']);
|
|
$leads = Lead::whereIn('id', $validated['lead_ids'])->get();
|
|
if ($leads->count() !== count(array_unique($validated['lead_ids'])) || $leads->contains(fn (Lead $lead) => ! $this->canAssignToAgent($lead, $agent))) {
|
|
return response()->json(['message' => 'دسترسی غیرمجاز'], 403);
|
|
}
|
|
|
|
$leads = $this->assignmentService->bulkAssign(
|
|
$validated['lead_ids'],
|
|
$validated['agent_id'],
|
|
auth()->id()
|
|
);
|
|
ActivityLogger::log('lead_bulk_owner_changed', count($leads)." leads assigned to user {$agent->id}");
|
|
|
|
return response()->json(['assigned' => count($leads)]);
|
|
}
|
|
|
|
public function roundRobin(Request $request): JsonResponse
|
|
{
|
|
$validated = $request->validate([
|
|
'lead_ids' => 'required|array|min:1',
|
|
'lead_ids.*' => 'exists:leads,id',
|
|
'agent_ids' => 'required|array|min:1',
|
|
'agent_ids.*' => 'exists:users,id',
|
|
]);
|
|
$agents = User::whereIn('id', $validated['agent_ids'])->get()->keyBy('id');
|
|
$leads = Lead::whereIn('id', $validated['lead_ids'])->get();
|
|
if (
|
|
$agents->count() !== count(array_unique($validated['agent_ids']))
|
|
|| $leads->count() !== count(array_unique($validated['lead_ids']))
|
|
|| $leads->contains(fn (Lead $lead) => Gate::denies('assign', $lead))
|
|
|| $agents->contains(fn (User $agent) => ! $this->agentIsAssignable($agent))
|
|
) {
|
|
return response()->json(['message' => 'دسترسی غیرمجاز'], 403);
|
|
}
|
|
|
|
$leads = $this->assignmentService->roundRobin(
|
|
$validated['lead_ids'],
|
|
$validated['agent_ids'],
|
|
auth()->id()
|
|
);
|
|
ActivityLogger::log('lead_round_robin_owner_changed', count($leads).' leads assigned by round robin');
|
|
|
|
return response()->json(['assigned' => count($leads)]);
|
|
}
|
|
|
|
public function reassign(Request $request): JsonResponse
|
|
{
|
|
$validated = $request->validate([
|
|
'lead_id' => 'required|exists:leads,id',
|
|
'agent_id' => 'required|exists:users,id',
|
|
]);
|
|
$lead = Lead::findOrFail($validated['lead_id']);
|
|
$agent = User::findOrFail($validated['agent_id']);
|
|
if (! $this->canAssignToAgent($lead, $agent)) {
|
|
return response()->json(['message' => 'دسترسی غیرمجاز'], 403);
|
|
}
|
|
|
|
$lead = $this->assignmentService->assignToAgent(
|
|
$validated['lead_id'],
|
|
$validated['agent_id'],
|
|
auth()->id()
|
|
);
|
|
ActivityLogger::log('lead_owner_changed', "Lead {$lead->id} reassigned to user {$agent->id}", $lead);
|
|
|
|
return response()->json($lead->load('assignedAgent'));
|
|
}
|
|
|
|
public function refer(Request $request, Lead $lead): JsonResponse
|
|
{
|
|
$validated = $request->validate(['user_id' => 'required|integer|exists:users,id']);
|
|
$actor = $request->user();
|
|
abort_unless(AccessControl::canAccessLead($actor, $lead), 403, 'به این لید دسترسی ندارید.');
|
|
if ($actor->hasRole('agent')) {
|
|
abort_unless($lead->assigned_to === $actor->id, 403, 'فقط لید تحت مسئولیت خود را میتوانید ارجاع دهید.');
|
|
} else {
|
|
Gate::authorize('assign', $lead);
|
|
}
|
|
|
|
$target = User::whereKey($validated['user_id'])->where('is_active', true)->firstOrFail();
|
|
abort_unless($target->hasAnyRole(['agent', 'supervisor']), 422, 'مقصد ارجاع باید کارشناس یا مدیر فروش باشد.');
|
|
if (! $actor->hasRole('admin')) {
|
|
abort_unless((bool) array_intersect(AccessControl::teamIds($actor), AccessControl::teamIds($target)), 403, 'مقصد ارجاع خارج از تیم شما است.');
|
|
}
|
|
|
|
$updated = $this->assignmentService->assignToAgent($lead->id, $target->id, $actor->id);
|
|
ActivityLogger::log('lead_referred', "Lead {$lead->id} referred from {$actor->id} to {$target->id}", $updated);
|
|
|
|
return response()->json($updated->load('assignedAgent'));
|
|
}
|
|
|
|
public function returnToPool(int $leadId): JsonResponse
|
|
{
|
|
$leadModel = Lead::findOrFail($leadId);
|
|
Gate::authorize('assign', $leadModel);
|
|
|
|
$lead = $this->assignmentService->returnToPool($leadId);
|
|
|
|
return response()->json($lead);
|
|
}
|
|
|
|
private function canAssignToAgent(Lead $lead, User $agent): bool
|
|
{
|
|
return Gate::allows('assign', $lead) && $this->agentIsAssignable($agent);
|
|
}
|
|
|
|
private function agentIsAssignable(User $agent): bool
|
|
{
|
|
$user = auth()->user();
|
|
|
|
if (! $agent->hasRole('agent') || ! $agent->is_active) {
|
|
return false;
|
|
}
|
|
|
|
if ($user?->hasRole('admin')) {
|
|
return true;
|
|
}
|
|
|
|
if ($user?->hasRole('supervisor')) {
|
|
return (bool) array_intersect(AccessControl::teamIds($user), $agent->teams()->pluck('teams.id')->all());
|
|
}
|
|
|
|
return false;
|
|
}
|
|
}
|