74 lines
3.1 KiB
PL/PgSQL
74 lines
3.1 KiB
PL/PgSQL
ALTER TABLE carts ADD CONSTRAINT cart_version_nonnegative CHECK (version >= 0);
|
|
ALTER TABLE cart_lines ADD CONSTRAINT cart_quantity_bounds CHECK (quantity BETWEEN 1 AND 100);
|
|
ALTER TABLE coupons ADD CONSTRAINT coupon_rule_valid CHECK (
|
|
(kind = 'FIXED' AND amount IS NOT NULL AND amount > 0 AND percent_bps IS NULL)
|
|
OR (kind = 'PERCENT' AND amount IS NULL AND percent_bps BETWEEN 1 AND 10000 AND percent_bps IS NOT NULL)
|
|
);
|
|
ALTER TABLE coupons ADD CONSTRAINT coupon_limits_valid CHECK (
|
|
minimum_subtotal >= 0 AND max_uses > 0 AND per_user_limit > 0 AND per_user_limit <= max_uses
|
|
AND ends_at > starts_at AND code ~ '^[A-Z0-9][A-Z0-9_-]{0,39}$'
|
|
AND currency IN ('INR', 'USD', 'EUR', 'GBP')
|
|
);
|
|
ALTER TABLE orders ADD CONSTRAINT order_totals_valid CHECK (
|
|
subtotal > 0 AND discount >= 0 AND discount <= subtotal
|
|
AND merchandise_total = subtotal - discount AND expires_at > created_at
|
|
);
|
|
ALTER TABLE order_lines ADD CONSTRAINT order_line_totals_valid CHECK (
|
|
quantity BETWEEN 1 AND 100 AND unit_price > 0 AND line_total = unit_price * quantity
|
|
);
|
|
|
|
CREATE FUNCTION protect_order_snapshot() RETURNS trigger LANGUAGE plpgsql AS $$
|
|
BEGIN
|
|
IF TG_OP = 'DELETE' THEN RAISE EXCEPTION 'Orders cannot be deleted'; END IF;
|
|
IF (to_jsonb(NEW) - 'status') IS DISTINCT FROM (to_jsonb(OLD) - 'status') THEN
|
|
RAISE EXCEPTION 'Order snapshots are immutable';
|
|
END IF;
|
|
IF OLD.status = 'CANCELLED' AND NEW.status <> 'CANCELLED' THEN
|
|
RAISE EXCEPTION 'Cancelled orders cannot be reopened';
|
|
END IF;
|
|
RETURN NEW;
|
|
END;
|
|
$$;
|
|
CREATE TRIGGER orders_snapshot_immutable BEFORE UPDATE OR DELETE ON orders
|
|
FOR EACH ROW EXECUTE FUNCTION protect_order_snapshot();
|
|
|
|
CREATE FUNCTION protect_order_line() RETURNS trigger LANGUAGE plpgsql AS $$
|
|
BEGIN
|
|
RAISE EXCEPTION 'Order lines are immutable';
|
|
END;
|
|
$$;
|
|
CREATE TRIGGER order_lines_immutable BEFORE UPDATE OR DELETE ON order_lines
|
|
FOR EACH ROW EXECUTE FUNCTION protect_order_line();
|
|
|
|
CREATE FUNCTION protect_coupon_rules() RETURNS trigger LANGUAGE plpgsql AS $$
|
|
BEGIN
|
|
IF (to_jsonb(NEW) - 'active') IS DISTINCT FROM (to_jsonb(OLD) - 'active') THEN
|
|
RAISE EXCEPTION 'Create a new coupon to change discount rules';
|
|
END IF;
|
|
RETURN NEW;
|
|
END;
|
|
$$;
|
|
CREATE TRIGGER coupon_rules_immutable BEFORE UPDATE ON coupons
|
|
FOR EACH ROW EXECUTE FUNCTION protect_coupon_rules();
|
|
|
|
CREATE FUNCTION protect_order_reservation() RETURNS trigger LANGUAGE plpgsql AS $$
|
|
BEGIN
|
|
IF OLD.order_id IS NOT NULL THEN
|
|
IF TG_OP = 'DELETE' THEN RAISE EXCEPTION 'Order reservations cannot be deleted'; END IF;
|
|
IF (to_jsonb(NEW) - 'status') IS DISTINCT FROM (to_jsonb(OLD) - 'status') THEN
|
|
RAISE EXCEPTION 'Order reservation allocation is immutable';
|
|
END IF;
|
|
END IF;
|
|
IF TG_OP = 'DELETE' THEN RETURN OLD; END IF;
|
|
RETURN NEW;
|
|
END;
|
|
$$;
|
|
CREATE TRIGGER order_reservation_immutable BEFORE UPDATE OR DELETE ON stock_reservations
|
|
FOR EACH ROW EXECUTE FUNCTION protect_order_reservation();
|
|
|
|
UPDATE roles SET permissions = ARRAY(
|
|
SELECT DISTINCT permission FROM unnest(permissions || ARRAY[
|
|
'coupons.manage', 'orders.read', 'orders.manage'
|
|
]::text[]) AS permission ORDER BY permission
|
|
) WHERE is_system = true;
|