Files
SGF/database/sql/industrial-budgets.sql
T

61 lines
4.3 KiB
PL/PgSQL

CREATE TABLE ib_budgets (
id bigserial PRIMARY KEY, lot_id bigint NOT NULL REFERENCES ic_lots(id),
version integer NOT NULL CHECK(version>0), previous_id bigint UNIQUE REFERENCES ib_budgets(id),
dimensions jsonb NOT NULL, amounts jsonb NOT NULL, evidence text NOT NULL CHECK(length(evidence)>=3),
actor_id bigint NOT NULL REFERENCES users(id), created_at timestamptz NOT NULL, UNIQUE(lot_id,version)
);
CREATE TABLE ib_decisions (
id bigserial PRIMARY KEY, budget_id bigint UNIQUE NOT NULL REFERENCES ib_budgets(id), version integer NOT NULL,
decision text NOT NULL CHECK(decision IN ('approved','refused')), reason text NOT NULL CHECK(length(reason)>=3),
actor_id bigint NOT NULL REFERENCES users(id), created_at timestamptz NOT NULL
);
CREATE TABLE ib_comparisons (
id bigserial PRIMARY KEY, lot_id bigint NOT NULL REFERENCES ic_lots(id), version integer NOT NULL CHECK(version>0),
previous_id bigint UNIQUE REFERENCES ib_comparisons(id), budget_id bigint NOT NULL REFERENCES ib_budgets(id),
result_id bigint NOT NULL REFERENCES ic_results(id), snapshot jsonb NOT NULL,
actor_id bigint NOT NULL REFERENCES users(id), created_at timestamptz NOT NULL, UNIQUE(lot_id,version)
);
CREATE TABLE ib_commands (
id bigserial PRIMARY KEY, lot_id bigint NOT NULL REFERENCES ic_lots(id),actor_id bigint NOT NULL REFERENCES users(id),
action text NOT NULL CHECK(action IN ('propose','decide','compare')),command_key text NOT NULL,request_hash text NOT NULL,
result jsonb NOT NULL,created_at timestamptz NOT NULL,UNIQUE(lot_id,actor_id,action,command_key)
);
CREATE TABLE ib_events(id bigserial PRIMARY KEY,command_id bigint UNIQUE NOT NULL REFERENCES ib_commands(id),payload jsonb NOT NULL,created_at timestamptz NOT NULL);
CREATE TABLE ib_outbox(event_id bigint PRIMARY KEY REFERENCES ib_events(id),state text NOT NULL CHECK(state='captured_no_stock_or_accounting'));
CREATE OR REPLACE FUNCTION sgf_ib_integrity() RETURNS trigger LANGUAGE plpgsql AS $$
DECLARE lid bigint; prior bigint; n integer; b ib_budgets; r ic_results; ref jsonb;
BEGIN
PERFORM sgf_ic_environment();
IF TG_TABLE_NAME='ib_decisions' THEN
SELECT * INTO STRICT b FROM ib_budgets WHERE id=NEW.budget_id;
lid=b.lot_id;
ELSE lid=NEW.lot_id; END IF;
PERFORM 1 FROM companies WHERE id=(SELECT company_id FROM ic_lots WHERE id=lid) FOR UPDATE;
IF TG_TABLE_NAME='ib_decisions' THEN
IF b.actor_id=NEW.actor_id OR b.version<>NEW.version OR EXISTS(SELECT 1 FROM ib_budgets WHERE previous_id=b.id) THEN RAISE EXCEPTION 'SGF_IB_DECISION_VERSION_IDENTITY'; END IF;
ELSIF TG_TABLE_NAME='ib_commands' THEN RETURN NEW;
ELSE
IF TG_TABLE_NAME='ib_budgets' THEN
SELECT coalesce(max(version),0) INTO n FROM ib_budgets WHERE lot_id=lid;
IF n>0 THEN SELECT id INTO STRICT prior FROM ib_budgets WHERE lot_id=lid AND version=n; END IF;
ELSE
SELECT coalesce(max(version),0) INTO n FROM ib_comparisons WHERE lot_id=lid;
IF n>0 THEN SELECT id INTO STRICT prior FROM ib_comparisons WHERE lot_id=lid AND version=n; END IF;
SELECT * INTO STRICT b FROM ib_budgets WHERE id=NEW.budget_id AND lot_id=lid;
SELECT * INTO STRICT r FROM ic_results WHERE id=NEW.result_id AND lot_id=lid;
IF NOT EXISTS(SELECT 1 FROM ib_decisions WHERE budget_id=b.id AND decision='approved') OR EXISTS(SELECT 1 FROM ib_budgets WHERE previous_id=b.id)
OR NOT EXISTS(SELECT 1 FROM ic_decisions WHERE result_id=r.id AND decision='approved') OR EXISTS(SELECT 1 FROM ic_results WHERE previous_id=r.id)
THEN RAISE EXCEPTION 'SGF_IB_APPROVED_CURRENT_REFERENCES'; END IF;
FOR ref IN SELECT value FROM jsonb_each(r.snapshot->'refs') LOOP
IF ref<>'null'::jsonb THEN PERFORM sgf_ic_input_current((ref->>'id')::bigint,lid,(ref->>'version')::integer); END IF;
END LOOP;
END IF;
IF NEW.version<>n+1 OR (n=0 AND NEW.previous_id IS NOT NULL) OR (n>0 AND NEW.previous_id IS DISTINCT FROM prior) THEN RAISE EXCEPTION 'SGF_IB_VERSION'; END IF;
END IF;
RETURN NEW;
END; $$;
CREATE TRIGGER ib_budget_integrity BEFORE INSERT ON ib_budgets FOR EACH ROW EXECUTE FUNCTION sgf_ib_integrity();
CREATE TRIGGER ib_decision_integrity BEFORE INSERT ON ib_decisions FOR EACH ROW EXECUTE FUNCTION sgf_ib_integrity();
CREATE TRIGGER ib_comparison_integrity BEFORE INSERT ON ib_comparisons FOR EACH ROW EXECUTE FUNCTION sgf_ib_integrity();
CREATE TRIGGER ib_command_integrity BEFORE INSERT ON ib_commands FOR EACH ROW EXECUTE FUNCTION sgf_ib_integrity();