Files
Investidor-V2/app/Http/Controllers/InvestmentStructureController.php
T
nala 250ac35fd1
tests / ci (push) Canceled after 0s
first commit
2026-09-28 10:01:09 +02:00

107 lines
6.0 KiB
PHP

<?php
namespace App\Http\Controllers;
use App\Models\ClusterProject;
use App\Models\EconomicCluster;
use App\Models\InvestmentGap;
use App\Models\Project;
use App\Models\ValueChain;
use App\Services\PortalAudit;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Illuminate\Validation\Rule;
use Inertia\Inertia;
use Inertia\Response;
class InvestmentStructureController extends Controller
{
public function index(Request $request, string $structure): Response
{
$filters = $request->validate(['q' => ['nullable', 'string', 'max:150']]);
$model = $structure === 'projects' ? Project::class : EconomicCluster::class;
$query = $model::query();
if ($term = $filters['q'] ?? null) {
$query->where(function ($q) use ($term): void {
$q->whereLike('name', "%{$term}%")->orWhereLike('code', "%{$term}%");
});
}
return Inertia::render('structures/index', ['structure' => $structure, 'filters' => $filters,
'records' => $query->orderBy('name')->orderBy('id')->paginate(20)->withQueryString()]);
}
public function edit(string $structure, ?string $id = null): Response
{
$model = $structure === 'projects' ? Project::class : EconomicCluster::class;
$record = $id ? $model::findOrFail($id) : null;
return Inertia::render('structures/editor', ['structure' => $structure, 'record' => $record,
'projects' => $structure === 'clusters' && $id ? Project::orderBy('name')->get(['id', 'name', 'code']) : [],
'chains' => $structure === 'clusters' && $id ? ValueChain::where('cluster_id', $id)->orderBy('code')->get() : [],
'gaps' => $structure === 'clusters' && $id ? InvestmentGap::where('cluster_id', $id)->orderBy('created_at')->get() : [],
'chainLinks' => $structure === 'clusters' && $id ? DB::table('value_chain_links')
->join('value_chains as origins', 'origins.id', '=', 'value_chain_links.from_value_chain_id')
->join('value_chains as destinations', 'destinations.id', '=', 'value_chain_links.to_value_chain_id')
->where('origins.cluster_id', $id)->where('destinations.cluster_id', $id)
->whereNull('origins.deleted_at')->whereNull('destinations.deleted_at')->whereNull('value_chain_links.deleted_at')
->orderBy('origins.code')->orderBy('destinations.code')
->get(['value_chain_links.id', 'origins.name as origin', 'destinations.name as destination', 'link_type']) : [],
'memberships' => $structure === 'clusters' && $id ? DB::table('cluster_projects')
->join('projects', 'projects.id', '=', 'cluster_projects.project_id')
->where('cluster_id', $id)->whereNull('cluster_projects.deleted_at')->whereNull('projects.deleted_at')
->orderBy('projects.name')->get(['cluster_projects.id', 'project_id', 'role', 'projects.name']) : [],
]);
}
public function save(Request $request, string $structure, ?string $id = null): RedirectResponse
{
$isProject = $structure === 'projects';
$model = $isProject ? Project::class : EconomicCluster::class;
$record = $id ? $model::findOrFail($id) : new $model;
$rules = [
'code' => ['required', 'string', 'max:100', Rule::unique($record->getTable(), 'code')->whereNull('deleted_at')->ignore($record->getKey())],
'name' => ['required', 'string', 'max:200'],
'status' => ['required', Rule::in($isProject ? ['draft', 'planned', 'active', 'suspended', 'completed', 'cancelled'] : ['planned', 'active', 'inactive'])],
];
if ($isProject) {
$rules += ['description' => ['nullable', 'string', 'max:10000'],
'budget_amount' => ['nullable', 'required_with:budget_currency', 'regex:/^\d{1,18}(\.\d{1,2})?$/'],
'budget_currency' => ['nullable', 'required_with:budget_amount', 'regex:/^[A-Z]{3}$/'],
'start_date' => ['nullable', 'date_format:Y-m-d'],
'end_date' => ['nullable', 'date_format:Y-m-d', ...($request->filled('start_date') ? ['after_or_equal:start_date'] : [])]];
} else {
$rules['sector'] = ['required', 'string', 'max:200'];
}
PortalAudit::save($record, $request->validate($rules), $request->user()->id);
return redirect('/management/'.$structure.'/'.$record->getKey().'/edit')->with('success', 'Registo guardado.');
}
public function linkProject(Request $request, EconomicCluster $cluster): RedirectResponse
{
$data = $request->validate(['project_id' => ['required', 'uuid', Rule::exists('projects', 'id')->whereNull('deleted_at')],
'role' => ['required', Rule::in(['anchor', 'complementary', 'supporting'])]]);
DB::transaction(function () use ($cluster, $data, $request) {
EconomicCluster::whereKey($cluster->id)->lockForUpdate()->firstOrFail();
$link = ClusterProject::where('cluster_id', $cluster->id)->where('project_id', $data['project_id'])->first() ?? new ClusterProject;
PortalAudit::save($link, [...$data, 'cluster_id' => $cluster->id], $request->user()->id);
});
return back()->with('success', 'Associação ao projecto guardada.');
}
public function saveChain(Request $request, EconomicCluster $cluster, ?ValueChain $chain = null): RedirectResponse
{
abort_if($chain && $chain->cluster_id !== $cluster->id, 404);
$data = $request->validate(['code' => ['required', 'string', 'max:100',
Rule::unique('value_chains', 'code')->where('cluster_id', $cluster->id)->whereNull('deleted_at')->ignore($chain?->id)],
'name' => ['required', 'string', 'max:200'],
'stage' => ['required', Rule::in(['input', 'production', 'processing', 'logistics', 'market'])]]);
PortalAudit::save($chain ?? new ValueChain, [...$data, 'cluster_id' => $cluster->id], $request->user()->id);
return back()->with('success', 'Etapa da cadeia de valor guardada.');
}
}