fix:修复多个单元测试发现的bug
This commit is contained in:
1 parent
c76991e874
commit
941ba902f6
15 files changed
+124
-46
No files matched your search
@@ -49,7 +49,7 @@ type ChannelCreateReq struct {
|
||||
BaseURL string `json:"base_url" dc:"API 基础地址(留空使用供应商默认地址)"`
|
||||
ApiKey string `json:"api_key" v:"required#请输入 API Key" dc:"API Key"`
|
||||
Priority int `json:"priority" d:"0" dc:"优先级"`
|
||||
Weight int `json:"weight" d:"100" v:"between:1,100" dc:"权重"`
|
||||
Weight int `json:"weight" d:"100" v:"between:0,100" dc:"权重"`
|
||||
TestModel string `json:"test_model" dc:"测试模型名"`
|
||||
Remark string `json:"remark" dc:"备注"`
|
||||
IsVIP bool `json:"is_vip" d:"false" dc:"是否VIP专属渠道"`
|
||||
|
||||
@@ -6,8 +6,8 @@ import "github.com/gogf/gf/v2/frame/g"
|
||||
|
||||
type UsageLogCleanupCreateReq struct {
|
||||
g.Meta `path:"/usage-logs/cleanup" method:"post" mime:"json" tags:"管理后台-日志清理" summary:"创建清理任务"`
|
||||
StartTime string `json:"start_time" v:"required|datetime" dc:"起始时间(RFC3339)"`
|
||||
EndTime string `json:"end_time" v:"required|datetime" dc:"截止时间(RFC3339)"`
|
||||
StartTime string `json:"start_time" v:"required" dc:"起始时间(RFC3339)"`
|
||||
EndTime string `json:"end_time" v:"required" dc:"截止时间(RFC3339)"`
|
||||
TenantID *int64 `json:"tenant_id,omitempty" dc:"指定租户(可选)"`
|
||||
ModelName string `json:"model_name,omitempty" dc:"指定模型(可选)"`
|
||||
Status string `json:"status,omitempty" dc:"指定状态(可选)"`
|
||||
|
||||
@@ -90,7 +90,10 @@ type TenantProjectApiKeyCreateReq struct {
|
||||
}
|
||||
|
||||
type TenantProjectApiKeyCreateRes struct {
|
||||
Data map[string]any `json:"data"`
|
||||
ID int64 `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Key string `json:"key"`
|
||||
KeyPrefix string `json:"key_prefix"`
|
||||
}
|
||||
|
||||
type TenantProjectApiKeyDeleteReq struct {
|
||||
|
||||
@@ -388,43 +388,45 @@ func (s *sAdmin) AdjustBalance(ctx context.Context, req *v1.AdminWalletAdjustReq
|
||||
amount := req.Amount
|
||||
description := req.Description
|
||||
|
||||
type walletRow struct {
|
||||
// 原子更新余额,避免并发竞态
|
||||
db := g.DB()
|
||||
updateQuery := "UPDATE bil_wallets SET balance = balance + ?, updated_at = ? WHERE tenant_id = ?"
|
||||
args := []interface{}{amount, gtime.Now(), tenantID}
|
||||
if amount < 0 {
|
||||
updateQuery += " AND balance >= ?"
|
||||
args = append(args, -amount)
|
||||
}
|
||||
result, err := db.Exec(ctx, updateQuery, args...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
affected, _ := result.RowsAffected()
|
||||
if affected == 0 {
|
||||
return nil, gerror.New("钱包不存在或余额不足")
|
||||
}
|
||||
|
||||
// 查询更新后的余额,用于记录流水
|
||||
var wallet struct {
|
||||
ID int64 `json:"id"`
|
||||
Balance float64 `json:"balance"`
|
||||
FrozenBalance float64 `json:"frozen_balance"`
|
||||
}
|
||||
var w *walletRow
|
||||
err := dao.BilWallets.Ctx(ctx).
|
||||
err = dao.BilWallets.Ctx(ctx).
|
||||
Where("tenant_id", tenantID).
|
||||
Fields("id, balance, frozen_balance").
|
||||
Scan(&w)
|
||||
if err != nil || w == nil {
|
||||
return nil, gerror.Newf("wallet not found for tenant %d", tenantID)
|
||||
}
|
||||
|
||||
// 检查扣减后余额是否为负
|
||||
if amount < 0 && w.Balance+amount < 0 {
|
||||
return nil, gerror.Newf("余额不足,当前余额 %.2f,无法扣减 %.2f", w.Balance, -amount)
|
||||
}
|
||||
|
||||
_, err = dao.BilWallets.Ctx(ctx).
|
||||
Where("id", w.ID).
|
||||
Data(do.BilWallets{
|
||||
Balance: w.Balance + amount,
|
||||
}).Update()
|
||||
Scan(&wallet)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// 记录流水(含变动后余额)
|
||||
balanceAfter := w.Balance + amount
|
||||
// 记录流水
|
||||
dao.BilTransactions.Ctx(ctx).Insert(do.BilTransactions{
|
||||
TenantId: tenantID,
|
||||
WalletId: w.ID,
|
||||
WalletId: wallet.ID,
|
||||
Type: "adjust",
|
||||
Amount: amount,
|
||||
BalanceAfter: balanceAfter,
|
||||
FrozenAfter: w.FrozenBalance,
|
||||
BalanceAfter: wallet.Balance,
|
||||
FrozenAfter: wallet.FrozenBalance,
|
||||
Description: description,
|
||||
})
|
||||
|
||||
|
||||
@@ -91,8 +91,15 @@ func (s *sAdmin) ErrorLogDetail(ctx context.Context, req *v1.ErrorLogDetailReq)
|
||||
|
||||
// ErrorLogResolve marks an error log as resolved.
|
||||
func (s *sAdmin) ErrorLogResolve(ctx context.Context, req *v1.ErrorLogResolveReq) (*v1.ErrorLogResolveRes, error) {
|
||||
count, err := dao.SysErrorLogs.Ctx(ctx).Where("id", req.Id).Count()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if count == 0 {
|
||||
return nil, common.NewNotFoundError("错误日志")
|
||||
}
|
||||
userID := common.GetCtxUserID(ctx)
|
||||
_, err := dao.SysErrorLogs.Ctx(ctx).
|
||||
_, err = dao.SysErrorLogs.Ctx(ctx).
|
||||
Where("id", req.Id).
|
||||
Data(g.Map{
|
||||
"resolved": true,
|
||||
|
||||
@@ -376,7 +376,14 @@ func (s *sAdmin) ListAnnouncements(ctx context.Context, req *v1.AnnouncementList
|
||||
|
||||
// PublishAnnouncement 发布公告
|
||||
func (s *sAdmin) PublishAnnouncement(ctx context.Context, req *v1.AnnouncementPublishReq) (*v1.AnnouncementPublishRes, error) {
|
||||
_, err := dao.NtfAnnouncements.Ctx(ctx).
|
||||
count, err := dao.NtfAnnouncements.Ctx(ctx).Where("id", req.Id).Count()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if count == 0 {
|
||||
return nil, common.NewNotFoundError("公告")
|
||||
}
|
||||
_, err = dao.NtfAnnouncements.Ctx(ctx).
|
||||
Where("id", req.Id).
|
||||
Data(do.NtfAnnouncements{
|
||||
Status: "published",
|
||||
|
||||
@@ -45,17 +45,16 @@ func (s *sAdmin) ListOrders(ctx context.Context, req *v1.OrderListReq) (*v1.Orde
|
||||
|
||||
// GetOrder 获取订单详情
|
||||
func (s *sAdmin) GetOrder(ctx context.Context, req *v1.OrderDetailReq) (*v1.OrderDetailRes, error) {
|
||||
var order map[string]any
|
||||
err := dao.OrdOrders.Ctx(ctx).
|
||||
record, err := dao.OrdOrders.Ctx(ctx).
|
||||
Where("id", req.Id).
|
||||
Scan(&order)
|
||||
if err = common.IgnoreScanNoRows(err); err != nil {
|
||||
One()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if order == nil {
|
||||
if record == nil {
|
||||
return nil, common.NewNotFoundError("订单")
|
||||
}
|
||||
return &v1.OrderDetailRes{Data: order}, nil
|
||||
return &v1.OrderDetailRes{Data: record.Map()}, nil
|
||||
}
|
||||
|
||||
// RefundOrder 发起退款
|
||||
|
||||
@@ -45,7 +45,14 @@ func (s *sAdmin) CreatePromoCode(ctx context.Context, req *v1.PromoCodeCreateReq
|
||||
|
||||
// UpdatePromoCode 更新优惠码
|
||||
func (s *sAdmin) UpdatePromoCode(ctx context.Context, req *v1.PromoCodeUpdateReq) (*v1.PromoCodeUpdateRes, error) {
|
||||
_, err := dao.OrdPromoCodes.Ctx(ctx).
|
||||
count, err := dao.OrdPromoCodes.Ctx(ctx).Where("id", req.Id).Count()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if count == 0 {
|
||||
return nil, common.NewNotFoundError("优惠码")
|
||||
}
|
||||
_, err = dao.OrdPromoCodes.Ctx(ctx).
|
||||
Where("id", req.Id).
|
||||
Data(req.Update).
|
||||
Update()
|
||||
|
||||
@@ -85,7 +85,14 @@ func (s *sAdmin) BatchCreateRedemptions(ctx context.Context, req *v1.RedemptionC
|
||||
|
||||
// DisableRedemption 禁用兑换码
|
||||
func (s *sAdmin) DisableRedemption(ctx context.Context, req *v1.RedemptionDisableReq) (*v1.RedemptionDisableRes, error) {
|
||||
_, err := dao.OrdRedemptions.Ctx(ctx).
|
||||
count, err := dao.OrdRedemptions.Ctx(ctx).Where("id", req.Id).Count()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if count == 0 {
|
||||
return nil, common.NewNotFoundError("兑换码")
|
||||
}
|
||||
_, err = dao.OrdRedemptions.Ctx(ctx).
|
||||
Where("id", req.Id).
|
||||
Where("status", "active").
|
||||
Data(do.OrdRedemptions{
|
||||
|
||||
@@ -160,7 +160,7 @@ func (s *sAdmin) CreateTenant(ctx context.Context, req *v1.TenantCreateReq) (*v1
|
||||
TenantId: tenantID,
|
||||
Balance: 0,
|
||||
FrozenBalance: 0,
|
||||
Currency: "CNY",
|
||||
Currency: "USD",
|
||||
}).Insert()
|
||||
if err != nil {
|
||||
return gerror.Wrapf(err, "create wallet")
|
||||
|
||||
@@ -10,6 +10,7 @@ import (
|
||||
|
||||
v1 "github.com/qianfree/team-api/api/admin/v1"
|
||||
"github.com/qianfree/team-api/internal/dao"
|
||||
"github.com/qianfree/team-api/internal/logic/common"
|
||||
do "github.com/qianfree/team-api/internal/model/do"
|
||||
)
|
||||
|
||||
@@ -22,6 +23,9 @@ func (s *sAdmin) UsageLogCleanupCreate(ctx context.Context, req *v1.UsageLogClea
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if startTime.After(endTime) {
|
||||
return nil, common.NewBadRequestError("起始时间不能晚于截止时间")
|
||||
}
|
||||
|
||||
batchSize := req.BatchSize
|
||||
if batchSize <= 0 {
|
||||
@@ -125,7 +129,14 @@ func (s *sAdmin) UsageLogCleanupList(ctx context.Context, req *v1.UsageLogCleanu
|
||||
}
|
||||
|
||||
func (s *sAdmin) UsageLogCleanupCancel(ctx context.Context, req *v1.UsageLogCleanupCancelReq) (*v1.UsageLogCleanupCancelRes, error) {
|
||||
_, err := dao.TskTasks.Ctx(ctx).
|
||||
count, err := dao.TskTasks.Ctx(ctx).Where("id", req.ID).Where("handler", "usage_log_cleanup").Count()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if count == 0 {
|
||||
return nil, common.NewNotFoundError("清理任务")
|
||||
}
|
||||
_, err = dao.TskTasks.Ctx(ctx).
|
||||
Where("id", req.ID).
|
||||
Where("handler", "usage_log_cleanup").
|
||||
Where("status", "pending").
|
||||
|
||||
@@ -129,7 +129,7 @@ func (s *sTenant) Register(ctx context.Context, req *v1.TenantRegisterReq) (*v1.
|
||||
TenantId: tenantID,
|
||||
Balance: 0,
|
||||
FrozenBalance: 0,
|
||||
Currency: "CNY",
|
||||
Currency: "USD",
|
||||
}).Insert()
|
||||
if err != nil {
|
||||
return gerror.Wrapf(err, "create wallet")
|
||||
|
||||
@@ -84,6 +84,10 @@ func (s *sTenant) ListMembers(ctx context.Context, req *v1.TenantMemberListReq)
|
||||
|
||||
// InviteMember generates an invitation link.
|
||||
func (s *sTenant) InviteMember(ctx context.Context, req *v1.TenantMemberInviteReq) (*v1.TenantMemberInviteRes, error) {
|
||||
role := middleware.GetUserRole(ctx)
|
||||
if role != "owner" && role != "admin" {
|
||||
return nil, common.NewForbiddenError("需要 owner 或 admin 权限")
|
||||
}
|
||||
tenantID := middleware.GetTenantID(ctx)
|
||||
creatorID := middleware.GetUserID(ctx)
|
||||
|
||||
@@ -359,6 +363,10 @@ func (s *sTenant) JoinByInvite(ctx context.Context, req *v1.TenantMemberJoinReq)
|
||||
|
||||
// CreateMember directly creates a member account within the tenant.
|
||||
func (s *sTenant) CreateMember(ctx context.Context, req *v1.TenantMemberCreateReq) (*v1.TenantMemberCreateRes, error) {
|
||||
role := middleware.GetUserRole(ctx)
|
||||
if role != "owner" && role != "admin" {
|
||||
return nil, common.NewForbiddenError("需要 owner 或 admin 权限")
|
||||
}
|
||||
tenantID := middleware.GetTenantID(ctx)
|
||||
|
||||
// Validate role
|
||||
@@ -465,6 +473,10 @@ func (s *sTenant) CreateMember(ctx context.Context, req *v1.TenantMemberCreateRe
|
||||
// RemoveMember removes a member from the tenant.
|
||||
// Revokes all API keys, anonymizes personal data, releases member model scopes.
|
||||
func (s *sTenant) RemoveMember(ctx context.Context, req *v1.TenantMemberRemoveReq) (*v1.TenantMemberRemoveRes, error) {
|
||||
role := middleware.GetUserRole(ctx)
|
||||
if role != "owner" && role != "admin" {
|
||||
return nil, common.NewForbiddenError("需要 owner 或 admin 权限")
|
||||
}
|
||||
tenantID := middleware.GetTenantID(ctx)
|
||||
currentUserID := middleware.GetUserID(ctx)
|
||||
memberID := req.Id
|
||||
@@ -597,6 +609,10 @@ func (s *sTenant) EnableMember(ctx context.Context, tenantID, userID int64) erro
|
||||
|
||||
// UpdateMemberRole updates a member's role.
|
||||
func (s *sTenant) UpdateMemberRole(ctx context.Context, req *v1.TenantMemberUpdateRoleReq) (*v1.TenantMemberUpdateRoleRes, error) {
|
||||
role := middleware.GetUserRole(ctx)
|
||||
if role != "owner" && role != "admin" {
|
||||
return nil, common.NewForbiddenError("需要 owner 或 admin 权限")
|
||||
}
|
||||
tenantID := middleware.GetTenantID(ctx)
|
||||
currentUserID := middleware.GetUserID(ctx)
|
||||
memberID := req.Id
|
||||
@@ -844,6 +860,10 @@ func (s *sTenant) ListMemberApiKeys(ctx context.Context, req *v1.TenantMemberApi
|
||||
|
||||
// ExportMembers exports the tenant member list as CSV or Excel.
|
||||
func (s *sTenant) ExportMembers(ctx context.Context, req *v1.TenantMemberExportReq) (*v1.TenantMemberExportRes, error) {
|
||||
role := middleware.GetUserRole(ctx)
|
||||
if role != "owner" && role != "admin" {
|
||||
return nil, common.NewForbiddenError("需要 owner 或 admin 权限")
|
||||
}
|
||||
tenantID := middleware.GetTenantID(ctx)
|
||||
|
||||
columns := []export.Column{
|
||||
|
||||
@@ -10,6 +10,7 @@ import (
|
||||
|
||||
v1 "github.com/qianfree/team-api/api/tenant/v1"
|
||||
"github.com/qianfree/team-api/internal/dao"
|
||||
"github.com/qianfree/team-api/internal/logic/common"
|
||||
"github.com/qianfree/team-api/internal/middleware"
|
||||
)
|
||||
|
||||
@@ -50,6 +51,10 @@ func (s *sTenant) MemberQuota(ctx context.Context, req *v1.TenantMemberQuotaReq)
|
||||
}
|
||||
|
||||
func (s *sTenant) MemberQuotaSet(ctx context.Context, req *v1.TenantMemberQuotaSetReq) (*v1.TenantMemberQuotaSetRes, error) {
|
||||
role := middleware.GetUserRole(ctx)
|
||||
if role != "owner" && role != "admin" {
|
||||
return nil, common.NewForbiddenError("需要 owner 或 admin 权限")
|
||||
}
|
||||
tenantID := middleware.GetTenantID(ctx)
|
||||
|
||||
if req.QuotaType == "periodic" && req.Period == "" {
|
||||
|
||||
@@ -79,6 +79,10 @@ func (s *sTenant) ProjectList(ctx context.Context, req *v1.TenantProjectListReq)
|
||||
|
||||
// ProjectCreate creates a new project for a tenant.
|
||||
func (s *sTenant) ProjectCreate(ctx context.Context, req *v1.TenantProjectCreateReq) (*v1.TenantProjectCreateRes, error) {
|
||||
role := middleware.GetUserRole(ctx)
|
||||
if role != "owner" && role != "admin" {
|
||||
return nil, common.NewForbiddenError("需要 owner 或 admin 权限")
|
||||
}
|
||||
tenantID := middleware.GetTenantID(ctx)
|
||||
userID := middleware.GetUserID(ctx)
|
||||
|
||||
@@ -113,6 +117,10 @@ func (s *sTenant) ProjectCreate(ctx context.Context, req *v1.TenantProjectCreate
|
||||
|
||||
// ProjectUpdate updates a project.
|
||||
func (s *sTenant) ProjectUpdate(ctx context.Context, req *v1.TenantProjectUpdateReq) (*v1.TenantProjectUpdateRes, error) {
|
||||
role := middleware.GetUserRole(ctx)
|
||||
if role != "owner" && role != "admin" {
|
||||
return nil, common.NewForbiddenError("需要 owner 或 admin 权限")
|
||||
}
|
||||
tenantID := middleware.GetTenantID(ctx)
|
||||
|
||||
var project *struct {
|
||||
@@ -162,6 +170,10 @@ func (s *sTenant) ProjectUpdate(ctx context.Context, req *v1.TenantProjectUpdate
|
||||
|
||||
// ProjectArchive archives a project and revokes all its keys.
|
||||
func (s *sTenant) ProjectArchive(ctx context.Context, req *v1.TenantProjectArchiveReq) (*v1.TenantProjectArchiveRes, error) {
|
||||
role := middleware.GetUserRole(ctx)
|
||||
if role != "owner" && role != "admin" {
|
||||
return nil, common.NewForbiddenError("需要 owner 或 admin 权限")
|
||||
}
|
||||
tenantID := middleware.GetTenantID(ctx)
|
||||
|
||||
var project *struct {
|
||||
@@ -447,12 +459,10 @@ func (s *sTenant) ProjectApiKeyCreate(ctx context.Context, req *v1.TenantProject
|
||||
}
|
||||
|
||||
return &v1.TenantProjectApiKeyCreateRes{
|
||||
Data: map[string]any{
|
||||
"id": id,
|
||||
"name": req.Name,
|
||||
"key": rawKey,
|
||||
"key_prefix": prefix,
|
||||
},
|
||||
ID: id,
|
||||
Name: req.Name,
|
||||
Key: rawKey,
|
||||
KeyPrefix: prefix,
|
||||
}, nil
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user