7021a51747
## Summary This PR implements credit rollover functionality for billing, allowing unused credits from one billing period to carry over to the next (capped at the current period's subscription tier cap). ## Changes ### New Services - **StripeCreditGrantService**: Interacts with Stripe's Billing Credits API to create credit grants, retrieve customer credit balances, and void grants - **BillingCreditRolloverService**: Contains the rollover logic - calculates unused credits and creates new grants for the next period - **BillingWebhookCreditGrantService**: Handles `billing.credit_grant.created` and `billing.credit_grant.updated` webhooks to update billing alerts ### Modified Services - **StripeBillingAlertService**: Updated to include credit balance when calculating usage threshold alerts - **BillingUsageService**: Returns rollover credits to the frontend for display - **BillingSubscriptionService**: Queries credit balance when creating billing alerts - **BillingWebhookInvoiceService**: Triggers rollover processing on `invoice.finalized` webhook ### Frontend - Updated `SettingsBillingCreditsSection` to display base credits, rollover credits, and total available - Updated GraphQL query to fetch new `rolloverCredits` and `totalGrantedCredits` fields ### Stripe SDK Upgrade - Upgraded from v17.3.1 to v19.3.1 to get proper types for billing.credit_grant events - Fixed breaking changes: invoice.subscription path, subscription period fields location, removed properties ## How it works 1. When `invoice.finalized` webhook is received for `subscription_cycle`, the system: - Calculates usage from the previous period - Determines unused credits (tier cap - usage) - Caps rollover at current tier cap - Creates a Stripe credit grant with expiration at end of new period 2. When credit grants are created/updated/voided: - Billing alerts are recreated with the updated credit balance 3. The UI displays: - Base credits (from subscription tier) - Rollover credits (from previous periods) - Total available credits ## Edge Cases Handled - Credit grant voided: `billing.credit_grant.updated` webhook triggers alert update - Credit grant expired: Stripe's `creditBalanceSummary` API excludes expired grants - No unused credits: Rollover service skips grant creation - Customer ID as object: Controller extracts `.id` from expanded customer
34 lines
765 B
TypeScript
34 lines
765 B
TypeScript
import type Stripe from 'stripe';
|
|
export const createMockStripePriceCreatedData = (
|
|
overrides = {},
|
|
): Stripe.PriceCreatedEvent.Data => ({
|
|
object: {
|
|
id: 'price_1Q',
|
|
object: 'price',
|
|
active: true,
|
|
billing_scheme: 'per_unit',
|
|
created: 1733734326,
|
|
currency: 'usd',
|
|
custom_unit_amount: null,
|
|
livemode: false,
|
|
lookup_key: null,
|
|
metadata: {},
|
|
nickname: null,
|
|
product: 'prod_RLN',
|
|
recurring: {
|
|
interval: 'month',
|
|
interval_count: 1,
|
|
meter: null,
|
|
trial_period_days: null,
|
|
usage_type: 'licensed',
|
|
},
|
|
tax_behavior: 'unspecified',
|
|
tiers_mode: null,
|
|
transform_quantity: null,
|
|
type: 'recurring',
|
|
unit_amount: 0,
|
|
unit_amount_decimal: '0',
|
|
...overrides,
|
|
},
|
|
});
|