> */ public function represented(User $actor): array { if (! $this->available()) { return []; } $readOnly = app(PortalProfileAccess::class)->has($actor, 'auditor'); return array_values(DB::table('memberships as m')->join('organizations as o', 'o.id', '=', 'm.organization_id') ->where('m.user_id', $actor->id)->whereNull('m.deleted_at')->whereNull('o.deleted_at') ->get(['o.id', 'o.name', 'o.version_no', 'o.incorporation_country_code', 'o.incorporation_country_provenance', 'm.role']) ->unique('id')->map(fn ($o) => ['id' => $o->id, 'name' => $o->name, 'version' => $o->version_no, 'country' => $o->incorporation_country_code, 'provenance' => json_decode($o->incorporation_country_provenance ?? 'null', true), 'canEdit' => ! $readOnly && in_array($o->role, ['admin', 'manager', 'officer'], true)])->all()); } public function authorize(User $actor, string $id, bool $write = false): void { abort_unless($this->available(), 409, 'Extensão do país de constituição ainda não instalada.'); abort_if($write && app(PortalProfileAccess::class)->has($actor, 'auditor'), 403, 'Auditor só consulta o cadastro mestre, mesmo com representação ou outros papéis.'); $roles = $write ? ['admin', 'manager', 'officer'] : ['admin', 'manager', 'officer', 'viewer']; abort_unless(DB::table('memberships')->where('organization_id', $id)->where('user_id', $actor->id) ->whereNull('deleted_at')->whereIn('role', $roles)->exists() && DB::table('organizations')->where('id', $id)->whereNull('deleted_at')->exists(), 403, 'Representação da organização não autorizada.'); } /** @param array $data * @return array{version:int, country:string} */ public function save(User $actor, string $id, array $data): array { $this->authorize($actor, $id, true); $data = Validator::make($data, ['version' => 'required|integer|min:1', 'country' => ['required', 'string', app(CountryCatalogue::class)->rule()], 'source_reference' => 'required|string|min:5|max:2000'], [ 'country.required' => 'Selecione o país de constituição da organização.', 'source_reference.required' => 'Indique a fonte ou referência deste país.', 'source_reference.min' => 'A referência deve ter pelo menos cinco caracteres.', ])->validate(); return DB::transaction(function () use ($actor, $id, $data) { DB::table('memberships')->where('organization_id', $id)->where('user_id', $actor->id)->lockForUpdate()->get(); $this->authorize($actor, $id, true); $row = DB::table('organizations')->where('id', $id)->lockForUpdate()->firstOrFail(); abort_unless((int) $row->version_no === (int) $data['version'], 409, 'Organização alterada. Recarregue.'); $provenance = ['kind' => 'representative_declaration', 'reference' => $data['source_reference'], 'actor_id' => $actor->id, 'at' => now()->toIso8601String(), 'source_system' => $row->source_system, 'external_id' => $row->external_id, 'verification' => 'country_declared_not_independently_verified']; DB::table('organizations')->where('id', $id)->update(['incorporation_country_code' => $data['country'], 'incorporation_country_provenance' => json_encode($provenance, JSON_THROW_ON_ERROR), 'version_no' => $row->version_no + 1]); DB::table('audit_events')->insert(['source_system' => 'organization-country', 'entity_type' => 'organizations', 'actor_user_id' => $actor->id, 'action' => 'incorporation_country_saved', 'data_classification' => 'restricted', 'before_data' => json_encode(['organization_id' => $id, 'snapshot' => Crypt::encryptString(json_encode($row, JSON_THROW_ON_ERROR))]), 'after_data' => json_encode(['organization_id' => $id, 'version' => $row->version_no + 1, 'snapshot' => Crypt::encryptString(json_encode(['country' => $data['country'], 'provenance' => $provenance], JSON_THROW_ON_ERROR))])]); return ['version' => $row->version_no + 1, 'country' => $data['country']]; }); } /** @return array */ public function snapshot(User $actor, string $id): array { $this->authorize($actor, $id); $org = DB::table('organizations')->where('id', $id)->lockForUpdate()->firstOrFail(); abort_unless($org->incorporation_country_code !== null, 422, 'País de constituição não informado no cadastro mestre.'); return ['organization_id' => $id, 'organization_version' => $org->version_no, 'country' => $org->incorporation_country_code, 'provenance' => json_decode($org->incorporation_country_provenance, true), 'reused_at' => now()->toIso8601String(), 'reused_by' => $actor->id]; } }