varias alteracoes
tests / ci (push) Canceled after 0s

This commit is contained in:
2026-10-06 14:50:12 +02:00
parent 4f35313d06
commit e65cb26901
333 changed files with 54656 additions and 2058 deletions
@@ -0,0 +1,85 @@
<?php
namespace App\Http\Controllers;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Str;
use Illuminate\Validation\Rule;
class InvestmentStructureRelationController extends Controller
{
private const TABLES = [
'cluster-project' => ['cluster_projects', 'cluster_id', 'project_id', 'economic_clusters', 'projects'],
'corridor-project' => ['corridor_projects', 'corridor_id', 'project_id', 'development_corridors', 'projects'],
'corridor-cluster' => ['corridor_clusters', 'corridor_id', 'cluster_id', 'development_corridors', 'economic_clusters'],
];
public function store(Request $request, string $kind): RedirectResponse
{
[$table, $left, $right, $leftTable, $rightTable] = $this->definition($kind);
$data = $request->validate([
$left => ['required', 'uuid', Rule::exists($leftTable, 'id')->whereNull('deleted_at')],
$right => ['required', 'uuid', Rule::exists($rightTable, 'id')->whereNull('deleted_at')],
'association_type' => ['required', Rule::in(['official', 'influence', 'proximity', 'potential', 'historical'])],
'source_reference' => ['required', 'string', 'min:10', 'max:2000'],
'evidence_reference' => ['required', 'string', 'min:3', 'max:2000'],
'valid_from' => ['required', 'date_format:Y-m-d'],
'valid_until' => ['nullable', 'date_format:Y-m-d', 'after_or_equal:valid_from'],
...($kind === 'cluster-project' ? ['role' => ['required', Rule::in(['anchor', 'complementary', 'supporting'])]] : []),
]);
DB::transaction(function () use ($data, $table, $left, $right, $leftTable, $request): void {
DB::table($leftTable)->where('id', $data[$left])->lockForUpdate()->firstOrFail();
$existing = DB::table($table)->where($left, $data[$left])->where($right, $data[$right])->whereNull('deleted_at')->lockForUpdate()->first();
abort_if($existing !== null, 409, 'Associacao ja registada.');
$values = [...$data, 'association_type' => $data['association_type'], 'validation_status' => 'pending',
'editor_id' => $request->user()->id, 'validator_id' => null, 'version_no' => 1,
'deleted_at' => null, 'updated_at' => now()];
$id = (string) Str::uuid();
DB::table($table)->insert([...$values, 'id' => $id, 'source_system' => 'portal-management']);
$this->audit($request, $table, $id, 'submitted', 1);
});
return back()->with('success', 'Associacao submetida para revisao independente.');
}
public function review(Request $request, string $kind, string $id, string $action): RedirectResponse
{
abort_unless(in_array($action, ['validate', 'revoke'], true), 404);
[$table] = $this->definition($kind);
$data = $request->validate(['version_no' => ['required', 'integer', 'min:1']]);
DB::transaction(function () use ($request, $table, $id, $action, $data): void {
$relation = DB::table($table)->where('id', $id)->lockForUpdate()->first();
abort_unless($relation !== null, 404);
abort_if((int) $relation->version_no !== (int) $data['version_no'], 409, 'Versao da associacao alterada.');
if ($action === 'validate') {
abort_if((int) $relation->editor_id === (int) $request->user()->id, 403, 'A associacao exige revisao independente.');
abort_unless($relation->validation_status === 'pending' && $relation->source_reference && $relation->evidence_reference && $relation->valid_from, 422, 'Fonte, evidencia ou vigencia em falta.');
}
$nextVersion = (int) $relation->version_no + 1;
DB::table($table)->where('id', $id)->update(['validation_status' => $action === 'validate' ? 'validated' : 'revoked',
'validator_id' => $request->user()->id, 'version_no' => $nextVersion, 'updated_at' => now()]);
$this->audit($request, $table, $id, $action, $nextVersion);
});
return back()->with('success', $action === 'validate' ? 'Associacao validada.' : 'Associacao revogada.');
}
/** @return array{string,string,string,string,string} */
private function definition(string $kind): array
{
abort_unless(isset(self::TABLES[$kind]), 404);
return self::TABLES[$kind];
}
private function audit(Request $request, string $table, string $id, string $action, int $version): void
{
DB::table('audit_events')->insert(['source_system' => 'investment-structure-relations', 'entity_type' => $table,
'entity_id' => $id, 'actor_user_id' => $request->user()->id, 'action' => $action,
'after_data' => json_encode(['version_no' => $version, 'validation_status' => $action === 'validate' ? 'validated' : null], JSON_THROW_ON_ERROR)]);
}
}