fix: align report date defaults with recent periods

This commit is contained in:
Yvan
2026-11-05 14:26:36 +08:00
parent 31584c73bf
commit 22ba319f7f
16 changed files with 181 additions and 70 deletions
+3 -15
View File
@@ -137,23 +137,11 @@ func (uc *AnalyticsUsecase) list(ctx context.Context, kind AnalyticsKind, filter
filter.PromoteName = ""
filter.PromoteType = nil
}
if filter.EndDate == nil || kind == GameAnalytics && filter.StartDate == nil {
now := uc.now().In(portraitLocation)
day := time.Date(now.Year(), now.Month(), now.Day(), 0, 0, 0, 0, portraitLocation)
if kind == GameAnalytics && filter.StartDate == nil {
filter.StartDate = &day
}
if filter.EndDate == nil {
filter.EndDate = &day
}
}
if filter.StartDate != nil && filter.EndDate.Before(*filter.StartDate) {
filter.StartDate, filter.EndDate = reportDateDefaults(filter.StartDate, filter.EndDate, 30, uc.now())
if filter.EndDate.Before(*filter.StartDate) {
return nil, ErrAnalyticsDateOrder
}
filter.Begin = ""
if filter.StartDate != nil {
filter.Begin = filter.StartDate.Format("2006-01-02")
}
filter.Begin = filter.StartDate.Format("2006-01-02")
filter.End = filter.EndDate.Format("2006-01-02")
out := &AnalyticsPage{Rows: []*AnalyticsRow{}, Begin: filter.Begin, End: filter.End, Available: true}
scope := AnalyticsScope{Viewer: viewer, IncludeSub: pref.IncludeSubPromote, IDCardDedup: pref.IDCardDedup}
+5 -5
View File
@@ -63,8 +63,8 @@ func TestGameAnalyticsSummaryUsesAllRowsAndCorrectDenominators(t *testing.T) {
if len(page.Rows) != 1 || page.Total != 2 || page.Rows[0].ID != 2 || page.Summary.Counts.Register != 5 || page.Summary.Pay != "50.00" || page.Summary.PayRate != "30.00" || page.Summary.ARPU != "5.00" || page.Summary.ARPPU != "16.67" {
t.Fatalf("游戏汇总、分页或分母错误: %+v", page)
}
if page.Begin != "2026-11-04" || page.End != "2026-11-04" {
t.Fatal("后台缺省统计日期应为当天")
if page.Begin != "2026-10-06" || page.End != "2026-11-04" {
t.Fatal("后台缺省统计日期应为含今天的近30天")
}
}
func TestChannelAnalyticsSummaryDependsOnViewer(t *testing.T) {
@@ -82,7 +82,7 @@ func TestChannelAnalyticsSummaryDependsOnViewer(t *testing.T) {
}
}
func TestChannelAnalyticsAllPagesSummaryAndOpenDateRange(t *testing.T) {
func TestChannelAnalyticsAllPagesSummaryAndDefaultDateRange(t *testing.T) {
uc, repo := analyticsFixture()
repo.data.EffectiveCount = 3
for _, pageNum := range []int{1, 2, 8} {
@@ -90,8 +90,8 @@ func TestChannelAnalyticsAllPagesSummaryAndOpenDateRange(t *testing.T) {
if err != nil || page.Total != 2 || page.Summary.Counts.Register != 5 || page.Summary.Counts.Active != 10 || page.Summary.Counts.Pay != 3 || page.Summary.Counts.NewPay != 2 || page.Summary.Pay != "50.00" || page.Summary.PayRate != "30.00" || page.EffectiveCount != 3 {
t.Fatalf("翻页不能改变完整合计: page=%d %+v %v", pageNum, page, err)
}
if page.Begin != "" || page.End != "2026-11-04" || repo.filter.StartDate != nil {
t.Fatalf("渠道统计缺省应从最早数据统计至今天: %+v", repo.filter)
if page.Begin != "2026-10-06" || page.End != "2026-11-04" || repo.filter.StartDate == nil {
t.Fatalf("渠道统计缺省应为含今天的近30天: %+v", repo.filter)
}
}
for _, sample := range []struct {
+2 -7
View File
@@ -119,18 +119,13 @@ func (uc *LedgerUsecase) prepare(ctx context.Context, filter LedgerFilter) (Ledg
viewer := portraitUserScope(a)
viewer.All = actor.AuthorityID == 888
scope := LedgerScope{Viewer: viewer, IncludeSub: pref.IncludeSubPromote, Unrestricted: viewer.All && strings.TrimSpace(filter.BusierAccount) == ""}
begin, end := filter.StartDate, filter.EndDate
if begin == nil || end == nil {
now := uc.now().In(portraitLocation)
yesterday := time.Date(now.Year(), now.Month(), now.Day()-1, 0, 0, 0, 0, portraitLocation)
first := yesterday.AddDate(0, 0, -6)
begin, end = &first, &yesterday
}
begin, end := reportDateDefaults(filter.StartDate, filter.EndDate, 30, uc.now())
if end.Before(*begin) {
return scope, filter, ErrLedgerInput
}
filter.BeginUnix = begin.Unix()
filter.EndUnix = end.AddDate(0, 0, 1).Unix() - 1
filter.StartDate, filter.EndDate = begin, end
return scope, filter, nil
}
func registrationSort(field string) string {
+2 -2
View File
@@ -46,8 +46,8 @@ func TestLedgerDateDefaultsAndBusinessScope(t *testing.T) {
if _, err := uc.Registrations(accountContext(7, 901), LedgerFilter{SortField: "payAmount"}, LedgerListOptions{Limit: 10}); err != nil {
t.Fatal(err)
}
if time.Unix(r.filter.BeginUnix, 0).In(portraitLocation).Format("2006-01-02 15:04:05") != "2026-10-28 00:00:00" || time.Unix(r.filter.EndUnix, 0).In(portraitLocation).Format("2006-01-02 15:04:05") != "2026-11-03 23:59:59" {
t.Fatal("未传日期应取截至昨日的七天")
if time.Unix(r.filter.BeginUnix, 0).In(portraitLocation).Format("2006-01-02 15:04:05") != "2026-10-06 00:00:00" || time.Unix(r.filter.EndUnix, 0).In(portraitLocation).Format("2006-01-02 15:04:05") != "2026-11-04 23:59:59" {
t.Fatal("未传日期应取含今天的近30天")
}
if r.scope.Unrestricted || !r.scope.Viewer.IncludeSelf || r.filter.SortField != "totalPayAmount" {
t.Fatal("商务范围或排序别名错误")
+1 -4
View File
@@ -70,10 +70,7 @@ func (uc *RankingUsecase) List(ctx context.Context, kind RankingKind, f Analytic
if kind != ChannelRanking && kind != BusinessRanking && kind != GameRanking {
return nil, ErrAnalyticsInput
}
if f.StartDate == nil || f.EndDate == nil {
day := workbenchWindow(uc.now()).Today
f.StartDate, f.EndDate = &day, &day
}
f.StartDate, f.EndDate = reportDateDefaults(f.StartDate, f.EndDate, 7, uc.now())
if f.EndDate.Before(*f.StartDate) {
return nil, ErrAnalyticsDateOrder
}
+3
View File
@@ -46,6 +46,9 @@ func TestRankingComparisonsAndBusinessCountSemantics(t *testing.T) {
if err != nil || p.Active[0].Value != "5" || p.PayRate[0].Value != "40.00" || p.Register[0].Name != "二级商务 (L2)" || p.Register[0].SourceDB != "" {
t.Fatal("商务需加总各渠道人数,不全局去重")
}
if p.Begin != "2026-10-29" || p.End != "2026-11-04" || r.filter.PreviousBegin != "2026-10-22" || r.filter.PreviousEnd != "2026-10-28" {
t.Fatal("排行榜缺省为含今天的近7天,上期范围应等长")
}
calls := r.calls
p, err = uc.List(accountContext(9, 903), BusinessRanking, AnalyticsFilter{})
if err != nil || len(p.Register) != 0 || r.calls != calls {
+18
View File
@@ -0,0 +1,18 @@
package business
import "time"
// reportDateDefaults fills missing bounds without discarding an explicit date.
// Reports include the end date, so a 30-day period starts 29 days earlier.
func reportDateDefaults(begin, end *time.Time, days int, now time.Time) (*time.Time, *time.Time) {
if end == nil {
local := now.In(portraitLocation)
day := time.Date(local.Year(), local.Month(), local.Day(), 0, 0, 0, 0, portraitLocation)
end = &day
}
if begin == nil {
first := end.AddDate(0, 0, 1-days)
begin = &first
}
return begin, end
}
@@ -0,0 +1,75 @@
package business
import (
"testing"
"time"
)
func TestAnalyticsDefaultDatesBoundListAndExportQueries(t *testing.T) {
date := func(value string) *time.Time {
parsed, err := time.ParseInLocation("2006-01-02", value, portraitLocation)
if err != nil {
t.Fatal(err)
}
return &parsed
}
for _, kind := range []AnalyticsKind{ChannelAnalytics, GameAnalytics} {
for _, sample := range []struct {
name, start, end, wantStart, wantEnd string
now time.Time
}{
{"empty", "", "", "2026-10-06", "2026-11-04", time.Date(2026, 11, 4, 9, 0, 0, 0, portraitLocation)},
{"China day across UTC midnight", "", "", "2025-12-03", "2026-01-01", time.Date(2025, 12, 31, 17, 0, 0, 0, time.UTC)},
{"only end across leap day", "", "2024-03-01", "2024-02-01", "2024-03-01", time.Now()},
{"only start", "2026-01-01", "", "2026-01-01", "2026-11-04", time.Date(2026, 11, 4, 9, 0, 0, 0, portraitLocation)},
{"explicit historical year", "2023-01-01", "2023-12-31", "2023-01-01", "2023-12-31", time.Now()},
} {
t.Run(string(kind)+"/"+sample.name, func(t *testing.T) {
uc, repo := analyticsFixture()
uc.now = func() time.Time { return sample.now }
filter := AnalyticsFilter{}
if sample.start != "" {
filter.StartDate = date(sample.start)
}
if sample.end != "" {
filter.EndDate = date(sample.end)
}
for _, export := range []bool{false, true} {
var page *AnalyticsPage
var err error
if export {
page, err = uc.ListAll(accountContext(7, 901), kind, filter)
} else {
page, err = uc.List(accountContext(7, 901), kind, filter, 1, 10)
}
if err != nil {
t.Fatal(err)
}
if page.Begin != sample.wantStart || page.End != sample.wantEnd || repo.filter.Begin != page.Begin || repo.filter.End != page.End || repo.filter.StartDate == nil || repo.filter.EndDate == nil {
t.Fatalf("export=%v expected %s..%s, got %+v", export, sample.wantStart, sample.wantEnd, repo.filter)
}
}
})
}
}
}
func TestLedgerPartialDateDoesNotDiscardHistoricalEnd(t *testing.T) {
uc, repo, _ := ledgerFixture()
end := time.Date(2024, 3, 1, 0, 0, 0, 0, portraitLocation)
for _, export := range []bool{false, true} {
filter := LedgerFilter{EndDate: &end}
var err error
if export {
_, err = uc.ExportSpends(accountContext(7, 901), filter)
} else {
_, err = uc.Registrations(accountContext(7, 901), filter, LedgerListOptions{Limit: 10})
}
if err != nil {
t.Fatal(err)
}
if time.Unix(repo.filter.BeginUnix, 0).In(portraitLocation).Format("2006-01-02 15:04:05") != "2024-02-01 00:00:00" || time.Unix(repo.filter.EndUnix, 0).In(portraitLocation).Format("2006-01-02 15:04:05") != "2024-03-01 23:59:59" {
t.Fatalf("historical end date was discarded: %+v", repo.filter)
}
}
}
+1 -5
View File
@@ -89,11 +89,7 @@ func (uc *ServerAnalysisUsecase) List(ctx context.Context, f ServerAnalysisFilte
if err != nil {
return nil, err
}
if f.StartDate == nil || f.EndDate == nil {
now := uc.now().In(portraitLocation)
day := time.Date(now.Year(), now.Month(), now.Day(), 0, 0, 0, 0, portraitLocation)
f.StartDate, f.EndDate = &day, &day
}
f.StartDate, f.EndDate = reportDateDefaults(f.StartDate, f.EndDate, 30, uc.now())
if f.EndDate.Before(*f.StartDate) {
return nil, ErrAnalyticsDateOrder
}
@@ -38,7 +38,7 @@ func TestServerAnalysisSummaryZerosSortingAndLimits(t *testing.T) {
uc.now = func() time.Time { return time.Date(2026, 11, 4, 9, 0, 0, 0, portraitLocation) }
f := ServerAnalysisFilter{AnalyticsFilter: AnalyticsFilter{GameNames: []string{"游戏"}}}
p, err := uc.List(accountContext(7, 901), f, 1, 1)
if err != nil || p.Total != 2 || len(p.Rows) != 1 || p.Rows[0].ServerNum != "01" || p.Summary.Pay != "30.01" || p.Summary.Counts.Register != 5 || p.Summary.ARPU != "6.00" || p.Begin != "2026-11-04" {
if err != nil || p.Total != 2 || len(p.Rows) != 1 || p.Rows[0].ServerNum != "01" || p.Summary.Pay != "30.01" || p.Summary.Counts.Register != 5 || p.Summary.ARPU != "6.00" || p.Begin != "2026-10-06" || p.End != "2026-11-04" {
t.Fatalf("汇总、四舍五入或分页错误: %+v %v", p, err)
}
if !r.scope.IncludeSub || !r.scope.IDCardDedup || r.scope.Viewer.All {