Files
SGF/scripts/industrial-cost-concurrency.php
T
2026-10-27 13:57:09 +02:00

27 lines
4.7 KiB
PHP

<?php
require __DIR__.'/../vendor/autoload.php';$app=require __DIR__.'/../bootstrap/app.php';$app->make(\Illuminate\Contracts\Console\Kernel::class)->bootstrap();
use App\Modules\Industry\IndustrialCosts;
use App\Shared\Context\CompanyContext;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Str;
use Symfony\Component\Process\Process;
IndustrialCosts::guard();$f=json_decode(file_get_contents('C:/laragon/data/sgf-tempo/secrets/browser-fixture.json'),true,32,JSON_THROW_ON_ERROR);$fx=$f['industrial'];$proof=[];$key=fn()=>(string)Str::uuid();
$base=['tenant'=>$f['tenant'],'company'=>$f['company'],'unit'=>$f['unit'],'lot'=>$fx['lot']];
$pair=function($one,$two)use($base){
$a=new Process([PHP_BINARY,'scripts/industrial-cost-worker.php','--env=testing'],base_path(),null,json_encode($one+$base+['pause'=>true]));$b=new Process([PHP_BINARY,'scripts/industrial-cost-worker.php','--env=testing'],base_path(),null,json_encode($two+$base));
$a->start();if(!$a->waitUntil(fn($t,$v)=>str_contains($v,'LOCK_HELD')))throw new RuntimeException('Industrial concurrent lock not observed.');$b->start();$a->wait();$b->wait();$out=[];
foreach([$a,$b] as $p){if(!$p->isSuccessful())throw new RuntimeException('Industrial worker failed.');$lines=array_values(array_filter(explode("\n",trim($p->getOutput())),fn($v)=>str_starts_with($v,'{')));$out[]=json_decode(end($lines),true,32,JSON_THROW_ON_ERROR);}return $out;
};
$check=function($out,bool $replay){if($out[0]['status']!==200||$out[1]['status']!==($replay?200:409)||($replay&&(!$out[1]['result']['replayed']||$out[0]['result']['id']!==$out[1]['result']['id'])))throw new RuntimeException('Unexpected concurrent industrial result.');};
$old=DB::table('ic_inputs')->where(['lot_id'=>$fx['lot'],'kind'=>'criterion'])->orderByDesc('version')->first();
$input=['method'=>'input','actor'=>$f['manager_id'],'key'=>$key(),'input'=>['kind'=>'criterion','source_ref'=>$old->source_ref,'version'=>$old->version+1,'previous_id'=>$old->id,'data'=>json_decode($old->data,true),'evidence'=>'Revisão concorrente sintética.']];$out=$pair($input,$input);$check($out,true);$proof['criterion_repetition_one_version']=true;$id=$out[0]['result']['id'];$ver=$out[0]['result']['version'];
$decision=['method'=>'decide','actor'=>$f['reader_id'],'key'=>$key(),'input'=>['type'=>'input','id'=>$id,'version'=>$ver,'decision'=>'approved','reason'=>'Validação concorrente de hipótese sintética.']];$check($pair($decision,$decision),true);$proof['decision_repetition_one_effect']=true;
$one=$input;$one['key']=$key();$one['input']['version']=$ver+1;$one['input']['previous_id']=$id;$two=$one;$two['key']=$key();$two['input']['data']['capacity']='20';$out=$pair($one,$two);$check($out,false);$proof['competing_criteria_one_successor']=true;$cid=$out[0]['result']['id'];$cv=$out[0]['result']['version'];
app(CompanyContext::class)->selectFor($f['reader_id'],$f['tenant'],$f['company'],$f['unit']);app(IndustrialCosts::class)->decide($fx['lot'],$f['reader_id'],['type'=>'input','id'=>$cid,'version'=>$cv,'decision'=>'approved','reason'=>'Validado critério sintético vencedor.'],$key());
$refs=$fx['refs']+['criterion'=>['id'=>$cid,'version'=>$cv]];$last=DB::table('ic_results')->where('lot_id',$fx['lot'])->orderByDesc('version')->first();
$calc=['method'=>'calculate','actor'=>$f['manager_id'],'key'=>$key(),'input'=>['currency'=>'MZN','version'=>$last->version+1,'previous_id'=>$last->id,'refs'=>$refs]];$out=$pair($calc,$calc);$check($out,true);$proof['calculation_repetition_one_snapshot']=true;
$last=DB::table('ic_results')->where('lot_id',$fx['lot'])->orderByDesc('version')->first();$calc['key']=$key();$calc['input']['version']=$last->version+1;$calc['input']['previous_id']=$last->id;$calc['input']['refs']['material_rate']=null;$two=$calc;$two['key']=$key();$two['input']['refs']=$refs;$check($pair($calc,$two),false);$proof['competing_calculations_one_current_allocation']=true;
$last=DB::table('ic_results')->where('lot_id',$fx['lot'])->orderByDesc('version')->first();$calc['key']=$key();$calc['input']['version']=$last->version+1;$calc['input']['previous_id']=$last->id;$calc['input']['refs']=$refs;
$stale=['method'=>'decide','actor'=>$f['reader_id'],'key'=>$key(),'input'=>['type'=>'result','id'=>$last->id,'version'=>$last->version,'decision'=>'approved','reason'=>'Aprovação agora obsoleta.']];$check($pair($calc,$stale),false);$proof['new_result_refuses_old_approval']=true;
file_put_contents(base_path('docs/proofs/industrial-cost-concurrency.json'),json_encode(['policy'=>IndustrialCosts::POLICY,'database'=>'sgf_tempo_test','overlapping_processes_per_case'=>2,'checks'=>$proof,'synthetic_only'=>true],JSON_PRETTY_PRINT|JSON_THROW_ON_ERROR));echo "Six overlapping industrial concurrency cases passed; historical allocations not accumulated.\n";