Files
SGF/scripts/ledger-cost-correction-proof.php
T
2026-11-04 09:37:20 +02:00

39 lines
12 KiB
PHP

<?php
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Str;
use Tempo\Finance\Payables\Payables;
if(config('cost_ledger.correction_enabled')!==true||!DB::getSchemaBuilder()->hasTable('gl_cost_correction_capability'))throw new LogicException('Explicit new correction capability required');
if($phase==='ledger-cost-correction-ready'){
$output=$s['root'].'/cost-correction-fixture.json';if(file_exists($output)||DB::table('gl_proposals')->exists())throw new LogicException('Fresh correction fixture required');Illuminate\Support\Facades\Date::setTestNow('2026-10-29 12:00:00');
$p=$command('prepare','effect-prepare',$body);$command('validate','validate',['proposal_id'=>$p['proposal_id'],'revision'=>$p['revision'],'decision'=>'approved','reason'=>'Independent original cost275 review.']);$j=$command('prepare','post',['proposal_id'=>$p['proposal_id'],'revision'=>$p['revision'],'reason'=>'Original reviewed cost275, immutable correction baseline.']);$original=(array)DB::table('gl_journals')->where('id',$j['journal_id'])->first();$oldCalc=(array)DB::table('dc_calculations')->where('id',$g['calculation_id'])->first();
$u=$enter('prepare');$rate=$dc->rate($g['order_id'],$u->id,['entry_id'=>$g['material_id'],'entry_version'=>1,'identifier'=>'QA-COST-MATERIAL','version'=>2,'previous_id'=>$g['rate_ids']['material'],'currency'=>'MZN','unit'=>'UN','amount'=>'60.00','evidence'=>'Explicit authorised correction hypothesis2UNx60=120, labour175 retained.'],(string)Str::uuid());$u=$enter('validate');$dc->decide($g['order_id'],$u->id,['kind'=>'rate','id'=>$rate['id'],'version'=>2,'decision'=>'approved','reason'=>'Independent exact successor rate60 review.'],(string)Str::uuid());$u=$enter('prepare');$calc=$dc->calculate($g['order_id'],$u->id,['version'=>2,'previous_id'=>$g['calculation_id'],'currency'=>'MZN','lines'=>[['entry_id'=>$g['material_id'],'entry_version'=>1,'rate_id'=>$rate['id'],'rate_version'=>2],['entry_id'=>$g['time_id'],'entry_version'=>1,'rate_id'=>$g['rate_ids']['time'],'rate_version'=>1]]],(string)Str::uuid());$u=$enter('validate');$dc->decide($g['order_id'],$u->id,['kind'=>'calculation','id'=>$calc['id'],'version'=>2,'decision'=>'approved','reason'=>'Independent selected cost120+175=295, no inventory valuation.'],(string)Str::uuid());
$source=app(App\Modules\Accounting\CostLedgerSource::class)->source($enter('read'),$g['order_id']);if($source['principal_minor']!==29500||$ledger->costs($enter('read'),$g['order_id'])['cost']['accounting_state']!=='requires_correction')throw new LogicException('Actual successor295 must require explicit correction');
file_put_contents($output,json_encode(['passed'=>true,'original_journal_id'=>$j['journal_id'],'original_journal_sha256'=>hash('sha256',Payables::canonical($original)),'original_calculation_sha256'=>hash('sha256',Payables::canonical($oldCalc)),'replacement_rate_id'=>$rate['id'],'replacement_calculation_id'=>$calc['id'],'original_minor'=>27500,'replacement_minor'=>29500,'difference_minor'=>2000,'source_fingerprint'=>$sourceFingerprint(),'no_correction_groups_yet'=>true],JSON_PRETTY_PRINT|JSON_THROW_ON_ERROR));echo "New correction fixture: actual original275 posted; actual successor rate60/calculation295 independently approved; no correction group yet.\n";exit;
}
$cg=json_decode(file_get_contents($s['root'].'/cost-correction-fixture.json'),true,64,JSON_THROW_ON_ERROR);$correctionBody=['journal_id'=>$cg['original_journal_id'],'journal_on'=>'2026-10-29','period_key'=>'QA-2026-10','reason'=>'Explicit indivisible reversal275 and replacement295, selected known direct cost.'];$captureCorrection=fn()=>$command('prepare','correct-prepare',$correctionBody);$approveCorrection=fn($p)=>$command('validate','correct-validate',['correction_id'=>$p['correction_id'],'revision'=>$p['revision'],'decision'=>'approved','reason'=>'Independent review of original275, latest295, delta20 and four pair lines.']);$postCorrectionBody=fn($p)=>['correction_id'=>$p['correction_id'],'revision'=>$p['revision'],'reason'=>'Apply reviewed cost correction pair atomically once.'];
$originalsIntact=function()use($cg,$g,$sourceFingerprint){return $sourceFingerprint()===$cg['source_fingerprint']&&hash('sha256',Payables::canonical((array)DB::table('gl_journals')->where('id',$cg['original_journal_id'])->first()))===$cg['original_journal_sha256']&&hash('sha256',Payables::canonical((array)DB::table('dc_calculations')->where('id',$g['calculation_id'])->first()))===$cg['original_calculation_sha256'];};
if($phase==='ledger-cost-correction-cases'){require __DIR__.'/ledger-cost-correction-cases.php';exit;}
if($phase==='ledger-cost-correction-ui-postcheck'){
$output=$s['root'].'/cost-correction-ui-postcheck.json';if(file_exists($output))throw new LogicException('Completed UI postcheck preserved');$u=$enter('prepare');$data=$ledger->costs($u,$g['order_id']);$page=view('accounting.cost-ledger',['data'=>$data])->render();$generic=view('accounting.general-ledger',['data'=>$ledger->listing($u)])->render();$legacy=Tempo\Finance\GeneralLedger\CycleWorkspace::render($ledger->cycle($u),['host'=>'Synthetic read probe','csrf'=>'qa','context'=>null,'scope'=>$scope,'financial_url'=>'/supplier-payments','return_url'=>'/general-ledger','page_url'=>'/general-ledger/cycle']);
if(!str_contains($page,'Captura superada')||str_contains($page,'data-action="post"')||str_contains($generic,'data-action="post"')||str_contains($legacy,'data-action="post"'))throw new LogicException('An interface exposed isolated stale correction parts');file_put_contents($output,json_encode(['passed'=>true,'superseded_group_visible_without_action'=>true,'cost_generic_and_legacy_cycle_hide_isolated_part_application'=>true,'read_only'=>true],JSON_PRETTY_PRINT|JSON_THROW_ON_ERROR));echo "All three interfaces hide isolated parts, including stale reviewed/unposted captures; historical group visible.\n";exit;
}
if($phase==='ledger-cost-correction-defaults'){
$output=$s['root'].'/cost-correction-defaults.json';if(file_exists($output))throw new LogicException('Completed defaults preserved');$v=getenv('SGF_COST_CORRECTION_QA');$a=$_ENV['SGF_COST_CORRECTION_QA']??null;$b=$_SERVER['SGF_COST_CORRECTION_QA']??null;putenv('SGF_COST_CORRECTION_QA');unset($_ENV['SGF_COST_CORRECTION_QA'],$_SERVER['SGF_COST_CORRECTION_QA']);try{$default=(require $c['root'].'/config/cost_ledger.php')['correction_enabled'];}finally{if($v!==false)putenv('SGF_COST_CORRECTION_QA='.$v);if($a!==null)$_ENV['SGF_COST_CORRECTION_QA']=$a;if($b!==null)$_SERVER['SGF_COST_CORRECTION_QA']=$b;}
if($default!==false||config('cost_ledger.correction_enabled')!==true)throw new LogicException('Correction default must be off, only explicit new QA composition on');file_put_contents($output,json_encode(['passed'=>true,'default_without_environment'=>false,'explicit_new_qa_runtime'=>true,'real_environment_unchanged'=>true],JSON_PRETTY_PRINT|JSON_THROW_ON_ERROR));echo "Cost correction defaults off, explicit new QA runtime only.\n";exit;
}
if($phase==='ledger-cost-correction-demo-preservation'){
$output=$s['root'].'/cost-correction-demo-preservation.json';if(file_exists($output)||!$originalsIntact()||DB::table('gl_corrections')->exists()||DB::table('gl_correction_results')->exists()||DB::table('gl_journals')->count()!==1||DB::table('gl_period_closures')->exists()||DB::table('permission_grants')->where('permission','like','general_ledger.%')->count()!==12)throw new LogicException('Team correction fixture unexpectedly changed; no reset');file_put_contents($output,json_encode(['passed'=>true,'original275_present'=>true,'actual_validated_successor295'=>true,'original_source_outbox_rights_exact'=>true,'initial_journals'=>1,'initial_correction_groups'=>0,'initial_closures'=>0,'ledger_grants'=>12,'distinct_ledger_rights'=>10,'no_business_writes'=>true],JSON_PRETTY_PRINT|JSON_THROW_ON_ERROR));echo "Team correction fixture preserved: original275/current295, twelve QA grants, no correction group or close.\n";exit;
}
if($phase==='ledger-cost-correction-security'){require __DIR__.'/ledger-cost-correction-security.php';exit;}
if($phase==='ledger-cost-correction-http-final'){
$output=$s['root'].'/cost-correction-http-final.json';if(file_exists($output))throw new LogicException('Completed final preserved');$data=$ledger->costs($enter('read'),$g['order_id']);$html=view('accounting.cost-ledger',['data'=>$data])->render();if(!$originalsIntact()||DB::table('gl_journals')->count()!==3||DB::table('gl_lines')->count()!==6||DB::table('gl_correction_results')->count()!==1||DB::table('gl_period_closures')->count()!==1||str_contains($html,'data-action='))throw new LogicException('Final correction/source/closed UI state differs');DB::select('SELECT gl_cost_pair_assert(id) FROM gl_corrections');file_put_contents($output,json_encode(['passed'=>true,'original_journal_calculation_source_outbox_rights_unchanged'=>true,'journals'=>3,'lines'=>6,'results'=>1,'closures'=>1,'closed_ui_no_commands'=>true],JSON_PRETTY_PRINT|JSON_THROW_ON_ERROR));echo "Correction HTTP final: original/source/outbox/rights exact, one pair/close and closed view without commands.\n";exit;
}
if($phase==='ledger-cost-correction-coexistence'){require __DIR__.'/ledger-cost-correction-coexistence.php';exit;}
if(in_array($phase,['ledger-cost-correction-race','ledger-cost-correction-worker'],true)){require __DIR__.'/ledger-cost-correction-race.php';exit;}
if($phase==='ledger-cost-correction-workflow'){
$output=$s['root'].'/cost-correction-workflow.json';if(file_exists($output)||DB::table('gl_corrections')->exists())throw new LogicException('Fresh correction workflow only');$p=$captureCorrection();$approveCorrection($p);$post=$postCorrectionBody($p);$key=(string)Str::uuid();$r=$command('prepare','correct-post',$post,$key);$replay=$command('prepare','correct-post',$post,$key);$other=$command('prepare','correct-post',$post);
$check=$command('prepare','period-prepare',['period_key'=>'QA-2026-10','reason'=>'Conference of resolved original and indivisible current cost correction.']);$command('validate','period-validate',['check_id'=>$check['check_id'],'revision'=>$check['revision'],'decision'=>'approved','reason'=>'Independent correction and period reconciliation.']);$command('prepare','period-close',['check_id'=>$check['check_id'],'revision'=>$check['revision'],'reason'=>'Close corrected cost QA period without reopening.']);$report=$ledger->report($enter('read'),'trial-balance',['from_on'=>'2026-10-01','to_on'=>'2026-10-31']);$account=$ledger->report($enter('read'),'account-ledger',['from_on'=>'2026-10-01','to_on'=>'2026-10-31','account_id'=>$g['accounts']['QA-CUSTO-DIRECTO']]);
if(!$replay['replayed']||$other['result_id']!==$r['result_id']||!$originalsIntact()||DB::table('gl_journals')->count()!==3||DB::table('gl_lines')->count()!==6||DB::table('gl_correction_results')->count()!==1||$report['totals']['debit_minor']!==84500||$account['closing_net_minor']!==29500||$ledger->costs($enter('read'),$g['order_id'])['cost']['accounting_state']!=='current')throw new LogicException('Cost correction outcome, period or preservation differs');DB::select('SELECT gl_assert_balanced(id) FROM gl_journals');DB::select('SELECT gl_cost_pair_assert(?)',[$r['correction_id']]);file_put_contents($output,json_encode(['passed'=>true,'journals'=>3,'lines'=>6,'correction_groups_applied'=>1,'gross_debit_minor'=>84500,'gross_credit_minor'=>84500,'cost_balance_minor'=>29500,'net_difference_minor'=>2000,'original_cost_calculation_source_outbox_rights_unchanged'=>true,'same_and_other_key_single_pair'=>true,'period_closed'=>true,'reports_reconciled'=>true],JSON_PRETTY_PRINT|JSON_THROW_ON_ERROR));echo "Actual correction275->295: three journals/six lines, gross845, balance295, one indivisible result and reviewed QA close; originals preserved.\n";exit;
}
throw new LogicException('Unknown correction proof phase');