chore(db): 合并迁移文件为单一 001_init.sql
- 将 002-006 迁移合并进 001_init.sql,只保留一个 init 文件 - 表结构直接采用最终态:移除旧 skins/orders/ship_logs 表、users 的 invite_code/parent_id 列,货币默认 POINT,手续费 fee_type 二选一 - 修复鸡生蛋问题:自营商户在 SQL 内直接插入,商品种子不再依赖 Go 代码后续创建的商户 - 商品价格一步到位,消除 006 价格补丁 - 简化 migrate.go:移除 ensureSelfMerchant/ensureWallet,清理无用 import - 编译与 go vet 通过,数据库重置后全新初始化验证通过
This commit is contained in:
@@ -11,10 +11,7 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"affiliate_dash/internal/model"
|
|
||||||
|
|
||||||
"gorm.io/gorm"
|
"gorm.io/gorm"
|
||||||
"gorm.io/gorm/clause"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
//go:embed migrations/*.sql
|
//go:embed migrations/*.sql
|
||||||
@@ -32,6 +29,7 @@ func (schemaMigration) TableName() string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Migrate 使用显式 SQL 迁移管理表结构,避免大型项目依赖隐式结构同步。
|
// Migrate 使用显式 SQL 迁移管理表结构,避免大型项目依赖隐式结构同步。
|
||||||
|
// 自营商户、默认钱包与商品目录种子数据均在 001_init.sql 中完成,无需在 Go 层补充。
|
||||||
func Migrate(db *gorm.DB) error {
|
func Migrate(db *gorm.DB) error {
|
||||||
return db.Transaction(func(tx *gorm.DB) error {
|
return db.Transaction(func(tx *gorm.DB) error {
|
||||||
if err := tx.Exec("SELECT pg_advisory_xact_lock(hashtext(?))", "affiliate_dash_schema_migrations").Error; err != nil {
|
if err := tx.Exec("SELECT pg_advisory_xact_lock(hashtext(?))", "affiliate_dash_schema_migrations").Error; err != nil {
|
||||||
@@ -40,14 +38,7 @@ func Migrate(db *gorm.DB) error {
|
|||||||
if err := ensureMigrationTable(tx); err != nil {
|
if err := ensureMigrationTable(tx); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if err := applySQLMigrations(tx); err != nil {
|
return applySQLMigrations(tx)
|
||||||
return err
|
|
||||||
}
|
|
||||||
merchant, err := ensureSelfMerchant(tx)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return ensureWallet(tx, merchant.ID)
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -139,30 +130,3 @@ func migrationChecksum(content []byte) string {
|
|||||||
sum := sha256.Sum256(content)
|
sum := sha256.Sum256(content)
|
||||||
return hex.EncodeToString(sum[:])
|
return hex.EncodeToString(sum[:])
|
||||||
}
|
}
|
||||||
|
|
||||||
func ensureSelfMerchant(tx *gorm.DB) (*model.Merchant, error) {
|
|
||||||
var merchant model.Merchant
|
|
||||||
err := tx.Where("code = ?", "self-operated").First(&merchant).Error
|
|
||||||
if err == nil {
|
|
||||||
return &merchant, nil
|
|
||||||
}
|
|
||||||
if err != gorm.ErrRecordNotFound {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
merchant = model.Merchant{
|
|
||||||
Code: "self-operated",
|
|
||||||
Name: "自营商户",
|
|
||||||
Status: model.MerchantStatusActive,
|
|
||||||
}
|
|
||||||
if err := tx.Create(&merchant).Error; err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return &merchant, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func ensureWallet(tx *gorm.DB, merchantID uint) error {
|
|
||||||
return tx.Clauses(clause.OnConflict{DoNothing: true}).Create(&model.WalletAccount{
|
|
||||||
MerchantID: merchantID,
|
|
||||||
Currency: "POINT",
|
|
||||||
}).Error
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -1,3 +1,13 @@
|
|||||||
|
-- ============================================================================
|
||||||
|
-- affiliate_dash 初始化脚本(唯一迁移文件)
|
||||||
|
-- 全平台统一使用积分(POINT)作为结算货币;商户手续费为"百分比或固定"二选一。
|
||||||
|
-- 本脚本幂等:所有 CREATE 均带 IF NOT EXISTS,种子数据均用 ON CONFLICT DO NOTHING。
|
||||||
|
-- ============================================================================
|
||||||
|
|
||||||
|
-- ----------------------------------------------------------------------------
|
||||||
|
-- 用户与商户
|
||||||
|
-- ----------------------------------------------------------------------------
|
||||||
|
|
||||||
CREATE TABLE IF NOT EXISTS users (
|
CREATE TABLE IF NOT EXISTS users (
|
||||||
id BIGSERIAL PRIMARY KEY,
|
id BIGSERIAL PRIMARY KEY,
|
||||||
created_at TIMESTAMPTZ,
|
created_at TIMESTAMPTZ,
|
||||||
@@ -6,16 +16,12 @@ CREATE TABLE IF NOT EXISTS users (
|
|||||||
username VARCHAR(64) NOT NULL,
|
username VARCHAR(64) NOT NULL,
|
||||||
password_hash VARCHAR(255) NOT NULL,
|
password_hash VARCHAR(255) NOT NULL,
|
||||||
nickname VARCHAR(64),
|
nickname VARCHAR(64),
|
||||||
role VARCHAR(32) NOT NULL DEFAULT 'distributor',
|
role VARCHAR(32) NOT NULL DEFAULT 'merchant',
|
||||||
status BIGINT DEFAULT 1,
|
status BIGINT DEFAULT 1
|
||||||
invite_code VARCHAR(32),
|
|
||||||
parent_id BIGINT
|
|
||||||
);
|
);
|
||||||
|
|
||||||
CREATE UNIQUE INDEX IF NOT EXISTS idx_users_username ON users (username);
|
CREATE UNIQUE INDEX IF NOT EXISTS idx_users_username ON users (username);
|
||||||
CREATE UNIQUE INDEX IF NOT EXISTS idx_users_invite_code ON users (invite_code);
|
|
||||||
CREATE INDEX IF NOT EXISTS idx_users_deleted_at ON users (deleted_at);
|
CREATE INDEX IF NOT EXISTS idx_users_deleted_at ON users (deleted_at);
|
||||||
CREATE INDEX IF NOT EXISTS idx_users_parent_id ON users (parent_id);
|
|
||||||
|
|
||||||
CREATE TABLE IF NOT EXISTS merchants (
|
CREATE TABLE IF NOT EXISTS merchants (
|
||||||
id BIGSERIAL PRIMARY KEY,
|
id BIGSERIAL PRIMARY KEY,
|
||||||
@@ -26,7 +32,11 @@ CREATE TABLE IF NOT EXISTS merchants (
|
|||||||
name VARCHAR(128) NOT NULL,
|
name VARCHAR(128) NOT NULL,
|
||||||
status VARCHAR(16) NOT NULL DEFAULT 'active',
|
status VARCHAR(16) NOT NULL DEFAULT 'active',
|
||||||
contact_name VARCHAR(64),
|
contact_name VARCHAR(64),
|
||||||
contact_info VARCHAR(128)
|
contact_info VARCHAR(128),
|
||||||
|
features TEXT NOT NULL DEFAULT 'products,orders,wallet,api,callbacks',
|
||||||
|
fee_type VARCHAR(16) NOT NULL DEFAULT 'rate',
|
||||||
|
fee_rate_bp BIGINT NOT NULL DEFAULT 0,
|
||||||
|
fee_fixed_amount BIGINT NOT NULL DEFAULT 0
|
||||||
);
|
);
|
||||||
|
|
||||||
CREATE UNIQUE INDEX IF NOT EXISTS idx_merchants_code ON merchants (code);
|
CREATE UNIQUE INDEX IF NOT EXISTS idx_merchants_code ON merchants (code);
|
||||||
@@ -48,80 +58,9 @@ CREATE UNIQUE INDEX IF NOT EXISTS idx_merchant_member ON merchant_members (merch
|
|||||||
CREATE INDEX IF NOT EXISTS idx_merchant_members_merchant_id ON merchant_members (merchant_id);
|
CREATE INDEX IF NOT EXISTS idx_merchant_members_merchant_id ON merchant_members (merchant_id);
|
||||||
CREATE INDEX IF NOT EXISTS idx_merchant_members_user_id ON merchant_members (user_id);
|
CREATE INDEX IF NOT EXISTS idx_merchant_members_user_id ON merchant_members (user_id);
|
||||||
|
|
||||||
CREATE TABLE IF NOT EXISTS skins (
|
-- ----------------------------------------------------------------------------
|
||||||
id BIGSERIAL PRIMARY KEY,
|
-- 开放接口凭证
|
||||||
created_at TIMESTAMPTZ,
|
-- ----------------------------------------------------------------------------
|
||||||
updated_at TIMESTAMPTZ,
|
|
||||||
deleted_at TIMESTAMPTZ,
|
|
||||||
merchant_id BIGINT NOT NULL DEFAULT 0,
|
|
||||||
name VARCHAR(128) NOT NULL,
|
|
||||||
sku VARCHAR(64) NOT NULL,
|
|
||||||
game VARCHAR(64),
|
|
||||||
category VARCHAR(64),
|
|
||||||
cover_url VARCHAR(512),
|
|
||||||
price DOUBLE PRECISION NOT NULL DEFAULT 0,
|
|
||||||
cost_price DOUBLE PRECISION DEFAULT 0,
|
|
||||||
commission DOUBLE PRECISION DEFAULT 0,
|
|
||||||
stock BIGINT DEFAULT 0,
|
|
||||||
status BIGINT DEFAULT 1,
|
|
||||||
description TEXT
|
|
||||||
);
|
|
||||||
|
|
||||||
DROP INDEX IF EXISTS idx_skins_sku;
|
|
||||||
CREATE UNIQUE INDEX IF NOT EXISTS idx_skins_merchant_sku ON skins (merchant_id, sku);
|
|
||||||
CREATE INDEX IF NOT EXISTS idx_skins_deleted_at ON skins (deleted_at);
|
|
||||||
CREATE INDEX IF NOT EXISTS idx_skins_merchant_id ON skins (merchant_id);
|
|
||||||
CREATE INDEX IF NOT EXISTS idx_skins_game ON skins (game);
|
|
||||||
CREATE INDEX IF NOT EXISTS idx_skins_category ON skins (category);
|
|
||||||
|
|
||||||
CREATE TABLE IF NOT EXISTS orders (
|
|
||||||
id BIGSERIAL PRIMARY KEY,
|
|
||||||
created_at TIMESTAMPTZ,
|
|
||||||
updated_at TIMESTAMPTZ,
|
|
||||||
deleted_at TIMESTAMPTZ,
|
|
||||||
merchant_id BIGINT NOT NULL DEFAULT 0,
|
|
||||||
order_no VARCHAR(64) NOT NULL,
|
|
||||||
skin_id BIGINT NOT NULL,
|
|
||||||
distributor_id BIGINT NOT NULL,
|
|
||||||
buyer_name VARCHAR(64),
|
|
||||||
amount DOUBLE PRECISION NOT NULL,
|
|
||||||
commission_amt DOUBLE PRECISION DEFAULT 0,
|
|
||||||
status VARCHAR(32) DEFAULT 'pending',
|
|
||||||
remark VARCHAR(255),
|
|
||||||
provider_order_no VARCHAR(64),
|
|
||||||
shipped_at TIMESTAMPTZ,
|
|
||||||
ship_fail_reason VARCHAR(512),
|
|
||||||
game_channel VARCHAR(64),
|
|
||||||
game_uid VARCHAR(128),
|
|
||||||
role_name VARCHAR(64),
|
|
||||||
pay_score BIGINT DEFAULT 0
|
|
||||||
);
|
|
||||||
|
|
||||||
CREATE UNIQUE INDEX IF NOT EXISTS idx_orders_order_no ON orders (order_no);
|
|
||||||
CREATE INDEX IF NOT EXISTS idx_orders_deleted_at ON orders (deleted_at);
|
|
||||||
CREATE INDEX IF NOT EXISTS idx_orders_merchant_id ON orders (merchant_id);
|
|
||||||
CREATE INDEX IF NOT EXISTS idx_orders_skin_id ON orders (skin_id);
|
|
||||||
CREATE INDEX IF NOT EXISTS idx_orders_distributor_id ON orders (distributor_id);
|
|
||||||
CREATE INDEX IF NOT EXISTS idx_orders_status ON orders (status);
|
|
||||||
CREATE INDEX IF NOT EXISTS idx_orders_provider_order_no ON orders (provider_order_no);
|
|
||||||
|
|
||||||
CREATE TABLE IF NOT EXISTS ship_logs (
|
|
||||||
id BIGSERIAL PRIMARY KEY,
|
|
||||||
created_at TIMESTAMPTZ,
|
|
||||||
merchant_id BIGINT NOT NULL DEFAULT 0,
|
|
||||||
order_no VARCHAR(64) NOT NULL,
|
|
||||||
order_id BIGINT,
|
|
||||||
ship_status VARCHAR(32) NOT NULL,
|
|
||||||
provider_order_no VARCHAR(64),
|
|
||||||
fail_reason VARCHAR(512),
|
|
||||||
payload TEXT,
|
|
||||||
result_status VARCHAR(32),
|
|
||||||
message VARCHAR(255)
|
|
||||||
);
|
|
||||||
|
|
||||||
CREATE INDEX IF NOT EXISTS idx_ship_logs_merchant_id ON ship_logs (merchant_id);
|
|
||||||
CREATE INDEX IF NOT EXISTS idx_ship_logs_order_no ON ship_logs (order_no);
|
|
||||||
CREATE INDEX IF NOT EXISTS idx_ship_logs_order_id ON ship_logs (order_id);
|
|
||||||
|
|
||||||
CREATE TABLE IF NOT EXISTS api_clients (
|
CREATE TABLE IF NOT EXISTS api_clients (
|
||||||
id BIGSERIAL PRIMARY KEY,
|
id BIGSERIAL PRIMARY KEY,
|
||||||
@@ -144,6 +83,22 @@ CREATE INDEX IF NOT EXISTS idx_api_clients_deleted_at ON api_clients (deleted_at
|
|||||||
CREATE INDEX IF NOT EXISTS idx_api_clients_merchant_id ON api_clients (merchant_id);
|
CREATE INDEX IF NOT EXISTS idx_api_clients_merchant_id ON api_clients (merchant_id);
|
||||||
CREATE INDEX IF NOT EXISTS idx_api_clients_status ON api_clients (status);
|
CREATE INDEX IF NOT EXISTS idx_api_clients_status ON api_clients (status);
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS api_request_nonces (
|
||||||
|
id BIGSERIAL PRIMARY KEY,
|
||||||
|
created_at TIMESTAMPTZ,
|
||||||
|
api_client_id BIGINT NOT NULL,
|
||||||
|
nonce VARCHAR(96) NOT NULL,
|
||||||
|
expires_at TIMESTAMPTZ NOT NULL
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE UNIQUE INDEX IF NOT EXISTS idx_api_nonce ON api_request_nonces (api_client_id, nonce);
|
||||||
|
CREATE INDEX IF NOT EXISTS idx_api_request_nonces_api_client_id ON api_request_nonces (api_client_id);
|
||||||
|
CREATE INDEX IF NOT EXISTS idx_api_request_nonces_expires_at ON api_request_nonces (expires_at);
|
||||||
|
|
||||||
|
-- ----------------------------------------------------------------------------
|
||||||
|
-- 商品目录与商户可售商品
|
||||||
|
-- ----------------------------------------------------------------------------
|
||||||
|
|
||||||
CREATE TABLE IF NOT EXISTS products (
|
CREATE TABLE IF NOT EXISTS products (
|
||||||
id BIGSERIAL PRIMARY KEY,
|
id BIGSERIAL PRIMARY KEY,
|
||||||
created_at TIMESTAMPTZ,
|
created_at TIMESTAMPTZ,
|
||||||
@@ -173,7 +128,7 @@ CREATE TABLE IF NOT EXISTS merchant_products (
|
|||||||
display_name VARCHAR(160),
|
display_name VARCHAR(160),
|
||||||
price_amount BIGINT NOT NULL DEFAULT 0,
|
price_amount BIGINT NOT NULL DEFAULT 0,
|
||||||
cost_amount BIGINT NOT NULL DEFAULT 0,
|
cost_amount BIGINT NOT NULL DEFAULT 0,
|
||||||
currency VARCHAR(12) NOT NULL DEFAULT 'CNY',
|
currency VARCHAR(12) NOT NULL DEFAULT 'POINT',
|
||||||
stock BIGINT NOT NULL DEFAULT -1,
|
stock BIGINT NOT NULL DEFAULT -1,
|
||||||
status VARCHAR(16) NOT NULL DEFAULT 'active',
|
status VARCHAR(16) NOT NULL DEFAULT 'active',
|
||||||
fulfillment_config TEXT
|
fulfillment_config TEXT
|
||||||
@@ -185,12 +140,16 @@ CREATE INDEX IF NOT EXISTS idx_merchant_products_merchant_id ON merchant_product
|
|||||||
CREATE INDEX IF NOT EXISTS idx_merchant_products_product_id ON merchant_products (product_id);
|
CREATE INDEX IF NOT EXISTS idx_merchant_products_product_id ON merchant_products (product_id);
|
||||||
CREATE INDEX IF NOT EXISTS idx_merchant_products_status ON merchant_products (status);
|
CREATE INDEX IF NOT EXISTS idx_merchant_products_status ON merchant_products (status);
|
||||||
|
|
||||||
|
-- ----------------------------------------------------------------------------
|
||||||
|
-- 钱包账户与流水
|
||||||
|
-- ----------------------------------------------------------------------------
|
||||||
|
|
||||||
CREATE TABLE IF NOT EXISTS wallet_accounts (
|
CREATE TABLE IF NOT EXISTS wallet_accounts (
|
||||||
id BIGSERIAL PRIMARY KEY,
|
id BIGSERIAL PRIMARY KEY,
|
||||||
created_at TIMESTAMPTZ,
|
created_at TIMESTAMPTZ,
|
||||||
updated_at TIMESTAMPTZ,
|
updated_at TIMESTAMPTZ,
|
||||||
merchant_id BIGINT NOT NULL,
|
merchant_id BIGINT NOT NULL,
|
||||||
currency VARCHAR(12) NOT NULL DEFAULT 'CNY',
|
currency VARCHAR(12) NOT NULL DEFAULT 'POINT',
|
||||||
available_balance BIGINT NOT NULL DEFAULT 0,
|
available_balance BIGINT NOT NULL DEFAULT 0,
|
||||||
frozen_balance BIGINT NOT NULL DEFAULT 0
|
frozen_balance BIGINT NOT NULL DEFAULT 0
|
||||||
);
|
);
|
||||||
@@ -219,6 +178,10 @@ CREATE INDEX IF NOT EXISTS idx_wallet_ledger_entries_wallet_account_id ON wallet
|
|||||||
CREATE INDEX IF NOT EXISTS idx_wallet_ledger_entries_type ON wallet_ledger_entries (type);
|
CREATE INDEX IF NOT EXISTS idx_wallet_ledger_entries_type ON wallet_ledger_entries (type);
|
||||||
CREATE INDEX IF NOT EXISTS idx_wallet_ledger_entries_reference_no ON wallet_ledger_entries (reference_no);
|
CREATE INDEX IF NOT EXISTS idx_wallet_ledger_entries_reference_no ON wallet_ledger_entries (reference_no);
|
||||||
|
|
||||||
|
-- ----------------------------------------------------------------------------
|
||||||
|
-- 履约订单与任务
|
||||||
|
-- ----------------------------------------------------------------------------
|
||||||
|
|
||||||
CREATE TABLE IF NOT EXISTS fulfillment_orders (
|
CREATE TABLE IF NOT EXISTS fulfillment_orders (
|
||||||
id BIGSERIAL PRIMARY KEY,
|
id BIGSERIAL PRIMARY KEY,
|
||||||
created_at TIMESTAMPTZ,
|
created_at TIMESTAMPTZ,
|
||||||
@@ -231,8 +194,13 @@ CREATE TABLE IF NOT EXISTS fulfillment_orders (
|
|||||||
product_sku VARCHAR(96) NOT NULL,
|
product_sku VARCHAR(96) NOT NULL,
|
||||||
product_name VARCHAR(160) NOT NULL,
|
product_name VARCHAR(160) NOT NULL,
|
||||||
quantity BIGINT NOT NULL DEFAULT 1,
|
quantity BIGINT NOT NULL DEFAULT 1,
|
||||||
|
base_amount BIGINT NOT NULL DEFAULT 0,
|
||||||
|
fee_type VARCHAR(16) NOT NULL DEFAULT 'rate',
|
||||||
|
fee_rate_bp BIGINT NOT NULL DEFAULT 0,
|
||||||
|
fee_fixed_amount BIGINT NOT NULL DEFAULT 0,
|
||||||
|
service_fee_amount BIGINT NOT NULL DEFAULT 0,
|
||||||
amount BIGINT NOT NULL,
|
amount BIGINT NOT NULL,
|
||||||
currency VARCHAR(12) NOT NULL DEFAULT 'CNY',
|
currency VARCHAR(12) NOT NULL DEFAULT 'POINT',
|
||||||
payment_status VARCHAR(16) NOT NULL DEFAULT 'pending',
|
payment_status VARCHAR(16) NOT NULL DEFAULT 'pending',
|
||||||
fulfillment_status VARCHAR(16) NOT NULL DEFAULT 'pending',
|
fulfillment_status VARCHAR(16) NOT NULL DEFAULT 'pending',
|
||||||
buyer_reference VARCHAR(128),
|
buyer_reference VARCHAR(128),
|
||||||
@@ -274,6 +242,10 @@ CREATE INDEX IF NOT EXISTS idx_fulfillment_jobs_status ON fulfillment_jobs (stat
|
|||||||
CREATE INDEX IF NOT EXISTS idx_fulfillment_jobs_next_run_at ON fulfillment_jobs (next_run_at);
|
CREATE INDEX IF NOT EXISTS idx_fulfillment_jobs_next_run_at ON fulfillment_jobs (next_run_at);
|
||||||
CREATE INDEX IF NOT EXISTS idx_fulfillment_jobs_provider_order_no ON fulfillment_jobs (provider_order_no);
|
CREATE INDEX IF NOT EXISTS idx_fulfillment_jobs_provider_order_no ON fulfillment_jobs (provider_order_no);
|
||||||
|
|
||||||
|
-- ----------------------------------------------------------------------------
|
||||||
|
-- 回调订阅与投递(事务性 outbox)
|
||||||
|
-- ----------------------------------------------------------------------------
|
||||||
|
|
||||||
CREATE TABLE IF NOT EXISTS callback_subscriptions (
|
CREATE TABLE IF NOT EXISTS callback_subscriptions (
|
||||||
id BIGSERIAL PRIMARY KEY,
|
id BIGSERIAL PRIMARY KEY,
|
||||||
created_at TIMESTAMPTZ,
|
created_at TIMESTAMPTZ,
|
||||||
@@ -315,17 +287,9 @@ CREATE INDEX IF NOT EXISTS idx_callback_deliveries_event ON callback_deliveries
|
|||||||
CREATE INDEX IF NOT EXISTS idx_callback_deliveries_status ON callback_deliveries (status);
|
CREATE INDEX IF NOT EXISTS idx_callback_deliveries_status ON callback_deliveries (status);
|
||||||
CREATE INDEX IF NOT EXISTS idx_callback_deliveries_next_attempt_at ON callback_deliveries (next_attempt_at);
|
CREATE INDEX IF NOT EXISTS idx_callback_deliveries_next_attempt_at ON callback_deliveries (next_attempt_at);
|
||||||
|
|
||||||
CREATE TABLE IF NOT EXISTS api_request_nonces (
|
-- ----------------------------------------------------------------------------
|
||||||
id BIGSERIAL PRIMARY KEY,
|
-- 审计日志
|
||||||
created_at TIMESTAMPTZ,
|
-- ----------------------------------------------------------------------------
|
||||||
api_client_id BIGINT NOT NULL,
|
|
||||||
nonce VARCHAR(96) NOT NULL,
|
|
||||||
expires_at TIMESTAMPTZ NOT NULL
|
|
||||||
);
|
|
||||||
|
|
||||||
CREATE UNIQUE INDEX IF NOT EXISTS idx_api_nonce ON api_request_nonces (api_client_id, nonce);
|
|
||||||
CREATE INDEX IF NOT EXISTS idx_api_request_nonces_api_client_id ON api_request_nonces (api_client_id);
|
|
||||||
CREATE INDEX IF NOT EXISTS idx_api_request_nonces_expires_at ON api_request_nonces (expires_at);
|
|
||||||
|
|
||||||
CREATE TABLE IF NOT EXISTS audit_logs (
|
CREATE TABLE IF NOT EXISTS audit_logs (
|
||||||
id BIGSERIAL PRIMARY KEY,
|
id BIGSERIAL PRIMARY KEY,
|
||||||
@@ -347,3 +311,96 @@ CREATE INDEX IF NOT EXISTS idx_audit_logs_request_id ON audit_logs (request_id);
|
|||||||
CREATE INDEX IF NOT EXISTS idx_audit_logs_action ON audit_logs (action);
|
CREATE INDEX IF NOT EXISTS idx_audit_logs_action ON audit_logs (action);
|
||||||
CREATE INDEX IF NOT EXISTS idx_audit_logs_entity_type ON audit_logs (entity_type);
|
CREATE INDEX IF NOT EXISTS idx_audit_logs_entity_type ON audit_logs (entity_type);
|
||||||
CREATE INDEX IF NOT EXISTS idx_audit_logs_entity_id ON audit_logs (entity_id);
|
CREATE INDEX IF NOT EXISTS idx_audit_logs_entity_id ON audit_logs (entity_id);
|
||||||
|
|
||||||
|
-- ============================================================================
|
||||||
|
-- 种子数据
|
||||||
|
-- ============================================================================
|
||||||
|
|
||||||
|
-- 1. 自营商户(平台默认租户,供 EnsureAdmin 关联成员)
|
||||||
|
INSERT INTO merchants (code, name, status, features, fee_type)
|
||||||
|
VALUES ('self-operated', '自营商户', 'active', 'products,orders,wallet,api,callbacks', 'rate')
|
||||||
|
ON CONFLICT (code) DO NOTHING;
|
||||||
|
|
||||||
|
-- 2. 自营商户积分钱包
|
||||||
|
INSERT INTO wallet_accounts (merchant_id, currency)
|
||||||
|
SELECT id, 'POINT' FROM merchants WHERE code = 'self-operated'
|
||||||
|
ON CONFLICT (merchant_id) DO NOTHING;
|
||||||
|
|
||||||
|
-- 3. 平台商品目录(和平精英商品,幂等)
|
||||||
|
INSERT INTO products (code, name, category, status)
|
||||||
|
SELECT v.code, v.name, v.category, 'active'
|
||||||
|
FROM (VALUES
|
||||||
|
('suit_alan_walker', '套装-Alan Walker', '套装'),
|
||||||
|
('suit_shadow_gothic', '套装-暗影哥特', '套装'),
|
||||||
|
('top_black_elite_trainer','黑色高级特训官上衣', '上衣'),
|
||||||
|
('m416_hamster_gray', 'M416-仓鼠灰灰', '枪械'),
|
||||||
|
('bag_cute_bear', '萌熊伴侣背包', '背包'),
|
||||||
|
('suit_dual_fluffy', '套装-双彩绵绵', '套装'),
|
||||||
|
('suit_pink_sheep', '套装-糯粉咩咩', '套装'),
|
||||||
|
('suit_first_peach', '套装-恋恋初桃', '套装'),
|
||||||
|
('suit_romantic_destiny', '套装-浪漫天命', '套装'),
|
||||||
|
('pack_western_cowboy', '西部牛仔大礼包', '礼包'),
|
||||||
|
('smoke_pink_sheep', '烟雾弹-糯粉咩咩', '投掷物'),
|
||||||
|
('frag_pink_sheep', '破片手榴弹-糯粉咩咩', '投掷物'),
|
||||||
|
('suit_hamster_gray', '套装-仓鼠灰灰', '套装'),
|
||||||
|
('suit_cute_bear', '套装-萌熊伴侣', '套装'),
|
||||||
|
('bag_pink_sheep', '糯粉咩咩背包', '背包'),
|
||||||
|
('helmet_pink_sheep', '糯粉咩咩头盔', '头盔'),
|
||||||
|
('bag_hamster_gray', '仓鼠灰灰背包', '背包'),
|
||||||
|
('helmet_hamster_gray', '仓鼠灰灰头盔', '头盔'),
|
||||||
|
('suit_western_mystery', '套装-西部谜踪', '套装'),
|
||||||
|
('helmet_panda_treasure', '国宝胖达头盔', '头盔'),
|
||||||
|
('suit_panda_round', '套装-胖达圆圆', '套装'),
|
||||||
|
('suit_panda_tuan', '套装-胖达团团', '套装'),
|
||||||
|
('pack_lava_ranger', '熔岩游骑兵礼包', '礼包'),
|
||||||
|
('suit_sand_dancer', '套装-狂沙舞者', '套装'),
|
||||||
|
('pack_star_roam_outfit', '星际漫游服装礼包', '礼包'),
|
||||||
|
('pack_star_roam_weapon', '星际漫游枪械礼包', '礼包'),
|
||||||
|
('suit_cloud_bear', '套装-绵云熊熊', '套装')
|
||||||
|
) AS v(code, name, category)
|
||||||
|
ON CONFLICT (code) DO NOTHING;
|
||||||
|
|
||||||
|
-- 4. 自营商户可售商品(价格一步到位,幂等,按 merchant_id + sku 唯一索引)
|
||||||
|
INSERT INTO merchant_products (merchant_id, product_id, sku, display_name, price_amount, cost_amount, currency, stock, status)
|
||||||
|
SELECT
|
||||||
|
m.id,
|
||||||
|
p.id,
|
||||||
|
p.code,
|
||||||
|
p.name,
|
||||||
|
v.price_amount,
|
||||||
|
v.cost_amount,
|
||||||
|
'POINT',
|
||||||
|
-1,
|
||||||
|
'active'
|
||||||
|
FROM (VALUES
|
||||||
|
('suit_alan_walker', 360, 360),
|
||||||
|
('suit_shadow_gothic', 888, 888),
|
||||||
|
('top_black_elite_trainer',360, 360),
|
||||||
|
('m416_hamster_gray', 1680, 1680),
|
||||||
|
('bag_cute_bear', 2880, 2880),
|
||||||
|
('suit_dual_fluffy', 1124, 1124),
|
||||||
|
('suit_pink_sheep', 1880, 1880),
|
||||||
|
('suit_first_peach', 988, 988),
|
||||||
|
('suit_romantic_destiny', 360, 360),
|
||||||
|
('pack_western_cowboy', 3200, 3200),
|
||||||
|
('smoke_pink_sheep', 488, 488),
|
||||||
|
('frag_pink_sheep', 488, 488),
|
||||||
|
('suit_hamster_gray', 1280, 1280),
|
||||||
|
('suit_cute_bear', 1680, 1680),
|
||||||
|
('bag_pink_sheep', 1680, 1680),
|
||||||
|
('helmet_pink_sheep', 1680, 1680),
|
||||||
|
('bag_hamster_gray', 1680, 1680),
|
||||||
|
('helmet_hamster_gray', 1680, 1680),
|
||||||
|
('suit_western_mystery', 1150, 1150),
|
||||||
|
('helmet_panda_treasure', 2340, 2340),
|
||||||
|
('suit_panda_round', 2340, 2340),
|
||||||
|
('suit_panda_tuan', 2340, 2340),
|
||||||
|
('pack_lava_ranger', 960, 960),
|
||||||
|
('suit_sand_dancer', 840, 840),
|
||||||
|
('pack_star_roam_outfit', 8360, 8360),
|
||||||
|
('pack_star_roam_weapon', 5160, 5160),
|
||||||
|
('suit_cloud_bear', 1348, 1348)
|
||||||
|
) AS v(sku, price_amount, cost_amount)
|
||||||
|
JOIN products p ON p.code = v.sku
|
||||||
|
JOIN merchants m ON m.code = 'self-operated'
|
||||||
|
ON CONFLICT (merchant_id, sku) DO NOTHING;
|
||||||
|
|||||||
@@ -1,22 +0,0 @@
|
|||||||
ALTER TABLE users ALTER COLUMN role SET DEFAULT 'merchant';
|
|
||||||
UPDATE users SET role = 'merchant' WHERE role = 'distributor';
|
|
||||||
DROP INDEX IF EXISTS idx_users_invite_code;
|
|
||||||
DROP INDEX IF EXISTS idx_users_parent_id;
|
|
||||||
ALTER TABLE users DROP COLUMN IF EXISTS invite_code;
|
|
||||||
ALTER TABLE users DROP COLUMN IF EXISTS parent_id;
|
|
||||||
|
|
||||||
ALTER TABLE merchants ADD COLUMN IF NOT EXISTS features TEXT NOT NULL DEFAULT 'products,orders,wallet,api,callbacks';
|
|
||||||
ALTER TABLE merchants ADD COLUMN IF NOT EXISTS fee_rate_bp BIGINT NOT NULL DEFAULT 0;
|
|
||||||
ALTER TABLE merchants ADD COLUMN IF NOT EXISTS fee_fixed_amount BIGINT NOT NULL DEFAULT 0;
|
|
||||||
|
|
||||||
ALTER TABLE skins DROP COLUMN IF EXISTS commission;
|
|
||||||
|
|
||||||
DROP INDEX IF EXISTS idx_orders_distributor_id;
|
|
||||||
ALTER TABLE orders DROP COLUMN IF EXISTS distributor_id;
|
|
||||||
ALTER TABLE orders DROP COLUMN IF EXISTS commission_amt;
|
|
||||||
|
|
||||||
ALTER TABLE fulfillment_orders ADD COLUMN IF NOT EXISTS base_amount BIGINT NOT NULL DEFAULT 0;
|
|
||||||
ALTER TABLE fulfillment_orders ADD COLUMN IF NOT EXISTS fee_rate_bp BIGINT NOT NULL DEFAULT 0;
|
|
||||||
ALTER TABLE fulfillment_orders ADD COLUMN IF NOT EXISTS fee_fixed_amount BIGINT NOT NULL DEFAULT 0;
|
|
||||||
ALTER TABLE fulfillment_orders ADD COLUMN IF NOT EXISTS service_fee_amount BIGINT NOT NULL DEFAULT 0;
|
|
||||||
UPDATE fulfillment_orders SET base_amount = amount WHERE base_amount = 0;
|
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
-- 手续费改为"百分比或固定"二选一:新增 fee_type 列。
|
|
||||||
ALTER TABLE merchants ADD COLUMN IF NOT EXISTS fee_type VARCHAR(16) NOT NULL DEFAULT 'rate';
|
|
||||||
ALTER TABLE fulfillment_orders ADD COLUMN IF NOT EXISTS fee_type VARCHAR(16) NOT NULL DEFAULT 'rate';
|
|
||||||
|
|
||||||
-- 清理旧演示链路遗留表:skins / orders / ship_logs。
|
|
||||||
-- 这些表属于旧的"皮肤源头"演示模型,已被商户履约模型(merchant_products / fulfillment_orders)取代。
|
|
||||||
DROP TABLE IF EXISTS ship_logs;
|
|
||||||
DROP TABLE IF EXISTS orders;
|
|
||||||
DROP TABLE IF EXISTS skins;
|
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
-- 全平台统一使用积分(POINT)作为结算货币,不再使用人民币(CNY)。
|
|
||||||
ALTER TABLE merchant_products ALTER COLUMN currency SET DEFAULT 'POINT';
|
|
||||||
ALTER TABLE wallet_accounts ALTER COLUMN currency SET DEFAULT 'POINT';
|
|
||||||
ALTER TABLE fulfillment_orders ALTER COLUMN currency SET DEFAULT 'POINT';
|
|
||||||
UPDATE merchant_products SET currency = 'POINT' WHERE currency = 'CNY';
|
|
||||||
UPDATE wallet_accounts SET currency = 'POINT' WHERE currency = 'CNY';
|
|
||||||
UPDATE fulfillment_orders SET currency = 'POINT' WHERE currency = 'CNY';
|
|
||||||
@@ -1,81 +0,0 @@
|
|||||||
-- 默认商品目录种子数据:为自营商户预置和平精英商品,成本单位为积分。
|
|
||||||
-- cost_amount = 消耗积分;price_amount = 价钱(元) * 10 = 售价积分。
|
|
||||||
|
|
||||||
-- 1. 插入平台商品目录(幂等)
|
|
||||||
INSERT INTO products (code, name, category, status)
|
|
||||||
SELECT v.code, v.name, v.category, 'active'
|
|
||||||
FROM (VALUES
|
|
||||||
('suit_alan_walker', '套装-Alan Walker', '套装'),
|
|
||||||
('suit_shadow_gothic', '套装-暗影哥特', '套装'),
|
|
||||||
('top_black_elite_trainer','黑色高级特训官上衣', '上衣'),
|
|
||||||
('m416_hamster_gray', 'M416-仓鼠灰灰', '枪械'),
|
|
||||||
('bag_cute_bear', '萌熊伴侣背包', '背包'),
|
|
||||||
('suit_dual_fluffy', '套装-双彩绵绵', '套装'),
|
|
||||||
('suit_pink_sheep', '套装-糯粉咩咩', '套装'),
|
|
||||||
('suit_first_peach', '套装-恋恋初桃', '套装'),
|
|
||||||
('suit_romantic_destiny', '套装-浪漫天命', '套装'),
|
|
||||||
('pack_western_cowboy', '西部牛仔大礼包', '礼包'),
|
|
||||||
('smoke_pink_sheep', '烟雾弹-糯粉咩咩', '投掷物'),
|
|
||||||
('frag_pink_sheep', '破片手榴弹-糯粉咩咩', '投掷物'),
|
|
||||||
('suit_hamster_gray', '套装-仓鼠灰灰', '套装'),
|
|
||||||
('suit_cute_bear', '套装-萌熊伴侣', '套装'),
|
|
||||||
('bag_pink_sheep', '糯粉咩咩背包', '背包'),
|
|
||||||
('helmet_pink_sheep', '糯粉咩咩头盔', '头盔'),
|
|
||||||
('bag_hamster_gray', '仓鼠灰灰背包', '背包'),
|
|
||||||
('helmet_hamster_gray', '仓鼠灰灰头盔', '头盔'),
|
|
||||||
('suit_western_mystery', '套装-西部谜踪', '套装'),
|
|
||||||
('helmet_panda_treasure', '国宝胖达头盔', '头盔'),
|
|
||||||
('suit_panda_round', '套装-胖达圆圆', '套装'),
|
|
||||||
('suit_panda_tuan', '套装-胖达团团', '套装'),
|
|
||||||
('pack_lava_ranger', '熔岩游骑兵礼包', '礼包'),
|
|
||||||
('suit_sand_dancer', '套装-狂沙舞者', '套装'),
|
|
||||||
('pack_star_roam_outfit', '星际漫游服装礼包', '礼包'),
|
|
||||||
('pack_star_roam_weapon', '星际漫游枪械礼包', '礼包'),
|
|
||||||
('suit_cloud_bear', '套装-绵云熊熊', '套装')
|
|
||||||
) AS v(code, name, category)
|
|
||||||
ON CONFLICT (code) DO NOTHING;
|
|
||||||
|
|
||||||
-- 2. 为自营商户创建可售商品(幂等,按 merchant_id + sku 唯一索引)
|
|
||||||
INSERT INTO merchant_products (merchant_id, product_id, sku, display_name, price_amount, cost_amount, currency, stock, status)
|
|
||||||
SELECT
|
|
||||||
m.id,
|
|
||||||
p.id,
|
|
||||||
p.code,
|
|
||||||
p.name,
|
|
||||||
v.price_amount,
|
|
||||||
v.cost_amount,
|
|
||||||
'POINT',
|
|
||||||
-1,
|
|
||||||
'active'
|
|
||||||
FROM (VALUES
|
|
||||||
('suit_alan_walker', 360, 360),
|
|
||||||
('suit_shadow_gothic', 888, 888),
|
|
||||||
('top_black_elite_trainer',360, 360),
|
|
||||||
('m416_hamster_gray', 1680, 1680),
|
|
||||||
('bag_cute_bear', 2880, 2880),
|
|
||||||
('suit_dual_fluffy', 1124, 1124),
|
|
||||||
('suit_pink_sheep', 1880, 1880),
|
|
||||||
('suit_first_peach', 988, 988),
|
|
||||||
('suit_romantic_destiny', 360, 360),
|
|
||||||
('pack_western_cowboy', 3200, 3200),
|
|
||||||
('smoke_pink_sheep', 488, 488),
|
|
||||||
('frag_pink_sheep', 488, 488),
|
|
||||||
('suit_hamster_gray', 1280, 1280),
|
|
||||||
('suit_cute_bear', 1680, 1680),
|
|
||||||
('bag_pink_sheep', 1680, 1680),
|
|
||||||
('helmet_pink_sheep', 1680, 1680),
|
|
||||||
('bag_hamster_gray', 1680, 1680),
|
|
||||||
('helmet_hamster_gray', 1680, 1680),
|
|
||||||
('suit_western_mystery', 1150, 1150),
|
|
||||||
('helmet_panda_treasure', 2340, 2340),
|
|
||||||
('suit_panda_round', 2340, 2340),
|
|
||||||
('suit_panda_tuan', 2340, 2340),
|
|
||||||
('pack_lava_ranger', 960, 960),
|
|
||||||
('suit_sand_dancer', 840, 840),
|
|
||||||
('pack_star_roam_outfit', 8360, 8360),
|
|
||||||
('pack_star_roam_weapon', 5160, 5160),
|
|
||||||
('suit_cloud_bear', 1348, 1348)
|
|
||||||
) AS v(sku, price_amount, cost_amount)
|
|
||||||
JOIN products p ON p.code = v.sku
|
|
||||||
JOIN merchants m ON m.code = 'self-operated'
|
|
||||||
ON CONFLICT (merchant_id, sku) DO NOTHING;
|
|
||||||
Reference in New Issue
Block a user