feat: 实现门店套餐分配功能并统一测试基础设施
All checks were successful
构建并部署到测试环境(无 SSH) / build-and-deploy (push) Successful in 5m30s
All checks were successful
构建并部署到测试环境(无 SSH) / build-and-deploy (push) Successful in 5m30s
新增功能: - 门店套餐分配管理(shop_package_allocation):支持门店套餐库存管理 - 门店套餐系列分配管理(shop_series_allocation):支持套餐系列分配和佣金层级设置 - 我的套餐查询(my_package):支持门店查询自己的套餐分配情况 测试改进: - 统一集成测试基础设施,新增 testutils.NewIntegrationTestEnv - 重构所有集成测试使用新的测试环境设置 - 移除旧的测试辅助函数和冗余测试文件 - 新增 test_helpers_test.go 统一任务测试辅助 技术细节: - 新增数据库迁移 000025_create_shop_allocation_tables - 新增 3 个 Handler、Service、Store 和对应的单元测试 - 更新 OpenAPI 文档和文档生成器 - 测试覆盖率:Service 层 > 90% Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
253
tests/integration/my_package_test.go
Normal file
253
tests/integration/my_package_test.go
Normal file
@@ -0,0 +1,253 @@
|
||||
package integration
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/break/junhong_cmp_fiber/internal/model"
|
||||
"github.com/break/junhong_cmp_fiber/pkg/constants"
|
||||
"github.com/break/junhong_cmp_fiber/pkg/response"
|
||||
"github.com/break/junhong_cmp_fiber/tests/testutils/integ"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestMyPackageAPI_ListMyPackages(t *testing.T) {
|
||||
env := integ.NewIntegrationTestEnv(t)
|
||||
|
||||
parentShop := env.CreateTestShop("一级店铺", 1, nil)
|
||||
childShop := env.CreateTestShop("二级店铺", 2, &parentShop.ID)
|
||||
agentAccount := env.CreateTestAccount("agent_my_pkg", "password123", constants.UserTypeAgent, &childShop.ID, nil)
|
||||
|
||||
series := createTestPackageSeriesForMyPkg(t, env, "测试系列")
|
||||
pkg := createTestPackageForMyPkg(t, env, series.ID, "测试套餐")
|
||||
|
||||
createTestAllocationForMyPkg(t, env, parentShop.ID, series.ID, 0)
|
||||
createTestAllocationForMyPkg(t, env, childShop.ID, series.ID, parentShop.ID)
|
||||
|
||||
t.Run("代理查看可售套餐列表", func(t *testing.T) {
|
||||
resp, err := env.AsUser(agentAccount).Request("GET", "/api/admin/my-packages?page=1&page_size=20", nil)
|
||||
require.NoError(t, err)
|
||||
defer resp.Body.Close()
|
||||
|
||||
assert.Equal(t, 200, resp.StatusCode)
|
||||
|
||||
var result response.Response
|
||||
err = json.NewDecoder(resp.Body).Decode(&result)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, 0, result.Code, "应返回成功: %s", result.Message)
|
||||
|
||||
t.Logf("ListMyPackages response: %+v", result.Data)
|
||||
})
|
||||
|
||||
t.Run("按系列ID筛选", func(t *testing.T) {
|
||||
url := fmt.Sprintf("/api/admin/my-packages?series_id=%d", series.ID)
|
||||
resp, err := env.AsUser(agentAccount).Request("GET", url, nil)
|
||||
require.NoError(t, err)
|
||||
defer resp.Body.Close()
|
||||
|
||||
var result response.Response
|
||||
err = json.NewDecoder(resp.Body).Decode(&result)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, 0, result.Code)
|
||||
})
|
||||
|
||||
t.Run("按套餐类型筛选", func(t *testing.T) {
|
||||
resp, err := env.AsUser(agentAccount).Request("GET", "/api/admin/my-packages?package_type=formal", nil)
|
||||
require.NoError(t, err)
|
||||
defer resp.Body.Close()
|
||||
|
||||
var result response.Response
|
||||
err = json.NewDecoder(resp.Body).Decode(&result)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, 0, result.Code)
|
||||
})
|
||||
|
||||
_ = pkg
|
||||
}
|
||||
|
||||
func TestMyPackageAPI_GetMyPackage(t *testing.T) {
|
||||
env := integ.NewIntegrationTestEnv(t)
|
||||
|
||||
parentShop := env.CreateTestShop("一级店铺", 1, nil)
|
||||
childShop := env.CreateTestShop("二级店铺", 2, &parentShop.ID)
|
||||
agentAccount := env.CreateTestAccount("agent_get_pkg", "password123", constants.UserTypeAgent, &childShop.ID, nil)
|
||||
|
||||
series := createTestPackageSeriesForMyPkg(t, env, "测试系列")
|
||||
pkg := createTestPackageForMyPkg(t, env, series.ID, "测试套餐")
|
||||
|
||||
createTestAllocationForMyPkg(t, env, parentShop.ID, series.ID, 0)
|
||||
createTestAllocationForMyPkg(t, env, childShop.ID, series.ID, parentShop.ID)
|
||||
|
||||
t.Run("获取可售套餐详情", func(t *testing.T) {
|
||||
url := fmt.Sprintf("/api/admin/my-packages/%d", pkg.ID)
|
||||
resp, err := env.AsUser(agentAccount).Request("GET", url, nil)
|
||||
require.NoError(t, err)
|
||||
defer resp.Body.Close()
|
||||
|
||||
assert.Equal(t, 200, resp.StatusCode)
|
||||
|
||||
var result response.Response
|
||||
err = json.NewDecoder(resp.Body).Decode(&result)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, 0, result.Code, "应返回成功: %s", result.Message)
|
||||
|
||||
if result.Data != nil {
|
||||
dataMap := result.Data.(map[string]interface{})
|
||||
assert.Equal(t, float64(pkg.ID), dataMap["id"])
|
||||
t.Logf("套餐详情: %+v", dataMap)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("获取不存在的套餐", func(t *testing.T) {
|
||||
resp, err := env.AsUser(agentAccount).Request("GET", "/api/admin/my-packages/999999", nil)
|
||||
require.NoError(t, err)
|
||||
defer resp.Body.Close()
|
||||
|
||||
var result response.Response
|
||||
err = json.NewDecoder(resp.Body).Decode(&result)
|
||||
require.NoError(t, err)
|
||||
assert.NotEqual(t, 0, result.Code, "应返回错误码")
|
||||
})
|
||||
}
|
||||
|
||||
func TestMyPackageAPI_ListMySeriesAllocations(t *testing.T) {
|
||||
env := integ.NewIntegrationTestEnv(t)
|
||||
|
||||
parentShop := env.CreateTestShop("一级店铺", 1, nil)
|
||||
childShop := env.CreateTestShop("二级店铺", 2, &parentShop.ID)
|
||||
agentAccount := env.CreateTestAccount("agent_series_alloc", "password123", constants.UserTypeAgent, &childShop.ID, nil)
|
||||
|
||||
series1 := createTestPackageSeriesForMyPkg(t, env, "系列1")
|
||||
series2 := createTestPackageSeriesForMyPkg(t, env, "系列2")
|
||||
|
||||
createTestAllocationForMyPkg(t, env, parentShop.ID, series1.ID, 0)
|
||||
createTestAllocationForMyPkg(t, env, childShop.ID, series1.ID, parentShop.ID)
|
||||
createTestAllocationForMyPkg(t, env, parentShop.ID, series2.ID, 0)
|
||||
createTestAllocationForMyPkg(t, env, childShop.ID, series2.ID, parentShop.ID)
|
||||
|
||||
t.Run("获取被分配的系列列表", func(t *testing.T) {
|
||||
resp, err := env.AsUser(agentAccount).Request("GET", "/api/admin/my-series-allocations?page=1&page_size=20", nil)
|
||||
require.NoError(t, err)
|
||||
defer resp.Body.Close()
|
||||
|
||||
assert.Equal(t, 200, resp.StatusCode)
|
||||
|
||||
var result response.Response
|
||||
err = json.NewDecoder(resp.Body).Decode(&result)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, 0, result.Code, "应返回成功: %s", result.Message)
|
||||
|
||||
t.Logf("ListMySeriesAllocations response: %+v", result.Data)
|
||||
})
|
||||
|
||||
t.Run("分页参数生效", func(t *testing.T) {
|
||||
resp, err := env.AsUser(agentAccount).Request("GET", "/api/admin/my-series-allocations?page=1&page_size=1", nil)
|
||||
require.NoError(t, err)
|
||||
defer resp.Body.Close()
|
||||
|
||||
var result response.Response
|
||||
err = json.NewDecoder(resp.Body).Decode(&result)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, 0, result.Code)
|
||||
})
|
||||
}
|
||||
|
||||
func TestMyPackageAPI_Auth(t *testing.T) {
|
||||
env := integ.NewIntegrationTestEnv(t)
|
||||
|
||||
t.Run("未认证请求应返回错误", func(t *testing.T) {
|
||||
resp, err := env.ClearAuth().Request("GET", "/api/admin/my-packages", nil)
|
||||
require.NoError(t, err)
|
||||
defer resp.Body.Close()
|
||||
|
||||
var result response.Response
|
||||
err = json.NewDecoder(resp.Body).Decode(&result)
|
||||
require.NoError(t, err)
|
||||
assert.NotEqual(t, 0, result.Code, "未认证请求应返回错误码")
|
||||
})
|
||||
|
||||
t.Run("未认证访问系列分配列表", func(t *testing.T) {
|
||||
resp, err := env.ClearAuth().Request("GET", "/api/admin/my-series-allocations", nil)
|
||||
require.NoError(t, err)
|
||||
defer resp.Body.Close()
|
||||
|
||||
var result response.Response
|
||||
err = json.NewDecoder(resp.Body).Decode(&result)
|
||||
require.NoError(t, err)
|
||||
assert.NotEqual(t, 0, result.Code, "未认证请求应返回错误码")
|
||||
})
|
||||
}
|
||||
|
||||
func createTestPackageSeriesForMyPkg(t *testing.T, env *integ.IntegrationTestEnv, name string) *model.PackageSeries {
|
||||
t.Helper()
|
||||
|
||||
timestamp := time.Now().UnixNano()
|
||||
series := &model.PackageSeries{
|
||||
SeriesCode: fmt.Sprintf("SERIES_MY_%d", timestamp),
|
||||
SeriesName: name,
|
||||
Status: constants.StatusEnabled,
|
||||
BaseModel: model.BaseModel{
|
||||
Creator: 1,
|
||||
Updater: 1,
|
||||
},
|
||||
}
|
||||
|
||||
err := env.TX.Create(series).Error
|
||||
require.NoError(t, err, "创建测试套餐系列失败")
|
||||
|
||||
return series
|
||||
}
|
||||
|
||||
func createTestPackageForMyPkg(t *testing.T, env *integ.IntegrationTestEnv, seriesID uint, name string) *model.Package {
|
||||
t.Helper()
|
||||
|
||||
timestamp := time.Now().UnixNano()
|
||||
pkg := &model.Package{
|
||||
PackageCode: fmt.Sprintf("PKG_%d", timestamp),
|
||||
PackageName: name,
|
||||
SeriesID: seriesID,
|
||||
PackageType: "formal",
|
||||
DurationMonths: 1,
|
||||
DataType: "real",
|
||||
RealDataMB: 1024,
|
||||
DataAmountMB: 1024,
|
||||
Price: 9900,
|
||||
SuggestedRetailPrice: 12800,
|
||||
Status: constants.StatusEnabled,
|
||||
ShelfStatus: 1,
|
||||
BaseModel: model.BaseModel{
|
||||
Creator: 1,
|
||||
Updater: 1,
|
||||
},
|
||||
}
|
||||
|
||||
err := env.TX.Create(pkg).Error
|
||||
require.NoError(t, err, "创建测试套餐失败")
|
||||
|
||||
return pkg
|
||||
}
|
||||
|
||||
func createTestAllocationForMyPkg(t *testing.T, env *integ.IntegrationTestEnv, shopID, seriesID, allocatorShopID uint) *model.ShopSeriesAllocation {
|
||||
t.Helper()
|
||||
|
||||
allocation := &model.ShopSeriesAllocation{
|
||||
ShopID: shopID,
|
||||
SeriesID: seriesID,
|
||||
AllocatorShopID: allocatorShopID,
|
||||
PricingMode: model.PricingModeFixed,
|
||||
PricingValue: 500,
|
||||
Status: constants.StatusEnabled,
|
||||
BaseModel: model.BaseModel{
|
||||
Creator: 1,
|
||||
Updater: 1,
|
||||
},
|
||||
}
|
||||
|
||||
err := env.TX.Create(allocation).Error
|
||||
require.NoError(t, err, "创建测试分配失败")
|
||||
|
||||
return allocation
|
||||
}
|
||||
Reference in New Issue
Block a user