18 lines
6.7 KiB
PHP
18 lines
6.7 KiB
PHP
<?php
|
|
require __DIR__.'/sgf-remunerations-proof-bootstrap.php';
|
|
$before=[];foreach(['permission_grants','wo_orders','cash_events','fx_versions','fo_versions','sd_outputs']as$t)$before[$t]=$host->table($t)->orderBy('id')->get()->toJson();$counts=[$host->table('rm_versions')->count(),$host->table('rm_commands')->count()];
|
|
$host->beginTransaction();try{
|
|
$wk=$uuid();$rk=$uuid();$pk=$uuid();$in=$input('worker',$wk,0,$workerData);$p=$preview(13,$in);$ok($host->table('rm_versions')->count()===$counts[0],'preview writes no version');[$w1,$wp,$wkey]=$command(13,$in);$ok($w1['state']==='prepared'&&$w1['version']===1,'worker individual preparation');$again=$confirm(13,$wp['preview']);$ok($again['replayed']&&$again['id']===$w1['id'],'same command replay no duplicate');$reject(fn()=>$preview(13,$input('worker',$wk,1,['decision'=>'approved'],'review')),403,'own review forbidden');$reject(fn()=>$preview(14,$in),403,'reviewer cannot prepare');$reject(fn()=>$preview(17,$in),403,'reader cannot prepare');[$w2]=$command(14,$input('worker',$wk,1,['decision'=>'approved'],'review'));$ok($w2['state']==='approved','distinct worker review');$reject(fn()=>$preview(13,$input('worker',$uuid(),0,$workerData)),409,'duplicate worker code refused');
|
|
[$r1]=$command(13,$input('rules',$rk,0,$rulesData));[$r2]=$command(14,$input('rules',$rk,1,['decision'=>'approved'],'review'));$pay=['operation'=>'establish','worker_key'=>$wk,'rules_key'=>$rk,'period'=>'2026-11','gross'=>'10000.00'];[$v1,$cut,$key]=$command(13,$input('payroll',$pk,0,$pay));$c=$v1['impact']['after']['proposal']['calculation'];$ok($c['net_cents']==='890000'&&$c['employer_cost_cents']==='1040000'&&$c['deductions_cents']==='110000','exact artificial gross10000 net8900 cost10400');$ok($c['rubrics']['worker_rate']['cents']==='30000'&&$c['rubrics']['retention_rate']['cents']==='80000'&&$c['rubrics']['employer_rate']['cents']==='40000','rubrics distinguish employee and employer');$ok(!$v1['impact']['debt_created']&&$v1['impact']['journals']===0&&$v1['impact']['payments']===0,'no financial effect');$reject(fn()=>$preview(13,$input('payroll',$uuid(),0,$pay)),409,'duplicate person period refused');
|
|
$stale=$preview(14,$input('payroll',$pk,1,['decision'=>'approved'],'review'));[$v2]=$command(13,$input('payroll',$pk,1,$pay));$reject(fn()=>$confirm(14,$stale['preview']),409,'stale review version refused');[$v3]=$command(14,$input('payroll',$pk,2,['decision'=>'approved'],'review'));$ok($v3['version']===3&&$v3['state']==='approved','current preparation reviewed distinctly');$select(17);$export=$rm->export($hrActor(17),$v3['id']);$ok(hash('sha256',$export['bytes'])===$export['sha256']&&str_contains($export['bytes'],'890000'),'frozen reviewed artifact SHA');
|
|
$changed=array_replace($pay,['operation'=>'amend','gross'=>'10001.00']);[$v4]=$command(13,$input('payroll',$pk,3,$changed));[$v5]=$command(14,$input('payroll',$pk,4,['decision'=>'refused'],'review'));$list=$listing('payroll',['record_key'=>$pk]);$ok($list['records']['data'][0]['effective']['id']===$v3['id'],'refusal preserves effective reviewed amount');[$v6]=$command(13,$input('payroll',$pk,5,$changed));[$v7]=$command(14,$input('payroll',$pk,6,['decision'=>'approved'],'review'));$ok($v7['impact']['after']['effective']['calculation']['net_cents']==='890089','reviewed correction updates net exactly');$select(17);$ok($rm->export($hrActor(17),$v3['id'])===$export,'old reviewed export bytes immutable after correction');
|
|
$cancel=array_replace($changed,['operation'=>'cancel']);[$v8]=$command(13,$input('payroll',$pk,7,$cancel));[$v9]=$command(14,$input('payroll',$pk,8,['decision'=>'approved'],'review'));$ok($v9['impact']['after']['effective']['status']==='cancelled','distinct cancellation preserved');$ok($listing()['page_totals']['approved_active_on_page']===0,'cancelled excluded from active page totals');$reject(fn()=>$preview(13,$input('payroll',$pk,9,$changed)),409,'cancelled record cannot be silently revived');
|
|
$tiny=App\Modules\HumanResources\Remunerations::calculate('0.01',$rulesData);$ok($tiny['net_cents']==='1'&&$tiny['rubrics']['worker_rate']['difference']==='3/100','cent difference exact rational preserved');$missing=App\Modules\HumanResources\Remunerations::calculate('10000.00',array_replace($rulesData,['retention_rate'=>null]));$ok(!$missing['complete']&&$missing['net_cents']===null&&$missing['rubrics']['retention_rate']['cents']===null,'missing parameter not zero net unknown');
|
|
$newRules=$uuid();$missingRules=array_replace($rulesData,['retention_rate'=>null]);[$a]=$command(13,$input('rules',$newRules,0,$missingRules));[$a]=$command(14,$input('rules',$newRules,1,['decision'=>'approved'],'review'));$p2=$uuid();$pay2=array_replace($pay,['period'=>'2026-10','rules_key'=>$newRules]);[$a]=$command(13,$input('payroll',$p2,0,$pay2));$reject(fn()=>$preview(14,$input('payroll',$p2,1,['decision'=>'approved'],'review')),409,'incomplete payroll cannot be approved complete');
|
|
$suspended=array_replace($workerData,['operation'=>'amend','status'=>'suspended']);[$a]=$command(13,$input('worker',$wk,2,$suspended));[$a]=$command(14,$input('worker',$wk,3,['decision'=>'approved'],'review'));$reject(fn()=>$preview(13,$input('payroll',$uuid(),0,array_replace($pay,['period'=>'2026-09']))),409,'suspended worker processing refused');
|
|
$reject(fn()=>$preview(13,$input('payroll',$uuid(),0,array_replace($pay,['worker_key'=>$uuid()]))),409,'foreign or unavailable dependency refused');$reject(fn()=>$preview(13,$in+['tenant_id'=>2]),422,'input context override refused');$reject(fn()=>$preview(13,$input('payroll',$uuid(),0,array_replace($pay,['gross'=>'1e4']))),422,'non documentary amount refused');$reject(fn()=>$confirm(13,$wp['preview'],'changed-generation'),409,'changed generation rejected');$select(17);$reject(fn()=>$rm->export($hrActor(17),$w2['id']),403,'worker cannot be exported as payroll');$reject(fn()=>$rm->receipt($hrActor(17),$wkey),404,'other actor cannot recover private command');$select(13,'rm-proof','accounting');$reject(fn()=>$rm->listing($hrActor(13),['kind'=>'worker']),403,'cross module read refused');
|
|
$select(13);config(['remunerations.enabled'=>false]);$reject(fn()=>$rm->listing($hrActor(13),['kind'=>'worker']),404,'disabled block unavailable');config(['remunerations.enabled'=>true]);
|
|
}finally{$host->rollBack();}
|
|
foreach($before as$t=>$json)$ok($host->table($t)->orderBy('id')->get()->toJson()===$json,'original unchanged '.$t);$ok([$host->table('rm_versions')->count(),$host->table('rm_commands')->count()]===$counts,'all synthetic case versions and receipts rolled back');
|
|
file_put_contents($work.'/remunerations-result.json',json_encode(['passed'=>true,'checks'=>$checks,'regression_only'=>true,'financial_writes'=>0,'all_case_rows_rolled_back'=>true],JSON_PRETTY_PRINT));echo json_encode(['passed'=>true,'checks'=>count($checks),'proof'=>$work.'/remunerations-result.json']).PHP_EOL;
|