fix(invitation): 修复邀请关系手机号与邀请码筛选并预加载统计

This commit is contained in:
yml2213
2026-10-17 15:35:44 +08:00
parent e37684d401
commit e6c4f58251
5 changed files with 201 additions and 23 deletions
@@ -0,0 +1,151 @@
package invitation
import (
"context"
"testing"
"time"
"hfb_sys/backend/internal/model"
)
func TestListAdminInvitationsFiltersPhoneAndInviteCode(t *testing.T) {
db := setupTestDB(t)
repo := NewRepository(db)
ctx := context.Background()
now := time.Now()
users := []model.User{
{Phone: "13812345678", Nickname: "邀请人甲", Status: "active", RealnameStatus: "verified"},
{Phone: "13911112222", Nickname: "被邀请人甲", Status: "active", RealnameStatus: "verified"},
{Phone: "13700001111", Nickname: "邀请人乙", Status: "active", RealnameStatus: "verified"},
{Phone: "13622223333", Nickname: "被邀请人乙", Status: "active", RealnameStatus: "verified"},
}
for i := range users {
if err := db.Create(&users[i]).Error; err != nil {
t.Fatalf("创建测试用户失败: %v", err)
}
}
records := []model.UserInvitation{
{
InviterID: users[0].ID,
InviteeID: users[1].ID,
InviteCode: "alpha01",
Status: StatusActive,
CreatedAt: now,
},
{
InviterID: users[2].ID,
InviteeID: users[3].ID,
InviteCode: "beta02",
Status: StatusActive,
CreatedAt: now,
},
}
for i := range records {
if err := db.Create(&records[i]).Error; err != nil {
t.Fatalf("创建邀请关系失败: %v", err)
}
}
cases := []struct {
name string
query AdminInvitationQuery
want int64
}{
{name: "通用手机号匹配邀请人", query: AdminInvitationQuery{Phone: "1234"}, want: 1},
{name: "通用手机号匹配被邀请人", query: AdminInvitationQuery{Phone: "139111"}, want: 1},
{name: "邀请码模糊匹配", query: AdminInvitationQuery{InviteCode: "beta"}, want: 1},
{name: "邀请人手机号模糊匹配", query: AdminInvitationQuery{InviterPhone: "137"}, want: 1},
{name: "被邀请人手机号模糊匹配", query: AdminInvitationQuery{InviteePhone: "1362"}, want: 1},
}
for _, tc := range cases {
t.Run(tc.name, func(t *testing.T) {
tc.query.Page = 1
tc.query.PageSize = 20
_, total, err := repo.ListAdminInvitations(ctx, tc.query)
if err != nil {
t.Fatalf("查询邀请关系失败: %v", err)
}
if total != tc.want {
t.Fatalf("查询结果数量 = %d, want %d", total, tc.want)
}
})
}
}
func TestListAdminRebateLedgersFiltersPartialPhoneAndOrderNo(t *testing.T) {
db := setupTestDB(t)
repo := NewRepository(db)
ctx := context.Background()
now := time.Now()
users := []model.User{
{Phone: "13812345678", Nickname: "邀请人甲", Status: "active", RealnameStatus: "verified"},
{Phone: "13911112222", Nickname: "被邀请人甲", Status: "active", RealnameStatus: "verified"},
{Phone: "13700001111", Nickname: "邀请人乙", Status: "active", RealnameStatus: "verified"},
{Phone: "13622223333", Nickname: "被邀请人乙", Status: "active", RealnameStatus: "verified"},
}
for i := range users {
if err := db.Create(&users[i]).Error; err != nil {
t.Fatalf("创建测试用户失败: %v", err)
}
}
ledgers := []model.InvitationRebateLedger{
{
OrderID: 1001,
OrderNo: "ORDER-ALPHA-1001",
Source: "rental_order",
InviterID: users[0].ID,
InviteeID: users[1].ID,
TradeRole: "buyer",
RateApplied: 0.6,
CycleStage: CycleFirstMonth,
Status: "settled",
RebateAmountCent: 100,
SettledAt: now,
},
{
OrderID: 1002,
OrderNo: "ORDER-BETA-1002",
Source: "pickup",
InviterID: users[2].ID,
InviteeID: users[3].ID,
TradeRole: "seller",
RateApplied: 0.3,
CycleStage: CycleSecondMonth,
Status: "settled",
RebateAmountCent: 200,
SettledAt: now,
},
}
for i := range ledgers {
if err := db.Create(&ledgers[i]).Error; err != nil {
t.Fatalf("创建返利流水失败: %v", err)
}
}
cases := []struct {
name string
query AdminRebateLedgerQuery
want int64
}{
{name: "订单号模糊匹配", query: AdminRebateLedgerQuery{OrderNo: "ALPHA"}, want: 1},
{name: "邀请人手机号模糊匹配", query: AdminRebateLedgerQuery{InviterPhone: "1381"}, want: 1},
{name: "被邀请人手机号模糊匹配", query: AdminRebateLedgerQuery{InviteePhone: "1362"}, want: 1},
}
for _, tc := range cases {
t.Run(tc.name, func(t *testing.T) {
tc.query.Page = 1
tc.query.PageSize = 20
_, total, err := repo.ListAdminRebateLedgers(ctx, tc.query)
if err != nil {
t.Fatalf("查询返利流水失败: %v", err)
}
if total != tc.want {
t.Fatalf("查询结果数量 = %d, want %d", total, tc.want)
}
})
}
}
+5 -2
View File
@@ -76,8 +76,11 @@ type UpdateConfigRequest struct {
// AdminInvitationQuery 后台查询邀请关系
type AdminInvitationQuery struct {
Page int `form:"page,default=1"`
PageSize int `form:"page_size,default=20"`
Page int `form:"page,default=1"`
PageSize int `form:"page_size,default=20"`
// Phone 为通用手机号搜索:同时匹配邀请人/被邀请人,支持模糊查询。
Phone string `form:"phone"`
InviteCode string `form:"invite_code"`
InviterPhone string `form:"inviter_phone"`
InviteePhone string `form:"invitee_phone"`
Status string `form:"status"`
@@ -845,11 +845,18 @@ func (r *Repository) ListAdminInvitations(ctx context.Context, query AdminInvita
Joins("LEFT JOIN users inviter ON inviter.id = ui.inviter_id").
Joins("LEFT JOIN users invitee ON invitee.id = ui.invitee_id")
if p := strings.TrimSpace(query.Phone); p != "" {
like := "%" + p + "%"
db = db.Where("(inviter.phone LIKE ? OR invitee.phone LIKE ?)", like, like)
}
if p := strings.TrimSpace(query.InviterPhone); p != "" {
db = db.Where("inviter.phone = ?", p)
db = db.Where("inviter.phone LIKE ?", "%"+p+"%")
}
if p := strings.TrimSpace(query.InviteePhone); p != "" {
db = db.Where("invitee.phone = ?", p)
db = db.Where("invitee.phone LIKE ?", "%"+p+"%")
}
if code := strings.TrimSpace(query.InviteCode); code != "" {
db = db.Where("ui.invite_code LIKE ?", "%"+code+"%")
}
if s := strings.TrimSpace(query.Status); s != "" {
db = db.Where("ui.status = ?", s)
@@ -928,13 +935,13 @@ func (r *Repository) ListAdminRebateLedgers(ctx context.Context, query AdminReba
Joins("LEFT JOIN users invitee ON invitee.id = irl.invitee_id")
if o := strings.TrimSpace(query.OrderNo); o != "" {
db = db.Where("irl.order_no = ?", o)
db = db.Where("irl.order_no LIKE ?", "%"+o+"%")
}
if p := strings.TrimSpace(query.InviterPhone); p != "" {
db = db.Where("inviter.phone = ?", p)
db = db.Where("inviter.phone LIKE ?", "%"+p+"%")
}
if p := strings.TrimSpace(query.InviteePhone); p != "" {
db = db.Where("invitee.phone = ?", p)
db = db.Where("invitee.phone LIKE ?", "%"+p+"%")
}
if t := strings.TrimSpace(query.TradeRole); t != "" {
db = db.Where("irl.trade_role = ?", t)