fix(backend): JWT config mapstructure tag 修复 + 模型从 hotel 重构为 shop
- 修复 JWTConfig 缺少 mapstructure tag 导致 access_expire_min 解析为 0, token 签发即过期,所有 API 请求返回 401 - 全部 config struct 补齐 mapstructure tag(secret/dsn/hmac_secret 等) - 模型层从 hotel/HotelID 统一重命名为 shop/ShopID - 删除旧 migrations(001-004),新增 001_init 综合迁移文件 - 更新 schema.sql、testutil、handler/service/model 相关引用 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
+43
-40
@@ -46,7 +46,7 @@ func SetupTestDB() *gorm.DB {
|
||||
|
||||
// SQLite 不支持 ENUM,直接用原始 SQL 建表
|
||||
stmts := []string{
|
||||
`CREATE TABLE IF NOT EXISTS hotels (
|
||||
`CREATE TABLE IF NOT EXISTS shops (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
created_at DATETIME,
|
||||
updated_at DATETIME,
|
||||
@@ -55,6 +55,9 @@ func SetupTestDB() *gorm.DB {
|
||||
code TEXT UNIQUE,
|
||||
address TEXT,
|
||||
phone TEXT,
|
||||
manager_name TEXT,
|
||||
business_license TEXT,
|
||||
shop_photos TEXT,
|
||||
custom_fields TEXT
|
||||
)`,
|
||||
`CREATE TABLE IF NOT EXISTS users (
|
||||
@@ -62,7 +65,7 @@ func SetupTestDB() *gorm.DB {
|
||||
created_at DATETIME,
|
||||
updated_at DATETIME,
|
||||
deleted_at DATETIME,
|
||||
hotel_id INTEGER NOT NULL,
|
||||
shop_id INTEGER NOT NULL,
|
||||
username TEXT,
|
||||
password_hash TEXT,
|
||||
real_name TEXT,
|
||||
@@ -71,13 +74,13 @@ func SetupTestDB() *gorm.DB {
|
||||
is_active INTEGER DEFAULT 1,
|
||||
custom_fields TEXT
|
||||
)`,
|
||||
`CREATE UNIQUE INDEX IF NOT EXISTS uk_hotel_username ON users(hotel_id, username)`,
|
||||
`CREATE UNIQUE INDEX IF NOT EXISTS uk_shop_username ON users(shop_id, username)`,
|
||||
`CREATE TABLE IF NOT EXISTS licenses (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
created_at DATETIME,
|
||||
updated_at DATETIME,
|
||||
deleted_at DATETIME,
|
||||
hotel_id INTEGER NOT NULL,
|
||||
shop_id INTEGER NOT NULL,
|
||||
license_key TEXT UNIQUE,
|
||||
device_id TEXT,
|
||||
type TEXT DEFAULT 'trial',
|
||||
@@ -91,7 +94,7 @@ func SetupTestDB() *gorm.DB {
|
||||
created_at DATETIME,
|
||||
updated_at DATETIME,
|
||||
deleted_at DATETIME,
|
||||
hotel_id INTEGER NOT NULL,
|
||||
shop_id INTEGER NOT NULL,
|
||||
name TEXT NOT NULL,
|
||||
parent_id INTEGER,
|
||||
sort_order INTEGER DEFAULT 0
|
||||
@@ -101,7 +104,7 @@ func SetupTestDB() *gorm.DB {
|
||||
created_at DATETIME,
|
||||
updated_at DATETIME,
|
||||
deleted_at DATETIME,
|
||||
hotel_id INTEGER NOT NULL,
|
||||
shop_id INTEGER NOT NULL,
|
||||
code TEXT,
|
||||
barcode TEXT,
|
||||
name TEXT NOT NULL,
|
||||
@@ -121,7 +124,7 @@ func SetupTestDB() *gorm.DB {
|
||||
created_at DATETIME,
|
||||
updated_at DATETIME,
|
||||
deleted_at DATETIME,
|
||||
hotel_id INTEGER NOT NULL,
|
||||
shop_id INTEGER NOT NULL,
|
||||
name TEXT NOT NULL,
|
||||
location TEXT,
|
||||
is_default INTEGER DEFAULT 0,
|
||||
@@ -132,7 +135,7 @@ func SetupTestDB() *gorm.DB {
|
||||
created_at DATETIME,
|
||||
updated_at DATETIME,
|
||||
deleted_at DATETIME,
|
||||
hotel_id INTEGER NOT NULL,
|
||||
shop_id INTEGER NOT NULL,
|
||||
code TEXT,
|
||||
name TEXT NOT NULL,
|
||||
type TEXT DEFAULT 'supplier',
|
||||
@@ -150,7 +153,7 @@ func SetupTestDB() *gorm.DB {
|
||||
created_at DATETIME,
|
||||
updated_at DATETIME,
|
||||
deleted_at DATETIME,
|
||||
hotel_id INTEGER NOT NULL,
|
||||
shop_id INTEGER NOT NULL,
|
||||
order_no TEXT,
|
||||
type TEXT DEFAULT 'purchase',
|
||||
warehouse_id INTEGER NOT NULL,
|
||||
@@ -164,14 +167,14 @@ func SetupTestDB() *gorm.DB {
|
||||
custom_fields TEXT,
|
||||
remark TEXT
|
||||
)`,
|
||||
`CREATE UNIQUE INDEX IF NOT EXISTS uk_hotel_sio_order_no ON stock_in_orders(hotel_id, order_no)`,
|
||||
`CREATE UNIQUE INDEX IF NOT EXISTS uk_shop_sio_order_no ON stock_in_orders(shop_id, order_no)`,
|
||||
`CREATE TABLE IF NOT EXISTS stock_in_items (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
created_at DATETIME,
|
||||
updated_at DATETIME,
|
||||
deleted_at DATETIME,
|
||||
order_id INTEGER NOT NULL,
|
||||
hotel_id INTEGER NOT NULL,
|
||||
shop_id INTEGER NOT NULL,
|
||||
product_id INTEGER NOT NULL,
|
||||
quantity REAL NOT NULL,
|
||||
unit_price REAL DEFAULT 0,
|
||||
@@ -185,7 +188,7 @@ func SetupTestDB() *gorm.DB {
|
||||
created_at DATETIME,
|
||||
updated_at DATETIME,
|
||||
deleted_at DATETIME,
|
||||
hotel_id INTEGER NOT NULL,
|
||||
shop_id INTEGER NOT NULL,
|
||||
order_no TEXT,
|
||||
type TEXT DEFAULT 'sale',
|
||||
warehouse_id INTEGER NOT NULL,
|
||||
@@ -199,14 +202,14 @@ func SetupTestDB() *gorm.DB {
|
||||
custom_fields TEXT,
|
||||
remark TEXT
|
||||
)`,
|
||||
`CREATE UNIQUE INDEX IF NOT EXISTS uk_hotel_soo_order_no ON stock_out_orders(hotel_id, order_no)`,
|
||||
`CREATE UNIQUE INDEX IF NOT EXISTS uk_shop_soo_order_no ON stock_out_orders(shop_id, order_no)`,
|
||||
`CREATE TABLE IF NOT EXISTS stock_out_items (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
created_at DATETIME,
|
||||
updated_at DATETIME,
|
||||
deleted_at DATETIME,
|
||||
order_id INTEGER NOT NULL,
|
||||
hotel_id INTEGER NOT NULL,
|
||||
shop_id INTEGER NOT NULL,
|
||||
product_id INTEGER NOT NULL,
|
||||
quantity REAL NOT NULL,
|
||||
unit_price REAL DEFAULT 0,
|
||||
@@ -216,16 +219,16 @@ func SetupTestDB() *gorm.DB {
|
||||
)`,
|
||||
`CREATE TABLE IF NOT EXISTS inventories (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
hotel_id INTEGER NOT NULL,
|
||||
shop_id INTEGER NOT NULL,
|
||||
warehouse_id INTEGER NOT NULL,
|
||||
product_id INTEGER NOT NULL,
|
||||
quantity REAL DEFAULT 0,
|
||||
updated_at DATETIME,
|
||||
UNIQUE(hotel_id, warehouse_id, product_id)
|
||||
UNIQUE(shop_id, warehouse_id, product_id)
|
||||
)`,
|
||||
`CREATE TABLE IF NOT EXISTS inventory_logs (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
hotel_id INTEGER NOT NULL,
|
||||
shop_id INTEGER NOT NULL,
|
||||
warehouse_id INTEGER NOT NULL,
|
||||
product_id INTEGER NOT NULL,
|
||||
direction TEXT,
|
||||
@@ -242,7 +245,7 @@ func SetupTestDB() *gorm.DB {
|
||||
created_at DATETIME,
|
||||
updated_at DATETIME,
|
||||
deleted_at DATETIME,
|
||||
hotel_id INTEGER NOT NULL,
|
||||
shop_id INTEGER NOT NULL,
|
||||
check_no TEXT,
|
||||
warehouse_id INTEGER NOT NULL,
|
||||
operator_id INTEGER NOT NULL,
|
||||
@@ -250,14 +253,14 @@ func SetupTestDB() *gorm.DB {
|
||||
check_date DATETIME,
|
||||
remark TEXT
|
||||
)`,
|
||||
`CREATE UNIQUE INDEX IF NOT EXISTS uk_hotel_check_no ON inventory_checks(hotel_id, check_no)`,
|
||||
`CREATE UNIQUE INDEX IF NOT EXISTS uk_shop_check_no ON inventory_checks(shop_id, check_no)`,
|
||||
`CREATE TABLE IF NOT EXISTS inventory_check_items (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
created_at DATETIME,
|
||||
updated_at DATETIME,
|
||||
deleted_at DATETIME,
|
||||
check_id INTEGER NOT NULL,
|
||||
hotel_id INTEGER NOT NULL,
|
||||
shop_id INTEGER NOT NULL,
|
||||
product_id INTEGER NOT NULL,
|
||||
system_qty REAL,
|
||||
actual_qty REAL,
|
||||
@@ -265,13 +268,13 @@ func SetupTestDB() *gorm.DB {
|
||||
)`,
|
||||
`CREATE TABLE IF NOT EXISTS number_rules (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
hotel_id INTEGER NOT NULL,
|
||||
shop_id INTEGER NOT NULL,
|
||||
type TEXT,
|
||||
prefix TEXT DEFAULT '',
|
||||
current_no INTEGER DEFAULT 0,
|
||||
date_format TEXT DEFAULT 'YYYYMMDD',
|
||||
updated_at DATETIME,
|
||||
UNIQUE(hotel_id, type)
|
||||
UNIQUE(shop_id, type)
|
||||
)`,
|
||||
}
|
||||
|
||||
@@ -284,16 +287,16 @@ func SetupTestDB() *gorm.DB {
|
||||
return db
|
||||
}
|
||||
|
||||
// CreateTestHotel 创建测试酒店
|
||||
func CreateTestHotel(db *gorm.DB, code string) *model.Hotel {
|
||||
hotel := &model.Hotel{
|
||||
Name: "Test Hotel " + code,
|
||||
// CreateTestShop 创建测试门店
|
||||
func CreateTestShop(db *gorm.DB, code string) *model.Shop {
|
||||
shop := &model.Shop{
|
||||
Name: "Test Shop " + code,
|
||||
Code: code,
|
||||
}
|
||||
if err := db.Create(hotel).Error; err != nil {
|
||||
panic(fmt.Sprintf("failed to create test hotel: %v", err))
|
||||
if err := db.Create(shop).Error; err != nil {
|
||||
panic(fmt.Sprintf("failed to create test shop: %v", err))
|
||||
}
|
||||
return hotel
|
||||
return shop
|
||||
}
|
||||
|
||||
// hashPassword 内部使用的密码哈希函数,避免循环依赖
|
||||
@@ -306,12 +309,12 @@ func hashPassword(plain string) string {
|
||||
}
|
||||
|
||||
// CreateTestUser 创建测试用户
|
||||
func CreateTestUser(db *gorm.DB, hotelID uint64, username, password, role string) *model.User {
|
||||
func CreateTestUser(db *gorm.DB, shopID uint64, username, password, role string) *model.User {
|
||||
hash := hashPassword(password)
|
||||
user := &model.User{
|
||||
TenantBase: model.TenantBase{
|
||||
Base: model.Base{},
|
||||
HotelID: hotelID,
|
||||
Base: model.Base{},
|
||||
ShopID: shopID,
|
||||
},
|
||||
Username: username,
|
||||
PasswordHash: hash,
|
||||
@@ -326,10 +329,10 @@ func CreateTestUser(db *gorm.DB, hotelID uint64, username, password, role string
|
||||
}
|
||||
|
||||
// CreateTestWarehouse 创建测试仓库
|
||||
func CreateTestWarehouse(db *gorm.DB, hotelID uint64, name string) *model.Warehouse {
|
||||
func CreateTestWarehouse(db *gorm.DB, shopID uint64, name string) *model.Warehouse {
|
||||
w := &model.Warehouse{
|
||||
TenantBase: model.TenantBase{
|
||||
HotelID: hotelID,
|
||||
ShopID: shopID,
|
||||
},
|
||||
Name: name,
|
||||
IsDefault: true,
|
||||
@@ -341,10 +344,10 @@ func CreateTestWarehouse(db *gorm.DB, hotelID uint64, name string) *model.Wareho
|
||||
}
|
||||
|
||||
// CreateTestProduct 创建测试商品
|
||||
func CreateTestProduct(db *gorm.DB, hotelID uint64, name string) *model.Product {
|
||||
func CreateTestProduct(db *gorm.DB, shopID uint64, name string) *model.Product {
|
||||
p := &model.Product{
|
||||
TenantBase: model.TenantBase{
|
||||
HotelID: hotelID,
|
||||
ShopID: shopID,
|
||||
},
|
||||
Name: name,
|
||||
Code: "P-" + name,
|
||||
@@ -357,13 +360,13 @@ func CreateTestProduct(db *gorm.DB, hotelID uint64, name string) *model.Product
|
||||
}
|
||||
|
||||
// GetAuthToken 生成测试 JWT token
|
||||
func GetAuthToken(userID, hotelID uint64, role string) string {
|
||||
func GetAuthToken(userID, shopID uint64, role string) string {
|
||||
InitConfig()
|
||||
now := time.Now()
|
||||
claims := middleware.Claims{
|
||||
UserID: userID,
|
||||
HotelID: hotelID,
|
||||
Role: role,
|
||||
UserID: userID,
|
||||
ShopID: shopID,
|
||||
Role: role,
|
||||
RegisteredClaims: jwt.RegisteredClaims{
|
||||
ExpiresAt: jwt.NewNumericDate(now.Add(time.Hour)),
|
||||
IssuedAt: jwt.NewNumericDate(now),
|
||||
|
||||
Reference in New Issue
Block a user