Files
SGF/scripts/sgf-composed-direct-cost-proof.php
2026-11-11 09:00:17 +02:00

32 lines
5.4 KiB
PHP

<?php
use Illuminate\Support\Str;
use App\Shared\Context\CompanyContext;
use App\Modules\Workshop\DirectCosts;
require __DIR__.'/sgf-ledger-proof-bootstrap.php';
config(['sales_ledger.synthetic_enabled'=>true,'cost_ledger.synthetic_enabled'=>true,'industrial_ledger.synthetic_enabled'=>true,'cost_ledger.correction_enabled'=>true,'industrial_ledger.correction_enabled'=>true]);
$fixture=json_decode(file_get_contents($s['root'].'/single-direct-cost.json'),true);$order=$fixture['order'];$old=$host->table('dc_calculations')->where('id',$fixture['calculation']['id'])->value('snapshot');
$host->beginTransaction();$native->beginTransaction();
try{
$p=$call('accounting_prepare','prepare',fn($e)=>$e->command('effect-prepare',['effect_type'=>'workshop.direct_cost.validated','source_id'=>$order,'journal_on'=>'2026-11-10','period_key'=>'QA-2026-INTEGRADO','rule_key'=>'workshop.direct_cost.validated','reason'=>'Custo275 proveniente da oficina e validado na mesma instalação.'],(string)Str::uuid()));
$call('accounting_review','validate',fn($e)=>$e->command('validate',['proposal_id'=>$p['proposal_id'],'revision'=>$p['revision'],'decision'=>'approved','reason'=>'Revisão contabilística distinta do custo275.'],(string)Str::uuid()));
$j=$call('accounting_prepare','post',fn($e)=>$e->command('post',['proposal_id'=>$p['proposal_id'],'revision'=>$p['revision'],'reason'=>'Aplicação explícita do custo original275.'],(string)Str::uuid()));
$ok((int)$native->table('gl_journals')->where('id',$j['journal_id'])->value('debit_minor')===27500,'original host workshop cost275 posts in the same native ledger');
$set=function($role)use($profiles,$f){$id=$profiles[$role]['user_id'];Illuminate\Support\Facades\Auth::guard('web')->setUser(App\Models\User::findOrFail($id));app(CompanyContext::class)->selectFor($id,$f['tenant'],$f['company'],$f['unit']);return $id;};
$dc=app(DirectCosts::class);$prepare=$set('finance_prepare');
$rate=$dc->rate($order,$prepare,['entry_id'=>$fixture['material'],'entry_version'=>1,'identifier'=>'QA-INTEGRADO-material','version'=>2,'previous_id'=>$fixture['rates']['material'],'currency'=>'MZN','unit'=>'UN','amount'=>'60','evidence'=>'Taxa sucessora QA60 para duas unidades.'],(string)Str::uuid())['id'];
$review=$set('finance_review');$dc->decide($order,$review,['kind'=>'rate','id'=>$rate,'version'=>2,'decision'=>'approved','reason'=>'Validação independente da taxa sucessora60.'],(string)Str::uuid());
$set('finance_prepare');$c=$dc->calculate($order,$prepare,['currency'=>'MZN','version'=>2,'previous_id'=>$fixture['calculation']['id'],'lines'=>[['entry_id'=>$fixture['material'],'entry_version'=>1,'rate_id'=>$rate,'rate_version'=>2],['entry_id'=>$fixture['time'],'entry_version'=>1,'rate_id'=>$fixture['rates']['time'],'rate_version'=>1]]],(string)Str::uuid());
$set('finance_review');$dc->decide($order,$review,['kind'=>'calculation','id'=>$c['id'],'version'=>2,'decision'=>'approved','reason'=>'Novo total295 validado, conservando o custo anterior.'],(string)Str::uuid());
$ok($dc->conference($order,$review)['snapshot']['selected_direct_total_exact']==='295','successor validated calculation uses120 material plus175 labour');
$ok($old===$host->table('dc_calculations')->where('id',$fixture['calculation']['id'])->value('snapshot'),'original275 calculation remains immutable');
$correction=$call('accounting_prepare','correct_prepare',fn($e)=>$e->command('correct-prepare',['journal_id'=>$j['journal_id'],'journal_on'=>'2026-11-10','period_key'=>'QA-2026-INTEGRADO','reason'=>'Correcção explicitamente autorizada275 para295 por par indivisível.'],(string)Str::uuid()));
$call('accounting_review','correct_validate',fn($e)=>$e->command('correct-validate',['correction_id'=>$correction['correction_id'],'revision'=>$correction['revision'],'decision'=>'approved','reason'=>'Revisão independente do estorno275 e substituição295.'],(string)Str::uuid()));
$key=(string)Str::uuid();$input=['correction_id'=>$correction['correction_id'],'revision'=>$correction['revision'],'reason'=>'Aplicação atómica dos dois lançamentos revistos.'];
$pair=$call('accounting_prepare','correct_post',fn($e)=>$e->command('correct-post',$input,$key));$retry=$call('accounting_prepare','correct_post',fn($e)=>$e->command('correct-post',$input,$key));
$ok($pair['reverse_journal_id']===$retry['reverse_journal_id']&&$pair['replacement_journal_id']===$retry['replacement_journal_id'],'correction replay recovers the original indivisible pair');
$ok((int)$native->table('gl_journals')->where('id',$pair['reverse_journal_id'])->value('debit_minor')===27500&&(int)$native->table('gl_journals')->where('id',$pair['replacement_journal_id'])->value('debit_minor')===29500,'same ledger retains reversal275 and replacement295');
$native->statement('SET CONSTRAINTS ALL IMMEDIATE');$ok(true,'balanced journal constraints validate the entire correction pair');
}finally{while($native->transactionLevel()>0)$native->rollBack();while($host->transactionLevel()>0)$host->rollBack();}
$ok($host->table('dc_calculations')->where('order_id',$order)->count()===1,'regression rolls back the successor without changing accepted original');
file_put_contents($work.'/direct-ledger-result.json',json_encode(['passed'=>true,'checks'=>$checks,'rolled_back'=>true,'same_native_book'=>true],JSON_PRETTY_PRINT));echo json_encode(['passed'=>true,'checks'=>count($checks),'proof'=>$work.'/direct-ledger-result.json']).PHP_EOL;