169 lines
9.2 KiB
Go
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("清空目标后首页应隐藏目标卡")
|
|
}
|
|
}
|