Files
hfb_sys/backend/internal/modules/distribution/site_crud_test.go
T
yml2213 1c3a75eef0 feat(distribution): 分销站点管理支持完整 CRUD、安全删除保护与管理员密码重置
- 后端支持分销站点编辑(域名唯一性校验、收号压价点位及税率更新)
- 后端支持分销站点安全删除校验(阻断存在业务订单、财务流水、结算批次或钱包余额的站点删除;对干净站点连带清理分成规则、展示账号绑定、支付通道配置及专有站长账号)
- 后端支持站长账号展示与超级管理员重置站长密码
- 主管理后台与分销后台前端全面支持筛选搜索、编辑模态窗、状态快捷切换、站长密码重置与安全删除确认
- 补充后端 CRUD、删除保护与密码重置覆盖率测试用例
2026-09-17 19:35:52 +08:00

159 lines
4.6 KiB
Go

package distribution
import (
"testing"
"hfb_sys/backend/internal/model"
"golang.org/x/crypto/bcrypt"
)
func TestSiteCRUD_UpdateSiteAndDomainUniqueness(t *testing.T) {
db := distributionTestDB(t)
repo := NewRepository(db)
ctx := t.Context()
_, err := repo.CreateSite(ctx, CreateSiteRequest{
SiteCode: "site_crud_a",
SiteName: "站点A",
Domain: "a.domain.test",
})
if err != nil {
t.Fatalf("CreateSite A failed: %v", err)
}
siteB, err := repo.CreateSite(ctx, CreateSiteRequest{
SiteCode: "site_crud_b",
SiteName: "站点B",
Domain: "b.domain.test",
})
if err != nil {
t.Fatalf("CreateSite B failed: %v", err)
}
// 1. 尝试将站点B的域名更新为已存在的站点A域名 -> 应该报错
dupDomain := "a.domain.test"
_, err = repo.UpdateSite(ctx, 0, siteB.ID, UpdateSiteRequest{
Domain: &dupDomain,
})
if err == nil {
t.Fatalf("expected error when updating to duplicate domain, got nil")
}
// 2. 正常更新站点B的名称、域名、状态为 disabled、展示主站账号为 false
newName := "站点B更新后"
newDomain := "b-new.domain.test"
newStatus := "disabled"
dispFalse := false
updated, err := repo.UpdateSite(ctx, 0, siteB.ID, UpdateSiteRequest{
SiteName: &newName,
Domain: &newDomain,
Status: &newStatus,
DisplayAccountEnabled: &dispFalse,
})
if err != nil {
t.Fatalf("UpdateSite failed: %v", err)
}
if updated.SiteName != newName || updated.Domain != newDomain || updated.Status != "disabled" || updated.DisplayAccountEnabled != false {
t.Fatalf("updated site values mismatch: %+v", updated)
}
}
func TestSiteCRUD_DeleteSiteProtectionAndCascade(t *testing.T) {
db := distributionTestDB(t)
repo := NewRepository(db)
ctx := t.Context()
// 1. 使用 OnboardSite 创建一个完整的测试分销站(包含成员与管理员)
onboardResp, err := repo.OnboardSite(ctx, OnboardSiteRequest{
SiteCode: "del_test_site",
SiteName: "待删除测试分销站",
Domain: "del.domain.test",
AdminUsername: "del_test_admin",
AdminPassword: "password123",
})
if err != nil {
t.Fatalf("OnboardSite failed: %v", err)
}
siteID := onboardResp.Site.ID
adminUserID := onboardResp.Member.AdminID
// 2. 测试密码重置
newPwd := "new_secret_pwd_666"
if err := repo.ResetSiteAdminPassword(ctx, 0, siteID, newPwd); err != nil {
t.Fatalf("ResetSiteAdminPassword failed: %v", err)
}
// 校验密码是否成功重置
var adminUser model.AdminUser
if err := db.First(&adminUser, adminUserID).Error; err != nil {
t.Fatalf("failed to find admin user: %v", err)
}
if err := bcrypt.CompareHashAndPassword([]byte(adminUser.PasswordHash), []byte(newPwd)); err != nil {
t.Fatalf("password hash does not match new password: %v", err)
}
// 3. 验证 ListSites 与 FindSite 能够正确携带管理员信息
sites, err := repo.ListSites(ctx)
if err != nil {
t.Fatalf("ListSites failed: %v", err)
}
var foundSite *SiteDTO
for i := range sites {
if sites[i].ID == siteID {
foundSite = &sites[i]
break
}
}
if foundSite == nil {
t.Fatalf("site not found in ListSites")
}
if foundSite.AdminUsername != "del_test_admin" {
t.Fatalf("expected admin_username del_test_admin, got %s", foundSite.AdminUsername)
}
// 4. 测试有订单时的删除保护
// 创建一笔模拟关联订单
dummyOrder := model.RentalOrder{
OrderNo: "ORD_DEL_TEST_001",
RenterID: 999,
AccountID: 888,
DistributionSiteID: &siteID,
}
if err := db.Create(&dummyOrder).Error; err != nil {
t.Fatalf("failed to create dummy order: %v", err)
}
err = repo.DeleteSite(ctx, 0, siteID)
if err == nil {
t.Fatalf("expected error when deleting site with orders, got nil")
}
// 删除此测试订单,继续测试级联删除
if err := db.Delete(&dummyOrder).Error; err != nil {
t.Fatalf("failed to remove dummy order: %v", err)
}
// 5. 测试无订单时的干净级联删除
if err := repo.DeleteSite(ctx, 0, siteID); err != nil {
t.Fatalf("DeleteSite failed: %v", err)
}
// 校验站点主体已删除
var checkSite model.DistributionSite
if err := db.First(&checkSite, siteID).Error; err == nil {
t.Fatalf("site should be deleted from db")
}
// 校验专属管理员用户已同步清理
var checkAdmin model.AdminUser
if err := db.First(&checkAdmin, adminUserID).Error; err == nil {
t.Fatalf("dedicated admin user should be deleted from db")
}
// 校验规则已清理
var ruleCount int64
db.Model(&model.DistributionRuleVersion{}).Where("site_id = ?", siteID).Count(&ruleCount)
if ruleCount > 0 {
t.Fatalf("expected 0 rules for deleted site, got %d", ruleCount)
}
}