fix: align superadmin sort fields

This commit is contained in:
2026-01-17 09:14:34 +08:00
parent b796636b5d
commit 94a10a3af0
5 changed files with 743 additions and 10 deletions

View File

@@ -157,6 +157,116 @@ func (s *SuperTestSuite) Test_CreateTenant() {
})
}
func (s *SuperTestSuite) Test_ListTenantsSortAggregates() {
Convey("ListTenants sort by aggregates", s.T(), func() {
ctx := s.T().Context()
database.Truncate(ctx, s.DB, models.TableNameUser, models.TableNameTenant, models.TableNameTenantUser, models.TableNameOrder)
owner1 := &models.User{Username: "tenant_sort_owner_1"}
owner2 := &models.User{Username: "tenant_sort_owner_2"}
owner3 := &models.User{Username: "tenant_sort_owner_3"}
member := &models.User{Username: "tenant_sort_member"}
models.UserQuery.WithContext(ctx).Create(owner1, owner2, owner3, member)
tenant1 := &models.Tenant{UserID: owner1.ID, Code: "t-sort-1", Name: "Tenant Sort 1", Status: consts.TenantStatusVerified}
tenant2 := &models.Tenant{UserID: owner2.ID, Code: "t-sort-2", Name: "Tenant Sort 2", Status: consts.TenantStatusVerified}
tenant3 := &models.Tenant{UserID: owner3.ID, Code: "t-sort-3", Name: "Tenant Sort 3", Status: consts.TenantStatusVerified}
models.TenantQuery.WithContext(ctx).Create(tenant1, tenant2, tenant3)
models.TenantUserQuery.WithContext(ctx).Create(
&models.TenantUser{TenantID: tenant1.ID, UserID: owner1.ID, Role: types.Array[consts.TenantUserRole]{consts.TenantUserRoleMember}},
&models.TenantUser{TenantID: tenant2.ID, UserID: owner2.ID, Role: types.Array[consts.TenantUserRole]{consts.TenantUserRoleMember}},
&models.TenantUser{TenantID: tenant2.ID, UserID: member.ID, Role: types.Array[consts.TenantUserRole]{consts.TenantUserRoleMember}},
&models.TenantUser{TenantID: tenant3.ID, UserID: owner3.ID, Role: types.Array[consts.TenantUserRole]{consts.TenantUserRoleMember}},
&models.TenantUser{TenantID: tenant3.ID, UserID: owner1.ID, Role: types.Array[consts.TenantUserRole]{consts.TenantUserRoleMember}},
&models.TenantUser{TenantID: tenant3.ID, UserID: member.ID, Role: types.Array[consts.TenantUserRole]{consts.TenantUserRoleMember}},
)
models.OrderQuery.WithContext(ctx).Create(
&models.Order{
TenantID: tenant1.ID,
UserID: owner1.ID,
Type: consts.OrderTypeContentPurchase,
Status: consts.OrderStatusPaid,
AmountOriginal: 300,
AmountDiscount: 0,
AmountPaid: 300,
IdempotencyKey: "tenant-sort-income-1",
},
&models.Order{
TenantID: tenant2.ID,
UserID: owner2.ID,
Type: consts.OrderTypeContentPurchase,
Status: consts.OrderStatusPaid,
AmountOriginal: 100,
AmountDiscount: 0,
AmountPaid: 100,
IdempotencyKey: "tenant-sort-income-2",
},
&models.Order{
TenantID: tenant3.ID,
UserID: owner3.ID,
Type: consts.OrderTypeContentPurchase,
Status: consts.OrderStatusPaid,
AmountOriginal: 200,
AmountDiscount: 0,
AmountPaid: 200,
IdempotencyKey: "tenant-sort-income-3",
},
)
Convey("should sort by user_count asc", func() {
filter := &super_dto.TenantListFilter{
Pagination: requests.Pagination{Page: 1, Limit: 10},
Asc: lo.ToPtr("user_count"),
}
res, err := Super.ListTenants(ctx, filter)
So(err, ShouldBeNil)
items := res.Items.([]super_dto.TenantItem)
So(items[0].ID, ShouldEqual, tenant1.ID)
So(items[1].ID, ShouldEqual, tenant2.ID)
So(items[2].ID, ShouldEqual, tenant3.ID)
})
Convey("should sort by user_count desc", func() {
filter := &super_dto.TenantListFilter{
Pagination: requests.Pagination{Page: 1, Limit: 10},
Desc: lo.ToPtr("user_count"),
}
res, err := Super.ListTenants(ctx, filter)
So(err, ShouldBeNil)
items := res.Items.([]super_dto.TenantItem)
So(items[0].ID, ShouldEqual, tenant3.ID)
So(items[2].ID, ShouldEqual, tenant1.ID)
})
Convey("should sort by income_amount_paid_sum asc", func() {
filter := &super_dto.TenantListFilter{
Pagination: requests.Pagination{Page: 1, Limit: 10},
Asc: lo.ToPtr("income_amount_paid_sum"),
}
res, err := Super.ListTenants(ctx, filter)
So(err, ShouldBeNil)
items := res.Items.([]super_dto.TenantItem)
So(items[0].ID, ShouldEqual, tenant2.ID)
So(items[1].ID, ShouldEqual, tenant3.ID)
So(items[2].ID, ShouldEqual, tenant1.ID)
})
Convey("should sort by income_amount_paid_sum desc", func() {
filter := &super_dto.TenantListFilter{
Pagination: requests.Pagination{Page: 1, Limit: 10},
Desc: lo.ToPtr("income_amount_paid_sum"),
}
res, err := Super.ListTenants(ctx, filter)
So(err, ShouldBeNil)
items := res.Items.([]super_dto.TenantItem)
So(items[0].ID, ShouldEqual, tenant1.ID)
So(items[2].ID, ShouldEqual, tenant2.ID)
})
})
}
func (s *SuperTestSuite) Test_WithdrawalApproval() {
Convey("Withdrawal Approval", s.T(), func() {
ctx := s.T().Context()
@@ -546,6 +656,92 @@ func (s *SuperTestSuite) Test_FinanceAnomalies() {
})
}
func (s *SuperTestSuite) Test_FinanceAnomalySorting() {
Convey("Finance Anomaly Sorting", s.T(), func() {
ctx := s.T().Context()
database.Truncate(ctx, s.DB, models.TableNameOrder, models.TableNameTenant, models.TableNameUser)
now := time.Now().Truncate(time.Second)
userOld := &models.User{Username: "balance_old", Balance: -100, CreatedAt: now.Add(-2 * time.Hour)}
userNew := &models.User{Username: "balance_new", Balance: -200, CreatedAt: now.Add(-1 * time.Hour)}
models.UserQuery.WithContext(ctx).Create(userOld, userNew)
orderOwner := &models.User{Username: "order_anomaly_owner"}
models.UserQuery.WithContext(ctx).Create(orderOwner)
tenant := &models.Tenant{UserID: orderOwner.ID, Code: "t-anomaly-sort", Name: "Anomaly Sort Tenant", Status: consts.TenantStatusVerified}
models.TenantQuery.WithContext(ctx).Create(tenant)
order1 := &models.Order{
TenantID: tenant.ID,
UserID: orderOwner.ID,
Type: consts.OrderTypeContentPurchase,
Status: consts.OrderStatusPaid,
AmountOriginal: 100,
AmountDiscount: 0,
AmountPaid: 100,
IdempotencyKey: "anomaly-sort-1",
}
order2 := &models.Order{
TenantID: tenant.ID,
UserID: orderOwner.ID,
Type: consts.OrderTypeContentPurchase,
Status: consts.OrderStatusPaid,
AmountOriginal: 200,
AmountDiscount: 0,
AmountPaid: 200,
IdempotencyKey: "anomaly-sort-2",
}
models.OrderQuery.WithContext(ctx).Create(order1, order2)
Convey("should sort balance anomalies by created_at asc", func() {
filter := &super_dto.SuperBalanceAnomalyFilter{
Pagination: requests.Pagination{Page: 1, Limit: 10},
Asc: lo.ToPtr("created_at"),
}
res, err := Super.ListBalanceAnomalies(ctx, filter)
So(err, ShouldBeNil)
items := res.Items.([]super_dto.SuperBalanceAnomalyItem)
So(items[0].UserID, ShouldEqual, userOld.ID)
So(items[1].UserID, ShouldEqual, userNew.ID)
})
Convey("should sort balance anomalies by user_id desc", func() {
filter := &super_dto.SuperBalanceAnomalyFilter{
Pagination: requests.Pagination{Page: 1, Limit: 10},
Desc: lo.ToPtr("user_id"),
}
res, err := Super.ListBalanceAnomalies(ctx, filter)
So(err, ShouldBeNil)
items := res.Items.([]super_dto.SuperBalanceAnomalyItem)
So(items[0].UserID, ShouldEqual, userNew.ID)
})
Convey("should sort order anomalies by order_id asc", func() {
filter := &super_dto.SuperOrderAnomalyFilter{
Pagination: requests.Pagination{Page: 1, Limit: 10},
Asc: lo.ToPtr("order_id"),
}
res, err := Super.ListOrderAnomalies(ctx, filter)
So(err, ShouldBeNil)
items := res.Items.([]super_dto.SuperOrderAnomalyItem)
So(items[0].OrderID, ShouldEqual, order1.ID)
So(items[1].OrderID, ShouldEqual, order2.ID)
})
Convey("should sort order anomalies by order_id desc", func() {
filter := &super_dto.SuperOrderAnomalyFilter{
Pagination: requests.Pagination{Page: 1, Limit: 10},
Desc: lo.ToPtr("order_id"),
}
res, err := Super.ListOrderAnomalies(ctx, filter)
So(err, ShouldBeNil)
items := res.Items.([]super_dto.SuperOrderAnomalyItem)
So(items[0].OrderID, ShouldEqual, order2.ID)
})
})
}
func (s *SuperTestSuite) Test_TenantHealth() {
Convey("TenantHealth", s.T(), func() {
ctx := s.T().Context()
@@ -597,7 +793,7 @@ func (s *SuperTestSuite) Test_TenantHealth() {
},
)
now := time.Now()
now := time.Now().Truncate(time.Second)
models.OrderQuery.WithContext(ctx).Create(
&models.Order{
TenantID: tenant1.ID,
@@ -648,6 +844,115 @@ func (s *SuperTestSuite) Test_TenantHealth() {
})
}
func (s *SuperTestSuite) Test_HealthOverview() {
Convey("HealthOverview", s.T(), func() {
ctx := s.T().Context()
database.Truncate(
ctx,
s.DB,
models.TableNameUser,
models.TableNameTenant,
models.TableNameTenantUser,
models.TableNameContent,
models.TableNameOrder,
models.TableNameMediaAsset,
)
owner := &models.User{Username: "health_overview_owner"}
models.UserQuery.WithContext(ctx).Create(owner)
tenant := &models.Tenant{
UserID: owner.ID,
Name: "Health Overview",
Code: "health_overview",
Status: consts.TenantStatusVerified,
}
models.TenantQuery.WithContext(ctx).Create(tenant)
models.TenantUserQuery.WithContext(ctx).Create(&models.TenantUser{
TenantID: tenant.ID,
UserID: owner.ID,
})
models.ContentQuery.WithContext(ctx).Create(&models.Content{
TenantID: tenant.ID,
UserID: owner.ID,
Title: "Health Content",
Status: consts.ContentStatusPublished,
})
now := time.Now()
models.OrderQuery.WithContext(ctx).Create(
&models.Order{
TenantID: tenant.ID,
UserID: owner.ID,
Type: consts.OrderTypeContentPurchase,
Status: consts.OrderStatusPaid,
AmountPaid: 1000,
PaidAt: now,
CreatedAt: now,
},
&models.Order{
TenantID: tenant.ID,
UserID: owner.ID,
Type: consts.OrderTypeContentPurchase,
Status: consts.OrderStatusFailed,
AmountPaid: 1000,
UpdatedAt: now,
CreatedAt: now,
},
)
models.MediaAssetQuery.WithContext(ctx).Create(
&models.MediaAsset{
TenantID: tenant.ID,
UserID: owner.ID,
ObjectKey: "failed.mp4",
Type: consts.MediaAssetTypeVideo,
Status: consts.MediaAssetStatusFailed,
CreatedAt: now,
UpdatedAt: now,
},
&models.MediaAsset{
TenantID: tenant.ID,
UserID: owner.ID,
ObjectKey: "ready.mp4",
Type: consts.MediaAssetTypeVideo,
Status: consts.MediaAssetStatusReady,
CreatedAt: now,
UpdatedAt: now,
},
&models.MediaAsset{
TenantID: tenant.ID,
UserID: owner.ID,
ObjectKey: "processing.mp4",
Type: consts.MediaAssetTypeVideo,
Status: consts.MediaAssetStatusProcessing,
CreatedAt: now.Add(-48 * time.Hour),
UpdatedAt: now.Add(-48 * time.Hour),
},
)
startAt := now.AddDate(0, 0, -7).Format(time.RFC3339)
endAt := now.Add(time.Second).Format(time.RFC3339)
filter := &super_dto.SuperHealthOverviewFilter{
TenantID: &tenant.ID,
StartAt: &startAt,
EndAt: &endAt,
UploadStuckHours: lo.ToPtr(int64(24)),
}
res, err := Super.HealthOverview(ctx, filter)
So(err, ShouldBeNil)
So(res.TenantTotal, ShouldEqual, 1)
So(res.OrderTotal, ShouldEqual, 2)
So(res.OrderFailed, ShouldEqual, 1)
So(res.UploadTotal, ShouldEqual, 3)
So(res.UploadFailed, ShouldEqual, 1)
So(res.UploadProcessingStuck, ShouldEqual, 1)
})
}
func (s *SuperTestSuite) Test_ContentReview() {
Convey("ContentReview", s.T(), func() {
ctx := s.T().Context()