authorizeAexAccess('aex.research.view'); $business_id = $this->aexUtil->getBusinessId(); $query = ResearchCase::where('business_id', $business_id) ->with(['listing', 'leadResearcher', 'tasks']) ->orderByDesc('created_at'); if ($status = $request->get('status')) { $query->where('status', $status); } $cases = $query->paginate(25); return view('assetexchange::research.index', compact('cases')); } public function create(Request $request) { $this->authorizeAexAccess('aex.research.create'); $business_id = $this->aexUtil->getBusinessId(); $listing = null; if ($request->filled('listing_id')) { $listing = Listing::where('business_id', $business_id)->findOrFail($request->listing_id); } return view('assetexchange::research.create', [ 'listing' => $listing, 'listings' => Listing::where('business_id', $business_id)->orderByDesc('id')->limit(200)->pluck('title', 'id'), 'users' => User::forDropdown($business_id, false, false, true), ]); } public function store(Request $request) { $this->authorizeAexAccess('aex.research.create'); $business = $this->aexUtil->getBusiness(); $listing = Listing::where('business_id', $business->id)->findOrFail($request->listing_id); $data = $request->validate([ 'listing_id' => 'required|exists:aex_listings,id', 'title' => 'nullable|string|max:255', 'lead_researcher_id' => 'nullable|integer', 'spawn_templates' => 'sometimes|boolean', ]); try { $case = $this->researchService->openCase($business, $listing, [ 'title' => $data['title'] ?? null, 'lead_researcher_id' => $data['lead_researcher_id'] ?? null, 'spawn_templates' => $request->boolean('spawn_templates', true), 'force_new' => true, ], auth()->user()); } catch (\Throwable $e) { return redirect()->back()->with('status', $e->getMessage()); } return redirect() ->action([self::class, 'workspace'], [$case->id]) ->with('status', __('assetexchange::lang.research_case_opened')); } public function workspace($id) { $this->authorizeAexAccess('aex.research.view'); $business_id = $this->aexUtil->getBusinessId(); $case = ResearchCase::where('business_id', $business_id) ->with(['listing.media', 'listing.catalogMatches', 'tasks.assignee', 'leadResearcher']) ->findOrFail($id); return view('assetexchange::research.workspace', [ 'case' => $case, 'categories' => $this->aexUtil->researchCategoryLabels(), 'users' => User::forDropdown($business_id, false, false, true), ]); } public function assignTask(Request $request, $taskId) { $this->authorizeAexAccess('aex.research.manage'); $business_id = $this->aexUtil->getBusinessId(); $task = ResearchTask::where('business_id', $business_id)->findOrFail($taskId); $data = $request->validate([ 'assignee_user_id' => 'required|integer', 'sync_crm' => 'sometimes|boolean', ]); $this->researchService->assignTask($task, (int) $data['assignee_user_id'], $request->boolean('sync_crm', true)); return redirect()->back()->with('status', __('assetexchange::lang.task_assigned')); } public function completeTask(Request $request, $taskId) { $this->authorizeAexAccess('aex.research.manage'); $business_id = $this->aexUtil->getBusinessId(); $task = ResearchTask::where('business_id', $business_id)->findOrFail($taskId); $data = $request->validate([ 'findings' => 'nullable|string', 'market_links' => 'nullable|string', 'quoted_prices' => 'nullable|string', ]); $findingsJson = array_filter([ 'market_links' => $data['market_links'] ?? null, 'quoted_prices' => $data['quoted_prices'] ?? null, ]); $this->researchService->completeTask($task, [ 'findings' => $data['findings'] ?? null, 'findings_json' => $findingsJson ?: null, ], auth()->user()); return redirect()->back()->with('status', __('assetexchange::lang.task_completed')); } public function closeCase(Request $request, $id) { $this->authorizeAexAccess('aex.research.manage'); $business_id = $this->aexUtil->getBusinessId(); $case = ResearchCase::where('business_id', $business_id)->findOrFail($id); $data = $request->validate(['summary' => 'nullable|string']); $this->researchService->closeCase($case, $data['summary'] ?? null, auth()->user()); return redirect() ->action([self::class, 'workspace'], [$case->id]) ->with('status', __('assetexchange::lang.research_case_closed')); } }