mirror of
https://github.com/Wei-Shaw/sub2api.git
synced 2026-10-14 12:02:27 +08:00
fix(billing): resolve shadow credential tier contract
This commit is contained in:
@@ -3001,6 +3001,50 @@ func TestOpenAIGatewayServiceRecordUsage_CodexDefaultEchoKeepsFastBilling(t *tes
|
||||
}
|
||||
}
|
||||
|
||||
func TestOpenAIGatewayServiceRecordUsage_ShadowUsesParentCredentialTierContract(t *testing.T) {
|
||||
usageRepo := &openAIRecordUsageLogRepoStub{inserted: true}
|
||||
svc := newOpenAIRecordUsageServiceForTest(
|
||||
usageRepo,
|
||||
&openAIRecordUsageUserRepoStub{},
|
||||
&openAIRecordUsageSubRepoStub{},
|
||||
nil,
|
||||
)
|
||||
parentID := int64(9001)
|
||||
accountRepo := &openAIRecordUsageAccountRepoStub{account: &Account{
|
||||
ID: parentID, Platform: PlatformOpenAI, Type: AccountTypeOAuth,
|
||||
}}
|
||||
svc.accountRepo = accountRepo
|
||||
serviceTier := "priority"
|
||||
tokens := UsageTokens{InputTokens: 100, OutputTokens: 50}
|
||||
|
||||
err := svc.RecordUsage(context.Background(), &OpenAIRecordUsageInput{
|
||||
Result: &OpenAIForwardResult{
|
||||
RequestID: "resp_shadow_codex_default_echo",
|
||||
ServiceTier: &serviceTier,
|
||||
UpstreamResponseServiceTier: "default",
|
||||
Usage: OpenAIUsage{InputTokens: tokens.InputTokens, OutputTokens: tokens.OutputTokens},
|
||||
Model: "gpt-5.6-sol",
|
||||
Duration: time.Second,
|
||||
},
|
||||
APIKey: &APIKey{ID: 1020},
|
||||
User: &User{ID: 2020},
|
||||
Account: &Account{
|
||||
ID: 3020, Platform: PlatformOpenAI, Type: AccountTypeAPIKey,
|
||||
ParentAccountID: &parentID,
|
||||
},
|
||||
})
|
||||
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, 1, accountRepo.calls)
|
||||
require.NotNil(t, usageRepo.lastLog)
|
||||
require.NotNil(t, usageRepo.lastLog.ServiceTier)
|
||||
require.Equal(t, "priority", *usageRepo.lastLog.ServiceTier)
|
||||
|
||||
fastCost, calcErr := svc.billingService.CalculateCostWithServiceTier("gpt-5.6-sol", tokens, 1.0, "priority")
|
||||
require.NoError(t, calcErr)
|
||||
require.InDelta(t, fastCost.TotalCost, usageRepo.lastLog.TotalCost, 1e-10)
|
||||
}
|
||||
|
||||
func TestOpenAIGatewayServiceRecordUsage_ServiceTierNeverRaisedByUpstreamResponse(t *testing.T) {
|
||||
usageRepo := &openAIRecordUsageLogRepoStub{inserted: true}
|
||||
userRepo := &openAIRecordUsageUserRepoStub{}
|
||||
|
||||
@@ -143,10 +143,14 @@ func (s *OpenAIGatewayService) RecordUsage(ctx context.Context, input *OpenAIRec
|
||||
user := input.User
|
||||
account := input.Account
|
||||
subscription := input.Subscription
|
||||
billingAccount, err := resolveCredentialAccount(ctx, s.accountRepo, account)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !isGrokVideoUsageResult(result, nil) {
|
||||
ApplyOpenAIImageBillingResolution(result)
|
||||
}
|
||||
logServiceTierBillingDowngrade("service.openai_gateway", account, result.RequestID, ApplyOpenAIServiceTierBillingResolution(account, result))
|
||||
logServiceTierBillingDowngrade("service.openai_gateway", account, result.RequestID, ApplyOpenAIServiceTierBillingResolution(billingAccount, result))
|
||||
|
||||
// OpenAI input_tokens 是总输入,包含缓存读取和缓存写入明细。
|
||||
// 将三类 token 拆成互斥桶,避免缓存写入同时按普通输入和 cache_write 重复计费。
|
||||
@@ -183,7 +187,6 @@ func (s *OpenAIGatewayService) RecordUsage(ctx context.Context, input *OpenAIRec
|
||||
videoMultiplier := resolveVideoRateMultiplier(apiKey, baseMultiplier)
|
||||
|
||||
var cost *CostBreakdown
|
||||
var err error
|
||||
billingModel := forwardResultBillingModel(result.Model, result.UpstreamModel)
|
||||
if result.BillingModel != "" {
|
||||
billingModel = strings.TrimSpace(result.BillingModel)
|
||||
@@ -207,13 +210,6 @@ func (s *OpenAIGatewayService) RecordUsage(ctx context.Context, input *OpenAIRec
|
||||
if result.ServiceTier != nil {
|
||||
serviceTier = strings.TrimSpace(*result.ServiceTier)
|
||||
}
|
||||
billingAccount := account
|
||||
if account.IsShadow() {
|
||||
billingAccount, err = resolveCredentialAccount(ctx, s.accountRepo, account)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
longContextBillingGate := openAILongContextBillingGate(billingAccount)
|
||||
cost, err = s.calculateOpenAIRecordUsageCost(
|
||||
ctx,
|
||||
|
||||
Reference in New Issue
Block a user