commit2
This commit is contained in:
@@ -0,0 +1,100 @@
|
||||
<?php
|
||||
// Only the specifically authorised 090000 and four unit grants; no real costing.
|
||||
require __DIR__.'/../vendor/autoload.php';
|
||||
$app=require __DIR__.'/../bootstrap/app.php';
|
||||
$app->make(\Illuminate\Contracts\Console\Kernel::class)->bootstrap();
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\Artisan;
|
||||
use App\Modules\Identity\Services\LocalDatabaseGuard;
|
||||
use App\Modules\Identity\Services\Permissions;
|
||||
use App\Modules\Identity\Services\Audit;
|
||||
use App\Modules\Workshop\DirectCosts;
|
||||
use App\Modules\Workshop\WorkshopWorkflow;
|
||||
use App\Shared\Context\CompanyContext;
|
||||
|
||||
function ensureDirectCost(bool $ok,string $message): void { if(!$ok)throw new RuntimeException($message); }
|
||||
function directCostFingerprint(string $table,?int $max=null): array {
|
||||
ensureDirectCost((bool)preg_match('/^[a-z_]+$/D',$table),'Unexpected table identifier.');
|
||||
$where=$max===null?'':' WHERE id <= '.$max;
|
||||
$r=DB::selectOne('SELECT count(*) AS n, md5(COALESCE(string_agg(row_to_json(t)::text, E\'\\n\' ORDER BY row_to_json(t)::text),\'\')) AS h FROM (SELECT * FROM "'.$table.'"'.$where.') t');
|
||||
return [(int)$r->n,$r->h]; // In memory only; no record contents exported.
|
||||
}
|
||||
ensureDirectCost(LocalDatabaseGuard::allows(),'Own SGF development application connection required.');
|
||||
ensureDirectCost($argv===[$argv[0],'--apply-confirmed-090000-and-four-grants'],'Exact confirmed operation argument required.');
|
||||
$migration='2026_10_27_090000_create_workshop_direct_costs';
|
||||
ensureDirectCost(!DB::table('migrations')->where('migration',$migration)->exists(),'090000 already installed; review changed state.');
|
||||
ensureDirectCost(DB::table('migrations')->where('migration','2026_10_27_080000_create_workshop_resource_records')->exists(),'Expected workshop installation missing.');
|
||||
ensureDirectCost(DB::table('migrations')->where('migration','2026_10_27_070000_create_simulated_receivables')->exists(),'Expected receivables installation missing.');
|
||||
$newTables=['dc_rates','dc_calculations','dc_decisions','dc_commands','dc_events','dc_outbox'];
|
||||
$tables=array_map(fn($r)=>$r->tablename,DB::select("SELECT tablename FROM pg_tables WHERE schemaname='public' ORDER BY tablename"));
|
||||
ensureDirectCost(!array_intersect($tables,$newTables),'Receivables tables already exist; review first.');
|
||||
$rights=[1=>['view','prepare'],2=>['view','validate']];
|
||||
$checkScope=function(): void {
|
||||
foreach([1=>['Osmane Nala','nala@tempo.co.mz'],2=>['Samira Nal','onala@me.com']] as $id=>[$name,$email]){
|
||||
ensureDirectCost(DB::table('users')->where(compact('id','name','email'))->exists(),'Confirmed account identity differs.');
|
||||
ensureDirectCost(DB::table('company_memberships')->where(['user_id'=>$id,'tenant_id'=>1,'company_id'=>1])->exists(),'Existing membership required.');
|
||||
$p=app(Permissions::class);$p->require($id,1,1,'company.view');$p->require($id,1,1,'unit.view',1);
|
||||
}
|
||||
ensureDirectCost(DB::table('companies')->where(['id'=>1,'tenant_id'=>1,'name'=>'Tempo Lda'])->exists(),'Confirmed company differs.');
|
||||
ensureDirectCost(DB::table('units')->where(['id'=>1,'tenant_id'=>1,'company_id'=>1,'name'=>'SEGI'])->exists(),'Confirmed unit differs.');
|
||||
ensureDirectCost(!DB::table('permission_grants')->where('permission','like','direct_costs.%')->exists(),'Unexpected existing direct cost rights; review first.');
|
||||
};
|
||||
$checkScope();
|
||||
$baseline=[];foreach($tables as $t)$baseline[$t]=directCostFingerprint($t);
|
||||
$max=[];foreach(['permission_grants','identity_audit'] as $t)$max[$t]=(int)DB::table($t)->max('id');
|
||||
$ledger=DB::table('migrations')->orderBy('id')->get()->map(fn($r)=>(array)$r)->all();
|
||||
$sourceHashes=[];foreach(['app/Modules/Workshop/DirectCosts.php','app/Modules/Services/ServiceReceivables.php','app/Modules/Services/ServiceInvoicing.php','app/Modules/Workshop/WorkshopWorkflow.php'] as $p)$sourceHashes[$p]=hash_file('sha256',base_path($p));
|
||||
$secrets=json_decode(file_get_contents('C:/laragon/data/sgf-tempo/secrets/database.json'),true,32,JSON_THROW_ON_ERROR);
|
||||
$owner=config('database.connections.'.config('database.default'));
|
||||
$owner['username']='sgf_dev_owner';$owner['password']=$secrets['dev_owner'];$owner['url']=null;
|
||||
config(['database.connections.sgf_direct_cost_owner'=>$owner]);unset($owner,$secrets);
|
||||
try {
|
||||
$connection=DB::connection('sgf_direct_cost_owner');
|
||||
$identity=$connection->selectOne('SELECT current_database() AS db,current_user AS role,inet_server_port() AS port,rolsuper,rolcreatedb,rolcreaterole,rolbypassrls FROM pg_roles WHERE rolname=current_user');
|
||||
ensureDirectCost($identity->db==='sgf_tempo_dev'&&$identity->role==='sgf_dev_owner'&&(int)$identity->port===55432&&!$identity->rolsuper&&!$identity->rolcreatedb&&!$identity->rolcreaterole&&!$identity->rolbypassrls,'Unexpected migration owner/destination.');
|
||||
$connection->transaction(function()use($migration,$baseline,$newTables): void {
|
||||
$applicationConnection=DB::getDefaultConnection();DB::setDefaultConnection('sgf_direct_cost_owner');
|
||||
try {
|
||||
$exit=Artisan::call('migrate',['--database'=>'sgf_direct_cost_owner','--path'=>'database/migrations/'.$migration.'.php','--force'=>true,'--no-interaction'=>true]);
|
||||
ensureDirectCost($exit===0,'Targeted migration failed.');
|
||||
foreach($baseline as $t=>$fp)if($t!=='migrations')ensureDirectCost(directCostFingerprint($t)===$fp,'Existing records changed during migration: '.$t);
|
||||
foreach($newTables as $t)ensureDirectCost(DB::table($t)->count()===0,'New tables must be empty.');
|
||||
} finally { DB::setDefaultConnection($applicationConnection); }
|
||||
});
|
||||
} finally { DB::purge('sgf_direct_cost_owner');config(['database.connections.sgf_direct_cost_owner'=>null]); }
|
||||
ensureDirectCost(LocalDatabaseGuard::allows(),'Application must remain sgf_dev_app.');
|
||||
$afterLedger=DB::table('migrations')->orderBy('id')->get()->map(fn($r)=>(array)$r)->all();
|
||||
ensureDirectCost(count($afterLedger)===count($ledger)+1&&array_slice($afterLedger,0,count($ledger))===$ledger&&end($afterLedger)['migration']===$migration,'Unexpected migration ledger delta.');
|
||||
$denials=[];
|
||||
$grants=DB::transaction(function()use($rights,$checkScope,$baseline,$max,&$denials): array {
|
||||
DB::table('companies')->where('id',1)->lockForUpdate()->firstOrFail();$checkScope();$grants=[];
|
||||
foreach($rights as $user=>$actions)foreach($actions as $action){
|
||||
$g=['user_id'=>$user,'tenant_id'=>1,'company_id'=>1,'unit_id'=>1,'permission'=>'direct_costs.'.$action];
|
||||
DB::table('permission_grants')->insert($g+['created_at'=>now(),'updated_at'=>now()]);
|
||||
Audit::record('direct_costs.initial_grant',null,1,1,1,subject:$user,details:['permission'=>$g['permission'],'reason'=>'Four unit grants specifically authorised; real operations remain blocked.']);$grants[]=$g;
|
||||
}
|
||||
foreach($baseline as $t=>$fp)if($t!=='migrations')ensureDirectCost(directCostFingerprint($t,$max[$t]??null)===$fp,'Prior records changed: '.$t);
|
||||
ensureDirectCost(DB::table('permission_grants')->where('id','>',$max['permission_grants'])->count()===4,'Exactly four new grants required.');
|
||||
ensureDirectCost(DB::table('identity_audit')->where('id','>',$max['identity_audit'])->count()===4&&DB::table('identity_audit')->where('id','>',$max['identity_audit'])->where('action','direct_costs.initial_grant')->count()===4,'Exactly four grant audit entries required.');
|
||||
$actual=DB::table('permission_grants')->where('permission','like','direct_costs.%')->get(['user_id','tenant_id','company_id','unit_id','permission'])->map(fn($r)=>(array)$r)->all();
|
||||
$sort=fn($a,$b)=>[$a['user_id'],$a['permission']]<=>[$b['user_id'],$b['permission']];usort($actual,$sort);$expected=$grants;usort($expected,$sort);ensureDirectCost($actual===$expected,'Granted accounts/rights/scope differ.');
|
||||
foreach([1,2] as $actor){app(CompanyContext::class)->selectFor($actor,1,1,1);$listing=app(DirectCosts::class)->listing($actor);ensureDirectCost($listing['blocked']&&$listing['orders']===[],'Normal direct cost listing must remain blocked.');}
|
||||
foreach(['guard','rate','calculate','decide','workshop','receivables','issuance'] as $entry){
|
||||
try {
|
||||
$r=app(DirectCosts::class);
|
||||
match($entry){'guard'=>DirectCosts::guard(),'rate'=>$r->rate(0,1,[],'blocked-probe'),'calculate'=>$r->calculate(0,1,[],'blocked-probe'),'decide'=>$r->decide(0,2,[],'blocked-probe'),'workshop'=>WorkshopWorkflow::guard(),'receivables'=>\App\Modules\Services\ServiceReceivables::guard(),'issuance'=>\App\Modules\Services\ServiceInvoicing::guard()};
|
||||
throw new RuntimeException('Operational entry did not refuse.');
|
||||
}catch(\Symfony\Component\HttpKernel\Exception\HttpException $e){ensureDirectCost($e->getStatusCode()===403,'Expected operational refusal.');$denials[$entry]=403;}
|
||||
}
|
||||
app(CompanyContext::class)->selectFor(1,1,1,1);$w=app(WorkshopWorkflow::class)->listing(1);ensureDirectCost($w['blocked']&&$w['orders']===[],'Workshop operational block must remain.');
|
||||
return $grants;
|
||||
});
|
||||
foreach(['dc','sr','wo'] as $prefix){
|
||||
try {DB::select('SELECT sgf_'.$prefix.'_environment()');throw new RuntimeException('SQL environment guard did not refuse.');}
|
||||
catch(\Illuminate\Database\QueryException $e){ensureDirectCost(str_contains($e->getMessage(),'SGF_'.strtoupper($prefix).'_TEST_DATABASE_ONLY'),'Unexpected SQL guard response.');}
|
||||
}
|
||||
foreach($sourceHashes as $p=>$hash)ensureDirectCost(hash_file('sha256',base_path($p))===$hash,'Functional source or guard changed.');
|
||||
foreach($newTables as $t)ensureDirectCost(DB::table($t)->count()===0,'New direct cost tables must remain empty.');
|
||||
$proof=['date'=>'2026-10-27','database'=>'sgf_tempo_dev','migration_applied'=>$migration,'only_one_migration_added'=>true,'workshop_080000_preserved'=>true,'preexisting_tables_checked'=>count($baseline),'prior_records_and_accesses_preserved'=>true,'new_empty_tables'=>$newTables,'new_grants'=>$grants,'audited_new_grants'=>4,'application_role'=>'sgf_dev_app','both_normal_account_listings_blocked'=>true,'entry_denials'=>$denials,'cost_receivables_and_workshop_sql_guards_refused'=>true,'functional_and_guard_sources_unchanged'=>true,'real_operations_created'=>false];
|
||||
file_put_contents(storage_path('app/private/direct-cost-dev-install-proof.json'),json_encode($proof,JSON_PRETTY_PRINT|JSON_THROW_ON_ERROR));
|
||||
echo 'Applied only 090000 and four audited grants; '.count($baseline)." prior tables preserved, six new tables empty, costing, workshop and operational/fiscal guards verified.\n";
|
||||
@@ -0,0 +1,26 @@
|
||||
<?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";
|
||||
@@ -0,0 +1,7 @@
|
||||
<?php
|
||||
require __DIR__.'/../vendor/autoload.php';$app=require __DIR__.'/../bootstrap/app.php';$app->make(\Illuminate\Contracts\Console\Kernel::class)->bootstrap();
|
||||
\App\Modules\Industry\IndustrialCosts::guard();$file='C:/laragon/data/sgf-tempo/secrets/browser-fixture.json';$base=json_decode(file_get_contents($file),true,32,JSON_THROW_ON_ERROR);
|
||||
if(\Illuminate\Support\Facades\DB::table('ic_lots')->exists())throw new RuntimeException('Fresh synthetic proof required; nothing deleted.');
|
||||
$f=\Tests\Support\IndustrialCostFixture::create($base+['manager'=>\App\Models\User::findOrFail($base['manager_id']),'reader'=>\App\Models\User::findOrFail($base['reader_id'])],false);
|
||||
file_put_contents($file,json_encode($base+['industrial'=>array_intersect_key($f,array_flip(['lot','refs','criterionData']))],JSON_THROW_ON_ERROR));
|
||||
echo "Industrial synthetic lot and seven validated origins/rates prepared; criterion and calculations remain for browser demonstration. No workshop events created.\n";
|
||||
@@ -0,0 +1,12 @@
|
||||
<?php
|
||||
// Read-only proposal. No apply or activation branch.
|
||||
require __DIR__.'/../vendor/autoload.php';$app=require __DIR__.'/../bootstrap/app.php';$app->make(\Illuminate\Contracts\Console\Kernel::class)->bootstrap();
|
||||
if(!\App\Modules\Identity\Services\LocalDatabaseGuard::allows())throw new RuntimeException('Own SGF development application database required.');
|
||||
$db=\Illuminate\Support\Facades\DB::class;$grants=[];
|
||||
foreach([1=>['view','prepare'],2=>['view','validate']] as $id=>$rights){
|
||||
$u=$db::table('users')->where('id',$id)->first(['id','name','email']);if(!$u||!$db::table('company_memberships')->where(['user_id'=>$id,'tenant_id'=>1,'company_id'=>1])->exists())throw new RuntimeException('Existing account/member required.');
|
||||
foreach($rights as $r){$g=['user_id'=>$id,'tenant_id'=>1,'company_id'=>1,'unit_id'=>1,'permission'=>'industrial_costs.'.$r];$grants[]=$g+['account'=>$u,'already_granted'=>$db::table('permission_grants')->where($g)->exists()];}
|
||||
}
|
||||
$company=$db::table('companies')->where(['id'=>1,'tenant_id'=>1])->value('name');$unit=$db::table('units')->where(['id'=>1,'company_id'=>1,'tenant_id'=>1])->value('name');if($company!=='Tempo Lda'||$unit!=='SEGI')throw new RuntimeException('Scope differs.');
|
||||
try{\App\Modules\Industry\IndustrialCosts::guard();throw new RuntimeException('Real industry costing not blocked.');}catch(\Symfony\Component\HttpKernel\Exception\HttpException $e){if($e->getStatusCode()!==403)throw $e;}
|
||||
echo json_encode(['mode'=>'preview_only','company'=>$company,'unit'=>$unit,'proposed_grants'=>$grants,'applied'=>false,'industrial_real_blocked'=>true,'migration_100000_applied'=>$db::table('migrations')->where('migration','2026_10_27_100000_create_industrial_cost_simulation')->exists()],JSON_PRETTY_PRINT|JSON_UNESCAPED_UNICODE|JSON_THROW_ON_ERROR).PHP_EOL;
|
||||
@@ -0,0 +1,10 @@
|
||||
<?php
|
||||
require __DIR__.'/../vendor/autoload.php';$app=require __DIR__.'/../bootstrap/app.php';$app->make(\Illuminate\Contracts\Console\Kernel::class)->bootstrap();\App\Modules\Industry\IndustrialCosts::guard();
|
||||
$f=json_decode(file_get_contents('C:/laragon/data/sgf-tempo/secrets/browser-fixture.json'),true,32,JSON_THROW_ON_ERROR);$db=\Illuminate\Support\Facades\DB::class;$rows=$db::table('ic_results')->where('lot_id',$f['industrial']['lot'])->orderBy('version')->get();if($rows->count()<2)throw new RuntimeException('Two browser scenarios required.');
|
||||
$full=json_decode($rows[0]->snapshot,true);$partial=json_decode($rows[1]->snapshot,true);
|
||||
foreach(['material_exact'=>'1000','labour_exact'=>'500','indirect_rate_exact'=>'60','allocated_exact'=>'300','residual_exact'=>'300','selected_total_exact'=>'1800','unit_cost_exact'=>'180'] as $k=>$v)if($full[$k]!==$v)throw new RuntimeException('Full scenario differs.');
|
||||
if($partial['known_cost_exact']!=='800'||$partial['unit_cost_exact']!==null||$partial['selected_total_exact']!==null||!$partial['incomplete']||$partial['reconciliation']['known_origins_exact']!=='1100')throw new RuntimeException('Partial scenario differs.');
|
||||
foreach([$rows[0],$rows[1]] as $r){$d=$db::table('ic_decisions')->where(['result_id'=>$r->id,'decision'=>'approved'])->first();if(!$d||$d->actor_id===$r->actor_id)throw new RuntimeException('Distinct validation required.');}
|
||||
if($db::table('wo_entries')->exists()||$db::table('dc_calculations')->exists())throw new RuntimeException('Workshop/direct cost events unexpectedly created.');
|
||||
$proof=['policy'=>'INDUSTRIAL-COST-SIM-v1','database'=>'sgf_tempo_test','synthetic_only'=>true,'real_browser_login'=>true,'csrf_enabled'=>true,'distinct_roles'=>true,'full'=>['material'=>'1000','labour'=>'500','pool'=>'600','capacity_hm'=>'10','used_hm'=>'5','rate'=>'60','allocated'=>'300','residual'=>'300','cost'=>'1800','good_units'=>'10','unit_cost'=>'180','origins'=>'2100'],'partial'=>['known'=>'800','total'=>null,'unit_cost'=>null,'incomplete'=>true,'known_origins'=>'1100','residual'=>'300'],'workshop_events_created'=>0,'hypothesis_only'=>true,'development_migration_applied'=>false,'real_grants_applied'=>false,'user_acceptance'=>false];
|
||||
file_put_contents(base_path('docs/proofs/industrial-cost-browser-results.json'),json_encode($proof,JSON_PRETTY_PRINT|JSON_THROW_ON_ERROR));echo "Browser results checked: 1800/180 and 800 incomplete, residual 300, distinct validations and no duplicated workshop events.\n";
|
||||
@@ -0,0 +1,7 @@
|
||||
<?php
|
||||
require __DIR__.'/../vendor/autoload.php';$app=require __DIR__.'/../bootstrap/app.php';$app->make(\Illuminate\Contracts\Console\Kernel::class)->bootstrap();
|
||||
\App\Modules\Industry\IndustrialCosts::guard();$in=json_decode(stream_get_contents(STDIN),true,32,JSON_THROW_ON_ERROR);
|
||||
app(\App\Shared\Context\CompanyContext::class)->selectFor($in['actor'],$in['tenant'],$in['company'],$in['unit']);
|
||||
if($in['pause']??false){$paused=false;\Illuminate\Support\Facades\DB::listen(function($q)use(&$paused){if(!$paused&&str_contains($q->sql,'"companies"')&&str_contains($q->sql,'for update')){$paused=true;echo "LOCK_HELD\n";flush();usleep(1200000);}});}
|
||||
try{$c=app(\App\Modules\Industry\IndustrialCosts::class);$out=$c->{$in['method']}($in['lot'],$in['actor'],$in['input'],$in['key']);echo json_encode(['status'=>200,'result'=>$out],JSON_THROW_ON_ERROR).PHP_EOL;}
|
||||
catch(\Symfony\Component\HttpKernel\Exception\HttpExceptionInterface $e){echo json_encode(['status'=>$e->getStatusCode()],JSON_THROW_ON_ERROR).PHP_EOL;}
|
||||
Reference in New Issue
Block a user