Files
SGF/scripts/ledger-cycle-final.php
2026-11-04 09:37:20 +02:00

24 lines
3.9 KiB
PHP

<?php
use Tempo\Finance\GeneralLedger\CycleWorkspace;
use Tempo\Finance\Payables\Payables;
$output=$s['root'].'/ledger-cycle-final.json';if(file_exists($output))throw new LogicException('Completed final proof preserved');$checks=0;
$ok=function(bool $v,string $why)use(&$checks){$checks++;if(!$v)throw new LogicException($why);};$before=$financialFingerprint();$native=$native??false;$reader=$enter('read');$sql=[];$mode=null;$capture=true;
DB::listen(function($e)use(&$sql,&$mode,&$capture){if(!$capture)return;$sql[]=$e->sql;if(!$mode&&str_contains($e->sql,'"gl_journals"')){$pdo=$e->connection->getPdo();$mode=['isolation'=>$pdo->query('SHOW transaction_isolation')->fetchColumn(),'read_only'=>$pdo->query('SHOW transaction_read_only')->fetchColumn()];}});
$workspace=$native?$ledger->workspace($reader):$ledger->cycle($reader);$capture=false;
$ok($mode===['isolation'=>'repeatable read','read_only'=>'on']&&!array_filter($sql,fn($q)=>str_contains(strtolower($q),'for update')),'Whole workspace shares coherent read snapshot without writer locks');
$ok(count($workspace['book']['journals'])===5&&count($workspace['book']['lines'])===10&&count($workspace['period_closures'])===1,'Retained complete cycle counts');
$ok($workspace['book']['totals']===['debit_minor'=>22000,'credit_minor'=>22000,'net_minor'=>0],'Gross period totals220 reconciled');
foreach(['validate','post'] as $action){$part=DB::table('gl_proposals')->where('snapshot->source->effect_type','journal.reversal')->first();$body=['proposal_id'=>$part->id,'revision'=>$part->revision,'reason'=>'Individual route must refuse corrective pair.'];if($action==='validate')$body['decision']='approved';$caught=false;try{$command($action==='post'?'prepare':'validate',$action,$body);}catch(DomainException $e){$caught=str_contains($e->getMessage(),'par de correcção');}$ok($caught,'Public individual route refuses corrective part with domain refusal');}
if(!$native){$flow=$ledger->flow($enter('read'),$g['local_source_id']);$ok(json_decode($flow['journal']->snapshot,true)['source']['effect_type']==='supplier_payable.recognised','Original recognition flow is not replaced by corrective/settlement effects');}
$events=DB::table('gl_events')->count();DB::beginTransaction();try{
for($i=0;$i<60;$i++)DB::table('gl_events')->insert($scope+['actor_id'=>$f['actors']['prepare'],'person'=>'explicit-qa-history-probe','kind'=>'qa.pagination','entity_id'=>1,'reason'=>'Rollback-only long history test.','previous'=>'{}','subsequent'=>'{}','created_at'=>now()]);
$data=$native?$ledger->workspace($enter('read'),2):$ledger->cycle($enter('read'),2);
$ok(count($data['book']['events'])===25&&$data['book']['evidence_pagination']['events']['last_page']>=3,'History remains bounded with further pages');
$html=CycleWorkspace::render($data,['host'=>'QA','csrf'=>'qa','return_url'=>'/','financial_url'=>'/supplier-payments','page_url'=>'/general-ledger/cycle']);
$ok(str_contains($html,'?page=3'),'Navigation reaches evidence pages after last journal page');
}finally{DB::rollBack();}
$ok($before===$financialFingerprint()&&DB::table('gl_events')->count()===$events,'Read and paging probes preserve original financial/ledger records');
if($native)$ok(fingerprint()===$g['native_originals_sha256'],'Native original invoice/items/external payments/stock/budget fingerprint preserved');
$ok(($native?(require $c['root'].'/config/general-ledger.php'):(require $c['root'].'/config/general_ledger.php'))['cycle_enabled']===false,'Destination cycle flag remains off');
file_put_contents($output,json_encode(['passed'=>true,'checks'=>$checks,'composition'=>$native?'native':'sgf','coherent_read'=>$mode,'writer_locks'=>0,'financial_sha256'=>$before,'financial_unchanged'=>true,'bounded_evidence_navigation'=>true,'individual_corrective_route_409'=>true,'native_originals_preserved'=>$native?true:null,'default_cycle_enabled'=>false],JSON_PRETTY_PRINT|JSON_THROW_ON_ERROR));echo "Final cycle preservation/read/navigation contract: $checks checks.\n";