Files
compras/app/Services/OrganizationAccess.php
T
nala 48347e2d3a
tests / ci (push) Canceled after 0s
commit5
2026-10-30 10:55:18 +02:00

102 lines
4.2 KiB
PHP

<?php
namespace App\Services;
use App\Enums\PurchasingRole;
use App\Models\User;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Schema;
class OrganizationAccess
{
public const PERMISSIONS = [
'requester' => 'Solicitar e acompanhar compras próprias',
'department_head' => 'Supervisão e aprovação do departamento',
'procurement' => 'Preparação e gestão operacional de compras',
'finance' => 'Conferência e operações financeiras',
'warehouse' => 'Recepção e operações de armazém',
'admin' => 'Administrar a empresa, utilizadores e parametrização',
];
public function active(?int $tenant): bool
{
return $tenant !== null && Schema::hasTable('organization_access') && DB::table('organization_access')->where('tenant_id', $tenant)->where('active', true)->exists();
}
/** @return list<string> */
public function permissions(User $user): array
{
if ($user->tenant_id === null) {
return [];
}
if (! $this->active($user->tenant_id)) {
return $user->purchasing_role === null || $user->purchasing_role === PurchasingRole::Configured ? [] : [$user->purchasing_role->value];
}
$rows = DB::table('organization_memberships as m')->join('organization_profiles as p', 'p.id', '=', 'm.profile_id')
->where('m.tenant_id', $user->tenant_id)->where('p.tenant_id', $user->tenant_id)->where('m.user_id', $user->id)
->where(fn ($q) => $q->whereNull('m.expires_at')->orWhere('m.expires_at', '>', now()))->get(['p.permissions']);
$permissions = [];
foreach ($rows as $row) {
$permissions = [...$permissions, ...json_decode($row->permissions, true, 32, JSON_THROW_ON_ERROR)];
}
return array_values(array_unique($permissions));
}
/** @param list<PurchasingRole|string> $functions */
public function allows(User $user, array $functions): bool
{
$requested = array_map(fn ($f) => $f instanceof PurchasingRole ? $f->value : $f, $functions);
return $user->tenant_id !== null && count(array_intersect($this->permissions($user), $requested)) > 0;
}
public function maintenanceOnly(User $user): bool
{
if (! $this->active($user->tenant_id)) {
return false;
}
$valid = DB::table('organization_memberships')->where('tenant_id', $user->tenant_id)->where('user_id', $user->id)->where(fn ($q) => $q->whereNull('expires_at')->orWhere('expires_at', '>', now()));
return (clone $valid)->where('maintenance', true)->exists() && ! (clone $valid)->where('maintenance', false)->exists();
}
public function departmentScoped(User $user): bool
{
$permissions = $this->permissions($user);
return in_array('department_head', $permissions, true) && ! array_intersect($permissions, ['admin', 'procurement', 'finance']);
}
public function canRequest(User $user): bool
{
return $user->tenant_id !== null && ($this->active($user->tenant_id) ? $this->allows($user, ['requester']) : ($user->purchasing_role !== null && $user->purchasing_role !== PurchasingRole::Configured));
}
public function profileLabel(User $user): string
{
if (! $this->active($user->tenant_id)) {
return $user->purchasing_role?->label() ?? 'Utilizador';
}
return DB::table('organization_memberships as m')->join('organization_profiles as p', 'p.id', '=', 'm.profile_id')->where('m.tenant_id', $user->tenant_id)->where('p.tenant_id', $user->tenant_id)->where('m.user_id', $user->id)
->where(fn ($q) => $q->whereNull('m.expires_at')->orWhere('m.expires_at', '>', now()))->orderBy('p.name')->pluck('p.name')->unique()->implode(' · ');
}
/** @param list<string> $fields
* @return array<string,mixed>
*/
public function actorSnapshot(User $user, array $fields): array
{
$snapshot = $user->only($fields);
if ($this->active($user->tenant_id)) {
if (array_key_exists('purchasing_role', $snapshot)) {
$snapshot['purchasing_role'] = $user->purchasing_role->value ?? '';
}
$snapshot['profile_label'] = $this->profileLabel($user);
}
return $snapshot;
}
}