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},