Files
kra-new/cmd/business_management_http_test.go
T

169 lines
9.2 KiB
Go

package main
import (
"encoding/json"
"fmt"
"net/http/httptest"
"path/filepath"
"strconv"
"strings"
"testing"
"time"
"github.com/gin-gonic/gin"
"github.com/glebarez/sqlite"
"gorm.io/gorm"
biz "kra/internal/biz/business"
"kra/internal/biz/system"
data "kra/internal/data/business"
systemdata "kra/internal/data/system"
"kra/internal/server/handler"
"kra/internal/server/router"
service "kra/internal/service/business"
)
func TestBusinessManagementHTTPGroupsGoalsAndEffectivenessAgree(t *testing.T) {
db, err := gorm.Open(sqlite.Open(filepath.Join(t.TempDir(), "management.db")), &gorm.Config{})
if err != nil {
t.Fatal(err)
}
pool, _ := db.DB()
t.Cleanup(func() { _ = pool.Close() })
for _, step := range append(systemdata.Migrations(), data.Migrations()...) {
if err := step.Migrate(db); err != nil {
t.Fatal(err)
}
}
for _, sql := range []string{
"INSERT INTO sys_users(id,uuid,username,nick_name,level,parent_id,id_path,enable) VALUES(1,'root','root','root',0,0,'0',1),(7,'owner','owner','甲组织',1,0,'0',1),(8,'branch','branch','甲分部',2,7,'0,7',1),(9,'worker','worker','甲成员',3,8,'0,7,8',1),(10,'other','other','外部组织',1,0,'0',1)",
"INSERT INTO sys_user_bind_platform(user_id,source_db,platform_busier_id,platform_busier_account,status) VALUES(9,'lx',14,'sdk','0'),(10,'hw',20,'outside','0')",
"CREATE TABLE tab_promote(id INTEGER,source_db TEXT,account TEXT,nickname TEXT,parent_name TEXT,real_name TEXT,promote_level INTEGER,register_type INTEGER,status INTEGER,lock_status INTEGER,parent_id INTEGER,top_promote_id INTEGER,busier_id INTEGER,create_time INTEGER,last_login_time INTEGER)",
"CREATE TABLE tab_spend(id INTEGER,source_db TEXT,user_id INTEGER,promote_id INTEGER,pay_amount DECIMAL(20,2),pay_time INTEGER,pay_status INTEGER)",
"CREATE TABLE tab_user(id INTEGER,source_db TEXT,promote_id INTEGER,puid INTEGER,idcard TEXT)",
"CREATE TABLE tab_promote_apply(source_db TEXT,promote_id INTEGER,game_id INTEGER,status INTEGER)",
"CREATE TABLE tab_sw_report_day(source_db TEXT,promote_id INTEGER,game_id INTEGER,game_name TEXT,dedup_mode INTEGER,stat_date DATE,total_pay DECIMAL(20,2))",
"CREATE TABLE tab_sw_report_day_key(source_db TEXT,promote_id INTEGER,game_id INTEGER,game_name TEXT,dedup_mode INTEGER,stat_date DATE,metric INTEGER,identity_key TEXT)",
} {
if err := db.Exec(sql).Error; err != nil {
t.Fatal(err)
}
}
loc := time.FixedZone("Asia/Shanghai", 8*3600)
now := time.Now().In(loc)
month := time.Date(now.Year(), now.Month(), 1, 0, 0, 0, 0, loc)
previous := month.AddDate(0, 0, -1).Unix()
stamp := month.Unix() + 1
if err := db.Exec("INSERT INTO tab_promote VALUES(100,'lx','channel','渠道甲','','',1,0,1,0,0,0,14,?,?),(101,'hw','outside','渠道乙','','',1,0,1,0,0,0,20,?,?),(102,'lx','new','新渠道','','',1,0,1,0,0,0,14,?,?)", previous, stamp, stamp, stamp, stamp, stamp).Error; err != nil {
t.Fatal(err)
}
if err := db.Exec("INSERT INTO tab_spend VALUES(1,'lx',1,100,3500,?,1),(2,'hw',1,101,99999,?,1),(3,'lx',1,102,99999,?,0)", stamp, stamp, stamp).Error; err != nil {
t.Fatal(err)
}
if err := db.Exec("INSERT INTO tab_sw_report_day VALUES('lx',100,1,'game',0,?,3500),('hw',101,1,'game',0,?,99999)", month.Format("2006-01-02"), month.Format("2006-01-02")).Error; err != nil {
t.Fatal(err)
}
provider := businessHTTPData{db}
accounts := biz.NewAccountUsecase(data.NewAccountRepo(provider))
preferences := biz.NewUserPreferenceUsecase(data.NewUserPreferenceRepo(provider))
settings := data.NewOtherSettingsRepo(provider)
effective := biz.NewEffectivenessUsecase(data.NewEffectivenessRepo(provider), settings)
teams := biz.NewTeamUsecase(data.NewTeamRepo(provider), accounts)
goalRepo := data.NewGoalRepo(provider)
performance := biz.NewPerformanceUsecase(data.NewPerformanceRepo(provider), teams, effective, goalRepo)
goals := biz.NewGoalUsecase(goalRepo, performance)
dashboard := biz.NewDashboardUsecase(data.NewDashboardRepo(provider), biz.NewWorkbenchUsecase(data.NewWorkbenchRepo(provider), accounts, preferences), effective)
engine := gin.New()
engine.Use(func(c *gin.Context) {
id, _ := strconv.ParseUint(c.GetHeader("X-Test-User"), 10, 64)
role := uint(901)
if id == 1 {
role = 888
} else if id == 8 {
role = 902
} else if id == 9 {
role = 903
}
c.Request = c.Request.WithContext(system.NewActorContext(c.Request.Context(), system.Actor{UserID: uint(id), AuthorityID: role}))
c.Next()
})
router.RegisterBusinessPerformance(engine.Group(""), handler.NewBusinessPerformance(service.NewBusinessPerformanceService(teams, performance, goals, dashboard)))
router.RegisterOtherSettings(engine.Group(""), handler.NewOtherSettings(service.NewOtherSettingsService(biz.NewOtherSettingsUsecase(settings, effective))))
channels := biz.NewChannelUsecase(data.NewChannelRepo(provider), nil, accounts, preferences, nil, effective)
engine.GET("/sw/promote/list", handler.NewChannel(service.NewChannelService(channels)).List)
call := func(user int, method, path, body string, code int) map[string]any {
t.Helper()
req := httptest.NewRequest(method, path, strings.NewReader(body))
req.Header.Set("Content-Type", "application/json")
req.Header.Set("X-Test-User", strconv.Itoa(user))
rec := httptest.NewRecorder()
engine.ServeHTTP(rec, req)
var value map[string]any
if err := json.Unmarshal(rec.Body.Bytes(), &value); err != nil {
t.Fatalf("%s: %s", path, rec.Body.String())
}
if value["code"] != float64(code) {
t.Fatalf("%s: %+v", path, value)
}
result, _ := value["data"].(map[string]any)
return result
}
view := call(7, "GET", "/sw/groups", "", 0)
if len(view["members"].([]any)) != 3 {
t.Fatal("不得包含其他一级组织")
}
view = call(7, "PUT", "/sw/groups", `{"revision":0,"groups":[{"name":"甲组","memberIds":[8,9]}]}`, 0)
if len(view["groups"].([]any)) != 1 {
t.Fatal("小组保存失败")
}
call(8, "PUT", "/sw/groups", `{"revision":1,"groups":[]}`, 7)
call(7, "PUT", "/sw/goals", fmt.Sprintf(`{"kind":"person","targetId":9,"month":%q,"open":0,"effective":1,"amount":3000}`, month.Format("2006-01")), 0)
call(9, "PUT", "/sw/goals", fmt.Sprintf(`{"kind":"person","targetId":9,"month":%q,"open":100}`, month.Format("2006-01")), 7)
query := fmt.Sprintf("/sw/performance?year=%d&beginMonth=%d&endMonth=%d", now.Year(), now.Month(), now.Month())
stats := call(7, "GET", query, "", 0)
total := stats["total"].(map[string]any)
if total["open"] != float64(1) || total["effective"] != float64(1) || total["pay"] != "3500.00" {
t.Fatalf("权限范围/开端与达标月份/流水错误: %+v", total)
}
groupID := uint64(view["groups"].([]any)[0].(map[string]any)["id"].(float64))
details := call(7, "GET", fmt.Sprintf("/sw/performance/details?kind=team&targetId=%d&begin=%s&end=%s&metric=effective", groupID, month.Format("2006-01-02"), now.Format("2006-01-02")), "", 0)
if details["total"] != float64(2) || len(details["rows"].([]any)) != 2 {
t.Fatal("team contribution drilldown must agree with summed member performance")
}
details = call(7, "GET", fmt.Sprintf("/sw/performance/details?kind=group&targetId=%d&memberIds=9&begin=%s&end=%s&metric=effective", groupID, month.Format("2006-01-02"), now.Format("2006-01-02")), "", 0)
if details["total"] != float64(1) {
t.Fatal("filtered matrix subtotal must return unique channels")
}
filtered := call(7, "GET", query+"&groupId=999", "", 0)
if filtered["matrixTotal"].(map[string]any)["open"] != float64(0) || filtered["total"].(map[string]any)["open"] != float64(1) {
t.Fatal("matrix filter must not corrupt scope cards")
}
overview := call(7, "GET", fmt.Sprintf("/sw/workbench/overview?sourceDbList=lx&period=custom&begin=%s&end=%s", month.Format("2006-01-02"), now.Format("2006-01-02")), "", 0)
cards := overview["cards"].(map[string]any)
if len(cards) != 8 || cards["lockedPromote"].(map[string]any)["value"] != nil || cards["terminatedPromote"].(map[string]any)["compareLabel"] != "事件数据未接入" {
t.Fatal("event cards must be visible without fabricating historical counts")
}
mine := call(9, "GET", "/sw/goals/mine", "", 0)
if mine["actual"].(map[string]any)["pay"] != "3500.00" {
t.Fatal("首页目标必须与绩效同源")
}
listed := call(7, "GET", "/sw/promote/list?sourceDb=lx&effective=true", "", 0)
if listed["total"] != float64(1) || listed["rows"].([]any)[0].(map[string]any)["effective"] != true {
t.Fatal("渠道有效端筛选未接通")
}
call(7, "GET", fmt.Sprintf("/sw/performance/details?kind=person&targetId=10&begin=%s&end=%s&metric=effective", month.Format("2006-01-02"), now.Format("2006-01-02")), "", 7)
call(1, "PUT", "/sw/settings/effectiveness", `{"amount":4000,"days":30}`, 0)
stats = call(7, "GET", query, "", 0)
if stats["total"].(map[string]any)["effective"] != float64(0) {
t.Fatal("修改规则后绩效未重算")
}
listed = call(7, "GET", "/sw/promote/list?sourceDb=lx&effective=true", "", 0)
if listed["total"] != float64(0) {
t.Fatal("渠道列表仍然使用旧规则")
}
call(7, "PUT", "/sw/business/profile", `{"userId":9,"realName":"新负责人","phoneNumber":"13900000009","hireDate":"2025-01-02","employment":"probation"}`, 0)
call(7, "PUT", "/sw/goals", fmt.Sprintf(`{"kind":"person","targetId":9,"month":%q,"open":null,"effective":null,"amount":null}`, month.Format("2006-01")), 0)
if call(9, "GET", "/sw/goals/mine", "", 0) != nil {
t.Fatal("清空目标后首页应隐藏目标卡")
}
}