18 lines
6.8 KiB
PHP
18 lines
6.8 KiB
PHP
<?php
|
|
$book=$argv[1]??'regression';require __DIR__.'/sgf-single-bootstrap.php';
|
|
$p=json_decode(file_get_contents($repo.'/docs/integration/sgf-fixed-assets-access-proposal.json'),true);$scope=$p['scope'];if(($p['approved']??false)!==true||$p['authorization']['decision']!=='Autorizar o ciclo integrado de activos QA'||$scope!==['tenant_id'=>1,'company_id'=>2,'unit_id'=>2]||$p['grants_per_book']!==array_merge(array_map(fn($u)=>['user_id'=>$u,'permission'=>'fixed_assets.view'],[15,16,17]),[['user_id'=>15,'permission'=>'fixed_assets.prepare'],['user_id'=>16,'permission'=>'fixed_assets.review']]))throw new LogicException('Exact approval required');if($book==='8085'&&!is_file($s['root'].'/assets-backup-pointer.json'))throw new LogicException('Backup first');
|
|
$sql=file_get_contents($repo.'/database/sql/fixed_assets.sql');$sha=hash('sha256',$sql);$grants=0;$accounts=0;$rules=0;
|
|
$host->transaction(function()use($host,$p,$sql,$sha,$tag,&$grants){if(!$host->getSchemaBuilder()->hasTable('fa_meta')){$host->unprepared($sql);$host->table('fa_meta')->insert(['policy'=>App\Modules\Accounting\FixedAssets::POLICY,'composition'=>$tag,'source_hash'=>$sha]);}else{$m=$host->table('fa_meta')->first();if(!$m||$m->source_hash!==$sha||$m->composition!==$tag)throw new LogicException('Schema differs');}
|
|
$host->statement('REVOKE ALL ON TABLE fa_meta,fa_versions,fa_commands FROM PUBLIC');$host->statement('REVOKE ALL ON SEQUENCE fa_versions_id_seq,fa_commands_id_seq FROM PUBLIC');$host->statement('REVOKE ALL ON FUNCTION fa_append_only() FROM PUBLIC');$old=$host->selectOne("SELECT pg_get_constraintdef(oid) d FROM pg_constraint WHERE conrelid='permission_grants'::regclass AND conname='permission_grants_scope_check'")->d;if(!str_contains($old,'fixed_assets.view')){if(!preg_match('/^CHECK \((.*)\)$/s',$old,$m))throw new LogicException('Unknown scope check');$host->statement('ALTER TABLE permission_grants DROP CONSTRAINT permission_grants_scope_check');$host->statement('ALTER TABLE permission_grants ADD CONSTRAINT permission_grants_scope_check CHECK (('.$m[1].") OR (unit_id IS NOT NULL AND permission IN('fixed_assets.view','fixed_assets.prepare','fixed_assets.review')))");}
|
|
foreach($p['grants_per_book']as$g){$g=$p['scope']+$g;if($host->table('permission_grants')->where($g)->exists())continue;$host->table('permission_grants')->insert($g);App\Modules\Identity\Services\Audit::record('access.granted_on_creation',null,1,2,2,$g['user_id'],['permission'=>$g['permission'],'reason'=>$p['authorization'],'limits'=>'Activos artificiais QA; sem operações reais.']);$grants++;}});
|
|
$nativeSql=file_get_contents($repo.'/database/sql/fixed_assets_native.sql');$nativeSha=hash('sha256',$nativeSql);
|
|
$native->transaction(function()use($native,$host,$scope,$p,$nativeSql,$nativeSha,&$accounts,&$rules,$work){Tempo\Finance\GeneralLedger\LedgerSchema::assertSynthetic($native);if(!$native->getSchemaBuilder()->hasTable('gl_asset_books')){
|
|
$original=$native->selectOne("SELECT pg_get_functiondef('gl_assert_balanced(bigint)'::regprocedure) d")->d;file_put_contents($work.'/gl-balanced-before-private.sql',$original);$needle="WHEN j.snapshot->'source'->>'effect_type'='sales.invoice' THEN 3 ELSE 2 END";if(substr_count($original,$needle)!==1)throw new LogicException('Unrecognised balance function');$replacement="WHEN j.snapshot->'source'->>'effect_type'='sales.invoice' THEN 3 WHEN j.snapshot->'source'->>'effect_type'='assets.writeoff' THEN jsonb_array_length(j.snapshot->'lines') ELSE 2 END";$native->unprepared(str_replace($needle,$replacement,$original));$native->unprepared($nativeSql);$native->table('gl_asset_books')->insert($scope+['policy'=>'QA-ASSET-JOURNAL-v1','host_database'=>$host->getDatabaseName(),'schema_sha256'=>$nativeSha]);
|
|
}else{$m=$native->table('gl_asset_books')->where($scope)->first();if(!$m||!in_array($m->schema_sha256,[$nativeSha,'4d0a0dae2a843979ce61c17c619070f67723b235b22989c1820acfe0686a21de'],true)||$m->host_database!==$host->getDatabaseName())throw new LogicException('Native schema mismatch');if(!$native->getSchemaBuilder()->hasTable('gl_asset_extension_versions'))$native->unprepared(substr($nativeSql,strpos($nativeSql,'-- ASSET_PAIR_EXTENSION_v1')));}
|
|
$extension=$native->table('gl_asset_extension_versions')->where('version',1)->first();if($extension){if($extension->source_hash!==$nativeSha)throw new LogicException('Asset extension mismatch');}else $native->table('gl_asset_extension_versions')->insert(['version'=>1,'source_hash'=>$nativeSha]);
|
|
$cycle=$native->selectOne("SELECT pg_get_functiondef('gl_cycle_pair_integrity()'::regprocedure) d")->d;if(!str_contains($cycle,'gl_asset_pair_assert')){$needle=" IF TG_TABLE_NAME='gl_correction_results' THEN";if(!str_contains($cycle,$needle))throw new LogicException('Unknown cycle guard');file_put_contents($work.'/gl-cycle-before-private.sql',$cycle);$at=strpos($cycle,$needle);$branch=" IF TG_TABLE_NAME='gl_correction_results' THEN IF EXISTS(SELECT 1 FROM gl_journals WHERE id=NEW.reverse_journal_id AND snapshot->'source'->>'effect_type'='assets.depreciation.reversal') THEN PERFORM gl_asset_pair_assert(NEW.correction_id); RETURN NEW; END IF; END IF;\n";$native->unprepared(substr($cycle,0,$at).$branch.substr($cycle,$at));}
|
|
foreach($p['new_accounts_per_book']as$a){if($native->table('gl_accounts')->where($scope+['code'=>$a['code']])->exists())continue;$native->table('gl_accounts')->insert($scope+['code'=>$a['code'],'label'=>$a['purpose'],'is_movement'=>true,'currency'=>'MZN']);$accounts++;}
|
|
$codes=$native->table('gl_accounts')->where($scope)->pluck('id','code');$plans=[['ADMISSION','assets.admitted','CUSTO','ORIGEM-QA'],['DEPRECIATION','assets.depreciation','GASTO-DEP','DEP-ACUM'],['WRITEOFF','assets.writeoff','DEP-ACUM','CUSTO'],['WRITEOFF-NO-DEP','assets.writeoff','GASTO-ABATE','CUSTO'],['CORRECTION-REVERSE','assets.depreciation.reversal','DEP-ACUM','GASTO-DEP'],['CORRECTION-REPLACE','assets.depreciation.replacement','GASTO-DEP','DEP-ACUM']];foreach($plans as[$key,$type,$debit,$credit]){if($native->table('gl_rules')->where($scope+['rule_key'=>'QA-ASSET-'.$key])->exists())continue;$native->table('gl_rules')->insert($scope+['rule_key'=>'QA-ASSET-'.$key,'version'=>1,'policy'=>'QA-ASSET-JOURNAL-v1','effect_type'=>$type,'currency'=>'MZN','valid_from'=>'2026-01-01','valid_to'=>'2026-12-31','debit_account_id'=>$codes['QA-ACTIVO-'.$debit],'credit_account_id'=>$codes['QA-ACTIVO-'.$credit],'created_by'=>15,'reason'=>'Regra artificial do ciclo de activos expressamente autorizado.','created_at'=>now()->utc()]);$rules++;}
|
|
});
|
|
file_put_contents($work.'/assets-setup.json',json_encode(['passed'=>true,'book'=>$book,'new_grants'=>$grants,'accounts'=>$accounts,'rules'=>$rules,'new_demo'=>false,'schema_sha256'=>$sha,'native_sha256'=>$nativeSha],JSON_PRETTY_PRINT));echo json_encode(['passed'=>true,'book'=>$book,'grants'=>$grants,'accounts'=>$accounts,'rules'=>$rules,'proof'=>$work.'/assets-setup.json']).PHP_EOL;
|