feat(admin): merge stash changes into comclib-analytics (order/finance/product + rpc sql)
This commit is contained in:
103
docs/sql/30_rpc/finance/rpc_admin_extract_list_v1.sql
Normal file
103
docs/sql/30_rpc/finance/rpc_admin_extract_list_v1.sql
Normal file
@@ -0,0 +1,103 @@
|
||||
-- =====================================================================================
|
||||
-- Admin 财务功能 - 提现申请列表分页查询 RPC
|
||||
-- 位置:docs/sql/30_rpc/finance/
|
||||
-- 对象类型:RPC 函数(SECURITY DEFINER)
|
||||
-- 版本:v1
|
||||
-- 依赖:ml_extract, ak_users 表已存在
|
||||
-- 权限:仅 admin 角色可执行(口径 A:全局数据访问通过 RPC)
|
||||
-- =====================================================================================
|
||||
|
||||
CREATE OR REPLACE FUNCTION public.rpc_admin_extract_list(
|
||||
p_page INTEGER DEFAULT 1,
|
||||
p_page_size INTEGER DEFAULT 15,
|
||||
p_status SMALLINT DEFAULT NULL,
|
||||
p_start_time TIMESTAMP WITH TIME ZONE DEFAULT NULL,
|
||||
p_end_time TIMESTAMP WITH TIME ZONE DEFAULT NULL,
|
||||
p_search TEXT DEFAULT NULL
|
||||
)
|
||||
RETURNS JSONB
|
||||
SECURITY DEFINER
|
||||
SET search_path = public
|
||||
LANGUAGE plpgsql
|
||||
AS $$
|
||||
DECLARE
|
||||
v_offset INTEGER;
|
||||
v_total BIGINT;
|
||||
v_items JSONB;
|
||||
BEGIN
|
||||
-- 1. 权限检查
|
||||
IF NOT EXISTS (
|
||||
SELECT 1 FROM public.ak_users
|
||||
WHERE id = auth.uid() AND role = 'admin'
|
||||
) THEN
|
||||
RAISE EXCEPTION 'Permission denied';
|
||||
END IF;
|
||||
|
||||
v_offset := (p_page - 1) * p_page_size;
|
||||
|
||||
-- 2. 获取总数
|
||||
SELECT COUNT(*) INTO v_total
|
||||
FROM public.ml_extract e
|
||||
LEFT JOIN public.ak_users u ON u.id = e.uid
|
||||
WHERE (p_status IS NULL OR e.status = p_status)
|
||||
AND (p_start_time IS NULL OR e.created_at >= p_start_time)
|
||||
AND (p_end_time IS NULL OR e.created_at <= p_end_time)
|
||||
AND (p_search IS NULL OR (
|
||||
COALESCE(u.username, '') ILIKE '%' || p_search || '%' OR
|
||||
COALESCE(u.email, '') ILIKE '%' || p_search || '%' OR
|
||||
COALESCE(e.real_name, '') ILIKE '%' || p_search || '%' OR
|
||||
COALESCE(e.bank_code, '') ILIKE '%' || p_search || '%' OR
|
||||
COALESCE(e.alipay_code, '') ILIKE '%' || p_search || '%' OR
|
||||
COALESCE(e.wechat_code, '') ILIKE '%' || p_search || '%'
|
||||
));
|
||||
|
||||
-- 3. 获取明细数据
|
||||
SELECT jsonb_agg(t) INTO v_items
|
||||
FROM (
|
||||
SELECT
|
||||
e.id,
|
||||
e.uid,
|
||||
e.real_name,
|
||||
e.extract_type,
|
||||
e.bank_code,
|
||||
e.bank_address,
|
||||
e.alipay_code,
|
||||
e.wechat_code,
|
||||
e.extract_price,
|
||||
e.service_fee,
|
||||
e.balance,
|
||||
e.status,
|
||||
e.refusal_reason,
|
||||
e.admin_id,
|
||||
e.payment_time,
|
||||
e.created_at,
|
||||
e.updated_at,
|
||||
u.username as user_name,
|
||||
u.email as user_email
|
||||
FROM public.ml_extract e
|
||||
LEFT JOIN public.ak_users u ON u.id = e.uid
|
||||
WHERE (p_status IS NULL OR e.status = p_status)
|
||||
AND (p_start_time IS NULL OR e.created_at >= p_start_time)
|
||||
AND (p_end_time IS NULL OR e.created_at <= p_end_time)
|
||||
AND (p_search IS NULL OR (
|
||||
COALESCE(u.username, '') ILIKE '%' || p_search || '%' OR
|
||||
COALESCE(u.email, '') ILIKE '%' || p_search || '%' OR
|
||||
COALESCE(e.real_name, '') ILIKE '%' || p_search || '%' OR
|
||||
COALESCE(e.bank_code, '') ILIKE '%' || p_search || '%' OR
|
||||
COALESCE(e.alipay_code, '') ILIKE '%' || p_search || '%' OR
|
||||
COALESCE(e.wechat_code, '') ILIKE '%' || p_search || '%'
|
||||
))
|
||||
ORDER BY e.created_at DESC
|
||||
LIMIT p_page_size
|
||||
OFFSET v_offset
|
||||
) t;
|
||||
|
||||
-- 4. 返回结果
|
||||
RETURN jsonb_build_object(
|
||||
'total', v_total,
|
||||
'items', COALESCE(v_items, '[]'::jsonb)
|
||||
);
|
||||
END;
|
||||
$$;
|
||||
|
||||
COMMENT ON FUNCTION public.rpc_admin_extract_list IS '管理员提现申请列表分页查询';
|
||||
78
docs/sql/30_rpc/finance/rpc_admin_extract_review_v1.sql
Normal file
78
docs/sql/30_rpc/finance/rpc_admin_extract_review_v1.sql
Normal file
@@ -0,0 +1,78 @@
|
||||
-- =====================================================================================
|
||||
-- Admin 财务功能 - 提现审核 RPC (口径 2)
|
||||
-- 位置:docs/sql/30_rpc/finance/
|
||||
-- 版本:v1
|
||||
-- 描述:提现审核通过时才扣除佣金并生成流水。
|
||||
-- 安全策略:SECURITY DEFINER, 入口鉴权, 固定 search_path
|
||||
-- =====================================================================================
|
||||
|
||||
CREATE OR REPLACE FUNCTION public.rpc_admin_extract_review(
|
||||
p_extract_id UUID,
|
||||
p_status SMALLINT, -- 1: 通过, -1: 驳回
|
||||
p_refusal_reason TEXT DEFAULT NULL
|
||||
)
|
||||
RETURNS VOID
|
||||
SECURITY DEFINER
|
||||
SET search_path = public
|
||||
LANGUAGE plpgsql
|
||||
AS $$
|
||||
DECLARE
|
||||
v_extract RECORD;
|
||||
v_user RECORD;
|
||||
BEGIN
|
||||
-- 1. 鉴权:仅 admin 角色可执行
|
||||
IF NOT EXISTS (
|
||||
SELECT 1 FROM public.ak_users
|
||||
WHERE id = auth.uid() AND role = 'admin'
|
||||
) THEN
|
||||
RAISE EXCEPTION 'Permission denied';
|
||||
END IF;
|
||||
|
||||
-- 2. 锁定并获取提现记录
|
||||
SELECT * INTO v_extract FROM public.ml_extract WHERE id = p_extract_id FOR UPDATE;
|
||||
IF NOT FOUND THEN RAISE EXCEPTION 'Extract record not found'; END IF;
|
||||
IF v_extract.status != 0 THEN RAISE EXCEPTION 'Record already processed'; END IF;
|
||||
|
||||
-- 3. 业务处理
|
||||
IF p_status = 1 THEN
|
||||
-- 审核通过:锁定并校验用户资金
|
||||
SELECT * INTO v_user FROM public.ak_users WHERE id = v_extract.uid FOR UPDATE;
|
||||
IF v_user.brokerage_price < v_extract.extract_price THEN
|
||||
RAISE EXCEPTION 'Insufficient brokerage balance';
|
||||
END IF;
|
||||
|
||||
-- 扣除佣金
|
||||
UPDATE public.ak_users
|
||||
SET brokerage_price = brokerage_price - v_extract.extract_price
|
||||
WHERE id = v_extract.uid;
|
||||
|
||||
-- 写入资金流水
|
||||
INSERT INTO public.ml_user_bill (uid, link_id, pm, title, category, type, number, balance)
|
||||
VALUES (
|
||||
v_extract.uid,
|
||||
p_extract_id::TEXT,
|
||||
0, -- 支出
|
||||
'佣金提现',
|
||||
'brokerage',
|
||||
'extract',
|
||||
v_extract.extract_price,
|
||||
v_user.brokerage_price - v_extract.extract_price
|
||||
);
|
||||
|
||||
-- 更新提现记录
|
||||
UPDATE public.ml_extract
|
||||
SET status = 1, admin_id = auth.uid(), payment_time = now()
|
||||
WHERE id = p_extract_id;
|
||||
|
||||
ELSIF p_status = -1 THEN
|
||||
-- 审核驳回:仅更新状态
|
||||
UPDATE public.ml_extract
|
||||
SET status = -1, refusal_reason = p_refusal_reason, admin_id = auth.uid()
|
||||
WHERE id = p_extract_id;
|
||||
ELSE
|
||||
RAISE EXCEPTION 'Invalid status';
|
||||
END IF;
|
||||
END;
|
||||
$$;
|
||||
|
||||
COMMENT ON FUNCTION public.rpc_admin_extract_review IS '管理员审核提现申请(口径 2:通过时扣款)';
|
||||
64
docs/sql/30_rpc/finance/rpc_admin_recharge_audit_v1.sql
Normal file
64
docs/sql/30_rpc/finance/rpc_admin_recharge_audit_v1.sql
Normal file
@@ -0,0 +1,64 @@
|
||||
-- =====================================================================================
|
||||
-- Admin 财务功能 - 充值补单/审计 RPC
|
||||
-- 位置:docs/sql/30_rpc/finance/
|
||||
-- 版本:v1
|
||||
-- 描述:由管理员发起的人工充值补单或离线支付审计确认。
|
||||
-- 安全策略:SECURITY DEFINER, 入口鉴权, 固定 search_path
|
||||
-- =====================================================================================
|
||||
|
||||
CREATE OR REPLACE FUNCTION public.rpc_admin_recharge_audit(
|
||||
p_recharge_id UUID,
|
||||
p_mark TEXT DEFAULT '管理员人工审计/补单'
|
||||
)
|
||||
RETURNS VOID
|
||||
SECURITY DEFINER
|
||||
SET search_path = public
|
||||
LANGUAGE plpgsql
|
||||
AS $$
|
||||
DECLARE
|
||||
v_recharge RECORD;
|
||||
v_user RECORD;
|
||||
BEGIN
|
||||
-- 1. 鉴权:仅 admin 角色可执行
|
||||
IF NOT EXISTS (
|
||||
SELECT 1 FROM public.ak_users
|
||||
WHERE id = auth.uid() AND role = 'admin'
|
||||
) THEN
|
||||
RAISE EXCEPTION 'Permission denied';
|
||||
END IF;
|
||||
|
||||
-- 2. 锁定并获取充值记录
|
||||
SELECT * INTO v_recharge FROM public.ml_user_recharge WHERE id = p_recharge_id FOR UPDATE;
|
||||
IF NOT FOUND THEN RAISE EXCEPTION 'Recharge record not found'; END IF;
|
||||
IF v_recharge.paid = 1 THEN RAISE EXCEPTION 'Recharge already paid'; END IF;
|
||||
|
||||
-- 3. 锁定并更新用户余额
|
||||
SELECT * INTO v_user FROM public.ak_users WHERE id = v_recharge.uid FOR UPDATE;
|
||||
|
||||
UPDATE public.ak_users
|
||||
SET now_money = now_money + v_recharge.price + v_recharge.give_price
|
||||
WHERE id = v_recharge.uid;
|
||||
|
||||
-- 4. 写入资金流水
|
||||
INSERT INTO public.ml_user_bill (uid, link_id, pm, title, category, type, number, balance, mark)
|
||||
VALUES (
|
||||
v_recharge.uid,
|
||||
v_recharge.order_no,
|
||||
1, -- 收入
|
||||
'用户充值',
|
||||
'now_money',
|
||||
'recharge',
|
||||
v_recharge.price + v_recharge.give_price,
|
||||
v_user.now_money + v_recharge.price + v_recharge.give_price,
|
||||
p_mark
|
||||
);
|
||||
|
||||
-- 5. 更新充值记录状态
|
||||
UPDATE public.ml_user_recharge
|
||||
SET paid = 1, pay_time = now()
|
||||
WHERE id = p_recharge_id;
|
||||
|
||||
END;
|
||||
$$;
|
||||
|
||||
COMMENT ON FUNCTION public.rpc_admin_recharge_audit IS '管理员人工审计/补单(更新用户余额并生成流水)';
|
||||
92
docs/sql/30_rpc/finance/rpc_admin_recharge_list_v1.sql
Normal file
92
docs/sql/30_rpc/finance/rpc_admin_recharge_list_v1.sql
Normal file
@@ -0,0 +1,92 @@
|
||||
-- =====================================================================================
|
||||
-- Admin 财务功能 - 充值记录列表分页查询 RPC
|
||||
-- 位置:docs/sql/30_rpc/finance/
|
||||
-- 对象类型:RPC 函数(SECURITY DEFINER)
|
||||
-- 版本:v1
|
||||
-- 依赖:ml_user_recharge, ak_users 表已存在
|
||||
-- 权限:仅 admin 角色可执行(口径 A:全局数据访问通过 RPC)
|
||||
-- =====================================================================================
|
||||
|
||||
CREATE OR REPLACE FUNCTION public.rpc_admin_recharge_list(
|
||||
p_page INTEGER DEFAULT 1,
|
||||
p_page_size INTEGER DEFAULT 15,
|
||||
p_paid SMALLINT DEFAULT NULL,
|
||||
p_start_time TIMESTAMP WITH TIME ZONE DEFAULT NULL,
|
||||
p_end_time TIMESTAMP WITH TIME ZONE DEFAULT NULL,
|
||||
p_search TEXT DEFAULT NULL
|
||||
)
|
||||
RETURNS JSONB
|
||||
SECURITY DEFINER
|
||||
SET search_path = public
|
||||
LANGUAGE plpgsql
|
||||
AS $$
|
||||
DECLARE
|
||||
v_offset INTEGER;
|
||||
v_total BIGINT;
|
||||
v_items JSONB;
|
||||
BEGIN
|
||||
-- 1. 权限检查
|
||||
IF NOT EXISTS (
|
||||
SELECT 1 FROM public.ak_users
|
||||
WHERE id = auth.uid() AND role = 'admin'
|
||||
) THEN
|
||||
RAISE EXCEPTION 'Permission denied';
|
||||
END IF;
|
||||
|
||||
v_offset := (p_page - 1) * p_page_size;
|
||||
|
||||
-- 2. 获取总数
|
||||
SELECT COUNT(*) INTO v_total
|
||||
FROM public.ml_user_recharge r
|
||||
LEFT JOIN public.ak_users u ON u.id = r.uid
|
||||
WHERE (p_paid IS NULL OR r.paid = p_paid)
|
||||
AND (p_start_time IS NULL OR r.created_at >= p_start_time)
|
||||
AND (p_end_time IS NULL OR r.created_at <= p_end_time)
|
||||
AND (p_search IS NULL OR (
|
||||
COALESCE(r.order_no, '') ILIKE '%' || p_search || '%' OR
|
||||
COALESCE(u.username, '') ILIKE '%' || p_search || '%' OR
|
||||
COALESCE(u.email, '') ILIKE '%' || p_search || '%'
|
||||
));
|
||||
|
||||
-- 3. 获取明细数据
|
||||
SELECT jsonb_agg(t) INTO v_items
|
||||
FROM (
|
||||
SELECT
|
||||
r.id,
|
||||
r.uid,
|
||||
r.order_no,
|
||||
r.recharge_type,
|
||||
r.price,
|
||||
r.give_price,
|
||||
r.paid,
|
||||
r.pay_time,
|
||||
r.channel_trade_no,
|
||||
r.status,
|
||||
r.created_at,
|
||||
r.updated_at,
|
||||
u.username as user_name,
|
||||
u.email as user_email
|
||||
FROM public.ml_user_recharge r
|
||||
LEFT JOIN public.ak_users u ON u.id = r.uid
|
||||
WHERE (p_paid IS NULL OR r.paid = p_paid)
|
||||
AND (p_start_time IS NULL OR r.created_at >= p_start_time)
|
||||
AND (p_end_time IS NULL OR r.created_at <= p_end_time)
|
||||
AND (p_search IS NULL OR (
|
||||
COALESCE(r.order_no, '') ILIKE '%' || p_search || '%' OR
|
||||
COALESCE(u.username, '') ILIKE '%' || p_search || '%' OR
|
||||
COALESCE(u.email, '') ILIKE '%' || p_search || '%'
|
||||
))
|
||||
ORDER BY r.created_at DESC
|
||||
LIMIT p_page_size
|
||||
OFFSET v_offset
|
||||
) t;
|
||||
|
||||
-- 4. 返回结果
|
||||
RETURN jsonb_build_object(
|
||||
'total', v_total,
|
||||
'items', COALESCE(v_items, '[]'::jsonb)
|
||||
);
|
||||
END;
|
||||
$$;
|
||||
|
||||
COMMENT ON FUNCTION public.rpc_admin_recharge_list IS '管理员充值记录列表分页查询';
|
||||
99
docs/sql/30_rpc/finance/rpc_admin_user_bill_list_v1.sql
Normal file
99
docs/sql/30_rpc/finance/rpc_admin_user_bill_list_v1.sql
Normal file
@@ -0,0 +1,99 @@
|
||||
-- =====================================================================================
|
||||
-- Admin 财务功能 - 资金流水列表分页查询 RPC
|
||||
-- 位置:docs/sql/30_rpc/finance/
|
||||
-- 对象类型:RPC 函数(SECURITY DEFINER)
|
||||
-- 版本:v1
|
||||
-- 依赖:ml_user_bill, ak_users 表已存在
|
||||
-- 权限:仅 admin 角色可执行(口径 A:全局数据访问通过 RPC)
|
||||
-- =====================================================================================
|
||||
|
||||
CREATE OR REPLACE FUNCTION public.rpc_admin_user_bill_list(
|
||||
p_page INTEGER DEFAULT 1,
|
||||
p_page_size INTEGER DEFAULT 15,
|
||||
p_category VARCHAR DEFAULT NULL,
|
||||
p_type VARCHAR DEFAULT NULL,
|
||||
p_pm SMALLINT DEFAULT NULL,
|
||||
p_start_time TIMESTAMP WITH TIME ZONE DEFAULT NULL,
|
||||
p_end_time TIMESTAMP WITH TIME ZONE DEFAULT NULL,
|
||||
p_search TEXT DEFAULT NULL
|
||||
)
|
||||
RETURNS JSONB
|
||||
SECURITY DEFINER
|
||||
SET search_path = public
|
||||
LANGUAGE plpgsql
|
||||
AS $$
|
||||
DECLARE
|
||||
v_offset INTEGER;
|
||||
v_total BIGINT;
|
||||
v_items JSONB;
|
||||
BEGIN
|
||||
-- 1. 权限检查
|
||||
IF NOT EXISTS (
|
||||
SELECT 1 FROM public.ak_users
|
||||
WHERE id = auth.uid() AND role = 'admin'
|
||||
) THEN
|
||||
RAISE EXCEPTION 'Permission denied';
|
||||
END IF;
|
||||
|
||||
v_offset := (p_page - 1) * p_page_size;
|
||||
|
||||
-- 2. 获取总数
|
||||
SELECT COUNT(*) INTO v_total
|
||||
FROM public.ml_user_bill b
|
||||
LEFT JOIN public.ak_users u ON u.id = b.uid
|
||||
WHERE (p_category IS NULL OR b.category = p_category)
|
||||
AND (p_type IS NULL OR b.type = p_type)
|
||||
AND (p_pm IS NULL OR b.pm = p_pm)
|
||||
AND (p_start_time IS NULL OR b.created_at >= p_start_time)
|
||||
AND (p_end_time IS NULL OR b.created_at <= p_end_time)
|
||||
AND (p_search IS NULL OR (
|
||||
COALESCE(b.title, '') ILIKE '%' || p_search || '%' OR
|
||||
COALESCE(u.username, '') ILIKE '%' || p_search || '%' OR
|
||||
COALESCE(u.email, '') ILIKE '%' || p_search || '%'
|
||||
));
|
||||
|
||||
-- 3. 获取明细数据
|
||||
SELECT jsonb_agg(t) INTO v_items
|
||||
FROM (
|
||||
SELECT
|
||||
b.id,
|
||||
b.uid,
|
||||
b.link_id,
|
||||
b.pm,
|
||||
b.title,
|
||||
b.category,
|
||||
b.type,
|
||||
b.number,
|
||||
b.balance,
|
||||
b.mark,
|
||||
b.status,
|
||||
b.created_at,
|
||||
b.updated_at,
|
||||
u.username as user_name,
|
||||
u.email as user_email
|
||||
FROM public.ml_user_bill b
|
||||
LEFT JOIN public.ak_users u ON u.id = b.uid
|
||||
WHERE (p_category IS NULL OR b.category = p_category)
|
||||
AND (p_type IS NULL OR b.type = p_type)
|
||||
AND (p_pm IS NULL OR b.pm = p_pm)
|
||||
AND (p_start_time IS NULL OR b.created_at >= p_start_time)
|
||||
AND (p_end_time IS NULL OR b.created_at <= p_end_time)
|
||||
AND (p_search IS NULL OR (
|
||||
COALESCE(b.title, '') ILIKE '%' || p_search || '%' OR
|
||||
COALESCE(u.username, '') ILIKE '%' || p_search || '%' OR
|
||||
COALESCE(u.email, '') ILIKE '%' || p_search || '%'
|
||||
))
|
||||
ORDER BY b.created_at DESC
|
||||
LIMIT p_page_size
|
||||
OFFSET v_offset
|
||||
) t;
|
||||
|
||||
-- 4. 返回结果
|
||||
RETURN jsonb_build_object(
|
||||
'total', v_total,
|
||||
'items', COALESCE(v_items, '[]'::jsonb)
|
||||
);
|
||||
END;
|
||||
$$;
|
||||
|
||||
COMMENT ON FUNCTION public.rpc_admin_user_bill_list IS '管理员资金流水列表分页查询';
|
||||
Reference in New Issue
Block a user