Files
SGF/app/Modules/Purchasing/SupplierPayables.php
T
2026-10-29 18:43:29 +02:00

73 lines
3.3 KiB
PHP

<?php
namespace App\Modules\Purchasing;
use App\Models\User;
use App\Modules\Identity\Services\Permissions;
use App\Shared\Context\CompanyContext;
use Illuminate\Support\Facades\DB;
use Tempo\Finance\Payables\Payables;
final class SupplierPayables
{
public static function guard(): void
{
$c = DB::connection();
abort_unless(app()->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;
}
}