commit melhorias1
This commit is contained in:
@@ -0,0 +1,28 @@
|
||||
CREATE TABLE fa_meta(policy text PRIMARY KEY,composition text NOT NULL,source_hash char(64) NOT NULL);
|
||||
CREATE TABLE fa_versions(
|
||||
id bigserial PRIMARY KEY,tenant_id bigint NOT NULL,company_id bigint NOT NULL,unit_id bigint NOT NULL,
|
||||
kind text NOT NULL CHECK(kind IN('asset','plan','charge','disposal')),record_key uuid NOT NULL,version bigint NOT NULL CHECK(version>0),previous_id bigint UNIQUE REFERENCES fa_versions(id),
|
||||
action text NOT NULL CHECK(action IN('prepare','review')),state text NOT NULL CHECK(state IN('prepared','approved','refused')),
|
||||
prepared_by bigint NOT NULL REFERENCES users(id),actor_id bigint NOT NULL REFERENCES users(id),
|
||||
preparer_identity char(64) NOT NULL,data jsonb NOT NULL,source_basis char(64) NOT NULL,
|
||||
impact jsonb NOT NULL,reason text NOT NULL CHECK(length(reason)>=10),created_at timestamptz NOT NULL,
|
||||
UNIQUE(tenant_id,company_id,unit_id,record_key,version),
|
||||
FOREIGN KEY(tenant_id,company_id,unit_id) REFERENCES units(tenant_id,company_id,id),
|
||||
CHECK(jsonb_typeof(data)='object'),CHECK(jsonb_typeof(impact)='object'),
|
||||
CHECK((action='prepare' AND state='prepared') OR (action='review' AND state IN('approved','refused'))),
|
||||
CHECK(action<>'review' OR prepared_by<>actor_id)
|
||||
);
|
||||
CREATE TABLE fa_commands(
|
||||
id bigserial PRIMARY KEY,tenant_id bigint NOT NULL,company_id bigint NOT NULL,unit_id bigint NOT NULL,
|
||||
actor_id bigint NOT NULL REFERENCES users(id),command_key uuid NOT NULL,request_hash char(64) NOT NULL,
|
||||
result jsonb NOT NULL,input jsonb NOT NULL,created_at timestamptz NOT NULL,
|
||||
UNIQUE(tenant_id,company_id,unit_id,actor_id,command_key)
|
||||
);
|
||||
CREATE FUNCTION fa_append_only() RETURNS trigger LANGUAGE plpgsql AS $$
|
||||
BEGIN RAISE EXCEPTION 'SGF_FIXED_ASSETS_APPEND_ONLY'; END; $$;
|
||||
CREATE TRIGGER fa_meta_immutable BEFORE UPDATE OR DELETE ON fa_meta FOR EACH ROW EXECUTE FUNCTION fa_append_only();
|
||||
CREATE TRIGGER fa_versions_immutable BEFORE UPDATE OR DELETE ON fa_versions FOR EACH ROW EXECUTE FUNCTION fa_append_only();
|
||||
CREATE TRIGGER fa_commands_immutable BEFORE UPDATE OR DELETE ON fa_commands FOR EACH ROW EXECUTE FUNCTION fa_append_only();
|
||||
|
||||
CREATE INDEX fa_versions_scope_latest ON fa_versions(tenant_id,company_id,unit_id,record_key,version DESC);
|
||||
CREATE INDEX fa_versions_kind ON fa_versions(tenant_id,company_id,unit_id,kind,id DESC);
|
||||
@@ -0,0 +1,40 @@
|
||||
CREATE TABLE gl_asset_books(tenant_id bigint NOT NULL,company_id bigint NOT NULL,unit_id bigint NOT NULL,policy text NOT NULL,host_database text NOT NULL,schema_sha256 char(64) NOT NULL,PRIMARY KEY(tenant_id,company_id,unit_id));
|
||||
CREATE FUNCTION gl_asset_guard() RETURNS trigger LANGUAGE plpgsql AS $$
|
||||
DECLARE s jsonb;k text;cost bigint;acc bigint;loss bigint;g gl_correction_results%ROWTYPE;o gl_journals%ROWTYPE;expected text[];
|
||||
BEGIN
|
||||
s:=NEW.snapshot->'source';k:=s->>'effect_type';IF k NOT LIKE 'assets.%' THEN RETURN NEW; END IF;
|
||||
IF NOT EXISTS(SELECT 1 FROM gl_asset_books b WHERE (b.tenant_id,b.company_id,b.unit_id)=(NEW.tenant_id,NEW.company_id,NEW.unit_id) AND b.policy='QA-ASSET-JOURNAL-v1' AND b.host_database=s->>'host_database') OR NEW.snapshot->'rule'->>'policy'<>'QA-ASSET-JOURNAL-v1' OR NEW.snapshot->'rule'->>'effect_type'<>k OR (s->>'tax_minor')::bigint<>0 OR (s->>'amount_minor')::bigint<>NEW.debit_minor THEN RAISE EXCEPTION 'ASSET_SOURCE_OR_RULE' USING ERRCODE='23514';END IF;
|
||||
expected:=CASE k WHEN 'assets.admitted' THEN ARRAY['QA-ACTIVO-CUSTO','QA-ACTIVO-ORIGEM-QA'] WHEN 'assets.depreciation' THEN ARRAY['QA-ACTIVO-GASTO-DEP','QA-ACTIVO-DEP-ACUM'] WHEN 'assets.depreciation.replacement' THEN ARRAY['QA-ACTIVO-GASTO-DEP','QA-ACTIVO-DEP-ACUM'] WHEN 'assets.depreciation.reversal' THEN ARRAY['QA-ACTIVO-DEP-ACUM','QA-ACTIVO-GASTO-DEP'] ELSE NULL END;
|
||||
IF k='assets.writeoff' THEN
|
||||
cost:=(s->>'cost_minor')::bigint;acc:=(s->>'accumulated_minor')::bigint;loss:=(s->>'carrying_minor')::bigint;
|
||||
IF cost<>NEW.debit_minor OR acc<0 OR loss<0 OR acc+loss<>cost THEN RAISE EXCEPTION 'ASSET_WRITEOFF_VALUES' USING ERRCODE='23514';END IF;
|
||||
expected:=CASE WHEN acc=0 THEN ARRAY['QA-ACTIVO-GASTO-ABATE','QA-ACTIVO-CUSTO'] WHEN loss=0 THEN ARRAY['QA-ACTIVO-DEP-ACUM','QA-ACTIVO-CUSTO'] ELSE ARRAY['QA-ACTIVO-DEP-ACUM','QA-ACTIVO-GASTO-ABATE','QA-ACTIVO-CUSTO'] END;
|
||||
END IF;
|
||||
IF expected IS NULL OR jsonb_array_length(NEW.snapshot->'lines')<>cardinality(expected) OR EXISTS(SELECT 1 FROM jsonb_array_elements(NEW.snapshot->'lines') WITH ORDINALITY x(line,n) WHERE x.line->>'account_code'<>expected[x.n]) THEN RAISE EXCEPTION 'ASSET_ACCOUNT_LINES' USING ERRCODE='23514';END IF;
|
||||
IF k IN('assets.depreciation.reversal','assets.depreciation.replacement') THEN
|
||||
SELECT * INTO g FROM gl_correction_results WHERE reverse_journal_id=NEW.id OR replacement_journal_id=NEW.id;
|
||||
SELECT * INTO o FROM gl_journals WHERE id=g.original_journal_id AND (tenant_id,company_id,unit_id)=(NEW.tenant_id,NEW.company_id,NEW.unit_id);
|
||||
IF g.id IS NULL OR o.id IS NULL OR o.snapshot->'source'->>'effect_type'<>'assets.depreciation' OR (s->>'source_id')::bigint<>o.id OR s->>'asset_key'<>o.snapshot->'source'->>'asset_key' OR (k='assets.depreciation.reversal' AND NEW.debit_minor<>o.debit_minor) THEN RAISE EXCEPTION 'ASSET_CORRECTION_PAIR_REQUIRED' USING ERRCODE='23514';END IF;
|
||||
END IF;
|
||||
RETURN NEW;
|
||||
END $$;
|
||||
CREATE CONSTRAINT TRIGGER gl_asset_journal_guard AFTER INSERT ON gl_journals DEFERRABLE INITIALLY DEFERRED FOR EACH ROW EXECUTE FUNCTION gl_asset_guard();
|
||||
CREATE TRIGGER gl_asset_books_immutable BEFORE UPDATE OR DELETE ON gl_asset_books FOR EACH ROW EXECUTE FUNCTION gl_append_only();
|
||||
REVOKE ALL ON TABLE gl_asset_books FROM PUBLIC;
|
||||
REVOKE ALL ON FUNCTION gl_asset_guard() FROM PUBLIC;
|
||||
|
||||
-- ASSET_PAIR_EXTENSION_v1
|
||||
CREATE TABLE gl_asset_extension_versions(version int PRIMARY KEY,source_hash char(64) NOT NULL);
|
||||
CREATE TRIGGER gl_asset_extension_versions_immutable BEFORE UPDATE OR DELETE ON gl_asset_extension_versions FOR EACH ROW EXECUTE FUNCTION gl_append_only();
|
||||
REVOKE ALL ON TABLE gl_asset_extension_versions FROM PUBLIC;
|
||||
CREATE FUNCTION gl_asset_pair_assert(group_id bigint) RETURNS void LANGUAGE plpgsql AS $$
|
||||
DECLARE g gl_corrections%ROWTYPE;r gl_correction_results%ROWTYPE;o gl_journals%ROWTYPE;a gl_journals%ROWTYPE;b gl_journals%ROWTYPE;
|
||||
BEGIN
|
||||
SELECT * INTO STRICT g FROM gl_corrections WHERE id=group_id;
|
||||
SELECT * INTO STRICT r FROM gl_correction_results WHERE correction_id=g.id AND (tenant_id,company_id,unit_id)=(g.tenant_id,g.company_id,g.unit_id);
|
||||
SELECT * INTO STRICT o FROM gl_journals WHERE id=g.original_journal_id AND (tenant_id,company_id,unit_id)=(g.tenant_id,g.company_id,g.unit_id);
|
||||
SELECT * INTO STRICT a FROM gl_journals WHERE id=r.reverse_journal_id AND proposal_id=g.reverse_proposal_id AND (tenant_id,company_id,unit_id)=(g.tenant_id,g.company_id,g.unit_id);
|
||||
SELECT * INTO STRICT b FROM gl_journals WHERE id=r.replacement_journal_id AND proposal_id=g.replacement_proposal_id AND (tenant_id,company_id,unit_id)=(g.tenant_id,g.company_id,g.unit_id);
|
||||
IF r.original_journal_id<>o.id OR r.actor_id<>g.prepared_by OR a.posted_by<>g.prepared_by OR b.posted_by<>g.prepared_by OR o.snapshot->'source'->>'effect_type'<>'assets.depreciation' OR a.snapshot->'source'->>'effect_type'<>'assets.depreciation.reversal' OR b.snapshot->'source'->>'effect_type'<>'assets.depreciation.replacement' OR (a.snapshot->'source'->>'source_id')::bigint<>o.id OR (b.snapshot->'source'->>'source_id')::bigint<>o.id OR a.debit_minor<>o.debit_minor OR a.snapshot->'source'->>'asset_key'<>o.snapshot->'source'->>'asset_key' OR b.snapshot->'source'->>'asset_key'<>o.snapshot->'source'->>'asset_key' OR a.snapshot->'source'->>'replacement_source_revision'<>b.snapshot->'source'->>'replacement_source_revision' THEN RAISE EXCEPTION 'ASSET_CORRECTION_PAIR_REQUIRED' USING ERRCODE='23514';END IF;
|
||||
END $$;
|
||||
REVOKE ALL ON FUNCTION gl_asset_pair_assert(bigint) FROM PUBLIC;
|
||||
@@ -0,0 +1,7 @@
|
||||
CREATE TABLE mi_draft_meta(policy text PRIMARY KEY,composition text NOT NULL,source_hash char(64) NOT NULL);
|
||||
CREATE TABLE mi_drafts(id bigserial PRIMARY KEY,tenant_id bigint NOT NULL,company_id bigint NOT NULL,unit_id bigint NOT NULL,draft_id bigint UNIQUE NOT NULL REFERENCES a_billing_drafts(id),source_id bigint UNIQUE NOT NULL REFERENCES a_service_drafts(id),actor_id bigint NOT NULL REFERENCES users(id),created_at timestamptz NOT NULL,FOREIGN KEY(tenant_id,company_id,unit_id) REFERENCES units(tenant_id,company_id,id));
|
||||
CREATE TRIGGER mi_draft_meta_immutable BEFORE UPDATE OR DELETE ON mi_draft_meta FOR EACH ROW EXECUTE FUNCTION mi_append_only();
|
||||
CREATE TRIGGER mi_drafts_immutable BEFORE UPDATE OR DELETE ON mi_drafts FOR EACH ROW EXECUTE FUNCTION mi_append_only();
|
||||
CREATE INDEX mi_drafts_scope ON mi_drafts(tenant_id,company_id,unit_id,id DESC);
|
||||
REVOKE ALL ON TABLE mi_draft_meta,mi_drafts FROM PUBLIC;
|
||||
REVOKE ALL ON SEQUENCE mi_drafts_id_seq FROM PUBLIC;
|
||||
@@ -0,0 +1,17 @@
|
||||
CREATE TABLE mi_meta(policy text PRIMARY KEY,composition text NOT NULL,source_hash char(64) NOT NULL);
|
||||
CREATE TABLE mi_calculations(
|
||||
id bigserial PRIMARY KEY,tenant_id bigint NOT NULL,company_id bigint NOT NULL,unit_id bigint NOT NULL,
|
||||
draft_id bigint NOT NULL REFERENCES a_billing_drafts(id),actor_id bigint NOT NULL REFERENCES users(id),
|
||||
fingerprint char(64) NOT NULL,snapshot jsonb NOT NULL,reason text NOT NULL CHECK(length(reason)>=10),created_at timestamptz NOT NULL,
|
||||
UNIQUE(tenant_id,company_id,unit_id,draft_id,fingerprint),
|
||||
FOREIGN KEY(tenant_id,company_id,unit_id) REFERENCES units(tenant_id,company_id,id)
|
||||
);
|
||||
CREATE TABLE mi_commands(id bigserial PRIMARY KEY,tenant_id bigint NOT NULL,company_id bigint NOT NULL,unit_id bigint NOT NULL,actor_id bigint NOT NULL REFERENCES users(id),command_key uuid NOT NULL,request_hash char(64) NOT NULL,input jsonb NOT NULL,result jsonb NOT NULL,created_at timestamptz NOT NULL,UNIQUE(tenant_id,company_id,unit_id,actor_id,command_key));
|
||||
CREATE FUNCTION mi_append_only() RETURNS trigger LANGUAGE plpgsql AS $$ BEGIN RAISE EXCEPTION 'MULTILINE_INVOICE_APPEND_ONLY';END $$;
|
||||
CREATE TRIGGER mi_meta_immutable BEFORE UPDATE OR DELETE ON mi_meta FOR EACH ROW EXECUTE FUNCTION mi_append_only();
|
||||
CREATE TRIGGER mi_calculations_immutable BEFORE UPDATE OR DELETE ON mi_calculations FOR EACH ROW EXECUTE FUNCTION mi_append_only();
|
||||
CREATE TRIGGER mi_commands_immutable BEFORE UPDATE OR DELETE ON mi_commands FOR EACH ROW EXECUTE FUNCTION mi_append_only();
|
||||
CREATE INDEX mi_calculations_scope ON mi_calculations(tenant_id,company_id,unit_id,draft_id,id DESC);
|
||||
REVOKE ALL ON TABLE mi_meta,mi_calculations,mi_commands FROM PUBLIC;
|
||||
REVOKE ALL ON SEQUENCE mi_calculations_id_seq,mi_commands_id_seq FROM PUBLIC;
|
||||
REVOKE ALL ON FUNCTION mi_append_only() FROM PUBLIC;
|
||||
Reference in New Issue
Block a user