@@ -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)]);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user