From 0818f552357a09b67bfeed1fbe7f56d5cf68dbca Mon Sep 17 00:00:00 2001 From: wangbo Date: Wed, 22 Jul 2026 00:57:50 +0800 Subject: [PATCH] =?UTF-8?q?fix(billing):=20=E4=BF=9D=E7=95=99=E8=A7=84?= =?UTF-8?q?=E5=88=99=E9=9B=86=E6=9C=AA=E8=A6=86=E7=9B=96=E7=9A=84=E5=9F=BA?= =?UTF-8?q?=E7=A1=80=E8=B5=84=E6=BA=90=E4=BB=B7=E6=A0=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/api/internal/store/billing_config.go | 10 +++++--- .../api/internal/store/billing_config_test.go | 25 +++++++++++++++++++ 2 files changed, 32 insertions(+), 3 deletions(-) diff --git a/apps/api/internal/store/billing_config.go b/apps/api/internal/store/billing_config.go index 9cb1114..cbf8d19 100644 --- a/apps/api/internal/store/billing_config.go +++ b/apps/api/internal/store/billing_config.go @@ -17,12 +17,16 @@ type EffectiveBillingConfigInput struct { func ResolveEffectiveBillingConfig(input EffectiveBillingConfigInput) map[string]any { config := mergeObjects(input.BaseConfig, nil) if len(input.InheritedRuleSetConfig) > 0 { - config = mergeObjects(input.InheritedRuleSetConfig, nil) + // Rule sets are allowed to cover only a subset of resource types. Keep + // base-model prices for resources that the inherited rule set does not + // define, while letting the rule set remain authoritative for matching + // top-level keys. + config = mergeObjects(config, input.InheritedRuleSetConfig) } else if len(input.LegacyPlatformModelConfig) > 0 { - config = mergeObjects(input.LegacyPlatformModelConfig, nil) + config = mergeObjects(config, input.LegacyPlatformModelConfig) } if len(input.ModelRuleSetConfig) > 0 { - config = mergeObjects(input.ModelRuleSetConfig, nil) + config = mergeObjects(config, input.ModelRuleSetConfig) } return mergeObjects(config, input.Override) } diff --git a/apps/api/internal/store/billing_config_test.go b/apps/api/internal/store/billing_config_test.go index 67be617..06a8ddc 100644 --- a/apps/api/internal/store/billing_config_test.go +++ b/apps/api/internal/store/billing_config_test.go @@ -62,6 +62,31 @@ func TestResolveEffectiveBillingConfigAppliesOverrideLast(t *testing.T) { } } +func TestResolveEffectiveBillingConfigPreservesBaseResourcesMissingFromRuleSet(t *testing.T) { + config := ResolveEffectiveBillingConfig(EffectiveBillingConfigInput{ + BaseConfig: map[string]any{ + "music": map[string]any{"basePrice": float64(20)}, + "audio": map[string]any{"basePrice": float64(1)}, + "video": map[string]any{"basePrice": float64(100)}, + }, + InheritedRuleSetConfig: map[string]any{ + "video": map[string]any{"basePrice": float64(416)}, + }, + }) + + assertBillingBasePrice(t, config, "music", 20) + assertBillingBasePrice(t, config, "audio", 1) + assertBillingBasePrice(t, config, "video", 416) +} + +func assertBillingBasePrice(t *testing.T, config map[string]any, resource string, want float64) { + t.Helper() + resourceConfig, ok := config[resource].(map[string]any) + if !ok || resourceConfig["basePrice"] != want { + t.Fatalf("%s base price = %#v, want %v", resource, config[resource], want) + } +} + func videoBillingConfig(basePrice float64) map[string]any { return map[string]any{ "video": map[string]any{"basePrice": basePrice},