Files
SGF/scripts/sgc-invoice-client-kernel-proof.php
T
2026-11-11 09:00:17 +02:00

34 lines
3.6 KiB
PHP

<?php
require __DIR__.'/sgc-invoice-proof-bootstrap.php';
require_once $repo.'/packages/sgc-invoice-client/src/InvoiceClient.php';
use Illuminate\Support\Facades\Crypt;
use Tempo\SgcInvoiceClient\InvoiceClient;
if(!is_file($proofRoot.'/authority-result.json')||is_file($proofRoot.'/client-kernel-result.json'))throw new LogicException('Fresh client contract proof required');
$old=json_decode(file_get_contents($proofRoot.'/initial-preview.json'),true);$cut=json_decode(Crypt::decryptString($old['data']['preview']),true);
$checks=[];$ok=function($v,$name)use(&$checks){if(!$v)throw new RuntimeException($name);$checks[]=$name;};
$invoiceBefore=$native->table('invoices')->orderBy('id')->get()->toJson();$auditBefore=$native->table('audit_logs')->count();
$calls=[];
$client=new InvoiceClient('synthetic',$secret['token'],$secret['context'],['tenant_id'=>91],$f['scope'],
function($method,$url,$headers,$body)use($send,&$calls){$calls[]=['method'=>$method,'path'=>parse_url($url,PHP_URL_PATH),'key'=>$headers['X-Idempotency-Key']];
$response=$send($body??[],$headers['X-Idempotency-Key'],[],parse_url($url,PHP_URL_PATH),null,$method);
return ['status'=>$response['status'],'json'=>$response['data']];});
$mapping=['id'=>'QA-PROTOCOL-MAPPING','version'=>1,'source_scope'=>['tenant_id'=>91],'target_scope'=>$f['scope'],
'order_id'=>$cut['order_id'],'lines'=>[],'authority'=>'sgf_only'];
$document=$cut['data'];foreach($document['items']as$i=>&$line){$ref='QA-SOURCE-LINE-'.$i;$mapping['lines'][$ref]=$line['purchase_order_item_id'];unset($line['purchase_order_item_id']);$line=['source_line_ref'=>$ref]+$line;}unset($line);
$draft=['reference'=>'QA-PROTOCOL-DRAFT','version'=>'QA-v1','state'=>'unregistered_draft','document'=>$document];
$intent=$client->intent($mapping,$draft,$cut['operation_key'],$cut['reason']);
$received=$client->preview($intent,'QA-v1',InvoiceClient::mappingHash($mapping));
$ok($received['phase']==='received_pending'&&$received['receipt']['replayed'],'prepared client recovers real existing native receipt through kernel');
$ok(count($calls)===2&&$calls[0]['method']==='GET'&&$calls[1]['method']==='POST','client performs exact context read and explicit preview/recovery only');
$ok($calls[0]['key']===$cut['operation_key']&&$calls[1]['key']===$cut['operation_key'],'native protocol retains one original UUID');
$draft['document']['number']='QA-SGC-CLIENT-PREVIEW-'.substr(basename($proofRoot),-12);
$fresh=$client->intent($mapping,$draft,(string)Illuminate\Support\Str::uuid(),$cut['reason']);
$preview=$client->preview($fresh,'QA-v1',InvoiceClient::mappingHash($mapping));
$ok($preview['phase']==='previewed'&&isset($preview['approval_hash'])&&$preview['impact']['budget_consumption_minor']===0,'prepared client consumes real native impact without confirming');
$ok($invoiceBefore===$native->table('invoices')->orderBy('id')->get()->toJson()&&$auditBefore===$native->table('audit_logs')->count(),'client contract proof adds no invoice or audit rows');
$ok(!str_contains(json_encode([$received,$preview]),$secret['token']),'serialised transport states exclude bearer credential');
file_put_contents($proofRoot.'/client-kernel-result.json',json_encode(['passed'=>true,'checks'=>$checks,'new_business_rows'=>0,'kernel_http'=>true,'tcp_8085'=>false,
'new_demo'=>false,'new_database'=>false,'sender_class_sha256'=>hash_file('sha256',$repo.'/packages/sgc-invoice-client/src/InvoiceClient.php'),
'reused_endpoint_proof_sha256'=>hash_file('sha256',$repo.'/docs/proofs/sgc-invoice-endpoint-20261110.json')],JSON_PRETTY_PRINT|JSON_THROW_ON_ERROR));
echo json_encode(['passed'=>true,'checks'=>count($checks)]).PHP_EOL;