commit de compras

This commit is contained in:
2026-11-04 09:37:20 +02:00
parent fcf31e8d48
commit 0b05a1192c
741 changed files with 114127 additions and 116 deletions
+13
View File
@@ -0,0 +1,13 @@
<?php
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Str;
$s=json_decode(file_get_contents(getenv('RECEIPT_COMPOSITION_STATE')),true,64,JSON_THROW_ON_ERROR);$out=$s['root'].'/origin.json';if(file_exists($out))throw new LogicException('Origin proof preserved');require $s['app'].'/vendor/autoload.php';$app=require $s['app'].'/bootstrap/app.php';$app->make(Illuminate\Contracts\Console\Kernel::class)->bootstrap();$f=json_decode(file_get_contents($s['root'].'/fixture.json'),true);$n=json_decode(file_get_contents($s['root'].'/native-extra-fixture.json'),true);$file=$s['root'].'/binding.json';$original=file_get_contents($file);$binding=json_decode($original,true);$binding['bindings'][implode(':',array_values($f['scope'])).':'.$f['actor']]=['tenant_id'=>$n['tenant'],'actor_id'=>$n['receiver'],'order_ids'=>[$n['order']],'warehouse_ids'=>[$n['warehouse']]];file_put_contents($file,json_encode($binding,JSON_PRETTY_PRINT|JSON_THROW_ON_ERROR));config(['database.connections.receipt_verify'=>$s['nativeConnection']]);$db=DB::connection('receipt_verify');$checks=[];$ok=function($v,$name)use(&$checks){if(!$v)throw new RuntimeException($name);$checks[]=$name;};
$socket=stream_socket_server('tcp://127.0.0.1:0');$port=(int)substr(strrchr(stream_socket_get_name($socket,false),':'),1);fclose($socket);$server=new Symfony\Component\Process\Process([PHP_BINARY,'-S','127.0.0.1:'.$port,'-t',$s['app'].'/public',dirname(__DIR__).'/scripts/receipt-composition-http.php'],$s['app'],null,null,120);$server->start();
try{
for($i=0;$i<80;$i++){if($socket=@fsockopen('127.0.0.1',$port,$errno,$error,.1)){fclose($socket);break;}usleep(50000);}$client=new GuzzleHttp\Client(['base_uri'=>'http://127.0.0.1:'.$port,'http_errors'=>false,'timeout'=>25]);$jar=new GuzzleHttp\Cookie\CookieJar;$r=$client->get('/qa/enter/actor',['cookies'=>$jar]);$session=json_decode((string)$r->getBody(),true);$url='/api/purchasing-receipts/orders/'.$n['order'];$call=function($path,$data=null)use($client,$jar,$session){$o=['cookies'=>$jar,'headers'=>['Accept'=>'application/json','X-SGF-Context'=>$session['context'],'X-CSRF-TOKEN'=>$session['csrf']]];if($data!==null)$o['json']=$data;$r=$client->request($data===null?'GET':'POST',$path,$o);return ['status'=>$r->getStatusCode(),'data'=>json_decode((string)$r->getBody(),true)];};
$d=$call($url);$r=$call($url.'/preview',['revision'=>$d['data']['revision'],'idempotency_key'=>(string)Str::uuid(),'delivery_note'=>'SGF-QA-ORIGIN','received_on'=>date('Y-m-d'),'warehouse_id'=>$n['warehouse'],'items'=>[['purchase_order_item_id'=>$n['line'],'received_quantity'=>'0.500','accepted_quantity'=>'0.500','quality_status'=>'compliant','stock_item_id'=>$n['stock'],'notes'=>null]]]);if($r['status']!==200)throw new RuntimeException('Origin preview failed');$preview=$r['data']['preview'];
$before=[$db->table('goods_receipts')->count(),$db->table('stock_movements')->count(),$db->table('audit_logs')->count()];$db->unprepared("CREATE FUNCTION public.receipt_origin_fail() RETURNS trigger LANGUAGE plpgsql AS \$\$ BEGIN IF NEW.action='sgf.receipt.confirmed' THEN RAISE EXCEPTION 'synthetic origin audit failure'; END IF; RETURN NEW; END \$\$; CREATE TRIGGER receipt_origin_fail BEFORE INSERT ON audit_logs FOR EACH ROW EXECUTE FUNCTION public.receipt_origin_fail()");
try{$r=$call($url.'/confirm',['preview'=>$preview]);$ok($r['status']===500,'failure to record SGF provenance refuses the whole confirmation');$ok($before===[$db->table('goods_receipts')->count(),$db->table('stock_movements')->count(),$db->table('audit_logs')->count()],'physical receipt and original audit roll back when provenance fails');}finally{$db->unprepared('DROP TRIGGER receipt_origin_fail ON audit_logs; DROP FUNCTION public.receipt_origin_fail()');}
$r=$call($url.'/confirm',['preview'=>$preview]);$ok($r['status']===201,'same intention recovers after provenance failure');$id=$r['data']['receipt']['id'];$audits=$db->table('audit_logs')->where('tenant_id',$n['tenant'])->where('action','sgf.receipt.confirmed')->get();$a=json_decode($audits[0]->after,true);$ok(count($audits)===1&&$a['receipt_id']===$id&&$a['sgf_context_key']===implode(':',array_values($f['scope'])).':'.$f['actor']&&$a['workflow_manifest']===$s['manifest_sha256'],'same transaction records exact SGF context, actor mapping and workflow manifest');$r=$call($url.'/confirm',['preview'=>$preview]);$ok($r['status']===200&&$db->table('audit_logs')->where('action','sgf.receipt.confirmed')->count()===1,'repetition duplicates neither business effect nor SGF provenance');$r=$call($url);$ok($r['data']['progress']['state']==='complete'&&(int)$r['data']['progress']['lines'][0]['accepted_milli']===2000,'fully accepted cumulative order reaches complete through SGF');
file_put_contents($out,json_encode(['passed'=>true,'checks'=>$checks,'origin_audit_atomic'=>true,'same_key_recovery'=>true,'complete_order'=>true],JSON_PRETTY_PRINT|JSON_THROW_ON_ERROR));echo count($checks)." origin audit checks passed.\n";
}finally{file_put_contents($file,$original);$server->stop(2);file_put_contents($s['root'].'/origin-http.log',$server->getOutput()."\n".$server->getErrorOutput());}