[REF-1467] fix: dynamic billing bugs for Kling/Wan/Fish/Fal/NanoBanana tools#2251
[REF-1467] fix: dynamic billing bugs for Kling/Wan/Fish/Fal/NanoBanana tools#2251alchemistklk wants to merge 1 commit intomainfrom
Conversation
…a tools Fix 6 code-level bugs in the dynamic billing engine affecting 10 tools: 1. getFieldTypeFromSchema: add oneOf/anyOf composite schema support with path-aware branch selection; fail-fast for $ref/allOf 2. Pricing tier matching: replace strict === with matchesTierValue() using strict-decimal-only coercion (no hex/empty false positives) 3. unitField validation: fail-closed when unitField not found in schema, with phase-aware lazy parsing 4. Video category: add 'video' to extractAndAggregateValue array branch 5. Per-rule finite validation: throw with actionable context on NaN/Infinity 6. billing.service: fix discountedPrice condition (> 0 → !== undefined), change default from 1 to 0, add source flags + warning policy, validate inputs, add finiteness guards 88 tests passing (73 calculation + 15 service). Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
📝 WalkthroughWalkthroughRefactors the billing service to validate direct pricing inputs, introduce explicit billing source tracking, and enhance schema-aware billing calculations. Adds comprehensive test suites covering pricing paths, dynamic and legacy billing fallbacks, free toolset handling, and schema traversal scenarios. Changes
Sequence DiagramsequenceDiagram
participant Client
participant BillingService
participant DirectPrice as Direct Price<br/>Validator
participant DynamicCalc as Dynamic<br/>Calculator
participant LegacyBilling as Legacy<br/>Billing
participant Cache as Redis<br/>Cache
Client->>BillingService: processBilling(input)
activate BillingService
BillingService->>DirectPrice: Validate direct price input
alt Direct price provided & valid
DirectPrice-->>BillingService: finalDiscountedPrice set
BillingService->>BillingService: resolvedFromDirectPrice = true
else Direct price invalid
DirectPrice-->>BillingService: error (invalid finite value)
else No direct price
BillingService->>BillingService: Check explicit no-charge
alt No-charge enabled
BillingService->>BillingService: resolvedFromExplicitNoCharge = true
else Try dynamic billing
BillingService->>DynamicCalc: calculateCreditsFromRules(schemas)
alt Dynamic succeeds
DynamicCalc-->>BillingService: finalDiscountedPrice updated
BillingService->>BillingService: resolvedFromDynamic = true
else Dynamic fails
BillingService->>LegacyBilling: calculateCredits fallback
LegacyBilling->>Cache: Query accumulator
Cache-->>LegacyBilling: usage data
LegacyBilling-->>BillingService: legacy credits
BillingService->>BillingService: resolvedFromLegacyBilling = true
end
end
end
BillingService->>BillingService: Apply free access override
BillingService->>BillingService: Final validation (non-finite → 0)
BillingService-->>Client: pricing result with source flags
deactivate BillingService
Estimated Code Review Effort🎯 4 (Complex) | ⏱️ ~45 minutes Possibly Related PRs
Suggested Reviewers
Poem
🚥 Pre-merge checks | ✅ 3✅ Passed checks (3 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches
🧪 Generate unit tests (beta)
Tip Try Coding Plans. Let us write the prompt for your AI agent so you can ship faster (with fewer bugs). Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
🧹 Nitpick comments (1)
apps/api/src/modules/tool/billing/billing.service.ts (1)
481-488: Consider using the_appliedFreeAccessOverrideflag.The
_appliedFreeAccessOverridevariable is assigned but not used. If this is intended for future logging or debugging, consider adding it to the audit trail or removing the underscore prefix if it should be used.💡 Suggestion: Use the flag for observability
let _appliedFreeAccessOverride = false; if (FREE_TOOLSET_KEYS.includes(toolsetKey) && finalDiscountedPrice > 0) { const hasFreeToolAccess = await this.checkFreeToolAccess(uid); if (hasFreeToolAccess) { _appliedFreeAccessOverride = true; finalDiscountedPrice = 0; + this.logger.debug( + `Free access override applied for ${toolsetKey}:${toolName}, uid=${uid}`, + ); } }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@apps/api/src/modules/tool/billing/billing.service.ts` around lines 481 - 488, The variable _appliedFreeAccessOverride is set when FREE_TOOLSET_KEYS includes toolsetKey and checkFreeToolAccess(uid) returns true but never used; either remove it entirely or surface it for observability by passing it into the existing audit/log call (or adding one) alongside finalDiscountedPrice and toolsetKey so callers can see that free-access override was applied; if you intend it as a public flag rename it (appliedFreeAccessOverride) and include it in the payload sent to the audit/event method or in processLogger.debug to avoid dead/underscored variables.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Nitpick comments:
In `@apps/api/src/modules/tool/billing/billing.service.ts`:
- Around line 481-488: The variable _appliedFreeAccessOverride is set when
FREE_TOOLSET_KEYS includes toolsetKey and checkFreeToolAccess(uid) returns true
but never used; either remove it entirely or surface it for observability by
passing it into the existing audit/log call (or adding one) alongside
finalDiscountedPrice and toolsetKey so callers can see that free-access override
was applied; if you intend it as a public flag rename it
(appliedFreeAccessOverride) and include it in the payload sent to the
audit/event method or in processLogger.debug to avoid dead/underscored
variables.
ℹ️ Review info
Configuration used: defaults
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (4)
apps/api/src/modules/tool/billing/billing.service.spec.tsapps/api/src/modules/tool/billing/billing.service.tsapps/api/src/modules/tool/utils/billing-calculation.spec.tsapps/api/src/modules/tool/utils/billing-calculation.ts
Code reviewFound 2 issues:
refly/apps/api/src/modules/tool/billing/billing.service.spec.ts Lines 124 to 130 in 592635f Production call for reference (note argument positions): refly/apps/api/src/modules/tool/billing/billing.service.ts Lines 672 to 683 in 592635f
refly/apps/api/src/modules/tool/billing/billing.service.ts Lines 480 to 488 in 592635f 🤖 Generated with Claude Code - If this code review was useful, please react with 👍. Otherwise, react with 👎. |
|
✅ Claude Code Reviewer (PASS) for REF-1467 No blocking findings were reported in the latest review run. Generated by openclio monitor. |
Summary
oneOf/anyOfschema support with path-aware branch selection ingetFieldTypeFromSchemamatchesTierValue)unitFieldvalidation with phase-aware lazy schema parsingvideocategory toextractAndAggregateValuearray aggregationprocessBilling: changediscountedPrice > 0→!== undefined, default from 1 → 0, add source flags + warning policy, validate inputs, add finiteness guardsTest plan
billing.service.spec.ts)🤖 Generated with Claude Code
Summary by CodeRabbit
Bug Fixes
Improvements