is('management/*', 'api/v2/investment/admin/*'); $zone = ($management ? InvestmentZone::query() : $zones->visible())->findOrFail($id); $publicFields = ['id', 'code', 'category', 'name', 'name_en', 'description', 'description_en', 'province', 'district', 'validation_status', 'updated_at']; $source = DB::table('investment_legal_sources')->where('id', $zone->legal_source_id)->first(['title', 'url', 'diploma', 'article', 'competent_entity', 'valid_from', 'valid_until', 'version_no']); $operator = DB::table('organizations')->where('id', $zone->operator_id)->whereNull('deleted_at') ->when(! $management, fn ($q) => $q->where('data_classification', 'public'))->value('name'); $field = ['zee' => 'zee_id', 'zfi' => 'zfi_id', 'industrial_park' => 'park_id'][$zone->category] ?? null; $opportunities = $field && ! $management ? app(InvestmentCatalogue::class)->query([$field => $id])->paginate(12)->withQueryString() : null; $related = collect(); foreach (['cluster_id', 'corridor_id', 'project_id'] as $foreign) { $relations = $zones->links(true)->where('zl.zone_id', $id)->whereNotNull('zl.'.$foreign); $related = $related->merge(InvestmentPortfolioController::visible()->whereIn($foreign, $relations->select('zl.'.$foreign))->get()); } $props = ['record' => $management ? $zone : $zone->only($publicFields), 'source' => $source, 'operator' => $operator, 'management' => $management, 'related' => $related->unique('id')->values(), 'relations' => $management ? DB::table('investment_zone_relations')->where('zone_id', $id)->orderByDesc('created_at')->limit(100)->get() : [], 'geometries' => $management ? DB::table('investment_zone_geometries')->where('zone_id', $id)->orderByDesc('created_at')->limit(100)->get() : [], 'targets' => $management ? ['opportunities' => Opportunity::orderBy('title')->limit(200)->get(['id', 'title']), 'dossiers' => InvestmentDossier::orderBy('title')->limit(200)->get(['id', 'title', 'project_id', 'cluster_id', 'corridor_id'])] : null, 'opportunities' => $opportunities, 'legalSources' => $management ? DB::table('investment_legal_sources')->orderByDesc('created_at')->limit(100)->get() : [], 'operators' => $management ? DB::table('organizations')->whereNull('deleted_at')->orderBy('name')->limit(200)->get(['id', 'name']) : [], 'links' => $management ? DB::table('investment_zone_links')->where('zone_id', $id)->orderByDesc('created_at')->limit(100)->get() : [], 'revisions' => $management ? DB::table('investment_zone_revisions')->where('zone_id', $id)->orderByDesc('version_no')->limit(20)->get(['version_no', 'action', 'sha256', 'created_at']) : []]; return $request->is('api/*') ? response()->json($props) : Inertia::render('investment/zone', $props); } public function index(Request $request, InvestmentZones $zones): Response|JsonResponse { $filters = $request->validate(['category' => ['nullable', 'in:zee,zfi,industrial_park'], 'q' => ['nullable', 'string', 'max:120'], 'page' => ['nullable', 'integer', 'min:1'], 'province_id' => ['nullable', 'uuid'], 'district_id' => ['nullable', 'uuid'], 'admin_post_id' => ['nullable', 'uuid'], 'locality_id' => ['nullable', 'uuid']]); $management = $request->is('management/*', 'api/v2/investment/admin/*'); $query = $management ? InvestmentZone::query() : $zones->visible(); $path = app(InvestmentGeography::class)->selection($filters); if ($path !== []) { $query->whereIn('primary_territory_id', app(InvestmentGeography::class)->descendants($path[array_key_last($path)]->id)); } $rows = $query->when($filters['category'] ?? null, fn ($q, $v) => $q->where('category', $v)) ->when($filters['q'] ?? null, fn ($q, $v) => $q->where(fn ($q) => $q->where('name', 'ilike', '%'.$v.'%')->orWhere('code', 'ilike', '%'.$v.'%'))) ->orderBy('name')->orderBy('id')->paginate(12, $management ? ['*'] : ['id', 'code', 'name', 'name_en', 'category', 'province', 'district', 'description', 'description_en', 'validation_status', 'updated_at'])->withQueryString(); $props = ['records' => $rows, 'filters' => $filters, 'management' => $management, 'territorySelection' => $path]; return $request->is('api/*') ? response()->json($props) : Inertia::render('investment/zones', $props); } public function save(Request $request, InvestmentZones $zones, ?string $id = null): JsonResponse { $data = $request->validate(['version_no' => [$id ? 'required' : 'nullable', 'integer', 'min:1'], 'code' => ['required', 'string', 'max:80', Rule::unique('investment_zones')->ignore($id)], 'category' => ['required', 'in:zee,zfi,industrial_park,pending'], 'name' => ['required', 'string', 'max:255'], 'name_en' => ['nullable', 'string', 'max:255'], 'description' => ['nullable', 'string', 'max:15000'], 'description_en' => ['nullable', 'string', 'max:15000'], 'province' => ['nullable', 'string', 'max:100'], 'district' => ['nullable', 'string', 'max:100'], 'operator_id' => ['nullable', 'uuid', Rule::exists('organizations', 'id')->whereNull('deleted_at')], 'legal_source_id' => ['nullable', 'uuid', 'exists:investment_legal_sources,id']]); if (! $id && $request->has('province_id')) { $geo = $request->validate(['province_id' => ['nullable', 'uuid'], 'district_id' => ['nullable', 'uuid'], 'admin_post_id' => ['nullable', 'uuid'], 'locality_id' => ['nullable', 'uuid']]); $path = app(InvestmentGeography::class)->selection($geo); $data['primary_territory_id'] = $path === [] ? null : $path[array_key_last($path)]->id; $data['territory_version'] = $path === [] ? 0 : 1; $data['province'] = $path[0]->name ?? null; $data['district'] = $path[1]->name ?? null; } return response()->json($zones->save($id, $data, $request->user()->id), $id ? 200 : 201); } public function transition(Request $request, InvestmentZones $zones, string $id, string $action): JsonResponse { if ($action === 'publish') { InvestmentZoneAccess::requireRole($request->user(), 'publishers'); } $data = $request->validate(['version_no' => ['required', 'integer', 'min:1']]); return response()->json($action === 'publish' ? $zones->publish($id, $data['version_no'], $request->user()->id) : $zones->suspend($id, $data['version_no'], $request->user()->id)); } public function revisions(string $id): JsonResponse { InvestmentZone::findOrFail($id); return response()->json(DB::table('investment_zone_revisions')->where('zone_id', $id)->orderByDesc('version_no')->paginate(20, ['id', 'version_no', 'actor_id', 'action', 'sha256', 'created_at'])); } }