49 lines
4.9 KiB
PHP
49 lines
4.9 KiB
PHP
<?php
|
|
// Additional integration checks only. All mutation probes roll back in this owned QA database.
|
|
$output=$s['root'].'/ledger-flow-cases.json';
|
|
if(file_exists($output)||!($g['integrated_flow']??false))throw new LogicException('Dedicated unfinished flow proof required');
|
|
$http=json_decode(file_get_contents($s['root'].'/ledger-flow-http.json'),true,64,JSON_THROW_ON_ERROR);
|
|
$checks=0;$check=function(bool $ok,string $why)use(&$checks){$checks++;if(!$ok)throw new LogicException($why);};
|
|
$reader=$enter('read');$before=$financialFingerprint();$queries=[];$mode=null;
|
|
DB::listen(function($event)use(&$queries,&$mode){$queries[]=$event->sql;if(str_contains($event->sql,'"gl_journals"')){$pdo=$event->connection->getPdo();$mode=['isolation'=>$pdo->query('SHOW transaction_isolation')->fetchColumn(),'read_only'=>$pdo->query('SHOW transaction_read_only')->fetchColumn()];}});
|
|
$data=$ledger->flow($reader,$g['local_source_id']);
|
|
$check($data['position']['id']===$http['obligation_id']&&$data['journal']->id===$http['journal_id'],'Same scoped financial and accounting origin');
|
|
$check($mode===['isolation'=>'repeatable read','read_only'=>'on'],'Single coherent read-only snapshot');
|
|
$check(!array_filter($queries,fn($q)=>str_contains(strtolower($q),'for update')),'No writer locks in flow read');
|
|
$check(count($data['financial_proposals'])===1&&count($data['financial_events'])<=25,'Bounded source evidence');
|
|
$reject=function(Closure $probe,int $expected=403)use($check){try{$probe();throw new LogicException('Expected access refusal');}catch(Symfony\Component\HttpKernel\Exception\HttpException $e){$check($e->getStatusCode()===$expected,'Explicit access refusal');}};
|
|
foreach(['general_ledger.view','supplier_payables.view'] as $permission){
|
|
DB::beginTransaction();try{
|
|
DB::table('permission_grants')->where($scope)->where(['user_id'=>$reader->id,'permission'=>$permission])->delete();
|
|
$reject(fn()=>$ledger->flow($reader,$g['local_source_id']));
|
|
}finally{DB::rollBack();}
|
|
}
|
|
DB::beginTransaction();try{
|
|
DB::table('pa_access')->where($scope)->where(['user_id'=>$reader->id,'action'=>'view'])->delete();
|
|
$reject(fn()=>$ledger->flow($reader,$g['local_source_id']));
|
|
}finally{DB::rollBack();}
|
|
DB::beginTransaction();try{
|
|
$row=(array)DB::table('pa_imported_sources')->where('id',$g['local_source_id'])->first();unset($row['id']);$row['unit_id']+=1000;$other=DB::table('pa_imported_sources')->insertGetId($row);
|
|
$reject(fn()=>$ledger->flow($reader,$other));
|
|
}finally{DB::rollBack();}
|
|
DB::beginTransaction();try{
|
|
$row=(array)DB::table('pa_imported_sources')->where('id',$g['local_source_id'])->first();unset($row['id']);$row['company_id']+=1000;$other=DB::table('pa_imported_sources')->insertGetId($row);
|
|
$reject(fn()=>$ledger->flow($reader,$other));
|
|
}finally{DB::rollBack();}
|
|
DB::beginTransaction();try{
|
|
$row=(array)DB::table('pa_imported_sources')->where('id',$g['local_source_id'])->first();unset($row['id']);$row['tenant_id']+=1000;$other=DB::table('pa_imported_sources')->insertGetId($row);
|
|
$reject(fn()=>$ledger->flow($reader,$other));
|
|
}finally{DB::rollBack();}
|
|
$data=$ledger->listing($enter('read'),['obligation_id'=>$http['obligation_id']]);
|
|
$check(count($data['events'])===3&&count($data['proposals'])===1&&count($data['journals'])===1,'Focus retains prepare, independent review and posting evidence');
|
|
$check($data['totals']===['debit_minor'=>6000,'credit_minor'=>6000,'net_minor'=>0],'Focused accounting totals reconciled');
|
|
$check($before===$financialFingerprint(),'All authorisation and foreign-scope probes rolled back');
|
|
$check(DB::table('pa_obligations')->count()===1&&DB::table('gl_journals')->count()===1&&DB::table('gl_lines')->count()===2,'One debt, one journal, two lines after retries');
|
|
$check(DB::table('gl_events')->where('kind','journal.posted')->count()===1,'One durable posting event');
|
|
$check(DB::table('permission_grants')->where('permission','like','general_ledger.%')->count()===6,'Only explicitly authorised synthetic grants retained');
|
|
$check(DB::table('gl_proposals')->value('prepared_by')!==DB::table('gl_reviews')->value('reviewed_by'),'Distinct accounting identities');
|
|
foreach(DB::table('pa_imported_sources')->get() as $row)$check(hash_equals($row->receipt_hash,hash('sha256',Tempo\Finance\Payables\Payables::canonical(json_decode($row->payload,true)))),'Document receipt unchanged');
|
|
$check((require $c['root'].'/config/general_ledger.php')['synthetic_enabled']===false,'Destination remains disabled');
|
|
file_put_contents($output,json_encode(['passed'=>true,'checks'=>$checks,'coherent_read'=>$mode,'flow_query_count'=>count($queries),'scope_refusals'=>['tenant','company','unit'],'revoked_rights_refused'=>true,'mutating_probes_rolled_back'=>true,'one_obligation_one_journal'=>true,'six_qa_grants'=>true,'default_enabled'=>false],JSON_PRETTY_PRINT|JSON_THROW_ON_ERROR));
|
|
echo "Integrated isolation, current permissions, source receipts, read snapshot and single effect verified: $checks checks.\n";
|