Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
85 commits
Select commit Hold shift + click to select a range
6dd933c
预付款退款退还已使用额度
qqjyy Apr 20, 2026
f32dc37
Merge pull request #1 from lynxtoncloud/stc
cts926 Apr 20, 2026
b796bdb
暂时用回监听机制
qqjyy Apr 20, 2026
e7dea72
Merge pull request #2 from lynxtoncloud/stc
cts926 Apr 20, 2026
8387c46
改变消费趋势时间范围
qqjyy Apr 20, 2026
1217fec
增加设置模型显示名称和模型输出类型
qqjyy Apr 21, 2026
cc68b83
增加prcing结构字段Modalities和DisplayName
qqjyy Apr 21, 2026
dc38021
Merge pull request #3 from lynxtoncloud/stc
cts926 Apr 21, 2026
c38d070
将企业折扣加入计费过程
qqjyy Apr 21, 2026
f619448
商业折扣应用于扣款
qqjyy Apr 22, 2026
babfc6d
更换商业折扣在计费流程的使用
qqjyy Apr 22, 2026
b83a5e8
增加应用折扣日志
qqjyy Apr 22, 2026
06a52d2
增加日志
qqjyy Apr 22, 2026
4456da0
增加日志
qqjyy Apr 23, 2026
6aa098f
更改getUserOrgDiscount使用表名
qqjyy Apr 23, 2026
79799c8
预扣费应用企业折扣,同时文本图片音频模型差额结算也应用企业折扣
qqjyy Apr 23, 2026
4049e3c
Merge remote-tracking branch 'origin/stc' into stc
Apr 23, 2026
c4a7c3c
fmj-4/23-登录不允许不同设备同时登录,7天登录有效期。聊天界面和模型界面适配手机端
Apr 23, 2026
b7303d7
Merge remote-tracking branch 'origin/stc' into stc
Apr 23, 2026
3a4d4c5
增加预扣款时应用企业折扣的具体日志
qqjyy Apr 23, 2026
1054b6d
取消文本音频模型应用企业折扣增加日志
qqjyy Apr 23, 2026
9bca53c
Merge remote-tracking branch 'origin/stc' into fmj
Apr 23, 2026
8d3334d
Merge pull request #4 from lynxtoncloud/fmj
Azilier7 Apr 23, 2026
acf6bb5
添加对ModelDisplayName和ModelModalities的初始化和更新处理
qqjyy Apr 23, 2026
1dd5d23
Merge pull request #5 from lynxtoncloud/stc
cts926 Apr 23, 2026
456f8a2
增加当OriginModelName为空时尝试从其他字段获取
qqjyy Apr 23, 2026
1206d02
增加当OriginModelName为空时尝试从其他字段获取
qqjyy Apr 23, 2026
cf19679
Merge remote-tracking branch 'origin/stc' into stc
qqjyy Apr 23, 2026
468bf12
解决视频模型调用消耗日志显示有误
qqjyy Apr 23, 2026
c1ab061
解决视频模型调用应用企业折扣有误
qqjyy Apr 23, 2026
b19c58a
解决重复应用企业折扣
qqjyy Apr 24, 2026
50b2f37
解决重复应用企业折扣
qqjyy Apr 24, 2026
4bb54d6
解决视频模型应用企业折扣后补扣
qqjyy Apr 24, 2026
87f3978
解决视频模型应用企业折扣后补扣
qqjyy Apr 24, 2026
abbce9a
Merge pull request #6 from lynxtoncloud/stc
cts926 Apr 24, 2026
88cfdd0
增加调用NormalizeRecordedQuota日志显示
qqjyy Apr 24, 2026
4ffbe50
测试NormalizeRecordedQuota
qqjyy Apr 24, 2026
c5328df
修改discountRate为orgDiscountRate
qqjyy Apr 24, 2026
ff877a0
Merge pull request #7 from lynxtoncloud/stc
cts926 Apr 24, 2026
baeb385
限制令牌限额不能小于零
qqjyy Apr 28, 2026
6b18e41
Merge pull request #8 from lynxtoncloud/stc
cts926 Apr 28, 2026
2b57c75
修改管理日志显示货币符号,小数点后位数
qqjyy Apr 28, 2026
150a13d
增加model_img字段显示和敏感词报错
qqjyy Apr 29, 2026
9a6bad0
Merge pull request #9 from lynxtoncloud/stc
cts926 Apr 29, 2026
0e23eb4
将有企业的成员的充值面板撤去,新增企业充值面板,只有企业拥有者有权进行企业充值,企业普通成员无权访问企业充值面板
qqjyy Apr 29, 2026
33168dc
日志页面耗时字段改为余额字段
qqjyy Apr 29, 2026
c34eecf
兑换码名字后加序号
qqjyy Apr 29, 2026
0f10fdf
Merge pull request #10 from lynxtoncloud/stc
cts926 Apr 29, 2026
e0d9832
限流中间件达到限流时返回具体"请求过于频繁,请稍后再试",限流条件改为同一IP一分钟20次
qqjyy Apr 30, 2026
e046cd5
修复:豆包图生视频请求的 content 项补齐 role,避免图片输入报 role 缺失错误
Yxin-art May 1, 2026
56c731c
修复:豆包视频任务仅对 image_url 设置 role,文本 content 禁止携带 role
Yxin-art May 2, 2026
67a54dc
fix(doubao): 视频任务图片统一为 reference_image
Yxin-art May 2, 2026
e84c31d
fix(doubao): 区分 r2v 与 i2v,修复 seedance 1.0 Pro 的 task_type
Yxin-art May 2, 2026
5e073fb
fix(doubao): 1.5 Pro 与 1.0 Pro 一样不走 r2v
Yxin-art May 2, 2026
fe0ea76
Merge remote-tracking branch 'origin/main' into stc
qqjyy May 6, 2026
b796d72
修改日志显示的余额
qqjyy May 6, 2026
02ebc73
修改退还用户已用额度
qqjyy May 6, 2026
ee9245c
任务提交失败时,无需退还用户已用额度
qqjyy May 6, 2026
36d28d3
异步任务资金调整改为强制立即写库
qqjyy May 6, 2026
ea1bd95
异步任务资金调整改回批量写库策略,日志快照按“数据库余额 + 未落库变更”记录。
qqjyy May 6, 2026
957bfad
Merge pull request #11 from lynxtoncloud/stc
cts926 May 6, 2026
5c82499
fix(doubao):视频任务图片支持裸 base64 并保留 metadata 中的 image_url role
Yxin-art May 7, 2026
8da1cc1
Merge branch 'dev2.0'
Yxin-art May 7, 2026
b156871
stc-5/7-21.12修复空返回仍然算任务成功
qqjyy May 7, 2026
fabdfda
Merge pull request #12 from lynxtoncloud/stc
cts926 May 7, 2026
4211409
stc-5/7-22.01解决文本等模型二次应用企业折扣
qqjyy May 7, 2026
05aa22b
Merge pull request #13 from lynxtoncloud/stc
cts926 May 7, 2026
1d46970
stc-5/8-15:53为用户使用量聚合表添加end_at字段
qqjyy May 8, 2026
0ba4d37
Merge pull request #14 from lynxtoncloud/stc
cts926 May 8, 2026
5d8cf8c
stc-5/12-10:41 feat(gateway): 新增 /v1/responses 请求转 chat completions 上…
qqjyy May 12, 2026
884c78f
stc-5/12-10:51 feat(gateway): 新增 /v1/responses 请求转 chat completions 上…
qqjyy May 12, 2026
b22cc9c
stc-5/12-15:27 feat(usage): 新增个人与企业分钟级模型用量聚合表
qqjyy May 12, 2026
057e862
Merge pull request #15 from lynxtoncloud/stc
cts926 May 12, 2026
aca670f
stc-5/13-10:04 fix(auth): 使用 Redis 存储验证码避免多实例校验失效
qqjyy May 13, 2026
ecc7fc8
stc-5/13-10:35 feat(auth): 新增单设备登录配置开关
qqjyy May 13, 2026
635a77c
feat(ops): 计费快照写入 Gin 上下文供上游运维日志消费
Yxin-art May 13, 2026
5e49edd
stc-5/13-15:34 fix(channel): 保存渠道时规范化 Base URL
qqjyy May 13, 2026
05fe523
Merge pull request #16 from lynxtoncloud/stc
cts926 May 13, 2026
a6e0806
stc-5/13-18:07 fix(channel): 修复渠道多模型时除首个外报模型ID错误
qqjyy May 13, 2026
c733683
Merge pull request #17 from lynxtoncloud/stc
cts926 May 13, 2026
eb9d639
·
qqjyy May 14, 2026
90ff23e
stc-5/14-14:39 fix(token):令牌额度不足时,切换列表展示下一位可用令牌使用
qqjyy May 14, 2026
2e3d921
Merge pull request #18 from lynxtoncloud/stc
cts926 May 14, 2026
c36449a
feat(logging): add GinLogWriterFactory hook for structured gin log ro…
Yxin-art May 14, 2026
5ce5a8a
stc-5/15-11:46 fix(logquota): 使用兑换码充值后,日志表记录的数据加上充值的具体金额
qqjyy May 15, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion common/constants.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ var WeChatAuthEnabled = false
var TelegramOAuthEnabled = false
var TurnstileCheckEnabled = false
var RegisterEnabled = true
var SingleDeviceLoginEnabled = true

