Files
SGF/scripts/sgf-multiline-invoice-concurrency.php
2026-11-11 15:04:01 +02:00

12 lines
4.8 KiB
PHP

<?php
use App\Modules\Services\{MultiLineInvoiceCalculation,ServiceInvoicing};use Illuminate\Support\Str;
require __DIR__.'/sgf-multiline-invoice-proof-bootstrap.php';$mode=$argv[1]??'';$directory=$argv[2]??'';if($book!=='regression'||!str_starts_with(str_replace('\\','/',$directory),str_replace('\\','/',$s['root']).'/multiline-concurrency-'))throw new LogicException('Regression only');
if($mode==='prepare'){$x=$fixture('added',['400','600'],'CONCURRENT');$result=['id'=>$x['draft']['id']];
$c=app(MultiLineInvoiceCalculation::class);$actor=$select('finance_prepare');$p=$c->preview($actor,['draft_id'=>$result['id'],'draft_version'=>1,'preparation_version'=>1,'rule_event_id'=>$ruleEvent,'reason'=>'Cálculo do rascunho recuperado explicitamente.'],(string)Str::uuid());$calc=$c->confirm($actor,$p['preview']);$actor=$select('commercial_prepare');$e=app(ServiceInvoicing::class);$code='TEST-MULTI-FAIL-'.strtoupper(substr((string)Str::uuid(),0,8));$series=$e->propose($actor,['kind'=>'series','identifier'=>$code,'data'=>['code'=>$code,'first_number'=>1,'state'=>'open','valid_from'=>'2026-11-01','valid_until'=>'2026-11-30','evidence'=>'Série artificicial de recuperação.']]);$temporal=$e->propose($actor,['kind'=>'temporal','identifier'=>'MULTI-FAIL-'.$result['id'],'data'=>['calculation_policy'=>MultiLineInvoiceCalculation::POLICY,'common_calculation_id'=>$calc['id'],'common_rule_event_id'=>$ruleEvent,'draft_id'=>$result['id'],'draft_version'=>1,'preparation_version'=>1,'valid_from'=>'2026-11-01','valid_until'=>'2026-11-30','period_start'=>'2026-11-01','period_end'=>'2026-11-30','issue_window_start'=>'2026-11-11','issue_window_end'=>'2026-11-11','event'=>'on_issue_within_deadline','readiness_basis'=>'Documento recuperado com cálculo actual.','evidence'=>'Origem e valores fictícios conferidos.']]);$actor=$select('commercial_review');foreach([$series,$temporal]as$p)$e->decide($p['id'],$actor,['version'=>1,'decision'=>'approved','reason'=>'Revisão independente do documento de recuperação.']);$actor=$select('commercial_prepare');$ready=$e->review($result['id'],$series['id'],$temporal['id'],$actor);$input=['series_id'=>$series['id'],'rule_id'=>$temporal['id'],'review_hash'=>$ready['review_hash']];$key=(string)Str::uuid();
file_put_contents($directory.'/cuts-private.json',json_encode(['draft'=>$result['id'],'input'=>$input,'first'=>$key,'second'=>(string)Str::uuid(),'counter'=>$code,'before'=>$host->table('si_invoices')->count()]));exit;}
if($mode==='inspect'){$pid=json_decode(file_get_contents($directory.'/locked.json'),true)['host_pid'];$rows=$host->select('SELECT pid,wait_event_type,wait_event,pg_blocking_pids(pid) blockers FROM pg_stat_activity WHERE ? = ANY(pg_blocking_pids(pid))',[$pid]);file_put_contents($directory.'/blocking.json',json_encode(['blocker_host_pid'=>$pid,'waiters'=>$rows,'company_for_update'=>true]));exit;}
$p=json_decode(file_get_contents($directory.'/cuts-private.json'),true);$actor=$select('commercial_prepare');$http=function($key)use($p){request()->request->replace($p['input']);request()->headers->set('Idempotency-Key',$key);try{$r=app(App\Modules\Services\Http\MultiLineInvoiceController::class)->issue(request(),$p['draft']);return['status'=>$r->getStatusCode(),'value'=>$r->getData(true)];}catch(Symfony\Component\HttpKernel\Exception\HttpExceptionInterface$e){return['status'=>$e->getStatusCode()];}};
if($mode==='first'){$host->beginTransaction();try{$out=$http($p['first']);if($out['status']!==200)throw new LogicException('First issuance failed');file_put_contents($directory.'/locked.json',json_encode(['host_pid'=>$host->selectOne('SELECT pg_backend_pid() pid')->pid]));$end=microtime(true)+25;while(!is_file($directory.'/release')&&microtime(true)<$end)usleep(50000);if(!is_file($directory.'/release'))throw new LogicException('Release missing');$host->commit();}finally{while($host->transactionLevel()>0)$host->rollBack();}exit;}
if($mode==='second'){$start=microtime(true);$out=$http($p['second']);file_put_contents($directory.'/second.json',json_encode(['status'=>$out['status'],'seconds'=>microtime(true)-$start]));exit;}
if($mode==='recover'){$second=$http($p['second']);$replay=$http($p['first']);$invoices=$host->table('si_invoices')->where('draft_id',$p['draft'])->count();$commands=$host->table('si_commands')->whereIn('command_key',[$p['first'],$p['second']])->count();$counter=(int)$host->table('si_counters')->where('code',$p['counter'])->value('last_number');$out=['passed'=>$second['status']===409&&$replay['status']===200&&$replay['value']['replayed']&&$invoices===1&&$commands===1&&$counter===1&&$host->table('si_invoices')->count()===$p['before']+1,'after_release'=>$second['status'],'original_replay'=>$replay['status'],'invoices'=>$invoices,'receipts'=>$commands,'last_number'=>$counter,'regression_only'=>true,'pending_receivable_and_journal'=>true];file_put_contents($directory.'/recovery.json',json_encode($out));echo json_encode($out).PHP_EOL;}