authorizeAexAccess('aex.listings.view'); $business_id = $this->aexUtil->getBusinessId(); if ($request->ajax()) { $filters = $request->only([ 'status', 'listing_type', 'scope_type', 'seller_contact_id', 'assigned_broker_user_id', 'visibility', 'search', ]); $query = $this->listingService->listQuery($business_id, $filters); return DataTables::of($query) ->addColumn('seller_name', fn ($row) => $row->seller?->name ?? '—') ->addColumn('broker_name', fn ($row) => $row->broker?->user_full_name ?? $row->broker?->first_name ?? '—') ->addColumn('type_label', fn ($row) => $this->aexUtil->listingTypeLabel($row->listing_type)) ->addColumn('status_label', fn ($row) => $this->aexUtil->statusLabel($row->status)) ->addColumn('asking_price_fmt', fn ($row) => $this->aexUtil->formatMoney($row->asking_price)) ->addColumn('submitted_at_fmt', fn ($row) => $this->aexUtil->formatDateTime($row->submitted_at)) ->addColumn('action', function ($row) { $html = '
'; return $html; }) ->rawColumns(['action']) ->make(true); } return view('assetexchange::listings.index', [ 'statuses' => $this->aexUtil->statusLabels(), 'listing_types' => $this->aexUtil->listingTypeLabels(), 'contacts' => $this->aexUtil->getContactsDropdown($business_id), 'brokers' => User::forDropdown($business_id, false, false, true), ]); } public function create() { $this->authorizeAexAccess('aex.listings.create'); $business_id = $this->aexUtil->getBusinessId(); return view('assetexchange::listings.create', [ 'contacts' => $this->aexUtil->getContactsDropdown($business_id), 'listing_types' => $this->aexUtil->listingTypeLabels(), ]); } public function store(Request $request) { $this->authorizeAexAccess('aex.listings.create'); $business = $this->aexUtil->getBusiness(); if (! $business) { abort(404); } $data = $request->validate([ 'title' => 'required|string|max:255', 'listing_type' => 'required|in:machine_new,machine_used,production_line_full,production_line_partial,subsystem,spare_lot', 'scope_type' => 'sometimes|in:whole,partial,component', 'seller_contact_id' => 'nullable|exists:contacts,id', 'description' => 'nullable|string', 'location_text' => 'nullable|string|max:255', 'site_country' => 'nullable|string|max:100', 'year_manufactured' => 'nullable|integer|min:1900|max:2100', 'condition_grade' => 'nullable|string|max:50', 'asking_price' => 'nullable|integer|min:0', 'price_negotiable' => 'sometimes|boolean', 'visibility' => 'sometimes|in:internal,portal,public', ]); $data['price_negotiable'] = $request->boolean('price_negotiable', true); try { $listing = $this->listingService->create($business, $data, auth()->user()); } catch (\Throwable $e) { return $this->aexUtil->jsonOrRedirect($request, false, $e->getMessage()); } return $this->aexUtil->jsonOrRedirect( $request, true, __('assetexchange::lang.listing_created'), action([self::class, 'show'], [$listing->id]) ); } public function show($id) { $this->authorizeAexAccess('aex.listings.view'); $business_id = $this->aexUtil->getBusinessId(); $listing = Listing::where('business_id', $business_id) ->with(['seller', 'broker', 'appraisals', 'deals', 'offers', 'media', 'catalogMatches', 'researchCases', 'priceInquiries']) ->findOrFail($id); $activeResearch = $listing->researchCases() ->whereIn('status', ['open', 'in_progress', 'review']) ->latest('id') ->first(); return view('assetexchange::listings.show', compact('listing', 'activeResearch')); } public function edit($id) { $this->authorizeAexAccess('aex.listings.update'); $business_id = $this->aexUtil->getBusinessId(); $listing = Listing::where('business_id', $business_id)->findOrFail($id); if (in_array($listing->status, ['sold', 'rejected', 'withdrawn'], true)) { abort(403, __('assetexchange::lang.listing_not_editable')); } return view('assetexchange::listings.edit', [ 'listing' => $listing, 'contacts' => $this->aexUtil->getContactsDropdown($business_id), 'listing_types' => $this->aexUtil->listingTypeLabels(), ]); } public function update(Request $request, $id) { $this->authorizeAexAccess('aex.listings.update'); $business_id = $this->aexUtil->getBusinessId(); $listing = Listing::where('business_id', $business_id)->findOrFail($id); $data = $request->validate([ 'title' => 'sometimes|string|max:255', 'listing_type' => 'sometimes|in:machine_new,machine_used,production_line_full,production_line_partial,subsystem,spare_lot', 'scope_type' => 'sometimes|in:whole,partial,component', 'seller_contact_id' => 'nullable|exists:contacts,id', 'description' => 'nullable|string', 'location_text' => 'nullable|string|max:255', 'site_country' => 'nullable|string|max:100', 'year_manufactured' => 'nullable|integer|min:1900|max:2100', 'condition_grade' => 'nullable|string|max:50', 'asking_price' => 'nullable|integer|min:0', 'price_negotiable' => 'sometimes|boolean', 'visibility' => 'sometimes|in:internal,portal,public', ]); if ($request->has('price_negotiable')) { $data['price_negotiable'] = $request->boolean('price_negotiable'); } try { $listing = $this->listingService->update($listing, $data, auth()->user()); } catch (\Throwable $e) { return $this->aexUtil->jsonOrRedirect($request, false, $e->getMessage()); } return $this->aexUtil->jsonOrRedirect( $request, true, __('assetexchange::lang.listing_updated'), action([self::class, 'show'], [$listing->id]) ); } public function destroy(Request $request, $id) { $this->authorizeAexAccess('aex.listings.delete'); $business_id = $this->aexUtil->getBusinessId(); $listing = Listing::where('business_id', $business_id)->findOrFail($id); $listing->delete(); return $this->aexUtil->jsonOrRedirect( $request, true, __('assetexchange::lang.listing_deleted'), action([self::class, 'index']) ); } public function submit(Request $request, $id) { $this->authorizeAexAccess('aex.listings.update'); $business = $this->aexUtil->getBusiness(); $listing = Listing::where('business_id', $business->id)->findOrFail($id); try { $listing = $this->listingService->submit($business, $listing, auth()->user()); } catch (\Throwable $e) { return $this->aexUtil->jsonOrRedirect($request, false, $e->getMessage()); } return $this->aexUtil->jsonOrRedirect( $request, true, __('assetexchange::lang.listing_submitted'), action([self::class, 'show'], [$listing->id]) ); } public function assignBroker(Request $request, $id) { $this->authorizeAexAccess('aex.listings.update'); $business = $this->aexUtil->getBusiness(); $listing = Listing::where('business_id', $business->id)->findOrFail($id); $data = $request->validate([ 'broker_user_id' => 'required|exists:users,id', ]); try { $listing = $this->listingService->assignBroker( $business, $listing, (int) $data['broker_user_id'], auth()->user() ); } catch (\Throwable $e) { return $this->aexUtil->jsonOrRedirect($request, false, $e->getMessage()); } return $this->aexUtil->jsonOrRedirect( $request, true, __('assetexchange::lang.broker_assigned'), action([self::class, 'show'], [$listing->id]) ); } }