35 lines
3.7 KiB
PHP
35 lines
3.7 KiB
PHP
<?php
|
|
require __DIR__.'/../vendor/autoload.php';
|
|
$app=require __DIR__.'/../bootstrap/app.php'; $app->make(\Illuminate\Contracts\Console\Kernel::class)->bootstrap();
|
|
if(!\App\Modules\Identity\Services\LocalDatabaseGuard::allows()) throw new RuntimeException('Own local development database required.');
|
|
$db=\Illuminate\Support\Facades\DB::class;
|
|
$file=storage_path('app/service-fiscal-preservation-before.json');
|
|
$before=in_array('--before',$argv,true); $grants=in_array('--after-grants',$argv,true);
|
|
$baseline=$before ? null : json_decode(file_get_contents($file),true,64,JSON_THROW_ON_ERROR);
|
|
$tables=$before ? array_map(fn($r)=>$r->tablename,$db::select("SELECT tablename FROM pg_tables WHERE schemaname='public' AND (tablename ~ '^(a_|b_|ca_|doc_|document_|service_calculation_)' OR tablename IN ('users','tenants','companies','units','company_memberships','permission_grants','identity_audit')) ORDER BY tablename")) : array_keys($baseline['tables']);
|
|
$summary=[];
|
|
foreach($tables as $table) {
|
|
if(!preg_match('/^[a-z_]+$/D',$table)) throw new RuntimeException('Unexpected table.');
|
|
$where='';
|
|
if($grants && in_array($table,['permission_grants','identity_audit'],true)) $where=' WHERE id <= '.(int)$baseline['max'][$table];
|
|
$r=$db::selectOne('SELECT count(*) AS n, md5(COALESCE(string_agg(row_to_json(t)::text, E\'\\n\' ORDER BY row_to_json(t)::text),\'\')) AS fingerprint FROM (SELECT * FROM "'.$table.'"'.$where.') t');
|
|
$summary[$table]=['count'=>(int)$r->n,'hash'=>$r->fingerprint];
|
|
}
|
|
if($before) {
|
|
file_put_contents($file,json_encode(['tables'=>$summary,'max'=>['permission_grants'=>(int)$db::table('permission_grants')->max('id'),'identity_audit'=>(int)$db::table('identity_audit')->max('id')]],JSON_THROW_ON_ERROR));
|
|
echo "Existing SGF development records fingerprinted in database; no record contents disclosed.\n"; exit;
|
|
}
|
|
if($summary!==$baseline['tables']) throw new RuntimeException('Existing SGF record fingerprint changed; review before proceeding.');
|
|
foreach(['sf_proposals','sf_decisions','sf_activation_events'] as $table) if($db::table($table)->count()!==0) throw new RuntimeException('Unexpected real fiscal lifecycle record.');
|
|
if($grants) {
|
|
$actual=$db::table('permission_grants')->where('permission','like','service_fiscal.%')->orderBy('user_id')->orderBy('permission')->get(['user_id','tenant_id','company_id','unit_id','permission'])->map(fn($r)=>(array)$r)->all();
|
|
$expected=[];
|
|
foreach([1=>['view','propose','calculate'],2=>['view','approve']] as $user=>$actions) foreach($actions as $a) $expected[]=['user_id'=>$user,'tenant_id'=>1,'company_id'=>1,'unit_id'=>$a==='calculate'?1:null,'permission'=>'service_fiscal.'.$a];
|
|
usort($expected,fn($a,$b)=>[$a['user_id'],$a['permission']]<=>[$b['user_id'],$b['permission']]);
|
|
if($actual!==$expected) throw new RuntimeException('Fiscal grants differ from specifically confirmed matrix.');
|
|
$new=$db::table('identity_audit')->where('id','>',$baseline['max']['identity_audit'])->where('action','service_fiscal.initial_grant')->count();
|
|
if($new!==5) throw new RuntimeException('Expected five audited initial grants.');
|
|
}
|
|
file_put_contents(base_path('docs/proofs/service-fiscal-dev-preservation'.($grants?'-grants':'').'.json'),json_encode(['database'=>'sgf_tempo_dev','preexisting_tables_checked'=>count($summary),'preexisting_records_unchanged'=>true,'new_fiscal_tables_empty'=>true,'real_profile_activated'=>false,'confirmed_grants_verified'=>$grants?5:0,'prior_grants_and_audit_unchanged'=>true],JSON_PRETTY_PRINT|JSON_THROW_ON_ERROR));
|
|
echo $grants ? "Exactly five confirmed fiscal grants and audit entries verified; prior records preserved; no real profile created or activated.\n" : "Migration preserved existing records and grants; all new fiscal tables empty.\n";
|