Files
SGF/scripts/workshop-billing-manual-verify.php

34 lines
4.5 KiB
PHP

<?php
// Reconcile the reported manual generation without altering records or credentials.
require __DIR__.'/../vendor/autoload.php';$app=require __DIR__.'/../bootstrap/app.php';$app->make(\Illuminate\Contracts\Console\Kernel::class)->bootstrap();
use Illuminate\Support\Facades\DB;
use App\Modules\Workshop\WorkshopBilling;
use App\Modules\Services\DraftValues;
function requireWorkshopManual(bool $ok,string $reason): void {if(!$ok)throw new RuntimeException($reason);}
WorkshopBilling::guard();
$identity=DB::selectOne('SELECT current_database() AS db,current_user AS role');
requireWorkshopManual($identity->db==='sgf_tempo_test'&&$identity->role==='sgf_test_runner','Unexpected database.');
$generations=DB::table('wb_generations')->get();requireWorkshopManual($generations->count()===1,'Exactly one synthetic generation required.');$g=$generations->first();
$p=DB::table('wb_proposals')->find($g->proposal_id);$review=DB::table('wb_decisions')->where(['proposal_id'=>$p->id,'version'=>$p->version,'decision'=>'approved'])->first();
requireWorkshopManual($review&&$review->actor_id!==$p->actor_id&&$g->actor_id===$p->actor_id,'Separate commercial identities required.');
$snapshot=json_decode($p->snapshot,true,64,JSON_THROW_ON_ERROR);$service=DB::table('a_service_drafts')->find($g->service_draft_id);$billing=DB::table('a_billing_drafts')->find($g->billing_draft_id);
requireWorkshopManual($service&&$billing&&$billing->source_id===$service->id&&$billing->state==='draft'&&$service->state==='draft','Draft destination chain differs.');
$sd=json_decode($service->data,true);$bd=json_decode($billing->data,true);
requireWorkshopManual($sd['currency']==='MZN'&&$bd['currency']==='MZN'&&DraftValues::base($sd)==='500'&&DraftValues::base($bd)==='500'&&$snapshot['base_exact']==='500','Commercial amounts differ.');
requireWorkshopManual(count($snapshot['lines'])===2&&count($bd['lines'])===2,'Two selected lines required.');
$claims=DB::table('wb_claims')->where('generation_id',$g->id)->get();requireWorkshopManual($claims->count()===2,'Two unique source claims required.');
foreach($snapshot['lines'] as $i=>$line){
$entry=DB::table('wo_entries')->where(['id'=>$line['entry_id'],'version'=>$line['entry_version'],'order_id'=>$g->order_id,'origin'=>$line['origin']])->first();
requireWorkshopManual($entry&&!$entry->outside_authority,'Source differs.');
requireWorkshopManual(DB::table('wo_decisions')->where(['entry_id'=>$entry->id,'entry_version'=>$entry->version,'decision'=>'verified'])->exists(),'Technical verification missing.');
requireWorkshopManual($claims->contains(fn($c)=>$c->entry_id===$entry->id&&$c->entry_version===$entry->version&&$c->origin===$entry->origin),'Source claim differs.');
foreach(['service_id','quantity','unit_price','description'] as $field)requireWorkshopManual($bd['lines'][$i][$field]===$line[$field],'Generated line differs: '.$field);
requireWorkshopManual($line['price_source']==='WORKSHOP-SALES-SYNTHETIC-v1','Unexpected price reference.');
requireWorkshopManual($entry->kind==='time'?($line['quantity']==='1.75'&&$line['unit_price']==='200'):($line['quantity']==='2'&&$line['unit_price']==='75'),'Quantity/price differs.');
}
requireWorkshopManual(!DB::table('b_internal_confirmations')->where('billing_draft_id',$billing->id)->exists(),'Unexpected internal confirmation.');
requireWorkshopManual($bd['tax_status']==='pending'&&$bd['accounting_status']==='not_processed','Unexpected fiscal/accounting state.');
$proof=['policy'=>WorkshopBilling::POLICY,'date'=>'2026-10-28','database'=>'sgf_tempo_test','method'=>'user_reported_manual_browser_and_read_only_reconciliation','order_id'=>$g->order_id,'proposal_id'=>$p->id,'proposal_version'=>$p->version,'service_draft_id'=>$service->id,'billing_draft_id'=>$billing->id,'commercial_base_exact'=>'500','currency'=>'MZN','source_claims'=>2,'distinct_commercial_review'=>true,'generated_lines_match_reviewed_proposal'=>true,'internal_confirmation_created'=>false,'fiscal_status'=>'pending','accounting_status'=>'not_processed','screenshots_received'=>false,'automated_browser_recovered'=>false,'records_changed'=>false,'user_acceptance'=>false,'closing_checkpoint_created'=>false];
file_put_contents(base_path('docs/proofs/workshop-billing-manual-results.json'),json_encode($proof,JSON_PRETTY_PRINT|JSON_THROW_ON_ERROR).PHP_EOL);
echo 'Manual generation reconciled: proposal #'.$p->id.' v'.$p->version.', service #'.$service->id.', billing draft #'.$billing->id.'; 500 MZN, two source claims, separate review, no internal confirmation. No records changed.'.PHP_EOL;