Files
SGF/scripts/industrial-budget-manual-prepare.php

31 lines
3.8 KiB
PHP

<?php
// Resume only the existing synthetic fixture. Never resets the database or creates grants.
require __DIR__.'/../vendor/autoload.php';$app=require __DIR__.'/../bootstrap/app.php';$app->make(\Illuminate\Contracts\Console\Kernel::class)->bootstrap();
use App\Modules\Industry\IndustrialBudgets;
use App\Modules\Identity\Services\Permissions;
use App\Models\User;
use Illuminate\Support\Facades\DB;
IndustrialBudgets::guard();
$identity=DB::selectOne('SELECT current_database() AS db,current_user AS role,inet_server_port() AS port');
if($identity->db!=='sgf_tempo_test'||$identity->role!=='sgf_test_runner'||(int)$identity->port!==55432)throw new RuntimeException('Unsafe manual proof destination.');
$m=User::where('email','gestor@example.test')->firstOrFail();$r=User::where('email','consulta@example.test')->firstOrFail();
if(DB::table('ic_lots')->count()!==1)throw new RuntimeException('Exactly one existing synthetic lot required; nothing deleted.');
$lot=DB::table('ic_lots')->first();$result=DB::table('ic_results')->where(['lot_id'=>$lot->id,'version'=>1])->first();
if(!$result||!str_starts_with($lot->reference,'LOT-TEST-'))throw new RuntimeException('Expected synthetic result missing.');
$s=json_decode($result->snapshot,true,64,JSON_THROW_ON_ERROR);
foreach(['material_exact'=>'1000','labour_exact'=>'500','allocated_exact'=>'300','residual_exact'=>'300','selected_total_exact'=>'1800','good_units'=>'10','currency'=>'MZN'] as $k=>$v)if($s[$k]!==$v)throw new RuntimeException('Full fixture differs.');
if(!DB::table('ic_decisions')->where(['result_id'=>$result->id,'decision'=>'approved','actor_id'=>$r->id])->exists())throw new RuntimeException('Distinct result approval required.');
$p=app(Permissions::class);
foreach([$m->id=>['industrial_budgets.view','industrial_budgets.prepare','industrial_budget_comparisons.view','industrial_budget_comparisons.prepare'],$r->id=>['industrial_budgets.view','industrial_budgets.validate','industrial_budget_comparisons.view']] as $u=>$rights)foreach($rights as $right)$p->require($u,$lot->tenant_id,$lot->company_id,$right,$lot->unit_id);
if($p->has($m->id,$lot->tenant_id,$lot->company_id,'industrial_budgets.validate',$lot->unit_id)||$p->has($r->id,$lot->tenant_id,$lot->company_id,'industrial_budgets.prepare',$lot->unit_id)||$p->has($r->id,$lot->tenant_id,$lot->company_id,'industrial_budget_comparisons.prepare',$lot->unit_id))throw new RuntimeException('Role separation differs.');
$file='C:/laragon/data/sgf-tempo/secrets/browser-fixture.json';$entry='C:/laragon/data/sgf-tempo/secrets/industrial-budget-manual-entry.txt';
if(!file_exists($file)){
$mp=bin2hex(random_bytes(20));$rp=bin2hex(random_bytes(20));
DB::transaction(function()use($m,$r,$mp,$rp){$m->password=$mp;$m->save();$r->password=$rp;$r->save();});
$f=['tenant'=>$lot->tenant_id,'company'=>$lot->company_id,'unit'=>$lot->unit_id,'manager_id'=>$m->id,'reader_id'=>$r->id,'budget_fixture'=>['lot'=>$lot->id,'result'=>$result->id,'refs'=>$s['refs']]];
file_put_contents($file,json_encode($f,JSON_THROW_ON_ERROR));
file_put_contents($entry,"SGF synthetic manual proof only - http://127.0.0.1:8002\r\nOsmane synthetic: gestor@example.test\r\nPassword: ".$mp."\r\nSamira synthetic: consulta@example.test\r\nPassword: ".$rp."\r\nNever paste these passwords into chat or reports.\r\n");unset($mp,$rp);
}
if(!file_exists($entry))throw new RuntimeException('Protected entry instructions missing; review locally.');
echo json_encode(['database'=>$identity->db,'role'=>$identity->role,'port'=>(int)$identity->port,'synthetic_roles_separate'=>true,'lot_id'=>$lot->id,'result_id'=>$result->id,'result_version'=>1,'existing_budgets'=>DB::table('ib_budgets')->count(),'existing_comparisons'=>DB::table('ib_comparisons')->count(),'credentials'=>'protected_local_file_only','database_reset'=>false,'grants_created'=>false],JSON_THROW_ON_ERROR).PHP_EOL;