Files
SGF/scripts/sgf-workshop-direct-workflow.php
T
2026-11-11 09:00:17 +02:00

37 lines
7.2 KiB
PHP

<?php
use Illuminate\Support\Facades\{DB,Auth};
use Illuminate\Support\Str;
use Carbon\Carbon;
use App\Shared\Context\{CompanyContext,ModuleRecords};
use App\Modules\Workshop\{WorkshopWorkflow,DirectCosts};
$book=$argv[1]??'regression';require __DIR__.'/sgf-single-bootstrap.php';
$profiles=json_decode(file_get_contents($s['root'].'/single-profiles.json'),true)['profiles'];$commercial=json_decode(file_get_contents($s['root'].'/single-commercial.json'),true);
config(['sgf_single_installation.enabled'=>true,'sgf_single_installation.schema_sha256'=>$host->table('sgf_composition_schema')->value('source_hash')]);
$path=$s['root'].'/single-direct-cost.json';$saved=is_file($path)?json_decode(file_get_contents($path),true):null;
$select=function($role,$module='workshop')use($profiles,$f,$app){$u=App\Models\User::findOrFail($profiles[$role]['user_id']);Auth::guard('web')->setUser($u);$r=Illuminate\Http\Request::create('/api/workshop','POST');$r->attributes->set('sgf_module',$module);$r->setUserResolver(fn()=>$u);$session=app('session')->driver();$session->start();$session->put('company_context',$f['scope']+['module_id'=>$module,'token'=>'direct-'.$role]);$r->setLaravelSession($session);$app->instance('request',$r);app(CompanyContext::class)->selectFor($u->id,$f['tenant'],$f['company'],$f['unit']);return $u->id;};
$key=fn()=>(string)Str::uuid();$oldNow=Carbon::getTestNow();
try{$result=$saved??$host->transaction(function()use($host,$profiles,$commercial,$f,$select,$key,$tag){
$client=$host->table('a_clients')->where('id',$commercial['client'])->first();if(!$client||!$host->table('a_history')->where(['area'=>'clients','record_id'=>$client->id,'version'=>1,'actor_id'=>$commercial['preparer']])->exists())throw new LogicException('New authorized client required');
ModuleRecords::associate('clients',$client->id,$commercial['preparer'],['tenant_id'=>$f['tenant'],'company_id'=>$f['company'],'unit_id'=>null],'workshop','Decisão individual do cliente QA recém-criado para a oficina integrada.',false,(int)$client->version);
$w=app(WorkshopWorkflow::class);$dc=app(DirectCosts::class);$manager=$profiles['workshop_manage']['user_id'];$tech=$profiles['workshop_record']['user_id'];$verifier=$profiles['workshop_verify']['user_id'];$day='2026-11-09';
Carbon::setTestNow(Carbon::parse($day.' 08:00:00',WorkshopWorkflow::ZONE));$select('workshop_manage');
$order=$w->open($manager,['reference'=>'OT-INTEGRADA-'.$tag,'client_id'=>$client->id,'equipment_identifier'=>'EQ-INTEGRADO-'.$tag,'equipment_description'=>'Equipamento exclusivamente sintético','request'=>'Intervenção sintética integrada','location'=>'Unidade QA','evidence'=>'QA-DIRECT-275'],$key())['id'];
$revision=fn()=>(int)$host->selectOne('SELECT sgf_wo_revision(?) AS v',[$order])->v;
$record=fn($actor,$kind,$data)=>$w->record($order,$actor,['kind'=>$kind,'origin'=>'QA-'.$kind.'-'.Str::uuid(),'version'=>1,'revision'=>$revision()]+$data,$key())['id'];
$record($manager,'assignment',['technician_id'=>$tech]);$select('workshop_record');$task=$record($tech,'task',['description'=>'Tarefa sintética de custo directo']);
$select('workshop_manage');$authorization=$record($manager,'authorization',['task_id'=>$task,'authorized_by'=>'Representante fictício','capacity'=>'Cliente QA','authorized_at'=>$day.'T07:59:00+02:00','channel'=>'Documento QA','scope'=>'Tarefa seleccionada','evidence'=>'QA-AUTH']);
Carbon::setTestNow(Carbon::parse($day.' 12:00:00',WorkshopWorkflow::ZONE));$select('workshop_record');
$time=$record($tech,'time',['task_id'=>$task,'authorization_id'=>$authorization,'starts_at'=>$day.'T09:00:00+02:00','ends_at'=>$day.'T11:00:00+02:00','mode'=>'reported','time_type'=>'work','pauses'=>[['start'=>$day.'T10:00:00+02:00','end'=>$day.'T10:15:00+02:00']],'evidence'=>'QA-TEMPO-105MIN']);
$points=[$task,$time];foreach(['delivered'=>'3','consumed'=>'2','returned'=>'1'] as $event=>$quantity){$id=$record($tech,'material',['task_id'=>$task,'authorization_id'=>$authorization,'starts_at'=>$day.'T11:00:00+02:00','resource'=>'QA-MATERIAL-DIRECTO-'.$tag,'unit'=>'UN','owner'=>'company','event'=>$event,'quantity'=>$quantity,'evidence'=>'QA-MATERIAL-DISTINTO-STOCK-VALORIZADO']);$points[]=$id;if($event==='consumed')$material=$id;}
$select('workshop_verify');foreach($points as $id)$w->verify($id,$verifier,['version'=>1,'revision'=>$revision(),'decision'=>'verified','reason'=>'Conferência técnica independente das origens sintéticas.'],$key());
$prepare=$select('finance_prepare','finance');$rates=[];foreach(['material'=>[$material,'UN','50'],'time'=>[$time,'H','100']] as $kind=>[$entry,$unit,$amount])$rates[$kind]=$dc->rate($order,$prepare,['entry_id'=>$entry,'entry_version'=>1,'identifier'=>'QA-INTEGRADO-'.$kind,'version'=>1,'previous_id'=>null,'currency'=>'MZN','unit'=>$unit,'amount'=>$amount,'evidence'=>'Taxa artificial expressamente seleccionada.'],$key())['id'];
$review=$select('finance_review','finance');foreach($rates as $id)$dc->decide($order,$review,['kind'=>'rate','id'=>$id,'version'=>1,'decision'=>'approved','reason'=>'Validação financeira distinta das duas taxas QA.'],$key());
$select('finance_prepare','finance');$input=['currency'=>'MZN','version'=>1,'previous_id'=>null,'lines'=>[['entry_id'=>$material,'entry_version'=>1,'rate_id'=>$rates['material'],'rate_version'=>1],['entry_id'=>$time,'entry_version'=>1,'rate_id'=>$rates['time'],'rate_version'=>1]]];$command=$key();$calculation=$dc->calculate($order,$prepare,$input,$command);$retry=$dc->calculate($order,$prepare,$input,$command);if($retry['id']!==$calculation['id'])throw new LogicException('Duplicate direct calculation');
$select('finance_review','finance');$dc->decide($order,$review,['kind'=>'calculation','id'=>$calculation['id'],'version'=>1,'decision'=>'approved','reason'=>'Custo275MZN completo e validado distintamente.'],$key());
$conference=$dc->conference($order,$review);if($conference['snapshot']['selected_direct_total_exact']!=='275')throw new LogicException('Expected100+175=275');
return compact('order','task','authorization','time','material','rates','calculation','day')+['total'=>'275','synthetic_only'=>true,'client'=>$client->id];
});}finally{Carbon::setTestNow($oldNow);}
file_put_contents($path,json_encode($result,JSON_PRETTY_PRINT|JSON_THROW_ON_ERROR));
$mapping=$native->transaction(function()use($host,$native,$result,$nf){$scope=['tenant_id'=>1,'company_id'=>2,'unit_id'=>2];$row=$native->table('gl_cost_sources')->where($scope)->where('order_id',$result['order'])->first();if($row)return $row->id;return $native->table('gl_cost_sources')->insertGetId($scope+['order_id'=>$result['order'],'material_origin'=>$host->table('wo_entries')->where('id',$result['material'])->value('origin'),'time_origin'=>$host->table('wo_entries')->where('id',$result['time'])->value('origin'),'period_key'=>'QA-2026-INTEGRADO','created_by'=>$nf['finance'],'reason'=>'Perímetro individual QA275; material distinto do artigo de valorização.','created_at'=>now()]);});
file_put_contents($work.'/direct-workflow-result.json',json_encode(['passed'=>true,'book'=>$book,'order'=>$result['order'],'mapping'=>$mapping,'total'=>'275','new_accounts'=>0,'distinct_technical_and_financial_review'=>true,'replay_without_duplicate'=>true],JSON_PRETTY_PRINT));echo json_encode(['passed'=>true,'total'=>'275','proof'=>$work.'/direct-workflow-result.json']).PHP_EOL;