chore: snapshot current aws standby and backup tooling work
This commit is contained in:
@@ -1,806 +0,0 @@
|
||||
package orderLogic
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/perfect-panel/server/internal/config"
|
||||
userLogic "github.com/perfect-panel/server/internal/logic/public/user"
|
||||
modelLog "github.com/perfect-panel/server/internal/model/log"
|
||||
"github.com/perfect-panel/server/internal/model/order"
|
||||
"github.com/perfect-panel/server/internal/model/user"
|
||||
"github.com/perfect-panel/server/internal/svc"
|
||||
"github.com/perfect-panel/server/internal/types"
|
||||
"github.com/perfect-panel/server/pkg/constant"
|
||||
"github.com/redis/go-redis/v9"
|
||||
"gorm.io/driver/mysql"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
// 普通用户 + 首单 → 双方赠N天
|
||||
func TestHandleCommission_GrantGiftDaysWhenCommissionDisabled_FirstOrder(t *testing.T) {
|
||||
logic, db, cleanup := setupInviteTestLogic(t, config.InviteConfig{
|
||||
ReferralPercentage: 0,
|
||||
OnlyFirstPurchase: false,
|
||||
GiftDays: 2,
|
||||
})
|
||||
defer cleanup()
|
||||
|
||||
referee := seedUser(t, db, 0, false)
|
||||
referer := seedUser(t, db, 0, false)
|
||||
referee.RefererId = referer.Id
|
||||
|
||||
baseExpire := time.Now().Add(72 * time.Hour).Truncate(time.Second)
|
||||
refereeSub := seedActiveSubscribe(t, db, referee.Id, baseExpire)
|
||||
refererSub := seedActiveSubscribe(t, db, referer.Id, baseExpire)
|
||||
|
||||
logic.handleCommission(context.Background(), referee, &order.Order{
|
||||
OrderNo: "ORD-GIFT-001",
|
||||
Type: OrderTypeSubscribe,
|
||||
IsNew: true, // 首单
|
||||
Amount: 100,
|
||||
FeeAmount: 0,
|
||||
CreatedAt: time.Now(),
|
||||
})
|
||||
|
||||
assertExpireIncreasedByDays(t, db, refereeSub.Id, baseExpire, 2)
|
||||
assertExpireIncreasedByDays(t, db, refererSub.Id, baseExpire, 2)
|
||||
|
||||
var giftCount int64
|
||||
if err := db.Model(&modelLog.SystemLog{}).Where("type = ?", modelLog.TypeGift.Uint8()).Count(&giftCount).Error; err != nil {
|
||||
t.Fatalf("count gift logs failed: %v", err)
|
||||
}
|
||||
if giftCount != 2 {
|
||||
t.Fatalf("expected 2 gift logs, got %d", giftCount)
|
||||
}
|
||||
}
|
||||
|
||||
// 普通用户 + 非首单 → 不赠送
|
||||
func TestHandleCommission_NoGiftDaysWhenCommissionDisabled_NotFirstOrder(t *testing.T) {
|
||||
logic, db, cleanup := setupInviteTestLogic(t, config.InviteConfig{
|
||||
ReferralPercentage: 0,
|
||||
OnlyFirstPurchase: false,
|
||||
GiftDays: 2,
|
||||
})
|
||||
defer cleanup()
|
||||
|
||||
referee := seedUser(t, db, 0, false)
|
||||
referer := seedUser(t, db, 0, false)
|
||||
referee.RefererId = referer.Id
|
||||
|
||||
baseExpire := time.Now().Add(72 * time.Hour).Truncate(time.Second)
|
||||
refereeSub := seedActiveSubscribe(t, db, referee.Id, baseExpire)
|
||||
refererSub := seedActiveSubscribe(t, db, referer.Id, baseExpire)
|
||||
|
||||
logic.handleCommission(context.Background(), referee, &order.Order{
|
||||
OrderNo: "ORD-GIFT-002",
|
||||
Type: OrderTypeSubscribe,
|
||||
IsNew: false, // 非首单
|
||||
Amount: 100,
|
||||
FeeAmount: 0,
|
||||
CreatedAt: time.Now(),
|
||||
})
|
||||
|
||||
// 到期时间不应延长
|
||||
assertExpireIncreasedByDays(t, db, refereeSub.Id, baseExpire, 0)
|
||||
assertExpireIncreasedByDays(t, db, refererSub.Id, baseExpire, 0)
|
||||
|
||||
var giftCount int64
|
||||
if err := db.Model(&modelLog.SystemLog{}).Where("type = ?", modelLog.TypeGift.Uint8()).Count(&giftCount).Error; err != nil {
|
||||
t.Fatalf("count gift logs failed: %v", err)
|
||||
}
|
||||
if giftCount != 0 {
|
||||
t.Fatalf("expected 0 gift logs for non-first order, got %d", giftCount)
|
||||
}
|
||||
}
|
||||
|
||||
// 渠道 + 首单 → 被邀请人赠N天 + 邀请人获佣金
|
||||
func TestHandleCommission_GiftDaysAndCommissionWhenChannelFirstOrder(t *testing.T) {
|
||||
logic, db, cleanup := setupInviteTestLogic(t, config.InviteConfig{
|
||||
ReferralPercentage: 10,
|
||||
OnlyFirstPurchase: false,
|
||||
GiftDays: 2,
|
||||
})
|
||||
defer cleanup()
|
||||
|
||||
referee := seedUser(t, db, 0, false)
|
||||
referer := seedUser(t, db, 0, false)
|
||||
referee.RefererId = referer.Id
|
||||
|
||||
baseExpire := time.Now().Add(96 * time.Hour).Truncate(time.Second)
|
||||
refereeSub := seedActiveSubscribe(t, db, referee.Id, baseExpire)
|
||||
|
||||
logic.handleCommission(context.Background(), referee, &order.Order{
|
||||
OrderNo: "ORD-COMM-001",
|
||||
Type: OrderTypeSubscribe,
|
||||
IsNew: true, // 首单
|
||||
Amount: 100,
|
||||
FeeAmount: 0,
|
||||
CreatedAt: time.Now(),
|
||||
})
|
||||
|
||||
// 被邀请人(首单)应获得赠送天数
|
||||
assertExpireIncreasedByDays(t, db, refereeSub.Id, baseExpire, 2)
|
||||
|
||||
// 邀请人应获得佣金
|
||||
var refererAfter user.User
|
||||
if err := db.First(&refererAfter, referer.Id).Error; err != nil {
|
||||
t.Fatalf("query referer failed: %v", err)
|
||||
}
|
||||
if refererAfter.Commission != 10 {
|
||||
t.Fatalf("expected referer commission=10, got %d", refererAfter.Commission)
|
||||
}
|
||||
|
||||
var giftCount int64
|
||||
if err := db.Model(&modelLog.SystemLog{}).Where("type = ?", modelLog.TypeGift.Uint8()).Count(&giftCount).Error; err != nil {
|
||||
t.Fatalf("count gift logs failed: %v", err)
|
||||
}
|
||||
if giftCount != 1 {
|
||||
t.Fatalf("expected 1 gift log for referee on first order with commission, got %d", giftCount)
|
||||
}
|
||||
}
|
||||
|
||||
// 渠道 + 非首单 → 只给邀请人佣金,不赠天
|
||||
func TestHandleCommission_OnlyCommissionWhenChannelNotFirstOrder(t *testing.T) {
|
||||
logic, db, cleanup := setupInviteTestLogic(t, config.InviteConfig{
|
||||
ReferralPercentage: 10,
|
||||
OnlyFirstPurchase: false,
|
||||
GiftDays: 2,
|
||||
})
|
||||
defer cleanup()
|
||||
|
||||
referee := seedUser(t, db, 0, false)
|
||||
referer := seedUser(t, db, 0, false)
|
||||
referee.RefererId = referer.Id
|
||||
|
||||
baseExpire := time.Now().Add(96 * time.Hour).Truncate(time.Second)
|
||||
refereeSub := seedActiveSubscribe(t, db, referee.Id, baseExpire)
|
||||
|
||||
logic.handleCommission(context.Background(), referee, &order.Order{
|
||||
OrderNo: "ORD-COMM-002",
|
||||
Type: OrderTypeSubscribe,
|
||||
IsNew: false, // 非首单
|
||||
Amount: 100,
|
||||
FeeAmount: 0,
|
||||
CreatedAt: time.Now(),
|
||||
})
|
||||
|
||||
// 被邀请人不应获得赠送天数
|
||||
assertExpireIncreasedByDays(t, db, refereeSub.Id, baseExpire, 0)
|
||||
|
||||
// 邀请人应获得佣金
|
||||
var refererAfter user.User
|
||||
if err := db.First(&refererAfter, referer.Id).Error; err != nil {
|
||||
t.Fatalf("query referer failed: %v", err)
|
||||
}
|
||||
if refererAfter.Commission != 10 {
|
||||
t.Fatalf("expected referer commission=10, got %d", refererAfter.Commission)
|
||||
}
|
||||
|
||||
var giftCount int64
|
||||
if err := db.Model(&modelLog.SystemLog{}).Where("type = ?", modelLog.TypeGift.Uint8()).Count(&giftCount).Error; err != nil {
|
||||
t.Fatalf("count gift logs failed: %v", err)
|
||||
}
|
||||
if giftCount != 0 {
|
||||
t.Fatalf("expected 0 gift logs when channel non-first order, got %d", giftCount)
|
||||
}
|
||||
}
|
||||
|
||||
func TestHandleCommission_NoGiftDaysWhenNoInviteRelation(t *testing.T) {
|
||||
logic, db, cleanup := setupInviteTestLogic(t, config.InviteConfig{
|
||||
ReferralPercentage: 0,
|
||||
OnlyFirstPurchase: false,
|
||||
GiftDays: 2,
|
||||
})
|
||||
defer cleanup()
|
||||
|
||||
// 没有邀请人的独立用户
|
||||
loneUser := seedUser(t, db, 0, false)
|
||||
// RefererId == 0,无邀请关系
|
||||
|
||||
baseExpire := time.Now().Add(72 * time.Hour).Truncate(time.Second)
|
||||
loneSub := seedActiveSubscribe(t, db, loneUser.Id, baseExpire)
|
||||
|
||||
logic.handleCommission(context.Background(), loneUser, &order.Order{
|
||||
OrderNo: "ORD-LONE-001",
|
||||
Type: OrderTypeSubscribe,
|
||||
IsNew: true,
|
||||
Amount: 100,
|
||||
FeeAmount: 0,
|
||||
CreatedAt: time.Now(),
|
||||
})
|
||||
|
||||
// 订阅到期时间不应该被延长
|
||||
var subAfter user.Subscribe
|
||||
if err := db.First(&subAfter, loneSub.Id).Error; err != nil {
|
||||
t.Fatalf("query subscribe failed: %v", err)
|
||||
}
|
||||
if !subAfter.ExpireTime.Equal(baseExpire) {
|
||||
t.Fatalf("expected no gift days for user without inviter, before=%v after=%v", baseExpire, subAfter.ExpireTime)
|
||||
}
|
||||
|
||||
// 不应产生赠天日志
|
||||
var giftCount int64
|
||||
if err := db.Model(&modelLog.SystemLog{}).Where("type = ?", modelLog.TypeGift.Uint8()).Count(&giftCount).Error; err != nil {
|
||||
t.Fatalf("count gift logs failed: %v", err)
|
||||
}
|
||||
if giftCount != 0 {
|
||||
t.Fatalf("expected 0 gift logs for user without inviter, got %d", giftCount)
|
||||
}
|
||||
}
|
||||
|
||||
// 先绑码后首单 → 双方赠N天
|
||||
func TestInviteFlow_BindThenFirstOrder_GrantGiftDays(t *testing.T) {
|
||||
logic, db, cleanup := setupInviteTestLogic(t, config.InviteConfig{
|
||||
ReferralPercentage: 0,
|
||||
OnlyFirstPurchase: false,
|
||||
GiftDays: 2,
|
||||
})
|
||||
defer cleanup()
|
||||
|
||||
referee := seedUser(t, db, 0, false)
|
||||
referer := seedUser(t, db, 0, false)
|
||||
referer.ReferCode = fmt.Sprintf("REF-%d", referer.Id)
|
||||
if err := db.Model(&user.User{}).Where("id = ?", referer.Id).Update("refer_code", referer.ReferCode).Error; err != nil {
|
||||
t.Fatalf("update referer code failed: %v", err)
|
||||
}
|
||||
|
||||
refereeBaseExpire := time.Now().Add(48 * time.Hour).Truncate(time.Second)
|
||||
refererBaseExpire := time.Now().Add(72 * time.Hour).Truncate(time.Second)
|
||||
refereeSub := seedActiveSubscribe(t, db, referee.Id, refereeBaseExpire)
|
||||
refererSub := seedActiveSubscribe(t, db, referer.Id, refererBaseExpire)
|
||||
|
||||
ctx := context.WithValue(context.Background(), constant.CtxKeyUser, referee)
|
||||
bindLogic := userLogic.NewBindInviteCodeLogic(ctx, logic.svc)
|
||||
if err := bindLogic.BindInviteCode(&types.BindInviteCodeRequest{InviteCode: referer.ReferCode}); err != nil {
|
||||
t.Fatalf("bind invite code failed: %v", err)
|
||||
}
|
||||
|
||||
var refereeAfterBind user.User
|
||||
if err := db.First(&refereeAfterBind, referee.Id).Error; err != nil {
|
||||
t.Fatalf("query referee after bind failed: %v", err)
|
||||
}
|
||||
if refereeAfterBind.RefererId != referer.Id {
|
||||
t.Fatalf("bind invite failed, expected referer_id=%d got=%d", referer.Id, refereeAfterBind.RefererId)
|
||||
}
|
||||
|
||||
// 首单 IsNew=true → 双方赠N天
|
||||
logic.handleCommission(context.Background(), &refereeAfterBind, &order.Order{
|
||||
OrderNo: "ORD-FLOW-001",
|
||||
Type: OrderTypeSubscribe,
|
||||
IsNew: true,
|
||||
Amount: 100,
|
||||
FeeAmount: 0,
|
||||
CreatedAt: time.Now(),
|
||||
})
|
||||
|
||||
assertExpireIncreasedByDays(t, db, refereeSub.Id, refereeBaseExpire, 2)
|
||||
assertExpireIncreasedByDays(t, db, refererSub.Id, refererBaseExpire, 2)
|
||||
}
|
||||
|
||||
// 先买订单后绑码再续费 → 不赠送(IsNew=false)
|
||||
func TestInviteFlow_OrderThenBind_NoGiftDays(t *testing.T) {
|
||||
logic, db, cleanup := setupInviteTestLogic(t, config.InviteConfig{
|
||||
ReferralPercentage: 0,
|
||||
OnlyFirstPurchase: false,
|
||||
GiftDays: 2,
|
||||
})
|
||||
defer cleanup()
|
||||
|
||||
referee := seedUser(t, db, 0, false)
|
||||
referer := seedUser(t, db, 0, false)
|
||||
referee.RefererId = referer.Id
|
||||
|
||||
baseExpire := time.Now().Add(72 * time.Hour).Truncate(time.Second)
|
||||
refereeSub := seedActiveSubscribe(t, db, referee.Id, baseExpire)
|
||||
refererSub := seedActiveSubscribe(t, db, referer.Id, baseExpire)
|
||||
|
||||
// 先前已有订单,IsNew=false(模拟先买订单后绑码的场景)
|
||||
logic.handleCommission(context.Background(), referee, &order.Order{
|
||||
OrderNo: "ORD-FLOW-002",
|
||||
Type: OrderTypeSubscribe,
|
||||
IsNew: false, // 已有历史订单
|
||||
Amount: 100,
|
||||
FeeAmount: 0,
|
||||
CreatedAt: time.Now(),
|
||||
})
|
||||
|
||||
assertExpireIncreasedByDays(t, db, refereeSub.Id, baseExpire, 0)
|
||||
assertExpireIncreasedByDays(t, db, refererSub.Id, baseExpire, 0)
|
||||
}
|
||||
|
||||
func TestHandleCommission_GiftDaysToRefereeFamilyOwnerWhenChannelFirstOrder(t *testing.T) {
|
||||
logic, db, cleanup := setupInviteTestLogic(t, config.InviteConfig{
|
||||
ReferralPercentage: 10,
|
||||
OnlyFirstPurchase: false,
|
||||
GiftDays: 2,
|
||||
})
|
||||
defer cleanup()
|
||||
|
||||
refereeOwner := seedUser(t, db, 0, false)
|
||||
referee := seedUser(t, db, 0, false)
|
||||
referer := seedUser(t, db, 0, false)
|
||||
seedFamily(t, db, refereeOwner.Id, referee.Id)
|
||||
referee.RefererId = referer.Id
|
||||
|
||||
ownerBaseExpire := time.Now().Add(96 * time.Hour).Truncate(time.Second)
|
||||
ownerSub := seedActiveSubscribe(t, db, refereeOwner.Id, ownerBaseExpire)
|
||||
|
||||
logic.handleCommission(context.Background(), referee, &order.Order{
|
||||
OrderNo: "ORD-FAMILY-REFEREE-001",
|
||||
Type: OrderTypeSubscribe,
|
||||
IsNew: true,
|
||||
Amount: 100,
|
||||
FeeAmount: 0,
|
||||
SubscriptionUserId: refereeOwner.Id,
|
||||
CreatedAt: time.Now(),
|
||||
})
|
||||
|
||||
assertExpireIncreasedByDays(t, db, ownerSub.Id, ownerBaseExpire, 2)
|
||||
assertUserCommission(t, db, referer.Id, 10)
|
||||
}
|
||||
|
||||
func TestHandleCommission_GiftDaysToRefererFamilyOwnerWhenCommissionDisabled(t *testing.T) {
|
||||
logic, db, cleanup := setupInviteTestLogic(t, config.InviteConfig{
|
||||
ReferralPercentage: 0,
|
||||
OnlyFirstPurchase: false,
|
||||
GiftDays: 2,
|
||||
})
|
||||
defer cleanup()
|
||||
|
||||
referee := seedUser(t, db, 0, false)
|
||||
refererOwner := seedUser(t, db, 0, false)
|
||||
referer := seedUser(t, db, 0, false)
|
||||
seedFamily(t, db, refererOwner.Id, referer.Id)
|
||||
referee.RefererId = referer.Id
|
||||
|
||||
refereeBaseExpire := time.Now().Add(72 * time.Hour).Truncate(time.Second)
|
||||
refererOwnerBaseExpire := time.Now().Add(96 * time.Hour).Truncate(time.Second)
|
||||
refereeSub := seedActiveSubscribe(t, db, referee.Id, refereeBaseExpire)
|
||||
refererOwnerSub := seedActiveSubscribe(t, db, refererOwner.Id, refererOwnerBaseExpire)
|
||||
|
||||
logic.handleCommission(context.Background(), referee, &order.Order{
|
||||
OrderNo: "ORD-FAMILY-REFERER-001",
|
||||
Type: OrderTypeSubscribe,
|
||||
IsNew: true,
|
||||
Amount: 100,
|
||||
FeeAmount: 0,
|
||||
CreatedAt: time.Now(),
|
||||
})
|
||||
|
||||
assertExpireIncreasedByDays(t, db, refereeSub.Id, refereeBaseExpire, 2)
|
||||
assertExpireIncreasedByDays(t, db, refererOwnerSub.Id, refererOwnerBaseExpire, 2)
|
||||
}
|
||||
|
||||
func TestHandleCommission_RefererFamilyMemberCommissionBehaviorUnchanged(t *testing.T) {
|
||||
logic, db, cleanup := setupInviteTestLogic(t, config.InviteConfig{
|
||||
ReferralPercentage: 10,
|
||||
OnlyFirstPurchase: false,
|
||||
GiftDays: 2,
|
||||
})
|
||||
defer cleanup()
|
||||
|
||||
referee := seedUser(t, db, 0, false)
|
||||
refererOwner := seedUser(t, db, 0, false)
|
||||
referer := seedUser(t, db, 0, false)
|
||||
seedFamily(t, db, refererOwner.Id, referer.Id)
|
||||
referee.RefererId = referer.Id
|
||||
|
||||
refereeBaseExpire := time.Now().Add(96 * time.Hour).Truncate(time.Second)
|
||||
refereeSub := seedActiveSubscribe(t, db, referee.Id, refereeBaseExpire)
|
||||
|
||||
logic.handleCommission(context.Background(), referee, &order.Order{
|
||||
OrderNo: "ORD-FAMILY-COMMISSION-001",
|
||||
Type: OrderTypeSubscribe,
|
||||
IsNew: true,
|
||||
Amount: 100,
|
||||
FeeAmount: 0,
|
||||
CreatedAt: time.Now(),
|
||||
})
|
||||
|
||||
assertExpireIncreasedByDays(t, db, refereeSub.Id, refereeBaseExpire, 2)
|
||||
assertUserCommission(t, db, referer.Id, 10)
|
||||
assertUserCommission(t, db, refererOwner.Id, 0)
|
||||
}
|
||||
|
||||
func TestHandleCommission_GiftDaysRecognizesUnlimitedSubscription(t *testing.T) {
|
||||
logic, db, cleanup := setupInviteTestLogic(t, config.InviteConfig{
|
||||
ReferralPercentage: 10,
|
||||
OnlyFirstPurchase: false,
|
||||
GiftDays: 2,
|
||||
})
|
||||
defer cleanup()
|
||||
|
||||
referee := seedUser(t, db, 0, false)
|
||||
referer := seedUser(t, db, 0, false)
|
||||
referee.RefererId = referer.Id
|
||||
|
||||
unlimitedExpire := time.UnixMilli(0)
|
||||
refereeSub := seedActiveSubscribe(t, db, referee.Id, unlimitedExpire)
|
||||
|
||||
logic.handleCommission(context.Background(), referee, &order.Order{
|
||||
OrderNo: "ORD-UNLIMITED-001",
|
||||
Type: OrderTypeSubscribe,
|
||||
IsNew: true,
|
||||
Amount: 100,
|
||||
FeeAmount: 0,
|
||||
CreatedAt: time.Now(),
|
||||
})
|
||||
|
||||
assertExpireIncreasedByDays(t, db, refereeSub.Id, unlimitedExpire, 0)
|
||||
var giftCount int64
|
||||
if err := db.Model(&modelLog.SystemLog{}).Where("type = ? AND object_id = ?", modelLog.TypeGift.Uint8(), referee.Id).Count(&giftCount).Error; err != nil {
|
||||
t.Fatalf("count gift logs failed: %v", err)
|
||||
}
|
||||
if giftCount != 1 {
|
||||
t.Fatalf("expected 1 gift log for unlimited subscription, got %d", giftCount)
|
||||
}
|
||||
}
|
||||
|
||||
func TestHandleCommission_IdempotentForRepeatedActivation(t *testing.T) {
|
||||
logic, db, cleanup := setupInviteTestLogic(t, config.InviteConfig{
|
||||
ReferralPercentage: 10,
|
||||
OnlyFirstPurchase: false,
|
||||
GiftDays: 2,
|
||||
})
|
||||
defer cleanup()
|
||||
|
||||
referee := seedUser(t, db, 0, false)
|
||||
referer := seedUser(t, db, 0, false)
|
||||
referee.RefererId = referer.Id
|
||||
|
||||
baseExpire := time.Now().Add(96 * time.Hour).Truncate(time.Second)
|
||||
refereeSub := seedActiveSubscribe(t, db, referee.Id, baseExpire)
|
||||
orderInfo := &order.Order{
|
||||
OrderNo: "ORD-IDEMPOTENT-001",
|
||||
Type: OrderTypeSubscribe,
|
||||
IsNew: true,
|
||||
Amount: 100,
|
||||
FeeAmount: 0,
|
||||
CreatedAt: time.Now(),
|
||||
}
|
||||
|
||||
logic.handleCommission(context.Background(), referee, orderInfo)
|
||||
logic.handleCommission(context.Background(), referee, orderInfo)
|
||||
|
||||
assertExpireIncreasedByDays(t, db, refereeSub.Id, baseExpire, 2)
|
||||
assertUserCommission(t, db, referer.Id, 10)
|
||||
assertLogCountForOrder(t, db, modelLog.TypeCommission.Uint8(), orderInfo.OrderNo, 1)
|
||||
assertLogCountForOrder(t, db, modelLog.TypeGift.Uint8(), orderInfo.OrderNo, 1)
|
||||
}
|
||||
|
||||
func TestHandleCommission_NoActiveSubscriptionWritesSkippedGiftLog(t *testing.T) {
|
||||
logic, db, cleanup := setupInviteTestLogic(t, config.InviteConfig{
|
||||
ReferralPercentage: 10,
|
||||
OnlyFirstPurchase: false,
|
||||
GiftDays: 2,
|
||||
})
|
||||
defer cleanup()
|
||||
|
||||
referee := seedUser(t, db, 0, false)
|
||||
referer := seedUser(t, db, 0, false)
|
||||
referee.RefererId = referer.Id
|
||||
orderInfo := &order.Order{
|
||||
OrderNo: "ORD-SKIPPED-001",
|
||||
Type: OrderTypeSubscribe,
|
||||
IsNew: true,
|
||||
Amount: 100,
|
||||
FeeAmount: 0,
|
||||
CreatedAt: time.Now(),
|
||||
}
|
||||
|
||||
logic.handleCommission(context.Background(), referee, orderInfo)
|
||||
|
||||
assertUserCommission(t, db, referer.Id, 10)
|
||||
assertLogCountForOrder(t, db, modelLog.TypeCommission.Uint8(), orderInfo.OrderNo, 1)
|
||||
assertLogCountForOrder(t, db, modelLog.TypeGift.Uint8(), orderInfo.OrderNo, 1)
|
||||
assertGiftLogRemarkContains(t, db, orderInfo.OrderNo, "skipped: no active subscription")
|
||||
}
|
||||
|
||||
func TestHandleCommission_GiftDaysZeroDoesNotWriteGiftLog(t *testing.T) {
|
||||
logic, db, cleanup := setupInviteTestLogic(t, config.InviteConfig{
|
||||
ReferralPercentage: 10,
|
||||
OnlyFirstPurchase: false,
|
||||
GiftDays: 0,
|
||||
})
|
||||
defer cleanup()
|
||||
|
||||
referee := seedUser(t, db, 0, false)
|
||||
referer := seedUser(t, db, 0, false)
|
||||
referee.RefererId = referer.Id
|
||||
baseExpire := time.Now().Add(96 * time.Hour).Truncate(time.Second)
|
||||
refereeSub := seedActiveSubscribe(t, db, referee.Id, baseExpire)
|
||||
orderInfo := &order.Order{
|
||||
OrderNo: "ORD-GIFT-ZERO-001",
|
||||
Type: OrderTypeSubscribe,
|
||||
IsNew: true,
|
||||
Amount: 100,
|
||||
FeeAmount: 0,
|
||||
CreatedAt: time.Now(),
|
||||
}
|
||||
|
||||
logic.handleCommission(context.Background(), referee, orderInfo)
|
||||
|
||||
assertExpireIncreasedByDays(t, db, refereeSub.Id, baseExpire, 0)
|
||||
assertUserCommission(t, db, referer.Id, 10)
|
||||
assertLogCountForOrder(t, db, modelLog.TypeCommission.Uint8(), orderInfo.OrderNo, 1)
|
||||
assertLogCountForOrder(t, db, modelLog.TypeGift.Uint8(), orderInfo.OrderNo, 0)
|
||||
}
|
||||
|
||||
func TestHandleCommission_GlobalOnlyFirstPurchaseBlocksCommissionAndGiftForNonFirstOrder(t *testing.T) {
|
||||
logic, db, cleanup := setupInviteTestLogic(t, config.InviteConfig{
|
||||
ReferralPercentage: 10,
|
||||
OnlyFirstPurchase: true,
|
||||
GiftDays: 2,
|
||||
})
|
||||
defer cleanup()
|
||||
|
||||
referee := seedUser(t, db, 0, false)
|
||||
referer := seedUser(t, db, 0, false)
|
||||
referee.RefererId = referer.Id
|
||||
baseExpire := time.Now().Add(96 * time.Hour).Truncate(time.Second)
|
||||
refereeSub := seedActiveSubscribe(t, db, referee.Id, baseExpire)
|
||||
orderInfo := &order.Order{
|
||||
OrderNo: "ORD-NONFIRST-GLOBAL-001",
|
||||
Type: OrderTypeRenewal,
|
||||
IsNew: false,
|
||||
Amount: 100,
|
||||
FeeAmount: 0,
|
||||
CreatedAt: time.Now(),
|
||||
}
|
||||
|
||||
logic.handleCommission(context.Background(), referee, orderInfo)
|
||||
|
||||
assertExpireIncreasedByDays(t, db, refereeSub.Id, baseExpire, 0)
|
||||
assertUserCommission(t, db, referer.Id, 0)
|
||||
assertLogCountForOrder(t, db, modelLog.TypeCommission.Uint8(), orderInfo.OrderNo, 0)
|
||||
assertLogCountForOrder(t, db, modelLog.TypeGift.Uint8(), orderInfo.OrderNo, 0)
|
||||
}
|
||||
|
||||
func TestHandleCommission_BothFamilySidesUseCorrectGiftOwners(t *testing.T) {
|
||||
logic, db, cleanup := setupInviteTestLogic(t, config.InviteConfig{
|
||||
ReferralPercentage: 0,
|
||||
OnlyFirstPurchase: false,
|
||||
GiftDays: 2,
|
||||
})
|
||||
defer cleanup()
|
||||
|
||||
refereeOwner := seedUser(t, db, 0, false)
|
||||
referee := seedUser(t, db, 0, false)
|
||||
refererOwner := seedUser(t, db, 0, false)
|
||||
referer := seedUser(t, db, 0, false)
|
||||
seedFamily(t, db, refereeOwner.Id, referee.Id)
|
||||
seedFamily(t, db, refererOwner.Id, referer.Id)
|
||||
referee.RefererId = referer.Id
|
||||
|
||||
refereeOwnerBaseExpire := time.Now().Add(72 * time.Hour).Truncate(time.Second)
|
||||
refererOwnerBaseExpire := time.Now().Add(96 * time.Hour).Truncate(time.Second)
|
||||
refereeOwnerSub := seedActiveSubscribe(t, db, refereeOwner.Id, refereeOwnerBaseExpire)
|
||||
refererOwnerSub := seedActiveSubscribe(t, db, refererOwner.Id, refererOwnerBaseExpire)
|
||||
orderInfo := &order.Order{
|
||||
OrderNo: "ORD-BOTH-FAMILIES-001",
|
||||
Type: OrderTypeSubscribe,
|
||||
IsNew: true,
|
||||
Amount: 100,
|
||||
FeeAmount: 0,
|
||||
SubscriptionUserId: refereeOwner.Id,
|
||||
CreatedAt: time.Now(),
|
||||
}
|
||||
|
||||
logic.handleCommission(context.Background(), referee, orderInfo)
|
||||
|
||||
assertExpireIncreasedByDays(t, db, refereeOwnerSub.Id, refereeOwnerBaseExpire, 2)
|
||||
assertExpireIncreasedByDays(t, db, refererOwnerSub.Id, refererOwnerBaseExpire, 2)
|
||||
assertNoSubscribeForUser(t, db, referee.Id)
|
||||
assertNoSubscribeForUser(t, db, referer.Id)
|
||||
assertLogCountForOrder(t, db, modelLog.TypeGift.Uint8(), orderInfo.OrderNo, 2)
|
||||
}
|
||||
|
||||
func setupInviteTestLogic(t *testing.T, inviteCfg config.InviteConfig) (*ActivateOrderLogic, *gorm.DB, func()) {
|
||||
t.Helper()
|
||||
|
||||
mysqlAddr := getenvDefault("TEST_MYSQL_ADDR", "127.0.0.1:3306")
|
||||
mysqlUser := getenvDefault("TEST_MYSQL_USER", "root")
|
||||
mysqlPassword := getenvDefault("TEST_MYSQL_PASSWORD", "rootpassword")
|
||||
|
||||
adminDSN := fmt.Sprintf("%s:%s@tcp(%s)/?charset=utf8mb4&parseTime=true&loc=Local&multiStatements=true", mysqlUser, mysqlPassword, mysqlAddr)
|
||||
adminDB, err := gorm.Open(mysql.Open(adminDSN), &gorm.Config{})
|
||||
if err != nil {
|
||||
t.Fatalf("open mysql admin connection failed: %v", err)
|
||||
}
|
||||
|
||||
dbName := fmt.Sprintf("ppanel_test_invite_%d", time.Now().UnixNano())
|
||||
if err := adminDB.Exec(fmt.Sprintf("CREATE DATABASE `%s` CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci", dbName)).Error; err != nil {
|
||||
t.Fatalf("create test database failed: %v", err)
|
||||
}
|
||||
|
||||
testDSN := fmt.Sprintf("%s:%s@tcp(%s)/%s?charset=utf8mb4&parseTime=true&loc=Local", mysqlUser, mysqlPassword, mysqlAddr, dbName)
|
||||
db, err := gorm.Open(mysql.Open(testDSN), &gorm.Config{})
|
||||
if err != nil {
|
||||
t.Fatalf("open test database failed: %v", err)
|
||||
}
|
||||
|
||||
if err := db.AutoMigrate(&user.User{}, &user.Device{}, &user.AuthMethods{}, &user.Subscribe{}, &user.UserFamily{}, &user.UserFamilyMember{}, &modelLog.SystemLog{}); err != nil {
|
||||
t.Fatalf("auto migrate failed: %v", err)
|
||||
}
|
||||
|
||||
redisAddr := getenvDefault("TEST_REDIS_ADDR", "127.0.0.1:6379")
|
||||
redisPassword := getenvDefault("TEST_REDIS_PASSWORD", "")
|
||||
rdb := redis.NewClient(&redis.Options{
|
||||
Addr: redisAddr,
|
||||
Password: redisPassword,
|
||||
DB: 0,
|
||||
})
|
||||
if err := rdb.Ping(context.Background()).Err(); err != nil {
|
||||
t.Fatalf("connect redis failed: %v", err)
|
||||
}
|
||||
_ = rdb.FlushDB(context.Background()).Err()
|
||||
|
||||
svcCtx := &svc.ServiceContext{
|
||||
DB: db,
|
||||
Redis: rdb,
|
||||
UserModel: user.NewModel(db, rdb),
|
||||
LogModel: modelLog.NewModel(db),
|
||||
Config: config.Config{
|
||||
Invite: inviteCfg,
|
||||
},
|
||||
}
|
||||
|
||||
return NewActivateOrderLogic(svcCtx), db, func() {
|
||||
_ = rdb.Close()
|
||||
sqlDB, _ := db.DB()
|
||||
if sqlDB != nil {
|
||||
_ = sqlDB.Close()
|
||||
}
|
||||
_ = adminDB.Exec(fmt.Sprintf("DROP DATABASE IF EXISTS `%s`", dbName)).Error
|
||||
}
|
||||
}
|
||||
|
||||
func seedUser(t *testing.T, db *gorm.DB, referralPercentage uint8, onlyFirstPurchase bool) *user.User {
|
||||
t.Helper()
|
||||
u := &user.User{
|
||||
Password: "pwd",
|
||||
Algo: "default",
|
||||
ReferralPercentage: referralPercentage,
|
||||
OnlyFirstPurchase: boolPtr(onlyFirstPurchase),
|
||||
Enable: boolPtr(true),
|
||||
IsAdmin: boolPtr(false),
|
||||
EnableBalanceNotify: boolPtr(false),
|
||||
EnableLoginNotify: boolPtr(false),
|
||||
EnableSubscribeNotify: boolPtr(false),
|
||||
EnableTradeNotify: boolPtr(false),
|
||||
}
|
||||
if err := db.Create(u).Error; err != nil {
|
||||
t.Fatalf("seed user failed: %v", err)
|
||||
}
|
||||
return u
|
||||
}
|
||||
|
||||
func seedFamily(t *testing.T, db *gorm.DB, ownerID int64, memberID int64) {
|
||||
t.Helper()
|
||||
family := &user.UserFamily{
|
||||
OwnerUserId: ownerID,
|
||||
MaxMembers: 3,
|
||||
Status: user.FamilyStatusActive,
|
||||
}
|
||||
if err := db.Create(family).Error; err != nil {
|
||||
t.Fatalf("seed family failed: %v", err)
|
||||
}
|
||||
now := time.Now()
|
||||
members := []user.UserFamilyMember{
|
||||
{
|
||||
FamilyId: family.Id,
|
||||
UserId: ownerID,
|
||||
Role: user.FamilyRoleOwner,
|
||||
Status: user.FamilyMemberActive,
|
||||
JoinSource: "test",
|
||||
JoinedAt: now,
|
||||
},
|
||||
{
|
||||
FamilyId: family.Id,
|
||||
UserId: memberID,
|
||||
Role: user.FamilyRoleMember,
|
||||
Status: user.FamilyMemberActive,
|
||||
JoinSource: "test",
|
||||
JoinedAt: now,
|
||||
},
|
||||
}
|
||||
if err := db.Create(&members).Error; err != nil {
|
||||
t.Fatalf("seed family members failed: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func seedActiveSubscribe(t *testing.T, db *gorm.DB, userID int64, expireAt time.Time) *user.Subscribe {
|
||||
t.Helper()
|
||||
sub := &user.Subscribe{
|
||||
UserId: userID,
|
||||
OrderId: 1,
|
||||
SubscribeId: 1,
|
||||
StartTime: time.Now().Add(-24 * time.Hour),
|
||||
ExpireTime: expireAt,
|
||||
Traffic: 1024,
|
||||
Token: fmt.Sprintf("token-%d-%d", userID, time.Now().UnixNano()),
|
||||
UUID: fmt.Sprintf("uuid-%d-%d", userID, time.Now().UnixNano()),
|
||||
Status: 1,
|
||||
}
|
||||
if err := db.Create(sub).Error; err != nil {
|
||||
t.Fatalf("seed subscribe failed: %v", err)
|
||||
}
|
||||
return sub
|
||||
}
|
||||
|
||||
func assertExpireIncreasedByDays(t *testing.T, db *gorm.DB, subscribeID int64, before time.Time, days int) {
|
||||
t.Helper()
|
||||
var after user.Subscribe
|
||||
if err := db.First(&after, subscribeID).Error; err != nil {
|
||||
t.Fatalf("query subscribe failed: %v", err)
|
||||
}
|
||||
expected := before.Add(time.Duration(days) * 24 * time.Hour)
|
||||
if !after.ExpireTime.Equal(expected) {
|
||||
t.Fatalf("expire time mismatch, expected=%v got=%v", expected, after.ExpireTime)
|
||||
}
|
||||
}
|
||||
|
||||
func assertUserCommission(t *testing.T, db *gorm.DB, userID int64, expected int64) {
|
||||
t.Helper()
|
||||
var u user.User
|
||||
if err := db.First(&u, userID).Error; err != nil {
|
||||
t.Fatalf("query user failed: %v", err)
|
||||
}
|
||||
if u.Commission != expected {
|
||||
t.Fatalf("expected user %d commission=%d, got %d", userID, expected, u.Commission)
|
||||
}
|
||||
}
|
||||
|
||||
func assertLogCountForOrder(t *testing.T, db *gorm.DB, logType uint8, orderNo string, expected int64) {
|
||||
t.Helper()
|
||||
var count int64
|
||||
if err := db.Model(&modelLog.SystemLog{}).
|
||||
Where("type = ? AND content LIKE ?", logType, "%"+orderNo+"%").
|
||||
Count(&count).Error; err != nil {
|
||||
t.Fatalf("count logs failed: %v", err)
|
||||
}
|
||||
if count != expected {
|
||||
t.Fatalf("expected log type %d count=%d for order %s, got %d", logType, expected, orderNo, count)
|
||||
}
|
||||
}
|
||||
|
||||
func assertGiftLogRemarkContains(t *testing.T, db *gorm.DB, orderNo string, want string) {
|
||||
t.Helper()
|
||||
var row modelLog.SystemLog
|
||||
if err := db.Model(&modelLog.SystemLog{}).
|
||||
Where("type = ? AND content LIKE ?", modelLog.TypeGift.Uint8(), "%"+orderNo+"%").
|
||||
First(&row).Error; err != nil {
|
||||
t.Fatalf("query gift log failed: %v", err)
|
||||
}
|
||||
if !strings.Contains(row.Content, want) {
|
||||
t.Fatalf("expected gift log content to contain %q, got %s", want, row.Content)
|
||||
}
|
||||
}
|
||||
|
||||
func assertNoSubscribeForUser(t *testing.T, db *gorm.DB, userID int64) {
|
||||
t.Helper()
|
||||
var count int64
|
||||
if err := db.Model(&user.Subscribe{}).Where("user_id = ?", userID).Count(&count).Error; err != nil {
|
||||
t.Fatalf("count subscribes failed: %v", err)
|
||||
}
|
||||
if count != 0 {
|
||||
t.Fatalf("expected user %d to have no direct subscriptions, got %d", userID, count)
|
||||
}
|
||||
}
|
||||
|
||||
func boolPtr(v bool) *bool {
|
||||
return &v
|
||||
}
|
||||
|
||||
func getenvDefault(key, fallback string) string {
|
||||
v := os.Getenv(key)
|
||||
if v == "" {
|
||||
return fallback
|
||||
}
|
||||
return v
|
||||
}
|
||||
@@ -1,199 +0,0 @@
|
||||
package orderLogic
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
modelOrder "github.com/perfect-panel/server/internal/model/order"
|
||||
"github.com/perfect-panel/server/internal/model/subscribe"
|
||||
"github.com/perfect-panel/server/internal/model/user"
|
||||
"github.com/stretchr/testify/require"
|
||||
"gorm.io/driver/sqlite"
|
||||
"gorm.io/gorm"
|
||||
"gorm.io/gorm/logger"
|
||||
)
|
||||
|
||||
func setupActivationEligibilityDB(t *testing.T) *gorm.DB {
|
||||
t.Helper()
|
||||
|
||||
db, err := gorm.Open(sqlite.Open(":memory:"), &gorm.Config{
|
||||
Logger: logger.Default.LogMode(logger.Silent),
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
sqls := []string{
|
||||
`CREATE TABLE IF NOT EXISTS "user" (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
password VARCHAR(100) NOT NULL DEFAULT '',
|
||||
created_at DATETIME,
|
||||
updated_at DATETIME,
|
||||
deleted_at DATETIME DEFAULT NULL
|
||||
)`,
|
||||
`CREATE TABLE IF NOT EXISTS "user_device" (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
user_id INTEGER NOT NULL DEFAULT 0,
|
||||
identifier VARCHAR(255) NOT NULL DEFAULT '' UNIQUE,
|
||||
created_at DATETIME,
|
||||
updated_at DATETIME
|
||||
)`,
|
||||
`CREATE TABLE IF NOT EXISTS "user_family" (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
owner_user_id INTEGER NOT NULL DEFAULT 0,
|
||||
status TINYINT NOT NULL DEFAULT 1,
|
||||
deleted_at DATETIME DEFAULT NULL
|
||||
)`,
|
||||
`CREATE TABLE IF NOT EXISTS "user_family_member" (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
family_id INTEGER NOT NULL DEFAULT 0,
|
||||
user_id INTEGER NOT NULL DEFAULT 0,
|
||||
role TINYINT NOT NULL DEFAULT 0,
|
||||
status TINYINT NOT NULL DEFAULT 0,
|
||||
join_source VARCHAR(32) NOT NULL DEFAULT '',
|
||||
deleted_at DATETIME DEFAULT NULL
|
||||
)`,
|
||||
`CREATE TABLE IF NOT EXISTS "order" (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
user_id INTEGER NOT NULL DEFAULT 0,
|
||||
order_no VARCHAR(255) NOT NULL DEFAULT '' UNIQUE,
|
||||
type TINYINT NOT NULL DEFAULT 1,
|
||||
status TINYINT NOT NULL DEFAULT 1,
|
||||
subscribe_id INTEGER NOT NULL DEFAULT 0,
|
||||
quantity INTEGER NOT NULL DEFAULT 1,
|
||||
created_at DATETIME,
|
||||
updated_at DATETIME
|
||||
)`,
|
||||
}
|
||||
for _, sql := range sqls {
|
||||
require.NoError(t, db.Exec(sql).Error)
|
||||
}
|
||||
|
||||
return db
|
||||
}
|
||||
|
||||
func insertActivationUser(t *testing.T, db *gorm.DB, userID int64, createdAt time.Time) {
|
||||
t.Helper()
|
||||
require.NoError(t, db.Exec(
|
||||
`INSERT INTO "user" (id, created_at, updated_at) VALUES (?, ?, datetime('now'))`,
|
||||
userID,
|
||||
createdAt.UTC().Format("2006-01-02 15:04:05"),
|
||||
).Error)
|
||||
}
|
||||
|
||||
func insertActivationDevice(t *testing.T, db *gorm.DB, userID int64, identifier string, createdAt time.Time) {
|
||||
t.Helper()
|
||||
require.NoError(t, db.Exec(
|
||||
`INSERT INTO "user_device" (user_id, identifier, created_at, updated_at) VALUES (?, ?, ?, datetime('now'))`,
|
||||
userID,
|
||||
identifier,
|
||||
createdAt.UTC().Format("2006-01-02 15:04:05"),
|
||||
).Error)
|
||||
}
|
||||
|
||||
func insertActivationFamily(t *testing.T, db *gorm.DB, familyID, ownerUserID int64) {
|
||||
t.Helper()
|
||||
require.NoError(t, db.Exec(
|
||||
`INSERT INTO "user_family" (id, owner_user_id, status) VALUES (?, ?, 1)`,
|
||||
familyID,
|
||||
ownerUserID,
|
||||
).Error)
|
||||
}
|
||||
|
||||
func insertActivationFamilyMember(t *testing.T, db *gorm.DB, familyID, userID int64, role, status uint8, joinSource string) {
|
||||
t.Helper()
|
||||
require.NoError(t, db.Exec(
|
||||
`INSERT INTO "user_family_member" (family_id, user_id, role, status, join_source) VALUES (?, ?, ?, ?, ?)`,
|
||||
familyID,
|
||||
userID,
|
||||
role,
|
||||
status,
|
||||
joinSource,
|
||||
).Error)
|
||||
}
|
||||
|
||||
func insertActivationOrder(t *testing.T, db *gorm.DB, orderNo string, userID, subscribeID int64, status uint8) {
|
||||
t.Helper()
|
||||
require.NoError(t, db.Exec(
|
||||
`INSERT INTO "order" (user_id, order_no, type, status, subscribe_id, quantity, created_at, updated_at)
|
||||
VALUES (?, ?, 1, ?, ?, 1, datetime('now'), datetime('now'))`,
|
||||
userID,
|
||||
orderNo,
|
||||
status,
|
||||
subscribeID,
|
||||
).Error)
|
||||
}
|
||||
|
||||
func TestValidateNewUserOnlyEligibilityAtActivation_UsesEarliestBoundDeviceTime(t *testing.T) {
|
||||
db := setupActivationEligibilityDB(t)
|
||||
|
||||
const (
|
||||
ownerUserID = int64(1)
|
||||
memberUserID = int64(2)
|
||||
familyID = int64(10)
|
||||
subscribeID = int64(100)
|
||||
)
|
||||
|
||||
insertActivationUser(t, db, ownerUserID, time.Now().Add(-1*time.Hour))
|
||||
insertActivationUser(t, db, memberUserID, time.Now().Add(-72*time.Hour))
|
||||
insertActivationDevice(t, db, memberUserID, "activation-old-device", time.Now().Add(-72*time.Hour))
|
||||
insertActivationFamily(t, db, familyID, ownerUserID)
|
||||
insertActivationFamilyMember(t, db, familyID, ownerUserID, user.FamilyRoleOwner, user.FamilyMemberActive, "owner_init")
|
||||
insertActivationFamilyMember(t, db, familyID, memberUserID, user.FamilyRoleMember, user.FamilyMemberActive, "bind_email_with_verification")
|
||||
|
||||
err := validateNewUserOnlyEligibilityAtActivation(
|
||||
context.Background(),
|
||||
db,
|
||||
&modelOrder.Order{
|
||||
UserId: ownerUserID,
|
||||
OrderNo: "activation-check-old-device",
|
||||
Type: OrderTypeSubscribe,
|
||||
Quantity: 1,
|
||||
SubscribeId: subscribeID,
|
||||
},
|
||||
&subscribe.Subscribe{
|
||||
Id: subscribeID,
|
||||
Discount: `[{"quantity":1,"discount":90,"new_user_only":true}]`,
|
||||
},
|
||||
)
|
||||
|
||||
require.Error(t, err)
|
||||
require.Contains(t, err.Error(), "is not a new user")
|
||||
}
|
||||
|
||||
func TestValidateNewUserOnlyEligibilityAtActivation_SharesHistoryAcrossBoundScope(t *testing.T) {
|
||||
db := setupActivationEligibilityDB(t)
|
||||
|
||||
const (
|
||||
ownerUserID = int64(11)
|
||||
memberUserID = int64(12)
|
||||
familyID = int64(20)
|
||||
subscribeID = int64(200)
|
||||
)
|
||||
|
||||
insertActivationUser(t, db, ownerUserID, time.Now().Add(-1*time.Hour))
|
||||
insertActivationUser(t, db, memberUserID, time.Now().Add(-2*time.Hour))
|
||||
insertActivationDevice(t, db, memberUserID, "activation-shared-device", time.Now().Add(-2*time.Hour))
|
||||
insertActivationFamily(t, db, familyID, ownerUserID)
|
||||
insertActivationFamilyMember(t, db, familyID, ownerUserID, user.FamilyRoleOwner, user.FamilyMemberActive, "owner_init")
|
||||
insertActivationFamilyMember(t, db, familyID, memberUserID, user.FamilyRoleMember, user.FamilyMemberActive, "bind_email_with_verification")
|
||||
insertActivationOrder(t, db, "previous-finished-order", memberUserID, subscribeID, OrderStatusFinished)
|
||||
|
||||
err := validateNewUserOnlyEligibilityAtActivation(
|
||||
context.Background(),
|
||||
db,
|
||||
&modelOrder.Order{
|
||||
UserId: ownerUserID,
|
||||
OrderNo: "current-paid-order",
|
||||
Type: OrderTypeSubscribe,
|
||||
Quantity: 1,
|
||||
SubscribeId: subscribeID,
|
||||
},
|
||||
&subscribe.Subscribe{
|
||||
Id: subscribeID,
|
||||
Discount: `[{"quantity":1,"discount":90,"new_user_only":true}]`,
|
||||
},
|
||||
)
|
||||
|
||||
require.Error(t, err)
|
||||
require.Contains(t, err.Error(), "already activated")
|
||||
}
|
||||
Reference in New Issue
Block a user