Files
hfb_sys/backend/internal/modules/pointsmall/repository_test.go
T

109 lines
3.6 KiB
Go

package pointsmall
import (
"errors"
"testing"
"hfb_sys/backend/internal/database"
"hfb_sys/backend/internal/model"
)
func TestRedeemDeductsAvailablePointsAndStock(t *testing.T) {
db := database.NewTestDB()
user := model.User{Phone: "13900009601", PointsAvailable: 500}
if err := db.Create(&user).Error; err != nil {
t.Fatalf("create user failed: %v", err)
}
product := model.PointsMallProduct{
Title: "测试兑换码",
Description: "测试商品",
RedemptionInstructions: "联系客服领取",
PointsPrice: 100,
Stock: 2,
PerUserLimit: 2,
Status: "online",
}
if err := db.Create(&product).Error; err != nil {
t.Fatalf("create product failed: %v", err)
}
repo := NewRepository(db)
req := RedeemRequest{
Quantity: 2,
ContactName: "张三",
ContactPhone: "13800138000",
CustomerRemark: "请发送到邮箱",
}
invalidReq := req
invalidReq.ContactPhone = "123"
if _, err := repo.Redeem(t.Context(), user.ID, product.ID, invalidReq); !errors.Is(err, ErrInvalidInput) {
t.Fatalf("invalid contact phone error = %v, want ErrInvalidInput", err)
}
redemption, err := repo.Redeem(t.Context(), user.ID, product.ID, req)
if err != nil {
t.Fatalf("redeem failed: %v", err)
}
if redemption.TotalPoints != 200 {
t.Fatalf("total points = %d, want 200", redemption.TotalPoints)
}
if redemption.ContactName != req.ContactName ||
redemption.ContactPhone != req.ContactPhone ||
redemption.CustomerRemark != req.CustomerRemark {
t.Fatalf("redemption contact = %+v, want %+v", redemption, req)
}
var savedUser model.User
if err := db.First(&savedUser, user.ID).Error; err != nil {
t.Fatalf("find user failed: %v", err)
}
if savedUser.PointsAvailable != 300 || savedUser.RenterGrowthPoints != 0 {
t.Fatalf("points after redeem = available %d lifetime %d", savedUser.PointsAvailable, savedUser.RenterGrowthPoints)
}
var savedProduct model.PointsMallProduct
if err := db.First(&savedProduct, product.ID).Error; err != nil {
t.Fatalf("find product failed: %v", err)
}
if savedProduct.Stock != 0 || savedProduct.RedeemedCount != 2 {
t.Fatalf("product stock/redeemed = %d/%d", savedProduct.Stock, savedProduct.RedeemedCount)
}
req.Quantity = 1
if _, err := repo.Redeem(t.Context(), user.ID, product.ID, req); !errors.Is(err, ErrRedeemLimitExceeded) && !errors.Is(err, ErrProductUnavailable) {
t.Fatalf("repeat redeem error = %v, want limit or unavailable", err)
}
completed, err := repo.CompleteRedemption(t.Context(), 99, redemption.ID, "已发放")
if err != nil {
t.Fatalf("complete redemption failed: %v", err)
}
if completed.Status != "completed" {
t.Fatalf("redemption status = %s, want completed", completed.Status)
}
}
func TestSummaryIncludesGrowthLevelRules(t *testing.T) {
db := database.NewTestDB()
user := model.User{
Phone: "13900009602",
RenterGrowthPoints: 1000,
PointsAvailable: 432,
}
if err := db.Create(&user).Error; err != nil {
t.Fatalf("create user failed: %v", err)
}
summary, err := NewRepository(db).Summary(t.Context(), user.ID)
if err != nil {
t.Fatalf("summary failed: %v", err)
}
if !summary.GrowthEnabled || len(summary.Levels) != 4 {
t.Fatalf("growth config = enabled %v levels %d", summary.GrowthEnabled, len(summary.Levels))
}
if summary.LevelCode != "diamond" || summary.PointsMultiplierBps != 15_000 {
t.Fatalf(
"current level = %s multiplier %d, want diamond/15000",
summary.LevelCode,
summary.PointsMultiplierBps,
)
}
if summary.Levels[2].DiscountBps != 9800 || summary.Levels[2].DepositFreeQuotaCent != 100_000 {
t.Fatalf("diamond rules = %+v", summary.Levels[2])
}
}