Files
SGF/scripts/invoice-concurrency.php
T

23 lines
2.6 KiB
PHP

<?php
use Illuminate\Support\Facades\DB;
use Symfony\Component\Process\Process;
require __DIR__.'/../vendor/autoload.php';
$app=require __DIR__.'/../bootstrap/app.php'; $app->make(\Illuminate\Contracts\Console\Kernel::class)->bootstrap();
\App\Modules\Services\ServiceInvoicing::guard();
$f=json_decode(file_get_contents('C:/laragon/data/sgf-tempo/secrets/browser-fixture.json'),true,32,JSON_THROW_ON_ERROR);
$fixture=$f+$f['invoice']+['manager'=>\App\Models\User::findOrFail($f['manager_id']),'reader'=>\App\Models\User::findOrFail($f['reader_id'])];
$fixture=DB::transaction(fn()=>\Tests\Support\InvoiceFixture::additionalDraft($fixture));
$review=app(\App\Modules\Services\ServiceInvoicing::class)->review($fixture['draft'],$fixture['series'],$fixture['rule'],$f['manager_id']);
if(!$review['ready']) throw new RuntimeException('Synthetic concurrent revision not ready.');
$input=['actor'=>$f['manager_id'],'tenant'=>$f['tenant'],'company'=>$f['company'],'unit'=>$f['unit'],'draft'=>$fixture['draft'],'key'=>(string)\Illuminate\Support\Str::uuid(),'input'=>['series_id'=>$fixture['series'],'rule_id'=>$fixture['rule'],'review_hash'=>$review['review_hash']]];
$before=DB::table('si_invoices')->count();
$a=new Process([PHP_BINARY,'scripts/invoice-worker.php','--env=testing'],base_path(),null,json_encode($input+['pause'=>true]));
$b=new Process([PHP_BINARY,'scripts/invoice-worker.php','--env=testing'],base_path(),null,json_encode($input));
$a->start();if(!$a->waitUntil(fn($type,$buffer)=>str_contains($buffer,'LOCK_HELD')))throw new RuntimeException('No overlapping lock established.');
$b->start();$a->wait();$b->wait();$results=[];
foreach([$a,$b] as $p){if(!$p->isSuccessful())throw new RuntimeException('Synthetic worker failed.');$lines=array_values(array_filter(explode("\n",trim($p->getOutput())),fn($s)=>str_starts_with($s,'{')));$results[]=json_decode(end($lines),true,32,JSON_THROW_ON_ERROR);}
if($results[0]['id']!==$results[1]['id'] || $results[0]['replayed'] || !$results[1]['replayed'] || DB::table('si_invoices')->count()!==$before+1)throw new RuntimeException('Duplicate or missing concurrent invoice.');
if(DB::table('si_invoices')->distinct()->count('number')!==DB::table('si_invoices')->count())throw new RuntimeException('Series number repeated.');
file_put_contents(base_path('docs/proofs/invoice-concurrency.json'),json_encode(['database'=>'sgf_tempo_test','overlapping_processes'=>2,'one_invoice_one_replay'=>true,'numbers_distinct_in_shared_series'=>true,'prior_documents_preserved'=>true],JSON_PRETTY_PRINT|JSON_THROW_ON_ERROR));
echo "Concurrent synthetic issuance verified: one invoice, one replay, shared series without duplicate number.\n";