user()->can('score_leads') && AccessControl::canAccessLead($request->user(), $lead), 403); return response()->json($this->scoring->score($lead)); } public function bulkScore(Request $request): JsonResponse { abort_unless($request->user()->can('score_leads'), 403); $ids = $request->validate(['ids' => 'required|array|min:1|max:100', 'ids.*' => 'integer|exists:leads,id'])['ids']; $query = Lead::whereKey($ids); AccessControl::scopeLeads($query, $request->user()); $scored = $query->get()->map(fn (Lead $lead) => $this->scoring->score($lead)); return response()->json(['count' => $scored->count(), 'data' => $scored]); } public function slaRules(Request $request): JsonResponse { abort_unless($request->user()->can('view_sla'), 403); return response()->json(SlaRule::where('event', '!=', 'stale_deal')->latest()->get()); } public function storeSlaRule(Request $request): JsonResponse { abort_unless($request->user()->can('manage_sla'), 403); $data = $request->validate([ 'name' => 'required|string|max:120', 'event' => 'required|in:first_contact,follow_up', 'warning_minutes' => 'required|integer|min:1|max:525600', 'breach_minutes' => 'required|integer|gt:warning_minutes|max:525600', 'scope' => 'nullable|array|max:10', 'is_active' => 'boolean', ]); return response()->json(SlaRule::create($data + ['created_by' => $request->user()->id]), 201); } public function breaches(Request $request): JsonResponse { abort_unless($request->user()->can('view_sla'), 403); $query = SlaBreach::with('rule:id,name,event', 'assignee:id,name', 'breachable'); if ($request->user()->hasRole('agent')) { $query->where('assigned_to', $request->user()->id); } elseif ($request->user()->hasRole('supervisor')) { $query->whereIn('assigned_to', AccessControl::teamMemberIds($request->user())); } if ($request->filled('status')) { $query->where('status', $request->string('status')); } return response()->json($query->latest()->paginate(min((int) $request->get('per_page', 20), 100))); } public function detect(Request $request): JsonResponse { abort_unless($request->user()->can('manage_sla'), 403); return response()->json(['created' => $this->slaMonitor->run()]); } public function resolve(Request $request, SlaBreach $slaBreach): JsonResponse { abort_unless($request->user()->can('manage_sla') || $slaBreach->assigned_to === $request->user()->id, 403); $slaBreach->update(['status' => 'resolved', 'resolved_at' => now()]); ActivityLogger::log('sla_breach_resolved', "SLA breach {$slaBreach->id} resolved", $slaBreach); return response()->json($slaBreach->fresh(['rule', 'assignee:id,name'])); } }