package business import ( "context" "testing" "time" ) type activationRepoFake struct { ActivationRepo accounts []ActivationAccount requested uint scope ActivationScope filter ActivationFilter record *Activation query ActivationSpendQuery items []*ActivationSpendItem listCalls int } func (r *activationRepoFake) OwnAccounts(_ context.Context, id uint) ([]ActivationAccount, error) { r.requested = id return r.accounts, nil } func (r *activationRepoFake) List(_ context.Context, scope ActivationScope, filter ActivationFilter, _ ...ListOption) (*ActivationPage, error) { r.listCalls++ r.scope = scope r.filter = filter return &ActivationPage{Rows: []*Activation{}, Available: true}, nil } func (r *activationRepoFake) Find(context.Context, uint64) (*Activation, error) { return r.record, nil } func (r *activationRepoFake) Spend(_ context.Context, q ActivationSpendQuery) ([]*ActivationSpendItem, error) { r.query = q return r.items, nil } func activationFixture() (*ActivationUsecase, *activationRepoFake) { a := &accountRepoFake{accounts: map[uint]*Account{1: {ID: 1, Level: 0}, 7: {ID: 7, Level: 1}, 8: {ID: 8, Level: 2, IDPath: "0,7"}}} r := &activationRepoFake{accounts: []ActivationAccount{{"lx", " Own "}, {"LX", "own"}, {"hw", "Other"}, {"lx", ""}, {"unknown", "Own"}}} return NewActivationUsecase(r, NewAccountUsecase(a)), r } func TestActivationScopeIncludesOwnAccountsOnly(t *testing.T) { uc, r := activationFixture() if _, err := uc.List(accountContext(8, 902), ActivationFilter{BusierAccount: "oWn", Statuses: []string{"已达标"}}); err != nil { t.Fatal(err) } if r.requested != 8 || r.scope.All || len(r.scope.Accounts) != 1 || r.scope.Accounts[0] != (ActivationAccount{"lx", "Own"}) || r.filter.BusierAccount != "" || r.filter.Statuses[0] != "reached" { t.Fatalf("本人账号或中文状态筛选错误: %+v", r) } page, err := uc.List(accountContext(7, 901), ActivationFilter{BusierAccount: "下级账号"}) if err != nil || page.Total != 0 || r.listCalls != 1 { t.Fatal("无匹配绑定应直接返回空集") } if _, err := uc.List(accountContext(1, 888), ActivationFilter{BusierAccount: "any"}); err != nil || !r.scope.All || r.filter.BusierAccount != "any" { t.Fatal("超管可筛全部 OA 绑定") } } func TestActivationSpendScopeCutoffAndExactMoney(t *testing.T) { uc, r := activationFixture() start := time.Date(2026, 11, 3, 0, 0, 0, 0, time.FixedZone("CST", 8*3600)) reach, unbind := start.Add(time.Hour), start.Add(2*time.Hour) id := uint64(100) r.record = &Activation{ID: 10, PromoteID: &id, PlatformName: "lx", BusierAccount: "OWN", BindAt: &start, ReachAt: &reach, UnbindAt: &unbind, Status: "reached"} r.items = []*ActivationSpendItem{{Amount: "9007199254740993.01"}, {Amount: "0.09"}} detail, err := uc.SpendDetail(accountContext(8, 902), 10) if err != nil || detail.TotalAmount != "9007199254740993.10" || r.query.Start != start.Unix() || r.query.End == nil || *r.query.End != reach.Unix() { t.Fatalf("达标截止或精确金额错误: %+v %+v %v", detail, r.query, err) } r.record.Status = "unbound" if _, err := uc.SpendDetail(accountContext(8, 902), 10); err != nil || *r.query.End != unbind.Unix() { t.Fatal("解绑截止错误") } r.record.PlatformName = "hw" if _, err := uc.SpendDetail(accountContext(8, 902), 10); err != ErrActivationScope { t.Fatal("同名商务不能读取另一平台的激活流水") } r.record.PlatformName = "lx" r.record.BusierAccount = "not-owned" if _, err := uc.SpendDetail(accountContext(8, 902), 10); err != ErrActivationScope { t.Fatal("非本人绑定可读取流水") } r.record.BindAt = nil if _, err := uc.SpendDetail(accountContext(1, 888), 10); err != ErrActivationPending { t.Fatal("未审核绑定不应查询流水") } }