package qualityowner import ( "errors" "testing" "hfb_sys/backend/internal/database" "hfb_sys/backend/internal/model" ) func TestActivateAndAdminDisableRefundDeposit(t *testing.T) { db := database.NewTestDB() user := model.User{ Phone: "13900009301", RealnameStatus: "verified", Status: "active", } if err := db.Create(&user).Error; err != nil { t.Fatalf("创建用户失败: %v", err) } account := model.WalletAccount{ UserID: user.ID, AvailableBalanceCent: 30_000, Status: "active", } if err := db.Create(&account).Error; err != nil { t.Fatalf("创建钱包失败: %v", err) } repo := NewRepository(db) status, err := repo.Activate(t.Context(), user.ID) if err != nil { t.Fatalf("开通优质号主失败: %v", err) } if !status.Active || status.DepositAmountCent != 20_000 || status.DepositSource != DepositSourcePaid { t.Fatalf("开通后的状态不正确: %+v", status) } if status.AvailableBalanceCent != 10_000 { t.Fatalf("可用余额 = %d, want 10000", status.AvailableBalanceCent) } if err := db.First(&account, account.ID).Error; err != nil { t.Fatalf("读取钱包失败: %v", err) } if account.FrozenBalanceCent != 20_000 { t.Fatalf("冻结余额 = %d, want 20000", account.FrozenBalanceCent) } status, err = repo.AdminSet(t.Context(), 99, user.ID, AdminSetRequest{ Enabled: false, Reason: "用户申请取消优质号主", }, AuditMeta{RequestID: "quality-owner-disable"}) if err != nil { t.Fatalf("取消优质号主失败: %v", err) } if status.Active || status.DepositAmountCent != 0 { t.Fatalf("取消后的状态不正确: %+v", status) } if status.AvailableBalanceCent != 30_000 { t.Fatalf("退款后可用余额 = %d, want 30000", status.AvailableBalanceCent) } if err := db.First(&account, account.ID).Error; err != nil { t.Fatalf("读取退款后钱包失败: %v", err) } if account.FrozenBalanceCent != 0 { t.Fatalf("退款后冻结余额 = %d, want 0", account.FrozenBalanceCent) } var ledgerCount int64 if err := db.Model(&model.WalletLedger{}).Where("user_id = ?", user.ID).Count(&ledgerCount).Error; err != nil { t.Fatalf("统计钱包流水失败: %v", err) } if ledgerCount != 4 { t.Fatalf("钱包流水条数 = %d, want 4", ledgerCount) } var auditCount int64 if err := db.Model(&model.AuditLog{}). Where("action = ? AND biz_id = ?", "admin_user.set_quality_owner", user.ID). Count(&auditCount).Error; err != nil { t.Fatalf("统计审计日志失败: %v", err) } if auditCount != 1 { t.Fatalf("后台设置审计日志条数 = %d, want 1", auditCount) } } func TestAdminCanGrantQualityOwnerWithoutWalletDeposit(t *testing.T) { db := database.NewTestDB() user := model.User{ Phone: "13900009302", RealnameStatus: "verified", Status: "active", } if err := db.Create(&user).Error; err != nil { t.Fatalf("创建用户失败: %v", err) } repo := NewRepository(db) status, err := repo.AdminSet(t.Context(), 99, user.ID, AdminSetRequest{ Enabled: true, Reason: "客服核验后手动开通", }, AuditMeta{RequestID: "quality-owner-enable"}) if err != nil { t.Fatalf("后台开通优质号主失败: %v", err) } if !status.Active || status.DepositSource != DepositSourceManual || status.DepositAmountCent != 20_000 { t.Fatalf("后台开通状态不正确: %+v", status) } var ledgerCount int64 if err := db.Model(&model.WalletLedger{}).Where("user_id = ?", user.ID).Count(&ledgerCount).Error; err != nil { t.Fatalf("统计钱包流水失败: %v", err) } if ledgerCount != 0 { t.Fatalf("后台手动开通不应产生钱包流水,实际 %d 条", ledgerCount) } } func TestCancelQualityOwnerRequiresNoActivePremiumListings(t *testing.T) { db := database.NewTestDB() user := model.User{ Phone: "13900009303", RealnameStatus: "verified", Status: "active", } if err := db.Create(&user).Error; err != nil { t.Fatalf("创建用户失败: %v", err) } account := model.WalletAccount{ UserID: user.ID, AvailableBalanceCent: 30_000, Status: "active", } if err := db.Create(&account).Error; err != nil { t.Fatalf("创建钱包失败: %v", err) } repo := NewRepository(db) if _, err := repo.Activate(t.Context(), user.ID); err != nil { t.Fatalf("开通优质号主失败: %v", err) } premiumListing := model.RentalListing{ ListingNo: "QO-CANCEL-ACTIVE", AccountID: 1, OwnerID: user.ID, Status: "published", ReviewStatus: "approved", IsPremium: true, } if err := db.Create(&premiumListing).Error; err != nil { t.Fatalf("创建极品专区商品失败: %v", err) } status, err := repo.Status(t.Context(), user.ID) if err != nil { t.Fatalf("读取优质号主状态失败: %v", err) } if status.ActivePremiumListings != 1 || status.CanCancel { t.Fatalf("进行中极品商品统计不正确: %+v", status) } if _, err := repo.Cancel(t.Context(), user.ID, AuditMeta{}); !errors.Is(err, ErrActivePremiumListings) { t.Fatalf("用户取消 error = %v, want ErrActivePremiumListings", err) } if _, err := repo.AdminSet(t.Context(), 99, user.ID, AdminSetRequest{ Enabled: false, Reason: "后台尝试取消", }, AuditMeta{}); !errors.Is(err, ErrActivePremiumListings) { t.Fatalf("后台取消 error = %v, want ErrActivePremiumListings", err) } if err := db.Model(&premiumListing).Updates(map[string]any{ "status": "offline", "review_status": "none", }).Error; err != nil { t.Fatalf("下架极品商品失败: %v", err) } draftListing := model.RentalListing{ ListingNo: "QO-CANCEL-DRAFT", AccountID: 2, OwnerID: user.ID, Status: "draft", ReviewStatus: "none", IsPremium: true, } if err := db.Create(&draftListing).Error; err != nil { t.Fatalf("创建极品专区草稿失败: %v", err) } status, err = repo.Cancel(t.Context(), user.ID, AuditMeta{RequestID: "quality-owner-self-cancel"}) if err != nil { t.Fatalf("自动取消优质号主失败: %v", err) } if status.Active || status.DepositAmountCent != 0 || status.AvailableBalanceCent != 30_000 { t.Fatalf("取消后的状态不正确: %+v", status) } var gotDraft model.RentalListing if err := db.First(&gotDraft, draftListing.ID).Error; err != nil { t.Fatalf("读取草稿失败: %v", err) } if gotDraft.Status != "offline" { t.Fatalf("取消后草稿状态 = %s, want offline", gotDraft.Status) } var auditCount int64 if err := db.Model(&model.AuditLog{}). Where("action = ? AND biz_id = ?", "quality_owner.cancel", user.ID). Count(&auditCount).Error; err != nil { t.Fatalf("统计自动取消审计日志失败: %v", err) } if auditCount != 1 { t.Fatalf("自动取消审计日志条数 = %d, want 1", auditCount) } }