小程序虚拟支付
This commit is contained in:
79
sql/member_pay.sql
Normal file
79
sql/member_pay.sql
Normal file
@@ -0,0 +1,79 @@
|
||||
-- ============================================================================
|
||||
-- 会员购买(微信小程序虚拟支付 · 道具直购)
|
||||
-- 适用:个人主体小程序(服务类目含「工具」),月支付限额 10 万元
|
||||
-- 执行前请确认已备份;本脚本幂等性由 `IF NOT EXISTS` / 存在性判断保证。
|
||||
-- ============================================================================
|
||||
|
||||
-- 1. users:等级有效期 + session_key ----------------------------------------
|
||||
-- level_expire_at:会员到期时间,NULL = 永久(管理员手动分配的等级保持 NULL)
|
||||
-- session_key :微信 session_key,用户态签名 signature 需要
|
||||
SET @db := DATABASE();
|
||||
|
||||
SET @sql := (
|
||||
SELECT IF(COUNT(*) = 0,
|
||||
'ALTER TABLE `users` ADD COLUMN `level_expire_at` datetime DEFAULT NULL COMMENT ''等级/会员到期时间,NULL=永久'' AFTER `level_key`',
|
||||
'SELECT ''users.level_expire_at already exists'' AS msg')
|
||||
FROM information_schema.COLUMNS
|
||||
WHERE TABLE_SCHEMA = @db AND TABLE_NAME = 'users' AND COLUMN_NAME = 'level_expire_at'
|
||||
);
|
||||
PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt;
|
||||
|
||||
SET @sql := (
|
||||
SELECT IF(COUNT(*) = 0,
|
||||
'ALTER TABLE `users` ADD COLUMN `session_key` varchar(128) DEFAULT NULL COMMENT ''微信 session_key(虚拟支付签名用)'' AFTER `openid`',
|
||||
'SELECT ''users.session_key already exists'' AS msg')
|
||||
FROM information_schema.COLUMNS
|
||||
WHERE TABLE_SCHEMA = @db AND TABLE_NAME = 'users' AND COLUMN_NAME = 'session_key'
|
||||
);
|
||||
PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt;
|
||||
|
||||
-- 2. member_plans:会员套餐 --------------------------------------------------
|
||||
CREATE TABLE IF NOT EXISTS `member_plans` (
|
||||
`id` bigint NOT NULL AUTO_INCREMENT,
|
||||
`plan_key` varchar(32) NOT NULL COMMENT '套餐标识,如 vip-month',
|
||||
`name` varchar(64) NOT NULL COMMENT '展示名,如 月卡',
|
||||
`subtitle` varchar(128) DEFAULT NULL COMMENT '副标题',
|
||||
`level_key` varchar(32) NOT NULL COMMENT '购买后生效的等级',
|
||||
`duration_days` int NOT NULL DEFAULT 30 COMMENT '有效天数',
|
||||
`price_cents` bigint NOT NULL DEFAULT 0 COMMENT '价格(分),须与微信后台道具价格一致',
|
||||
`product_id` varchar(64) NOT NULL COMMENT '微信虚拟支付道具 ID',
|
||||
`badge` varchar(32) DEFAULT NULL COMMENT '角标文案',
|
||||
`sort` int NOT NULL DEFAULT 0,
|
||||
`is_enabled` tinyint NOT NULL DEFAULT 1 COMMENT '1 上架 / 0 下架',
|
||||
`remark` varchar(255) DEFAULT NULL,
|
||||
`created_at` datetime DEFAULT NULL,
|
||||
`updated_at` datetime DEFAULT NULL,
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY `uk_plan_key` (`plan_key`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='会员套餐(道具直购)';
|
||||
|
||||
-- 3. member_orders:会员订单 -------------------------------------------------
|
||||
CREATE TABLE IF NOT EXISTS `member_orders` (
|
||||
`id` bigint NOT NULL AUTO_INCREMENT,
|
||||
`out_trade_no` varchar(64) NOT NULL COMMENT '业务单号,唯一,8-32 位且不能以下划线开头',
|
||||
`wx_order_id` varchar(64) DEFAULT NULL COMMENT '平台单号,发货/对账以此为准,用于幂等去重',
|
||||
`user_id` bigint NOT NULL,
|
||||
`openid` varchar(64) NOT NULL COMMENT '支付时使用的 openid,主动查单需要',
|
||||
`plan_key` varchar(32) NOT NULL,
|
||||
`product_id` varchar(64) NOT NULL,
|
||||
`price_cents` bigint NOT NULL DEFAULT 0,
|
||||
`level_key` varchar(32) NOT NULL COMMENT '等级快照',
|
||||
`duration_days` int NOT NULL DEFAULT 0 COMMENT '天数快照',
|
||||
`status` tinyint NOT NULL DEFAULT 0 COMMENT '0 待支付 / 1 已发货 / 2 已退款 / 3 已关闭',
|
||||
`pay_channel` varchar(16) DEFAULT NULL COMMENT 'wxpay / apple',
|
||||
`attach` varchar(128) DEFAULT NULL COMMENT '透传数据',
|
||||
`paid_at` datetime DEFAULT NULL,
|
||||
`delivered_at` datetime DEFAULT NULL,
|
||||
`created_at` datetime DEFAULT NULL,
|
||||
`updated_at` datetime DEFAULT NULL,
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY `uk_out_trade_no` (`out_trade_no`),
|
||||
UNIQUE KEY `uk_wx_order_id` (`wx_order_id`),
|
||||
KEY `idx_user_created` (`user_id`, `created_at`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='会员订单(虚拟支付道具直购)';
|
||||
|
||||
-- 4. 套餐数据 ----------------------------------------------------------------
|
||||
-- 套餐种子由服务端 internal/logic/seed.go 在启动时幂等写入(与其他种子数据一致),
|
||||
-- 请在那里修改 product_id / 价格后重启服务即可。
|
||||
-- 注意:product_id 必须先在 MP 后台【虚拟支付 → 道具管理】创建并发布,
|
||||
-- 价格(分)也要与后台道具价格严格一致,否则支付会被平台拒绝。
|
||||
153
sql/quota.sql
Normal file
153
sql/quota.sql
Normal file
@@ -0,0 +1,153 @@
|
||||
-- ============================================================================
|
||||
-- 工具额度体系(免费 / 会员 / 付费次数包)建表脚本
|
||||
--
|
||||
-- ⚠️ 这份脚本是「给人看的对照版」。服务端启动时会自动执行等价且幂等的迁移
|
||||
-- (见 internal/logic/migrate.go),所以正常升级只需要重启后端,不用手工跑。
|
||||
-- 仅当你需要手工核对、或在没有服务端的环境里初始化时,才执行本文件。
|
||||
--
|
||||
-- 幂等:可重复执行。表用 CREATE TABLE IF NOT EXISTS,列先用 information_schema
|
||||
-- 判存在再 ALTER(MySQL 不支持 ADD COLUMN IF NOT EXISTS)。
|
||||
-- ============================================================================
|
||||
|
||||
-- ---------------------------------------------------------------------------
|
||||
-- 1. 工具额度配置(在「工具管理」里维护)
|
||||
-- ---------------------------------------------------------------------------
|
||||
SET @db := DATABASE();
|
||||
|
||||
SET @sql := IF(
|
||||
(SELECT COUNT(*) FROM information_schema.COLUMNS
|
||||
WHERE TABLE_SCHEMA = @db AND TABLE_NAME = 'tools' AND COLUMN_NAME = 'free_quota') = 0,
|
||||
'ALTER TABLE `tools` ADD COLUMN `free_quota` int NOT NULL DEFAULT 3 COMMENT ''免费额度(每周期次数)''',
|
||||
'SELECT 1');
|
||||
PREPARE s FROM @sql; EXECUTE s; DEALLOCATE PREPARE s;
|
||||
|
||||
SET @sql := IF(
|
||||
(SELECT COUNT(*) FROM information_schema.COLUMNS
|
||||
WHERE TABLE_SCHEMA = @db AND TABLE_NAME = 'tools' AND COLUMN_NAME = 'member_quota') = 0,
|
||||
'ALTER TABLE `tools` ADD COLUMN `member_quota` int NOT NULL DEFAULT 100 COMMENT ''会员额度(每周期次数)''',
|
||||
'SELECT 1');
|
||||
PREPARE s FROM @sql; EXECUTE s; DEALLOCATE PREPARE s;
|
||||
|
||||
SET @sql := IF(
|
||||
(SELECT COUNT(*) FROM information_schema.COLUMNS
|
||||
WHERE TABLE_SCHEMA = @db AND TABLE_NAME = 'tools' AND COLUMN_NAME = 'pay_cost') = 0,
|
||||
'ALTER TABLE `tools` ADD COLUMN `pay_cost` int NOT NULL DEFAULT 1 COMMENT ''付费额度每次消耗系数''',
|
||||
'SELECT 1');
|
||||
PREPARE s FROM @sql; EXECUTE s; DEALLOCATE PREPARE s;
|
||||
|
||||
-- ---------------------------------------------------------------------------
|
||||
-- 2. 额度周期:用户与会员套餐各自的覆盖值(0 = 跟随全局设置)
|
||||
-- ---------------------------------------------------------------------------
|
||||
SET @sql := IF(
|
||||
(SELECT COUNT(*) FROM information_schema.COLUMNS
|
||||
WHERE TABLE_SCHEMA = @db AND TABLE_NAME = 'users' AND COLUMN_NAME = 'quota_period_days') = 0,
|
||||
'ALTER TABLE `users` ADD COLUMN `quota_period_days` int NOT NULL DEFAULT 0 COMMENT ''额度重置周期(天),0=跟随全局''',
|
||||
'SELECT 1');
|
||||
PREPARE s FROM @sql; EXECUTE s; DEALLOCATE PREPARE s;
|
||||
|
||||
SET @sql := IF(
|
||||
(SELECT COUNT(*) FROM information_schema.COLUMNS
|
||||
WHERE TABLE_SCHEMA = @db AND TABLE_NAME = 'member_plans' AND COLUMN_NAME = 'quota_period_days') = 0,
|
||||
'ALTER TABLE `member_plans` ADD COLUMN `quota_period_days` int NOT NULL DEFAULT 0 COMMENT ''购买后生效的额度周期(天),0=不调整''',
|
||||
'SELECT 1');
|
||||
PREPARE s FROM @sql; EXECUTE s; DEALLOCATE PREPARE s;
|
||||
|
||||
-- ---------------------------------------------------------------------------
|
||||
-- 3. 订单表承载两类商品(会员套餐 / 次数包)
|
||||
-- ---------------------------------------------------------------------------
|
||||
SET @sql := IF(
|
||||
(SELECT COUNT(*) FROM information_schema.COLUMNS
|
||||
WHERE TABLE_SCHEMA = @db AND TABLE_NAME = 'member_orders' AND COLUMN_NAME = 'order_type') = 0,
|
||||
'ALTER TABLE `member_orders` ADD COLUMN `order_type` tinyint NOT NULL DEFAULT 1 COMMENT ''1=会员套餐 2=次数包''',
|
||||
'SELECT 1');
|
||||
PREPARE s FROM @sql; EXECUTE s; DEALLOCATE PREPARE s;
|
||||
|
||||
SET @sql := IF(
|
||||
(SELECT COUNT(*) FROM information_schema.COLUMNS
|
||||
WHERE TABLE_SCHEMA = @db AND TABLE_NAME = 'member_orders' AND COLUMN_NAME = 'pack_key') = 0,
|
||||
'ALTER TABLE `member_orders` ADD COLUMN `pack_key` varchar(64) NOT NULL DEFAULT '''' COMMENT ''次数包档位''',
|
||||
'SELECT 1');
|
||||
PREPARE s FROM @sql; EXECUTE s; DEALLOCATE PREPARE s;
|
||||
|
||||
SET @sql := IF(
|
||||
(SELECT COUNT(*) FROM information_schema.COLUMNS
|
||||
WHERE TABLE_SCHEMA = @db AND TABLE_NAME = 'member_orders' AND COLUMN_NAME = 'tool_key') = 0,
|
||||
'ALTER TABLE `member_orders` ADD COLUMN `tool_key` varchar(64) NOT NULL DEFAULT '''' COMMENT ''次数包绑定工具''',
|
||||
'SELECT 1');
|
||||
PREPARE s FROM @sql; EXECUTE s; DEALLOCATE PREPARE s;
|
||||
|
||||
SET @sql := IF(
|
||||
(SELECT COUNT(*) FROM information_schema.COLUMNS
|
||||
WHERE TABLE_SCHEMA = @db AND TABLE_NAME = 'member_orders' AND COLUMN_NAME = 'times') = 0,
|
||||
'ALTER TABLE `member_orders` ADD COLUMN `times` int NOT NULL DEFAULT 0 COMMENT ''次数包次数''',
|
||||
'SELECT 1');
|
||||
PREPARE s FROM @sql; EXECUTE s; DEALLOCATE PREPARE s;
|
||||
|
||||
-- ---------------------------------------------------------------------------
|
||||
-- 4. 次数包档位(在「次数包管理」里维护;product_id 必须与 MP 后台道具一致)
|
||||
-- ---------------------------------------------------------------------------
|
||||
CREATE TABLE IF NOT EXISTS `quota_packs` (
|
||||
`id` bigint unsigned NOT NULL AUTO_INCREMENT,
|
||||
`pack_key` varchar(64) NOT NULL COMMENT '档位标识,跨端契约',
|
||||
`name` varchar(64) NOT NULL DEFAULT '' COMMENT '展示名',
|
||||
`times` int NOT NULL DEFAULT 0 COMMENT '可用次数',
|
||||
`price_cents` bigint NOT NULL DEFAULT 0 COMMENT '价格(分)',
|
||||
`product_id` varchar(64) NOT NULL DEFAULT '' COMMENT '微信虚拟支付道具 ID',
|
||||
`valid_days` int NOT NULL DEFAULT 365 COMMENT '有效期天数,默认一年',
|
||||
`tool_key` varchar(64) NOT NULL DEFAULT '' COMMENT '绑定工具,空=通用档位',
|
||||
`badge` varchar(32) NOT NULL DEFAULT '' COMMENT '角标文案',
|
||||
`sort` int NOT NULL DEFAULT 0,
|
||||
`is_enabled` tinyint NOT NULL DEFAULT 1,
|
||||
`remark` varchar(255) NOT NULL DEFAULT '',
|
||||
`created_at` datetime DEFAULT NULL,
|
||||
`updated_at` datetime DEFAULT NULL,
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY `uk_pack_key` (`pack_key`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='次数包档位(付费额度包)';
|
||||
|
||||
-- ---------------------------------------------------------------------------
|
||||
-- 5. 用户付费额度余额(按工具绑定,买断制)
|
||||
-- ---------------------------------------------------------------------------
|
||||
CREATE TABLE IF NOT EXISTS `user_tool_quota` (
|
||||
`id` bigint unsigned NOT NULL AUTO_INCREMENT,
|
||||
`user_id` bigint NOT NULL,
|
||||
`tool_key` varchar(64) NOT NULL,
|
||||
`times_left` int NOT NULL DEFAULT 0 COMMENT '剩余次数',
|
||||
`total_bought` int NOT NULL DEFAULT 0 COMMENT '累计购买次数',
|
||||
`expire_at` datetime DEFAULT NULL COMMENT '到期时间,NULL 视为已过期',
|
||||
`created_at` datetime DEFAULT NULL,
|
||||
`updated_at` datetime DEFAULT NULL,
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY `uk_user_tool` (`user_id`,`tool_key`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='用户工具付费额度余额';
|
||||
|
||||
-- ---------------------------------------------------------------------------
|
||||
-- 6. 用户周期用量(滚动窗口,归零由服务端在读写时判定)
|
||||
-- ---------------------------------------------------------------------------
|
||||
CREATE TABLE IF NOT EXISTS `user_quota_usage` (
|
||||
`id` bigint unsigned NOT NULL AUTO_INCREMENT,
|
||||
`user_id` bigint NOT NULL,
|
||||
`tool_key` varchar(64) NOT NULL,
|
||||
`period_start` datetime NOT NULL COMMENT '当前周期起点',
|
||||
`period_end` datetime NOT NULL COMMENT '当前周期终点',
|
||||
`free_used` int NOT NULL DEFAULT 0 COMMENT '本周期已用免费额度',
|
||||
`member_used` int NOT NULL DEFAULT 0 COMMENT '本周期已用会员额度',
|
||||
`updated_at` datetime DEFAULT NULL,
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY `uk_user_tool` (`user_id`,`tool_key`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='用户工具额度周期用量';
|
||||
|
||||
-- ---------------------------------------------------------------------------
|
||||
-- 7. 后台可改的全局配置(额度周期等)
|
||||
-- ---------------------------------------------------------------------------
|
||||
CREATE TABLE IF NOT EXISTS `settings` (
|
||||
`k` varchar(64) NOT NULL,
|
||||
`v` varchar(255) NOT NULL DEFAULT '',
|
||||
`remark` varchar(255) NOT NULL DEFAULT '',
|
||||
`updated_at` datetime DEFAULT NULL,
|
||||
PRIMARY KEY (`k`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='后台可改的全局配置';
|
||||
|
||||
-- 种子数据(服务端启动时也会幂等写入同样的内容)
|
||||
INSERT IGNORE INTO `settings` (`k`, `v`, `remark`, `updated_at`)
|
||||
VALUES ('quota_period_days', '7', '全局默认额度重置周期(天)', NOW());
|
||||
Reference in New Issue
Block a user