CRM/backend/app/Http/Controllers/Api/AssignmentController.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;
}
}