diff --git a/apps/studio/components/interfaces/Organization/BillingSettings/CreditBalance.tsx b/apps/studio/components/interfaces/Organization/BillingSettings/CreditBalance.tsx index ca1d7e2520..72a964c198 100644 --- a/apps/studio/components/interfaces/Organization/BillingSettings/CreditBalance.tsx +++ b/apps/studio/components/interfaces/Organization/BillingSettings/CreditBalance.tsx @@ -3,6 +3,7 @@ import { useParams } from 'common' import { CreditCodeRedemption } from './CreditCodeRedemption' import { CreditTopUp } from './CreditTopUp' +import { getTotalCreditBalanceCents } from './helpers' import { ScaffoldSection, ScaffoldSectionContent, @@ -31,13 +32,14 @@ const CreditBalance = () => { isSuccess, } = useOrgSubscriptionQuery({ orgSlug: slug }, { enabled: canReadSubscriptions }) - const customerBalance = (subscription?.customer_balance ?? 0) / 100 - const isCredit = customerBalance < 0 - const isDebt = customerBalance > 0 - const balance = - isCredit && customerBalance !== 0 - ? customerBalance.toFixed(2).toString().replace('-', '') - : customerBalance.toFixed(2) + const combinedCreditBalanceCents = getTotalCreditBalanceCents({ + customerBalance: subscription?.customer_balance, + prepaidCreditsBalance: subscription?.prepaid_credits_balance, + }) + const combinedCreditBalance = combinedCreditBalanceCents / 100 + const hasCredits = combinedCreditBalanceCents > 0 + const hasDebt = combinedCreditBalanceCents < 0 + const balance = Math.abs(combinedCreditBalance).toFixed(2) return ( @@ -47,8 +49,11 @@ const CreditBalance = () => {

Credit Balance

- Credits will be applied to future invoices, before charging your payment method. If your - credit balance runs out, your default payment method will be charged. + Credits will be applied to future invoices, before charging your payment method. This + balance includes purchased credits and any prorated credits from plan changes. +

+

+ If your credits run out, your default payment method will be charged.

@@ -79,10 +84,10 @@ const CreditBalance = () => {
Balance
- {isDebt &&

-

} + {hasDebt &&

-

}

$

{balance}

- {isCredit &&

/credits

} + {hasCredits &&

/credits

}
)} diff --git a/apps/studio/components/interfaces/Organization/BillingSettings/CreditCodeRedemption.tsx b/apps/studio/components/interfaces/Organization/BillingSettings/CreditCodeRedemption.tsx index ffdf1c7705..ff1479f94a 100644 --- a/apps/studio/components/interfaces/Organization/BillingSettings/CreditCodeRedemption.tsx +++ b/apps/studio/components/interfaces/Organization/BillingSettings/CreditCodeRedemption.tsx @@ -26,6 +26,7 @@ import { Admonition, ShimmeringLoader, TimestampInfo } from 'ui-patterns' import { FormItemLayout } from 'ui-patterns/form/FormItemLayout/FormItemLayout' import { z } from 'zod' +import { getTotalCreditBalanceCents } from './helpers' import { ButtonTooltip } from '@/components/ui/ButtonTooltip' import { UpgradePlanButton } from '@/components/ui/UpgradePlanButton' import { useOrganizationCreditCodeRedemptionMutation } from '@/data/organizations/organization-credit-code-redemption-mutation' @@ -59,6 +60,12 @@ export const CreditCodeRedemption = ({ const { data: org, isLoading: isOrgLoading } = useOrganizationQuery({ slug }) const { data: customerProfile, isLoading: isCustomerProfileLoading } = useOrganizationCustomerProfileQuery({ slug }) + const combinedCreditBalanceCents = customerProfile + ? getTotalCreditBalanceCents({ + customerBalance: customerProfile.balance, + prepaidCreditsBalance: customerProfile.prepaid_credits_balance, + }) + : undefined const { can: canRedeemCode, isSuccess: isPermissionsLoaded } = useAsyncCheckPermissions( PermissionAction.BILLING_WRITE, @@ -282,12 +289,12 @@ export const CreditCodeRedemption = ({ )} /> - {customerProfile && customerProfile.balance < 0 && ( + {combinedCreditBalanceCents !== undefined && combinedCreditBalanceCents > 0 && (
Current Balance

$

-

{customerProfile.balance / -100}

+

{combinedCreditBalanceCents / 100}

/credits

diff --git a/apps/studio/components/interfaces/Organization/BillingSettings/helpers.ts b/apps/studio/components/interfaces/Organization/BillingSettings/helpers.ts index fb80aa7b2a..afa26fd431 100644 --- a/apps/studio/components/interfaces/Organization/BillingSettings/helpers.ts +++ b/apps/studio/components/interfaces/Organization/BillingSettings/helpers.ts @@ -94,3 +94,13 @@ export const generateUpgradeReasons = (originalPlan?: string, upgradedPlan?: str return reasons } + +// For `customerBalance`, negative sign means credit. +// Negate it first so both sources contribute as positive credit amounts before combining. +export const getTotalCreditBalanceCents = ({ + customerBalance = 0, + prepaidCreditsBalance = 0, +}: { + customerBalance?: number + prepaidCreditsBalance?: number +}) => -customerBalance + prepaidCreditsBalance diff --git a/packages/api-types/types/platform.d.ts b/packages/api-types/types/platform.d.ts index 30cb5676d1..d78a970759 100644 --- a/packages/api-types/types/platform.d.ts +++ b/packages/api-types/types/platform.d.ts @@ -6071,6 +6071,7 @@ export interface components { billing_name?: string billing_via_partner: boolean email: string + prepaid_credits_balance?: number tax_id: { country: string type: string @@ -6767,6 +6768,7 @@ export interface components { id: 'free' | 'pro' | 'team' | 'enterprise' | 'platform' name: string } + prepaid_credits_balance?: number project_addons: { addons: { /** @enum {string} */