76 lines
6.5 KiB
PHP
76 lines
6.5 KiB
PHP
<?php
|
|
|
|
namespace App\Shared\Installation;
|
|
|
|
use App\Models\User;
|
|
use App\Shared\Context\{CompanyContext,ModuleNavigation};
|
|
use Illuminate\Http\Request;
|
|
use Illuminate\Support\Facades\DB;
|
|
|
|
/** One explicit chooser over approved local identities, not an authentication bypass outside QA. */
|
|
final class PresentationEntry
|
|
{
|
|
private const TOUR=[
|
|
'commercial'=>['sgf:read_only','/?start=service_invoice_setup','Comercial','Clientes, orçamentos, documentos e PDF; passagem explícita para recebíveis'],
|
|
'purchasing'=>['purchasing:actor','/purchasing/workspace','Compras','Fornecedores, requisição, propostas, ordem, recepção, factura e obrigação'],
|
|
'stock'=>['purchasing:validator','/stock/final','Stock','Artigos, armazéns, existências, trânsito, lotes, contagem e histórico'],
|
|
'workshop'=>['sgf:workshop_manage','/?start=workshop','Oficinas','Equipamento, cliente, agenda, ordem, autorização e apontamentos verificados'],
|
|
'finance'=>['sgf:read_only','/?start=service_receivables','Financeiro','Recebíveis, obrigações, Caixa, conferência de extracto e indicadores'],
|
|
'accounting'=>['sgf:read_only','/general-ledger','Contabilidade','Origens, diário integrado, plano, balancete, razão e mapas fiscais internos'],
|
|
'human_resources'=>['hr:hr_read','/?start=remunerations','Recursos Humanos','Cadastro fictício, regras artificiais, processamento interno e revisão distinta; acesso próprio'],
|
|
];
|
|
private function guard():void
|
|
{
|
|
abort_unless(in_array(request()->ip(),['127.0.0.1','::1'],true),404);
|
|
CompositionRuntime::assert();
|
|
abort_unless(is_string(config('sgf_single_installation.profiles_sha256'))&&preg_match('/^[a-f0-9]{64}$/D',config('sgf_single_installation.profiles_sha256')),503);
|
|
}
|
|
|
|
private function profiles():array
|
|
{
|
|
$pin=config('sgf_single_installation.profiles_sha256');$out=[];$context=app(CompanyContext::class);
|
|
$rows=DB::table('sgf_presentation_profiles')->orderBy('profile_key')->get();
|
|
abort_unless($rows->count()===10&&$rows->every(fn($r)=>hash_equals($r->source_hash,$pin)),503,'Perfis QA não conferidos.');
|
|
try{
|
|
foreach($rows as $row){
|
|
$context->selectFor((int)$row->user_id,(int)$row->tenant_id,(int)$row->company_id,(int)$row->unit_id);
|
|
$out['sgf:'.$row->profile_key]=['user_id'=>(int)$row->user_id,'label'=>$row->label,'scope'=>['tenant_id'=>(int)$row->tenant_id,'company_id'=>(int)$row->company_id,'unit_id'=>(int)$row->unit_id],'modules'=>app(ModuleNavigation::class)->available($context)];
|
|
}
|
|
if(config('human_resources.enabled')===true){foreach(HumanResourcesProfiles::registered() as$row){
|
|
$context->selectFor($row->user_id,$row->tenant_id,$row->company_id,$row->unit_id);
|
|
$out['hr:'.$row->profile_key]=['user_id'=>$row->user_id,'label'=>$row->label,'scope'=>['tenant_id'=>$row->tenant_id,'company_id'=>$row->company_id,'unit_id'=>$row->unit_id],'modules'=>app(ModuleNavigation::class)->available($context)];
|
|
}}
|
|
$scope=config('purchasing_workspace.scope');
|
|
foreach(config('purchasing_workspace.profiles',[]) as $key=>$profile){
|
|
$context->selectFor($profile['user_id'],$scope['tenant_id'],$scope['company_id'],$scope['unit_id']);
|
|
$out['purchasing:'.$key]=['user_id'=>$profile['user_id'],'label'=>$profile['label'].' — Compras','scope'=>$scope,'modules'=>app(ModuleNavigation::class)->available($context)];
|
|
}
|
|
}finally{$context->clear();}
|
|
return $out;
|
|
}
|
|
|
|
public function screen(Request $r)
|
|
{
|
|
$this->guard();abort_if($r->query()!==[],422);
|
|
$profiles=$this->profiles();$tour=[];foreach(self::TOUR as $module=>[$key,$url,$label,$description])if(isset($profiles[$key])&&in_array($module,array_column($profiles[$key]['modules'],'id'),true))$tour[$module]=['profile'=>$key,'function'=>$profiles[$key]['label'],'label'=>$label,'description'=>$description];
|
|
$primary=['commercial'=>['sgf:commercial_prepare','sgf:commercial_review'],'purchasing'=>array_map(fn($id)=>'purchasing:'.$id,['requester','approver','actor','issuer','validator','reviewer','auditor']),'stock'=>['purchasing:validator','sgf:workshop_verify','sgf:read_only'],'workshop'=>['sgf:workshop_manage','sgf:workshop_record','sgf:workshop_verify','sgf:finance_prepare','sgf:finance_review','purchasing:validator'],'finance'=>['sgf:finance_prepare','sgf:finance_review'],'accounting'=>['sgf:accounting_prepare','sgf:accounting_review','sgf:finance_prepare','sgf:finance_review']];
|
|
if(config('human_resources.enabled')===true)$primary['human_resources']=['hr:hr_prepare','hr:hr_review','hr:hr_read'];
|
|
$moduleProfiles=[];foreach($primary as $module=>$keys)foreach($keys as $key)if(isset($profiles[$key])&&in_array($module,array_column($profiles[$key]['modules'],'id'),true))$moduleProfiles[$module][$key]=$profiles[$key];
|
|
return response()->view('sgf-presentation-entry',['profiles'=>$profiles,'tour'=>$tour,'moduleProfiles'=>$moduleProfiles])->header('Cache-Control','no-store')->header('X-SGF-Installation',CompositionRuntime::physical()['composition']);
|
|
}
|
|
|
|
public function enter(Request $r)
|
|
{
|
|
$this->guard();$d=$r->validate(['profile'=>'required|string|max:100','module_id'=>'required|string|max:30','landing'=>'sometimes|in:'.implode(',',array_keys(self::TOUR))]);
|
|
abort_if(array_diff(array_keys($r->all()),['_token','profile','module_id','landing']),422);
|
|
$target='/';if(isset($d['landing'])){$route=self::TOUR[$d['landing']];abort_unless($d['profile']===$route[0]&&$d['module_id']===$d['landing'],403);$target=$route[1];}
|
|
$profile=$this->profiles()[$d['profile']]??null;
|
|
abort_unless($profile&&in_array($d['module_id'],array_column($profile['modules'],'id'),true),403,'Função ou módulo não autorizado.');
|
|
$user=User::findOrFail($profile['user_id']);auth()->login($user);$r->session()->regenerate();
|
|
$r->session()->put('auth_version',$user->auth_version);
|
|
$r->session()->put('company_context',$profile['scope']+['module_id'=>$d['module_id'],'token'=>bin2hex(random_bytes(24))]);
|
|
\App\Modules\Identity\Services\Audit::record('context.synthetic_profile_selected',$user->id,$profile['scope']['tenant_id'],$profile['scope']['company_id'],$profile['scope']['unit_id'],details:['module_id'=>$d['module_id'],'reason'=>'Escolha explícita da função QA aprovada, na instalação única.']);
|
|
return redirect($target);
|
|
}
|
|
}
|