manicanldes-backend/prisma/migrations/20260910183016_checkout_sna.../migration.sql

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;