76 lines
4.8 KiB
PHP
76 lines
4.8 KiB
PHP
<?php
|
|
|
|
namespace App\Http\Controllers;
|
|
|
|
use App\Models\InvestmentZone;
|
|
use Illuminate\Http\JsonResponse;
|
|
use Illuminate\Http\Request;
|
|
use Illuminate\Support\Facades\DB;
|
|
use Illuminate\Support\Str;
|
|
use Illuminate\Validation\Rule;
|
|
|
|
class InvestmentZoneRelationController extends Controller
|
|
{
|
|
public function store(Request $request, string $id): JsonResponse
|
|
{
|
|
$data = $request->validate(['cluster_id' => ['nullable', 'required_without_all:corridor_id,project_id', 'prohibits:corridor_id,project_id', 'uuid', Rule::exists('economic_clusters', 'id')->whereNull('deleted_at')],
|
|
'corridor_id' => ['nullable', 'required_without_all:cluster_id,project_id', 'prohibits:cluster_id,project_id', 'uuid', Rule::exists('development_corridors', 'id')->whereNull('deleted_at')],
|
|
'project_id' => ['nullable', 'required_without_all:cluster_id,corridor_id', 'prohibits:cluster_id,corridor_id', 'uuid', Rule::exists('projects', 'id')->whereNull('deleted_at')],
|
|
'association_type' => ['required', 'in:official,influence,proximity,potential,historical'],
|
|
'role' => ['required', 'in:primary,beneficiary,served,enabled,dependent,related,potential,historical'],
|
|
'source_reference' => ['required', 'string', 'min:10', 'max:2000'], 'justification' => ['required', 'string', 'min:10', 'max:3000'],
|
|
'legal_source_id' => ['nullable', 'required_if:association_type,official', 'uuid', 'exists:investment_legal_sources,id'],
|
|
'valid_from' => ['required', 'date_format:Y-m-d'], 'valid_until' => ['nullable', 'date_format:Y-m-d', 'after_or_equal:valid_from'],
|
|
'priority' => ['sometimes', 'integer', 'between:0,100'], 'is_primary' => ['sometimes', 'boolean']]);
|
|
|
|
return DB::transaction(function () use ($request, $id, $data) {
|
|
InvestmentZone::whereKey($id)->lockForUpdate()->firstOrFail();
|
|
$query = DB::table('investment_zone_relations')->where('zone_id', $id);
|
|
foreach (['cluster_id', 'corridor_id', 'project_id'] as $field) {
|
|
if (! empty($data[$field])) {
|
|
$query->where($field, $data[$field]);
|
|
}
|
|
}
|
|
abort_if($query->exists(), 409, 'Relação já registada.');
|
|
$relation = (string) Str::uuid();
|
|
DB::table('investment_zone_relations')->insert([...$data, 'id' => $relation, 'zone_id' => $id,
|
|
'editor_id' => $request->user()->id, 'created_at' => now(), 'updated_at' => now()]);
|
|
$this->audit($relation, $request->user()->id, 'created', 1);
|
|
|
|
return response()->json(DB::table('investment_zone_relations')->where('id', $relation)->first(), 201);
|
|
});
|
|
}
|
|
|
|
public function review(Request $request, string $id, string $action): JsonResponse
|
|
{
|
|
$data = $request->validate(['version_no' => ['required', 'integer', 'min:1']]);
|
|
|
|
return DB::transaction(function () use ($request, $id, $action, $data) {
|
|
$relation = DB::table('investment_zone_relations')->where('id', $id)->lockForUpdate()->first();
|
|
abort_unless($relation !== null, 404);
|
|
abort_if((int) $relation->version_no !== (int) $data['version_no'], 409, 'Versão alterada.');
|
|
if ($action === 'validate') {
|
|
abort_if((int) $relation->editor_id === $request->user()->id, 403, 'A relação exige revisão independente.');
|
|
abort_unless($relation->validation_status === 'pending', 422, 'Relação já analisada.');
|
|
if ($relation->legal_source_id) {
|
|
$source = DB::table('investment_legal_sources')->where('id', $relation->legal_source_id)->lockForUpdate()->first();
|
|
abort_unless($source && $source->validation_status === 'validated' && $source->valid_from <= today()->toDateString()
|
|
&& (! $source->valid_until || $source->valid_until >= today()->toDateString()), 422, 'Fonte válida em falta.');
|
|
}
|
|
}
|
|
DB::table('investment_zone_relations')->where('id', $id)->update(['validation_status' => $action === 'validate' ? 'validated' : 'revoked',
|
|
'validator_id' => $action === 'validate' ? $request->user()->id : $relation->validator_id,
|
|
'version_no' => $relation->version_no + 1, 'updated_at' => now()]);
|
|
$this->audit($id, $request->user()->id, $action, $relation->version_no + 1);
|
|
|
|
return response()->json(DB::table('investment_zone_relations')->where('id', $id)->first());
|
|
});
|
|
}
|
|
|
|
private function audit(string $id, int $actor, string $action, int $version): void
|
|
{
|
|
DB::table('audit_events')->insert(['source_system' => 'investment-zones', 'entity_type' => 'investment_zone_relations', 'entity_id' => $id,
|
|
'actor_user_id' => $actor, 'action' => $action, 'after_data' => json_encode(['version_no' => $version], JSON_THROW_ON_ERROR)]);
|
|
}
|
|
}
|