diff --git a/packages/billing/billing-queries.ts b/packages/billing/billing-queries.ts index f2e9de4852..bc768264b4 100644 --- a/packages/billing/billing-queries.ts +++ b/packages/billing/billing-queries.ts @@ -562,14 +562,17 @@ export async function spendCredits( if (!subscriptionCycle) { throw new Error('subscription cycle not found'); } - let availablePlanAllowanceCredits = await sumUpCreditsLedger(dbAdapter, { - creditType: [ - 'plan_allowance', - 'plan_allowance_used', - 'plan_allowance_expired', - ], - userId, - }); + let availablePlanAllowanceCredits = Math.max( + 0, + await sumUpCreditsLedger(dbAdapter, { + creditType: [ + 'plan_allowance', + 'plan_allowance_used', + 'plan_allowance_expired', + ], + subscriptionCycleId: subscriptionCycle.id, + }), + ); if (availablePlanAllowanceCredits >= creditsToSpend) { await addToCreditsLedger(dbAdapter, { diff --git a/packages/realm-server/tests/billing-test.ts b/packages/realm-server/tests/billing-test.ts index 30aae24912..4aa476b92d 100644 --- a/packages/realm-server/tests/billing-test.ts +++ b/packages/realm-server/tests/billing-test.ts @@ -995,6 +995,63 @@ module(basename(__filename), function () { ); }); + test('does not spend previous cycle plan allowance in current cycle', async function (assert) { + await addToCreditsLedger(dbAdapter, { + userId: user.id, + creditAmount: 100, + creditType: 'plan_allowance', + subscriptionCycleId: subscriptionCycle.id, + }); + + let nextSubscriptionCycle = await insertSubscriptionCycle(dbAdapter, { + subscriptionId: subscription.id, + periodStart: 2, + periodEnd: 3, + }); + await addToCreditsLedger(dbAdapter, { + userId: user.id, + creditAmount: 50, + creditType: 'plan_allowance', + subscriptionCycleId: nextSubscriptionCycle.id, + }); + + await spendCredits(dbAdapter, user.id, 80); + + assert.strictEqual( + await sumUpCreditsLedger(dbAdapter, { + subscriptionCycleId: subscriptionCycle.id, + creditType: [ + 'plan_allowance', + 'plan_allowance_used', + 'plan_allowance_expired', + ], + }), + 100, + ); + assert.strictEqual( + await sumUpCreditsLedger(dbAdapter, { + subscriptionCycleId: nextSubscriptionCycle.id, + creditType: [ + 'plan_allowance', + 'plan_allowance_used', + 'plan_allowance_expired', + ], + }), + 0, + ); + assert.strictEqual( + await sumUpCreditsLedger(dbAdapter, { + userId: user.id, + creditType: [ + 'plan_allowance', + 'plan_allowance_used', + 'plan_allowance_expired', + ], + }), + 100, + ); + }); + test('spends ai credits correctly when extra credits are available', async function (assert) { // User receives 2500 credits for the creator plan and spends 2490 credits await addToCreditsLedger(dbAdapter, {