Files
SGF/scripts/sgf-document-cancellation-schema.php
T
2026-11-11 09:00:17 +02:00

17 lines
4.2 KiB
PHP

<?php
$book=$argv[1]??'regression';require __DIR__.'/sgf-single-bootstrap.php';$host->transaction(function()use($host){
$record=$host->selectOne("SELECT pg_get_functiondef('sgf_sr_record_guard()'::regprocedure) d")->d;if(!str_contains($record,'reverse_reduction')){$new=str_replace("'reverse_receipt','reduction','due'","'reverse_receipt','reduction','reverse_reduction','due'",$record);if($new===$record)throw new LogicException('Unknown correction record guard');$host->unprepared($new);}
$def=$host->selectOne("SELECT pg_get_constraintdef(oid) d FROM pg_constraint WHERE conrelid='sr_effects'::regclass AND conname='sr_effects_kind_check'")->d;
if(!str_contains($def,'reverse_reduction')){$new=str_replace("'reduction'::text","'reduction'::text, 'reverse_reduction'::text",$def);if($new===$def)throw new LogicException('Unknown effect contract');$host->statement('ALTER TABLE sr_effects DROP CONSTRAINT sr_effects_kind_check');$host->statement('ALTER TABLE sr_effects ADD CONSTRAINT sr_effects_kind_check '.$new);}
$body=$host->selectOne("SELECT pg_get_functiondef('sgf_sr_effect_guard()'::regprocedure) d")->d;
if(!str_contains($body,'reverse_reduction')){$body=str_replace(["'reverse_allocation','reverse_reconcile'","WHEN kind='reverse_allocation' THEN -amount","THEN 'allocate' ELSE 'reconcile' END"],["'reverse_allocation','reverse_reconcile','reverse_reduction'","WHEN kind IN ('reverse_allocation','reverse_reduction') THEN -amount","THEN 'allocate' WHEN NEW.kind='reverse_reduction' THEN 'reduction' ELSE 'reconcile' END"],$body);$host->unprepared($body);}
if(!$host->getSchemaBuilder()->hasTable('sd_cancellations')){
$host->unprepared("CREATE TABLE sd_cancellations(id bigserial PRIMARY KEY,tenant_id bigint NOT NULL,company_id bigint NOT NULL,unit_id bigint NOT NULL,cancellation_key uuid NOT NULL,version int NOT NULL CHECK(version>0),output_id bigint NOT NULL REFERENCES sd_outputs(id),state text NOT NULL CHECK(state IN('prepared','cancelled')),actor_id bigint NOT NULL REFERENCES users(id),correction_id bigint NOT NULL REFERENCES sr_records(id),effect_id bigint REFERENCES sr_effects(id),snapshot jsonb NOT NULL,reason text NOT NULL CHECK(length(reason)>=10),created_at timestamptz NOT NULL DEFAULT now(),UNIQUE(tenant_id,company_id,unit_id,cancellation_key,version))");
$host->statement("CREATE UNIQUE INDEX sd_one_cancellation ON sd_cancellations(output_id) WHERE state='cancelled'");
$host->statement('CREATE TRIGGER sd_cancellation_immutable BEFORE UPDATE OR DELETE ON sd_cancellations FOR EACH ROW EXECUTE FUNCTION sgf_append_only_audit()');$host->statement('CREATE TRIGGER sd_cancellation_test BEFORE INSERT ON sd_cancellations FOR EACH ROW EXECUTE FUNCTION sgf_wo_test_only()');$host->statement('REVOKE ALL ON sd_cancellations FROM PUBLIC');$host->statement('REVOKE ALL ON SEQUENCE sd_cancellations_id_seq FROM PUBLIC');
}
$def=$host->selectOne("SELECT pg_get_constraintdef(oid) d FROM pg_constraint WHERE conrelid='sd_cancellations'::regclass AND conname='sd_cancellations_version_check'")->d;if(!str_contains($def,'version > 0')){$host->statement('ALTER TABLE sd_cancellations DROP CONSTRAINT sd_cancellations_version_check');$host->statement('ALTER TABLE sd_cancellations ADD CONSTRAINT sd_cancellations_version_check CHECK(version>0)');}
$index=$host->selectOne("SELECT pg_get_indexdef('sd_one_cancellation'::regclass) d")->d;if(!str_contains($index,'state')){$host->statement('DROP INDEX sd_one_cancellation');$host->statement("CREATE UNIQUE INDEX sd_one_cancellation ON sd_cancellations(output_id) WHERE state='cancelled'");}
});
$native->transaction(function()use($native,$f){$r=$native->table('gl_rules')->where($f['scope'])->where('rule_key','receivable.reduced')->firstOrFail();if(!$native->table('gl_rules')->where($f['scope'])->where('rule_key','receivable.reduction_reversed')->exists()){$v=(array)$r;unset($v['id']);$v['rule_key']=$v['effect_type']='receivable.reduction_reversed';$v['debit_account_id']=$r->credit_account_id;$v['credit_account_id']=$r->debit_account_id;$v['reason']='Reversão técnica QA ligada ao crédito original, sem reabertura.';$native->table('gl_rules')->insert($v);}});echo json_encode(['passed'=>true,'book'=>$book,'old_effects_not_modified'=>true]).PHP_EOL;