var EmailDomainRestrictionEnabled = false // 是否启用邮箱域名限制
var EmailAliasRestrictionEnabled = false // 是否启用邮箱别名限制
Expand Down Expand Up @@ -173,7 +174,7 @@ var (

CriticalRateLimitEnable bool
CriticalRateLimitNum = 20
CriticalRateLimitDuration int64 = 20 * 60
CriticalRateLimitDuration int64 = 60

UploadRateLimitNum = 10
UploadRateLimitDuration int64 = 60
Expand Down
14 changes: 14 additions & 0 deletions common/gin_log_writer_factory.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package common

import (
"io"
"os"
)

// GinLogWriterFactory, when set by the host application (e.g. LynxtonAPI), is used by
// logger.SetupLogger to build gin.DefaultWriter and gin.DefaultErrorWriter instead of the
// default io.MultiWriter(stdout, file) / io.MultiWriter(stderr, file).
//
// Implementations should write human-readable legacy lines to logFile as needed and emit
// structured logs separately (e.g. JSON on stdout) so container collectors see one format.
var GinLogWriterFactory func(stdout io.Writer, logFile *os.File) (out io.Writer, errOut io.Writer)
2 changes: 1 addition & 1 deletion common/init.go
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@ func InitEnv() {

CriticalRateLimitEnable = GetEnvOrDefaultBool("CRITICAL_RATE_LIMIT_ENABLE", true)
CriticalRateLimitNum = GetEnvOrDefault("CRITICAL_RATE_LIMIT", 20)
CriticalRateLimitDuration = int64(GetEnvOrDefault("CRITICAL_RATE_LIMIT_DURATION", 20*60))
CriticalRateLimitDuration = int64(GetEnvOrDefault("CRITICAL_RATE_LIMIT_DURATION", 60))

SearchRateLimitEnable = GetEnvOrDefaultBool("SEARCH_RATE_LIMIT_ENABLE", true)
SearchRateLimitNum = GetEnvOrDefault("SEARCH_RATE_LIMIT", 10)
Expand Down
7 changes: 7 additions & 0 deletions common/ops_hook.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package common

import "context"

// EmitAsyncBillingOpsLog is an optional hook set by Lynxton (after applog.Init) to emit structured JSON
// for async task billing (worker has no *gin.Context). When nil, new-api stays silent on this channel.
var EmitAsyncBillingOpsLog func(ctx context.Context, msg string, kv map[string]any)
46 changes: 46 additions & 0 deletions common/verification.go
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
package common

import (
"context"
"errors"
"strings"
"sync"
"time"

"github.com/go-redis/redis/v8"
"github.com/google/uuid"
)

Expand All @@ -23,6 +26,8 @@ var verificationMap map[string]verificationValue
var verificationMapMaxSize = 10
var VerificationValidMinutes = 10

const verificationRedisKeyPrefix = "verification:"

func GenerateVerificationCode(length int) string {
code := uuid.New().String()
code = strings.Replace(code, "-", "", -1)
Expand All @@ -33,6 +38,15 @@ func GenerateVerificationCode(length int) string {
}

func RegisterVerificationCodeWithKey(key string, code string, purpose string) {
key = normalizeVerificationKey(key)
if RedisEnabled && RDB != nil {
err := RDB.Set(context.Background(), verificationRedisKey(key, purpose), code, verificationTTL()).Err()
if err == nil {
return
}
SysLog("failed to save verification code to Redis, falling back to memory: " + err.Error())
}

verificationMutex.Lock()
defer verificationMutex.Unlock()
verificationMap[purpose+key] = verificationValue{
Expand All @@ -45,6 +59,19 @@ func RegisterVerificationCodeWithKey(key string, code string, purpose string) {
}

func VerifyCodeWithKey(key string, code string, purpose string) bool {
key = normalizeVerificationKey(key)
code = strings.TrimSpace(code)
if RedisEnabled && RDB != nil {
value, err := RDB.Get(context.Background(), verificationRedisKey(key, purpose)).Result()
if err == nil {
return code == value
}
if errors.Is(err, redis.Nil) {
return false
}
SysLog("failed to read verification code from Redis, falling back to memory: " + err.Error())
}

verificationMutex.Lock()
defer verificationMutex.Unlock()
value, okay := verificationMap[purpose+key]
Expand All @@ -56,6 +83,13 @@ func VerifyCodeWithKey(key string, code string, purpose string) bool {
}

func DeleteKey(key string, purpose string) {
key = normalizeVerificationKey(key)
if RedisEnabled && RDB != nil {
if err := RDB.Del(context.Background(), verificationRedisKey(key, purpose)).Err(); err != nil {
SysLog("failed to delete verification code from Redis: " + err.Error())
}
}

verificationMutex.Lock()
defer verificationMutex.Unlock()
delete(verificationMap, purpose+key)
Expand All @@ -71,6 +105,18 @@ func removeExpiredPairs() {
}
}

func verificationRedisKey(key string, purpose string) string {
return verificationRedisKeyPrefix + purpose + ":" + key
}

func verificationTTL() time.Duration {
return time.Duration(VerificationValidMinutes) * time.Minute
}

func normalizeVerificationKey(key string) string {
return strings.ToLower(strings.TrimSpace(key))
}

func init() {
verificationMutex.Lock()
defer verificationMutex.Unlock()
Expand Down
1 change: 1 addition & 0 deletions constant/api_type.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ const (
APITypeTencent
APITypeGemini
APITypeZhipuV4

APITypeOllama
APITypePerplexity
APITypeAws
Expand Down
11 changes: 11 additions & 0 deletions constant/context_key.go
Original file line number Diff line number Diff line change
Expand Up @@ -66,4 +66,15 @@ const (
// ContextKeyLanguage stores the user's language preference for i18n
ContextKeyLanguage ContextKey = "language"
ContextKeyIsStream ContextKey = "is_stream"

/* enterprise discount related keys */
ContextKeyOrgID ContextKey = "org_id"
ContextKeyOrgDiscountRate ContextKey = "org_discount_rate"

// Ops billing snapshot (set by new-api/service before RecordConsumeLog; read by Lynxton relay_request_summary).
ContextKeyOpsBillingPromptTokens ContextKey = "ops_billing_prompt_tokens"
ContextKeyOpsBillingCompletionTokens ContextKey = "ops_billing_completion_tokens"
ContextKeyOpsBillingTotalTokens ContextKey = "ops_billing_total_tokens"
ContextKeyOpsBillingConsumeQuota ContextKey = "ops_billing_consume_quota"
ContextKeyOpsBillingSnapshotFrom ContextKey = "ops_billing_snapshot_from"
)
12 changes: 11 additions & 1 deletion controller/channel.go
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,14 @@ func clearChannelInfo(channel *model.Channel) {
}
}

func normalizeChannelBaseURL(channel *model.Channel) {
if channel == nil || channel.BaseURL == nil {
return
}
normalized := strings.TrimRight(strings.TrimSpace(*channel.BaseURL), "/")
channel.BaseURL = &normalized
}

func GetAllChannels(c *gin.Context) {
pageInfo := common.GetPageQuery(c)
channelData := make([]*model.Channel, 0)
Expand Down Expand Up @@ -403,7 +411,7 @@ func GetChannelKey(c *gin.Context) {
}

// 记录操作日志
model.RecordLog(userId, model.LogTypeSystem, fmt.Sprintf("查看渠道密钥信息 (渠道ID: %d)", channelId))
model.RecordLog(userId, model.LogTypeSystem, fmt.Sprintf("查看渠道密钥信息 (渠道ID: %d)", channelId), 0)

// 返回渠道密钥
c.JSON(http.StatusOK, gin.H{
Expand Down Expand Up @@ -570,6 +578,7 @@ func AddChannel(c *gin.Context) {
common.ApiError(c, err)
return
}
normalizeChannelBaseURL(addChannelRequest.Channel)

// 使用统一的校验函数
if err := validateChannel(addChannelRequest.Channel, true); err != nil {
Expand Down Expand Up @@ -846,6 +855,7 @@ func UpdateChannel(c *gin.Context) {
common.ApiError(c, err)
return
}
normalizeChannelBaseURL(&channel.Channel)

// 使用统一的校验函数
if err := validateChannel(&channel.Channel, false); err != nil {
Expand Down
2 changes: 1 addition & 1 deletion controller/checkin.go
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ func DoCheckin(c *gin.Context) {
})
return
}
model.RecordLog(userId, model.LogTypeSystem, fmt.Sprintf("用户签到,获得额度 %s", logger.LogQuota(checkin.QuotaAwarded)))
model.RecordLog(userId, model.LogTypeSystem, fmt.Sprintf("用户签到,获得额度 %s", logger.LogQuota(checkin.QuotaAwarded)), checkin.QuotaAwarded)
c.JSON(http.StatusOK, gin.H{
"success": true,
"message": "签到成功",
Expand Down
8 changes: 7 additions & 1 deletion controller/model.go
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,7 @@ func ListModels(c *gin.Context, modelType int) {
}
if oaiModel, ok := openAIModelsMap[allowModel]; ok {
oaiModel.SupportedEndpointTypes = model.GetModelSupportEndpointTypes(allowModel)
oaiModel.Modalities = ratio_setting.GetModelModalities(allowModel)
userOpenAiModels = append(userOpenAiModels, oaiModel)
} else {
userOpenAiModels = append(userOpenAiModels, dto.OpenAIModels{
Expand All @@ -149,6 +150,7 @@ func ListModels(c *gin.Context, modelType int) {
Created: 1626777600,
OwnedBy: "custom",
SupportedEndpointTypes: model.GetModelSupportEndpointTypes(allowModel),
Modalities: ratio_setting.GetModelModalities(allowModel),
})
}
}
Expand Down Expand Up @@ -189,6 +191,7 @@ func ListModels(c *gin.Context, modelType int) {
}
if oaiModel, ok := openAIModelsMap[modelName]; ok {
oaiModel.SupportedEndpointTypes = model.GetModelSupportEndpointTypes(modelName)
oaiModel.Modalities = ratio_setting.GetModelModalities(modelName)
userOpenAiModels = append(userOpenAiModels, oaiModel)
} else {
userOpenAiModels = append(userOpenAiModels, dto.OpenAIModels{
Expand All @@ -197,6 +200,7 @@ func ListModels(c *gin.Context, modelType int) {
Created: 1626777600,
OwnedBy: "custom",
SupportedEndpointTypes: model.GetModelSupportEndpointTypes(modelName),
Modalities: ratio_setting.GetModelModalities(modelName),
})
}
}
Expand Down Expand Up @@ -273,6 +277,8 @@ func RetrieveModel(c *gin.Context, modelType int) {
Type: "model",
})
default:
aiModel.SupportedEndpointTypes = model.GetModelSupportEndpointTypes(modelId)
aiModel.Modalities = ratio_setting.GetModelModalities(modelId)
c.JSON(200, aiModel)
}
} else {
Expand All @@ -286,4 +292,4 @@ func RetrieveModel(c *gin.Context, modelType int) {
"error": openAIError,
})
}
}
}
24 changes: 24 additions & 0 deletions controller/option.go
Original file line number Diff line number Diff line change
Expand Up @@ -306,6 +306,30 @@ func UpdateOption(c *gin.Context) {
})
return
}
case "ModelDisplayName":
if err = ratio_setting.UpdateModelDisplayNameByJSONString(option.Value.(string)); err != nil {
c.JSON(http.StatusOK, gin.H{
"success": false,
"message": "模型显示名称设置失败: " + err.Error(),
})
return
}
case "ModelModalities":
if err = ratio_setting.UpdateModelModalitiesByJSONString(option.Value.(string)); err != nil {
c.JSON(http.StatusOK, gin.H{
"success": false,
"message": "模型输出类型设置失败: " + err.Error(),
})
return
}
case "ModelImg":
if err = ratio_setting.UpdateModelImgByJSONString(option.Value.(string)); err != nil {
c.JSON(http.StatusOK, gin.H{
"success": false,
"message": "模型图片设置失败: " + err.Error(),
})
return
}
}
err = model.UpdateOption(option.Key, option.Value.(string))
if err != nil {
Expand Down
7 changes: 6 additions & 1 deletion controller/redemption.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package controller

import (
"fmt"
"net/http"
"strconv"
"unicode/utf8"
Expand Down Expand Up @@ -84,9 +85,13 @@ func AddRedemption(c *gin.Context) {
var keys []string
for i := 0; i < redemption.Count; i++ {
key := common.GetUUID()
name := redemption.Name
if redemption.Count > 1 {
name = fmt.Sprintf("%s_%d", redemption.Name, i+1)
}
cleanRedemption := model.Redemption{
UserId: c.GetInt("id"),
Name: redemption.Name,
Name: name,
Key: key,
CreatedTime: common.GetTimestamp(),
Quota: redemption.Quota,
Expand Down
4 changes: 3 additions & 1 deletion controller/relay.go
Original file line number Diff line number Diff line change
Expand Up @@ -568,6 +568,8 @@ func RelayTask(c *gin.Context) {
if settleErr := service.SettleBilling(c, relayInfo, result.Quota); settleErr != nil {
common.SysError("settle task billing error: " + settleErr.Error())
}
recordedQuota := service.NormalizeRecordedQuota(c, relayInfo, result.Quota)
relayInfo.PriceData.Quota = recordedQuota
service.LogTaskConsumption(c, relayInfo)

task := model.InitTask(result.Platform, relayInfo)
Expand All @@ -583,7 +585,7 @@ func RelayTask(c *gin.Context) {
OriginModelName: relayInfo.OriginModelName,
PerCallBilling: common.StringsContains(constant.TaskPricePatches, relayInfo.OriginModelName) || relayInfo.PriceData.UsePrice,
}
task.Quota = result.Quota
task.Quota = recordedQuota
task.Data = result.TaskData
task.Action = relayInfo.Action
if insertErr := task.Insert(); insertErr != nil {
Expand Down
2 changes: 1 addition & 1 deletion controller/secure_verification.go
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,7 @@ func UniversalVerify(c *gin.Context) {
}

// 记录日志
model.RecordLog(userId, model.LogTypeSystem, fmt.Sprintf("通用安全验证成功 (验证方式: %s)", verifyMethod))
model.RecordLog(userId, model.LogTypeSystem, fmt.Sprintf("通用安全验证成功 (验证方式: %s)", verifyMethod), 0)

c.JSON(http.StatusOK, gin.H{
"success": true,
Expand Down
3 changes: 3 additions & 0 deletions controller/topup.go
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,9 @@ func getMinTopup() int64 {
}

func RequestEpay(c *gin.Context) {
if blockEnterpriseTopupForNonOwner(c) {
return
}
var req EpayRequest
err := c.ShouldBindJSON(&req)
if err != nil {
Expand Down
3 changes: 3 additions & 0 deletions controller/topup_creem.go
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,9 @@ func (*CreemAdaptor) RequestPay(c *gin.Context, req *CreemPayRequest) {
}

func RequestCreemPay(c *gin.Context) {
if blockEnterpriseTopupForNonOwner(c) {
return
}
var req CreemPayRequest

// 读取body内容用于打印,同时保留原始数据供后续使用
Expand Down
Loading