Files
compras/scripts/sgf-sourcing-core-proof.php
T
2026-11-02 20:27:11 +02:00

36 lines
4.1 KiB
PHP

<?php
require dirname(__DIR__).'/vendor/autoload.php';
foreach(['QuotationPricing','ProposalScoring','RequisitionFailure','Sourcing'] as $c)require_once dirname(__DIR__).'/packages/purchasing/src/'.$c.'.php';
require_once dirname(__DIR__).'/app/Services/ComparisonPolicy.php';
$engine=new Tempo\Purchasing\Sourcing\Sourcing;
$policy=App\Services\ComparisonPolicy::DEFAULTS;
$request=['status'=>'approved','requester_id'=>1,'data'=>['items'=>[['description'=>'Synthetic material','quantity'=>'1.000','tax_rate'=>'0.00']]]];
$state=['version'=>0,'suppliers'=>[],'quotes'=>[],'proposals'=>[],'confirmed'=>null];$checks=[];
$check=function($ok,$label)use(&$checks){if(!$ok)throw new RuntimeException($label);$checks[]=$label;};
$deny=function($call,$status,$label)use($check){try{$call();throw new RuntimeException('Unexpected success: '.$label);}catch(Tempo\Purchasing\Internal\RequisitionFailure $e){$check($e->status===$status,$label);}};
$step=function($s,$actor,$action,$input)use($engine,$request,$policy){$next=$engine->transition($s,$request,$actor,$action,$input,$policy,'2026-11-02');$next['version']=$s['version']+1;return $next;};
foreach([1,2,3] as $id){$state=$step($state,1,'select',['supplier'=>['id'=>$id,'eligible'=>true,'snapshot'=>['name'=>'Synthetic '.$id]]]);$state=$step($state,1,'quote',['supplier_id'=>$id,'reference'=>'Q-'.$id,'currency'=>'MZN','valid_until'=>'2026-12-31','delivery_days'=>5,'payment_terms'=>'30 days','items'=>[['line'=>0,'unit_price'=>(string)(90+$id*10)]]]);}
$check(!$engine->comparison($state,$policy,'2026-11-02')['ready'],'Existing minimum independent evaluations retained');
$evaluation=fn($id)=>['supplier_id'=>$id,'quote_revision'=>1,'quality'=>8,'history'=>8,'payment'=>8,'reason'=>'Synthetic evaluation reason'];
$deny(fn()=>$step($state,1,'evaluate',$evaluation(1)),403,'Requester cannot evaluate');
foreach([1,2,3] as $id)foreach([2,4] as $actor)$state=$step($state,$actor,'evaluate',$evaluation($id));
$comparison=$engine->comparison($state,$policy,'2026-11-02');$check($comparison['ready']&&$comparison['top_ids']===[1],'Existing weighted scoring identifies best eligible quote');
$proposal=['supplier_id'=>1,'comparison_hash'=>$comparison['fingerprint'],'reason'=>'Synthetic award proposal justification','delivery_date'=>'2027-01-15','delivery_location'=>'Local de entrega exclusivamente sintético OPER'];
$deny(fn()=>$step($state,1,'propose',$proposal),403,'Requester cannot propose award');
$state=$step($state,2,'propose',$proposal);
$confirmation=['proposal_index'=>0,'comparison_hash'=>$comparison['fingerprint'],'reason'=>'Independent synthetic confirmation'];
$deny(fn()=>$step($state,2,'confirm',$confirmation),403,'Proposer cannot confirm own award');
$deny(fn()=>$step($state,1,'confirm',$confirmation),403,'Requester cannot confirm award');
$changed=$step($state,1,'quote',['supplier_id'=>1,'reference'=>'Q-1-r2','currency'=>'MZN','valid_until'=>'2026-12-31','delivery_days'=>6,'payment_terms'=>'30 days','items'=>[['line'=>0,'unit_price'=>'100.00']]]);
$deny(fn()=>$step($changed,4,'confirm',$confirmation),409,'Quote revision invalidates existing award basis and evaluations');
$revoked=$state;$revoked['quotes'][1]['evaluations'][4]['eligible']=false;
$deny(fn()=>$step($revoked,4,'confirm',$confirmation),409,'Evaluator revocation invalidates confirmation basis');
$expired=$state;$expired['quotes'][1]['valid_until']='2026-11-01';
$deny(fn()=>$step($expired,4,'confirm',$confirmation),409,'Expired quote invalidates confirmation');
$ok=$step($state,4,'confirm',$confirmation);
$check($ok['confirmed']['confirmed_by']===4&&$ok['confirmed']['proposal']['proposed_by']===2,'Independent confirmation preserves exact proposed comparison');
$deny(fn()=>$step($ok,1,'quote',[]),409,'Confirmed process cannot be rewritten');
$check($state['proposals'][0]['comparison']['fingerprint']===$comparison['fingerprint'],'Comparison snapshot and justification preserved');
$report=['passed'=>true,'checks'=>$checks,'synthetic_only'=>true,'persistent_demo_accounts_created'=>false,'checked_at'=>gmdate('c')];
file_put_contents(dirname(__DIR__).'/docs/proofs/sgf-sourcing-core.json',json_encode($report,JSON_PRETTY_PRINT|JSON_THROW_ON_ERROR));echo json_encode($report,JSON_PRETTY_PRINT);