fix(task-center): 统一任务消费统计口径
修复任务中心全局消费任务只统计抽奖链路订单的问题,改为按真实已支付订单的实付金额计算,并统一使用支付时间优先的时间口径。补充全局消费任务测试并更新 SQLite 测试表结构,确保消费判断与福利活动口径一致。
This commit is contained in:
parent
e3007c4e0d
commit
cf82660a45
@ -226,23 +226,37 @@ func tierFingerprint(metric string, threshold int64, activityID int64, window st
|
||||
return fmt.Sprintf("%s-%d-%d-%s", metric, threshold, activityID, window)
|
||||
}
|
||||
|
||||
func paidTimeExpr() string {
|
||||
return "COALESCE(NULLIF(orders.paid_at, '1970-01-01 00:00:00'), orders.created_at)"
|
||||
}
|
||||
|
||||
func (s *service) fetchOrderMetricRows(ctx context.Context, userID int64, activityIDs []int64, start, end *time.Time) ([]orderMetricRow, error) {
|
||||
query := s.repo.GetDbR().WithContext(ctx).Table(model.TableNameOrders).
|
||||
Select("orders.id AS order_id, activity_issues.activity_id AS activity_id, COUNT(activity_draw_logs.id) AS draw_count, COALESCE(activities.price_draw, 0) AS ticket_price, orders.actual_amount").
|
||||
Joins("JOIN activity_draw_logs ON activity_draw_logs.order_id = orders.id").
|
||||
Joins("JOIN activity_issues ON activity_issues.id = activity_draw_logs.issue_id").
|
||||
Joins("LEFT JOIN activities ON activities.id = activity_issues.activity_id").
|
||||
Where("orders.user_id = ? AND orders.status = 2 AND orders.source_type != 1", userID).
|
||||
Group("orders.id, activity_issues.activity_id, activities.price_draw, orders.actual_amount")
|
||||
Select("orders.id AS order_id, 0 AS activity_id, 0 AS draw_count, 0 AS ticket_price, orders.actual_amount").
|
||||
Where("orders.user_id = ? AND orders.status = 2", userID)
|
||||
|
||||
if len(activityIDs) > 0 {
|
||||
query = query.Where("activity_issues.activity_id IN ?", activityIDs)
|
||||
}
|
||||
if start != nil {
|
||||
query = query.Where("orders.created_at >= ?", *start)
|
||||
query = query.Where(paidTimeExpr()+" >= ?", *start)
|
||||
}
|
||||
if end != nil {
|
||||
query = query.Where("orders.created_at <= ?", *end)
|
||||
query = query.Where(paidTimeExpr()+" <= ?", *end)
|
||||
}
|
||||
|
||||
if len(activityIDs) > 0 {
|
||||
query = s.repo.GetDbR().WithContext(ctx).Table(model.TableNameOrders).
|
||||
Select("orders.id AS order_id, activity_issues.activity_id AS activity_id, COUNT(activity_draw_logs.id) AS draw_count, COALESCE(activities.price_draw, 0) AS ticket_price, orders.actual_amount").
|
||||
Joins("JOIN activity_draw_logs ON activity_draw_logs.order_id = orders.id").
|
||||
Joins("JOIN activity_issues ON activity_issues.id = activity_draw_logs.issue_id").
|
||||
Joins("LEFT JOIN activities ON activities.id = activity_issues.activity_id").
|
||||
Where("orders.user_id = ? AND orders.status = 2 AND orders.source_type != 1", userID).
|
||||
Where("activity_issues.activity_id IN ?", activityIDs).
|
||||
Group("orders.id, activity_issues.activity_id, activities.price_draw, orders.actual_amount")
|
||||
if start != nil {
|
||||
query = query.Where(paidTimeExpr()+" >= ?", *start)
|
||||
}
|
||||
if end != nil {
|
||||
query = query.Where(paidTimeExpr()+" <= ?", *end)
|
||||
}
|
||||
}
|
||||
|
||||
var rows []orderMetricRow
|
||||
|
||||
@ -25,6 +25,7 @@ func ensureExtraTablesForServiceTest(t *testing.T, db *gorm.DB) {
|
||||
total_amount INTEGER NOT NULL DEFAULT 0,
|
||||
actual_amount INTEGER NOT NULL DEFAULT 0,
|
||||
remark TEXT,
|
||||
paid_at DATETIME,
|
||||
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
||||
deleted_at DATETIME
|
||||
@ -345,6 +346,74 @@ func TestGetUserProgress_UsesActualAmount(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestOrderAmount_GlobalTaskUsesAllPaidOrders(t *testing.T) {
|
||||
repo, err := mysql.NewSQLiteRepoForTest()
|
||||
if err != nil {
|
||||
t.Fatalf("创建 repo 失败: %v", err)
|
||||
}
|
||||
db := repo.GetDbW()
|
||||
initTestTables(t, db)
|
||||
ensureExtraTablesForServiceTest(t, db)
|
||||
|
||||
svc := New(nil, repo, nil, nil, nil)
|
||||
|
||||
now := time.Now()
|
||||
taskStart := now.Add(-24 * time.Hour)
|
||||
taskEnd := now.Add(24 * time.Hour)
|
||||
task := &tcmodel.Task{
|
||||
Name: "全局消费任务",
|
||||
Status: 1,
|
||||
Visibility: 1,
|
||||
StartTime: &taskStart,
|
||||
EndTime: &taskEnd,
|
||||
}
|
||||
if err := db.Create(task).Error; err != nil {
|
||||
t.Fatalf("创建任务失败: %v", err)
|
||||
}
|
||||
|
||||
tier := &tcmodel.TaskTier{
|
||||
TaskID: task.ID,
|
||||
Metric: MetricOrderAmount,
|
||||
Operator: OperatorGTE,
|
||||
Threshold: 1000,
|
||||
Window: WindowLifetime,
|
||||
ActivityID: 0,
|
||||
}
|
||||
if err := db.Create(tier).Error; err != nil {
|
||||
t.Fatalf("创建档位失败: %v", err)
|
||||
}
|
||||
|
||||
userID := int64(8888)
|
||||
inside := now.Format(time.DateTime)
|
||||
|
||||
// 普通实付订单:以前不会进 activity_draw_logs 链路,现在全局任务应计入
|
||||
db.Exec("INSERT INTO orders (id, user_id, status, source_type, total_amount, actual_amount, created_at) VALUES (801, ?, 2, 4, 4550, 4550, ?)", userID, inside)
|
||||
// 抽奖订单:也应计入
|
||||
db.Exec("INSERT INTO orders (id, user_id, status, source_type, total_amount, actual_amount, created_at) VALUES (802, ?, 2, 2, 2000, 2000, ?)", userID, inside)
|
||||
db.Exec("INSERT INTO activities (id, price_draw) VALUES (901, 500)")
|
||||
db.Exec("INSERT INTO activity_issues (id, activity_id) VALUES (902, 901)")
|
||||
db.Exec("INSERT INTO activity_draw_logs (order_id, issue_id) VALUES (802, 902)")
|
||||
// 零实付订单:金额应为0,但订单数仍按现有逻辑计入已支付订单
|
||||
db.Exec("INSERT INTO orders (id, user_id, status, source_type, total_amount, actual_amount, created_at) VALUES (803, ?, 2, 4, 1300, 0, ?)", userID, inside)
|
||||
|
||||
progress, err := svc.GetUserProgress(context.Background(), userID, task.ID)
|
||||
if err != nil {
|
||||
t.Fatalf("获取进度失败: %v", err)
|
||||
}
|
||||
|
||||
if progress.OrderAmount != 6550 {
|
||||
t.Fatalf("全局任务金额统计错误,期望 6550 实际 %d", progress.OrderAmount)
|
||||
}
|
||||
if progress.OrderCount != 3 {
|
||||
t.Fatalf("全局任务订单数错误,期望 3 实际 %d", progress.OrderCount)
|
||||
}
|
||||
|
||||
tierProgress := progress.TierProgressMap[tier.ID]
|
||||
if tierProgress.OrderAmount != 6550 {
|
||||
t.Fatalf("全局任务档位金额错误,期望 6550 实际 %d", tierProgress.OrderAmount)
|
||||
}
|
||||
}
|
||||
|
||||
func TestTimeWindow_ActivityPeriod(t *testing.T) {
|
||||
repo, err := mysql.NewSQLiteRepoForTest()
|
||||
if err != nil {
|
||||
|
||||
@ -682,6 +682,7 @@ func TestGetUserProgress_ActivityFilter_Integration(t *testing.T) {
|
||||
total_amount INTEGER NOT NULL DEFAULT 0,
|
||||
actual_amount INTEGER NOT NULL DEFAULT 0,
|
||||
remark TEXT,
|
||||
paid_at DATETIME,
|
||||
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
||||
deleted_at DATETIME
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user