json(InvestmentLegalSource::orderByDesc('created_at')->paginate(20)); } public function store(Request $request): JsonResponse { $data = $request->validate(['title' => ['required', 'string', 'max:255'], 'url' => ['required', 'url:https', 'max:2000'], 'diploma' => ['required', 'string', 'max:255'], 'article' => ['required', 'string', 'max:255'], 'competent_entity' => ['required', 'string', 'max:255'], 'valid_from' => ['required', 'date_format:Y-m-d'], 'valid_until' => ['nullable', 'date_format:Y-m-d', 'after_or_equal:valid_from']]); return DB::transaction(function () use ($request, $data) { $source = InvestmentLegalSource::create([...$data, 'owner_id' => $request->user()->id]); $source->refresh(); $this->audit($source, $request->user()->id, 'created'); return response()->json($source->fresh(), 201); }); } public function transition(Request $request, string $id, string $action): JsonResponse { if ($action === 'validate') { InvestmentZoneAccess::requireRole($request->user(), 'legal_reviewers'); } $data = $request->validate(['version_no' => ['required', 'integer', 'min:1']]); return DB::transaction(function () use ($request, $id, $action, $data) { $source = InvestmentLegalSource::whereKey($id)->lockForUpdate()->firstOrFail(); abort_if((int) $source->version_no !== (int) $data['version_no'], 409, 'Versão alterada.'); if ($action === 'validate') { abort_if((int) $source->owner_id === $request->user()->id, 403, 'Outra pessoa deve validar a fonte.'); abort_unless($source->validation_status === 'pending', 422, 'Crie nova referência para substituir fonte revogada.'); } $source->fill(['validation_status' => $action === 'validate' ? 'validated' : 'revoked', 'version_no' => (int) $source->version_no + 1, 'validator_id' => $action === 'validate' ? $request->user()->id : $source->validator_id, 'validated_at' => $action === 'validate' ? now() : $source->validated_at])->save(); $this->audit($source, $request->user()->id, $action); return response()->json($source); }); } private function audit(InvestmentLegalSource $source, int $actor, string $action): void { DB::table('audit_events')->insert(['source_system' => 'investment-zones', 'entity_type' => 'investment_legal_sources', 'entity_id' => $source->getKey(), 'actor_user_id' => $actor, 'action' => $action, 'after_data' => json_encode(['version_no' => $source->version_no, 'validation_status' => $source->validation_status, 'sha256' => hash('sha256', $source->toJson())], JSON_THROW_ON_ERROR)]); } }