30 lines
6.9 KiB
PHP
30 lines
6.9 KiB
PHP
<?php
|
|
if(!($s['read_overlay']??false)||!is_file($s['original_root'].'/integrated-result.json'))throw new LogicException('Completed regression book, new read application only');
|
|
$fingerprint=function($connection){$result=[];foreach($connection->select("SELECT tablename FROM pg_tables WHERE schemaname='public' ORDER BY tablename")as$table){if(!preg_match('/^[a-z0-9_]+$/D',$table->tablename))throw new LogicException('Unexpected fixture table');$name=$table->tablename;$row=$connection->selectOne('SELECT count(*) n,md5(coalesce(string_agg(row_to_json(t)::text,\'\' ORDER BY row_to_json(t)::text),\'\')) h FROM "'.$name.'" t');$result[$name]=[(int)$row->n,$row->h];}$result['sequences']=$connection->select("SELECT sequencename,last_value FROM pg_sequences WHERE schemaname='public' ORDER BY sequencename");return $result;};
|
|
$before=['host'=>$fingerprint(DB::connection()),'native'=>$fingerprint($db)];$saved=json_decode(file_get_contents($s['original_root'].'/integrated-result.json'),true);$id=$saved['source_ids']['request'];$base='/api/purchasing-dossiers';$url=$base.'/'.$id;
|
|
$ok($db->table('pa_obligations')->count()===1&&(int)$db->table('pa_obligations')->sum('principal_minor')===10000,'read proof reuses already-proven canonical responsibility without replaying commands');
|
|
$r=$call('issuer',$base.'?status=approved');$ok($r['status']===200&&$r['data']['total']===1&&$r['data']['per_page']===25&&$r['data']['data'][0]['id']===$id,'dossier list applies current origin and server status filter');
|
|
$r=$call('issuer',$base.'?search='.rawurlencode($db->table('requisitions')->where('id',$id)->value('number')));$ok($r['status']===200&&$r['data']['total']===1,'literal process number search returns existing source');
|
|
$r=$call('issuer',$base.'?page=2');$ok($r['status']===200&&$r['data']['data']===[],'second dossier list page contains no repeated source');
|
|
$r=$call('issuer',$url);$full=$r['data'];$ok($r['status']===200&&$full['read_only']===true&&$full['request']['id']===$id&&strlen($full['view_revision'])===64,'finance dossier identifies exact source and visible-page revision');
|
|
foreach(['quotes'=>3,'awards'=>1,'orders'=>1,'receipts'=>1,'invoices'=>1]as$stage=>$count)$ok($full['stages'][$stage]['accessible']===true&&$full['stages'][$stage]['pagination']['total']===$count&&count($full['stages'][$stage]['data'])===$count,'canonical '.$stage.' evidence is present with independent page');
|
|
$ok($full['stages']['orders']['data'][0]['id']===$saved['source_ids']['order']&&$full['stages']['invoices']['data'][0]['id']===$saved['source_ids']['invoice'],'dossier correlations use actual original order and invoice ids');
|
|
$position=$full['stages']['obligations']['data'][0];$ok($position['id']===$saved['source_ids']['obligation']&&$position['principal_minor']===10000&&$position['balance_minor']===10000&&$position['due_on']===null&&$position['source_conflict']===false,'canonical kernel supplies current balance with unknown due date');
|
|
$ok($full['stages']['obligations']['source_window']===true&&$full['stages']['obligations']['pagination']['total_sources']===1,'financial pagination describes bounded source window rather than invented global total');
|
|
$ok($full['events']['pagination']['per_page']===25&&count($full['events']['data'])===25,'authorised event timeline uses server pagination');$e2=$call('issuer',$url.'?events_page=2');$ok($e2['status']===200&&count($e2['data']['events']['data'])>0&&array_intersect(array_column($full['events']['data'],'id'),array_column($e2['data']['events']['data'],'id'))===[],'older event page preserves distinct existing history');
|
|
$r=$call('issuer',$url.'?quotes_page=2&awards_page=2&orders_page=2&receipts_page=2&invoices_page=2&obligations_page=2');$ok($r['status']===200&&$r['data']['stages']['quotes']['data']===[]&&$r['data']['stages']['invoices']['data']===[]&&$r['data']['stages']['obligations']['data']===[],'independent later evidence pages do not reload earlier records');
|
|
$r=$call('actor',$url);$ok($r['status']===200&&$r['data']['stages']['quotes']['accessible']===true&&$r['data']['stages']['invoices']===['accessible'=>false]&&$r['data']['stages']['obligations']===['accessible'=>false],'buyer sees procurement evidence without invoice or payable economics');
|
|
$r=$call('requester',$url);$owner=$r['data'];$ok($r['status']===200&&$owner['request']['id']===$id&&count(array_filter($owner['stages'],fn($v)=>$v!==['accessible'=>false]))===0,'request-only profile sees no downstream rows counts or amounts');
|
|
$ok(!array_filter($owner['events']['data'],fn($v)=>!str_starts_with($v['action'],'requisition.')&&$v['action']!=='sgf.request.command'),'request-only history excludes hidden-stage activity');
|
|
$ok(!array_filter($full['events']['data'],fn($v)=>array_diff(array_keys($v),['id','user_id','action','created_at'])),'event projection never embeds unrestricted before-after payloads');
|
|
$ok($call('validator',$url)['status']===403&&$call('reviewer',$url)['status']===403&&$call('auditor',$base)['status']===403,'physical-only and invoice-only profiles do not inherit request dossier rights');
|
|
$ok($call('issuer',$base.'?unknown=1')['status']===422&&$call('issuer',$url.'?events_page=0')['status']===422&&$call('issuer',$url.'?page=1')['status']===422,'unsupported filters and evidence pages refused');
|
|
$ok($call('issuer',$base.'/'.$n['foreign_requisition'])['status']===403&&$call('issuer',$base.'/999999')['status']===403,'foreign or unknown request exposes no dossier');
|
|
$enter('issuer',1,['module'=>'commercial']);$ok($call('issuer',$url,null,1)['status']===409,'different available module cannot inspect dossier');$enter('issuer',1,['foreign'=>1]);$ok($call('issuer',$url,null,1)['status']===403,'unmapped unit cannot inspect known dossier');
|
|
$ok($call('issuer',$url,null,0,['X-SGF-Context'=>'old'])['status']===409,'stale context generation cannot mix dossier reads');
|
|
$ok($call('issuer','/purchasing/dossiers')['status']===200&&str_contains($call('issuer','/purchasing/workspace')['body'],'href="/purchasing/dossiers"'),'authorised dossier screen is connected to common navigation');
|
|
$ok(!str_contains($call('validator','/purchasing/workspace')['body'],'href="/purchasing/dossiers"'),'physical-only navigation does not advertise request dossier');
|
|
$ok($call('issuer',$url,[])['status']===405,'dossier has no mutation endpoint');
|
|
$after=['host'=>$fingerprint(DB::connection()),'native'=>$fingerprint($db)];$ok(json_encode($before)===json_encode($after),'all original regression tables and sequences remain unchanged after read proof');
|
|
file_put_contents($out,json_encode(['passed'=>true,'checks'=>$checks,'reused_proof'=>'purchasing-integrated-composition-20261103.json','financial_commands_repeated'=>0,'before_sha256'=>hash('sha256',json_encode($before)),'after_sha256'=>hash('sha256',json_encode($after)),'tables_checked'=>count($before['host'])+count($before['native'])-2,'new_right_names'=>[],'visual_review'=>false,'deployment_capacity_validated'=>false],JSON_PRETTY_PRINT|JSON_THROW_ON_ERROR));echo count($checks)." dossier read checks passed.\n";
|