61 lines
4.0 KiB
PHP
61 lines
4.0 KiB
PHP
<?php
|
|
|
|
namespace Tempo\Purchasing\Delivery;
|
|
|
|
/** Builds a review overlay; never writes to the source host. */
|
|
final class AccessOverlay
|
|
{
|
|
public const LABELS = [
|
|
'purchasing_sourcing.prepare'=>'Preparar consultas e cotações', 'purchasing_sourcing.evaluate'=>'Avaliar cotações',
|
|
'purchasing_sourcing.propose'=>'Propor adjudicação', 'purchasing_sourcing.confirm'=>'Confirmar adjudicação independente',
|
|
'purchasing_requisitions.view' => 'Consultar requisições', 'purchasing_requisitions.prepare' => 'Preparar e submeter requisições',
|
|
'purchasing_requisitions.configure' => 'Configurar Compras internas', 'purchasing_requisitions.approve.department_head' => 'Aprovar como responsável de departamento',
|
|
'purchasing_requisitions.approve.procurement' => 'Aprovar como responsável de Compras', 'purchasing_requisitions.approve.finance' => 'Aprovar como responsável financeiro',
|
|
'purchasing_budget.create' => 'Preparar dotações', 'purchasing_budget.approve' => 'Aprovar dotações', 'purchasing_budget.record' => 'Registar e libertar reservas orçamentais',
|
|
'purchasing_budget.consume' => 'Registar consumo orçamental', 'purchasing_budget.view' => 'Consultar orçamento',
|
|
'purchasing_budget.reinforcement.propose' => 'Propor reforços orçamentais', 'purchasing_budget.reinforcement.review' => 'Rever reforços orçamentais',
|
|
];
|
|
|
|
public const RIGHTS = [
|
|
'purchasing_sourcing.prepare','purchasing_sourcing.evaluate','purchasing_sourcing.propose','purchasing_sourcing.confirm',
|
|
'purchasing_requisitions.view', 'purchasing_requisitions.prepare', 'purchasing_requisitions.configure',
|
|
'purchasing_requisitions.approve.department_head', 'purchasing_requisitions.approve.procurement', 'purchasing_requisitions.approve.finance',
|
|
'purchasing_budget.create', 'purchasing_budget.approve', 'purchasing_budget.record', 'purchasing_budget.consume', 'purchasing_budget.view',
|
|
'purchasing_budget.reinforcement.propose', 'purchasing_budget.reinforcement.review',
|
|
];
|
|
|
|
public static function prepare(string $host): array
|
|
{
|
|
$paths = ['app/Modules/Identity/Services/Permissions.php', 'app/Modules/Identity/Services/IdentityWorkflow.php'];
|
|
$result = [];
|
|
foreach ($paths as $path) {
|
|
$source = file_get_contents($host.'/'.$path);
|
|
$before = hash('sha256', $source);
|
|
if (str_ends_with($path, '/Permissions.php')) {
|
|
$source = self::replace($source, "public const UNIT = ['unit.view', 'unit.edit'];", 'public const UNIT = '.var_export(['unit.view', 'unit.edit', ...self::RIGHTS], true).';');
|
|
} else {
|
|
// Expanding a catalogue must never expand creation-time grants.
|
|
$source = self::replace($source, 'foreach (Permissions::UNIT as $permission)', "foreach (['unit.view', 'unit.edit'] as \$permission)");
|
|
$source = self::replace($source,
|
|
"if (\$unit && \$data['permission'] === 'unit.edit')",
|
|
"if (\$unit && \$data['permission'] !== 'unit.view')");
|
|
$source = self::replace($source,
|
|
"if (\$this->permissions->has(\$target->id, \$tenant, \$company, 'unit.edit', \$unit)) { \$this->permissions->require(\$actor, \$tenant, \$company, 'unit.edit', \$unit); }",
|
|
"foreach ((clone \$query)->where('unit_id', \$unit)->whereIn('permission', Permissions::UNIT)->get() as \$existing) { \$this->permissions->require(\$actor, \$tenant, \$company, \$existing->permission, \$unit); }");
|
|
}
|
|
$result[$path] = ['before_sha256' => $before, 'after_sha256' => hash('sha256', $source), 'contents' => $source];
|
|
}
|
|
|
|
return $result;
|
|
}
|
|
|
|
private static function replace(string $source, string $old, string $new): string
|
|
{
|
|
if (substr_count($source, $old) !== 1) {
|
|
throw new \RuntimeException('Host divergiu: reconciliar a alteração de identidade antes de preparar a entrega.');
|
|
}
|
|
|
|
return str_replace($old, $new, $source);
|
|
}
|
|
}
|