48 lines
4.9 KiB
PHP
48 lines
4.9 KiB
PHP
<?php
|
|
namespace App\Shared\Geography;
|
|
|
|
use App\Shared\Context\{CompanyContext,ModuleRecords};
|
|
use App\Modules\Identity\Services\Permissions;
|
|
use App\Modules\Purchasing\{ReceiptRuntime,SupplierAccess};
|
|
use Illuminate\Support\Facades\DB;
|
|
|
|
/** Geographic segmentation metadata; canonical addresses and supplier financial review are unchanged. */
|
|
final class Locations
|
|
{
|
|
public function run(string $kind,int $id,bool $edit,\Closure $work):mixed
|
|
{
|
|
Catalogue::guard();abort_unless(in_array($kind,['company','unit','client','supplier'],true)&&$id>0,404);
|
|
$ctx=app(CompanyContext::class);$s=$ctx->identifiers();$unit=$ctx->unitId();$actor=$ctx->userId();$host=DB::connection();$generation=hash('sha256',json_encode([$s,$unit,request()->session()->get('company_context.module_id'),request()->session()->get('company_context.token')],JSON_THROW_ON_ERROR));
|
|
return $host->transaction(function()use($kind,$id,$edit,$work,$ctx,$s,$unit,$actor,$host,$generation){
|
|
$host->table('companies')->where('id',$s['company_id'])->where('tenant_id',$s['tenant_id'])->lockForUpdate()->firstOrFail();$host->table('users')->where('id',$actor)->lockForUpdate()->firstOrFail();
|
|
abort_unless($host->table('company_memberships')->where($s)->where('user_id',$actor)->lockForUpdate()->first(),403);
|
|
$require=function(string $right,?int $u=null)use($host,$s,$actor){abort_unless($host->table('permission_grants')->where($s)->where(['user_id'=>$actor,'permission'=>$right,'unit_id'=>$u])->lockForUpdate()->first(),403);};
|
|
$require('company.view');if($unit!==null)$require('unit.view',$unit);
|
|
$base=$s+['unit_key'=>0,'module_key'=>'general','kind'=>$kind,'entity_id'=>$id,'provider'=>'sgf'];
|
|
if($kind==='supplier'){
|
|
abort_unless($unit!==null,403);$base['unit_key']=$unit;$base['module_key']='purchasing';
|
|
return app(ReceiptRuntime::class)->run($edit?'purchasing_suppliers.prepare':'purchasing_suppliers.view',function($native,$binding,$fingerprint,$origin)use($id,$edit,$work,$base,$host,$actor,$generation){
|
|
abort_unless($native->hasFunctions($edit?['procurement']:['admin','procurement','finance','department_head']),403);
|
|
$supplier=SupplierAccess::query($binding,$origin['sgf_context_key'])->lockForUpdate()->findOrFail($id);
|
|
if($edit)abort_unless(app(\Tempo\Purchasing\Embedded\Services\SupplierParticipation::class)->canPrepare($native),403);
|
|
$scope=$base;$scope['provider']=hash('sha256',DB::connection()->getDatabaseName());$entity=['id'=>$id,'name'=>$supplier->name,'version'=>(int)$supplier->version,'editable'=>$host->table('permission_grants')->where(['tenant_id'=>$base['tenant_id'],'company_id'=>$base['company_id'],'unit_id'=>$base['unit_key'],'user_id'=>$actor,'permission'=>'purchasing_suppliers.prepare'])->exists()&&app(\Tempo\Purchasing\Embedded\Services\SupplierParticipation::class)->canPrepare($native)];
|
|
return $work($host,$scope,$entity,$actor,hash('sha256',$fingerprint.$generation));
|
|
});
|
|
}
|
|
if($kind==='company'){abort_unless($id===$s['company_id'],403);$require($edit?'company.edit':'company.view');$entity=$host->table('companies')->where('tenant_id',$s['tenant_id'])->where('id',$id)->lockForUpdate()->first();}
|
|
elseif($kind==='unit'){abort_unless($id===$unit,403);$require($edit?'unit.edit':'unit.view',$id);$base['unit_key']=$id;$entity=$host->table('units')->where($s)->where('id',$id)->lockForUpdate()->first();}
|
|
else{$require('clients.view');if($edit)$require('clients.edit');abort_unless(ModuleRecords::active()==='commercial',403);$base['module_key']='commercial';$entity=ModuleRecords::query('a_clients')->where($s)->whereNull('unit_id')->where('id',$id)->lockForUpdate()->first();}
|
|
abort_unless($entity,403,'Registo fora do âmbito autorizado.');return $work($host,$base,['id'=>$id,'name'=>$entity->name,'version'=>(int)($entity->version??0),'updated_at'=>$entity->updated_at??null,'editable'=>$host->table('permission_grants')->where($s)->where(['unit_id'=>$kind==='unit'?$id:null,'user_id'=>$actor,'permission'=>match($kind){'company'=>'company.edit','unit'=>'unit.edit','client'=>'clients.edit'}])->exists()],$actor,$generation);
|
|
});
|
|
}
|
|
public static function current($db,array $scope):?array
|
|
{
|
|
$r=$db->table('geo_locations')->where($scope)->first();return $r?['revision'=>(int)$r->revision,'selection'=>$r->selection===null?null:json_decode($r->selection,true),'actor_id'=>(int)$r->actor_id,'reason'=>$r->reason,'updated_at'=>$r->updated_at]:null;
|
|
}
|
|
public static function hash(mixed $v):string{return hash('sha256',json_encode($v,JSON_THROW_ON_ERROR));}
|
|
public static function useHost($host,\Closure $work):mixed
|
|
{
|
|
$old=DB::getDefaultConnection();DB::setDefaultConnection($host->getName());try{return $work();}finally{DB::setDefaultConnection($old);}
|
|
}
|
|
}
|