environment('payable-testing'), 403, 'Obrigações apenas no ensaio isolado.'); if ($c->getDriverName() !== 'pgsql' || ! preg_match('/^payable_sgf_[a-f0-9]{12}$/D', $c->getDatabaseName()) || $c->getConfig('host') !== '127.0.0.1' || $c->selectOne('select current_database() as d')->d !== $c->getDatabaseName()) { throw new \LogicException('PAYABLE_QA_DATABASE_REFUSED'); } } public function scope(User $u): array { self::guard(); $c = app(CompanyContext::class); abort_unless(auth()->id() === $u->id && $c->userId() === $u->id && $c->unitId(), 403); $ids = $c->identifiers(); app(Permissions::class)->require($u->id, $ids['tenant_id'], $ids['company_id'], 'supplier_payables.view', $c->unitId()); return $c->identifiers() + ['unit_id' => $c->unitId()]; } public function can(User $u, string $a): bool { return DB::table('pa_access')->where($this->scope($u))->where(['user_id' => $u->id, 'action' => $a])->exists(); } public function document(User $u, int $id): array { $row = DB::table('pa_imported_sources')->where($this->scope($u))->where('id', $id)->first() ?? abort(403, 'Origem não mapeada neste contexto.'); $s = json_decode($row->payload, true, 64, JSON_THROW_ON_ERROR); abort_unless(hash_equals($row->receipt_hash, hash('sha256', Payables::canonical($s))), 409, 'Recibo de origem divergente.'); $s['local_id'] = $id; return $s; } public function engine(User $u): Payables { $scope = $this->scope($u); $person = DB::table('pa_access')->where($scope)->where(['user_id' => $u->id, 'action' => 'view'])->value('person'); abort_unless($person, 403); return new Payables(DB::connection(), $u->id, $person, $scope, function (string $a) use ($u, $scope, $person) { self::guard(); DB::table('companies')->where('tenant_id', $scope['tenant_id'])->where('id', $scope['company_id'])->lockForUpdate()->firstOrFail(); DB::table('users')->where('id', $u->id)->lockForUpdate()->firstOrFail(); abort_unless(DB::table('pa_access')->where($scope)->where(['user_id' => $u->id, 'action' => 'view'])->value('person') === $person, 409, 'Identidade de pessoa alterada; reabra a proposta.'); abort_unless($this->scope($u) === $scope, 409, 'Contexto mudou.'); app(CompanyContext::class)->selectFor($u->id, $scope['tenant_id'], $scope['company_id'], $scope['unit_id']); abort_unless($this->can($u, 'view') && $this->can($u, $a), 403); }, fn (int $id) => $this->document($u, $id)); } public function listing(User $u): array { $d = $this->engine($u)->listing(DB::table('pa_imported_sources')->where($this->scope($u))->pluck('id')->all()); $d['permissions'] = ['prepare' => $this->can($u, 'prepare'), 'validate' => $this->can($u, 'validate')]; return $d; } }