Skip to content

Billing cycle calculation uses fixed 30/90/365 day intervals — drifts for calendar month subscriptions #142

@Calebux

Description

@Calebux

Description

calculateNextRenewal() in the billing simulation service uses hardcoded fixed-day math:

case 'monthly': return addDays(date, 30);    // ← wrong: Feb has 28 days, July has 31
case 'quarterly': return addDays(date, 90);  // ← drifts ~3 days per year
case 'annual': return addDays(date, 365);    // ← misses leap years

For a monthly subscription starting January 31st:

  • Fixed 30 days: next renewal = March 2nd (skips February entirely)
  • Correct calendar month: next renewal = February 28th (end of month)

Over 12 months, a 30-day interval drifts ~5 days from the actual calendar date. Reminder notifications fire at the wrong time, and billing projections show incorrect dates.

Fix

Use date-fns calendar-aware functions (already installed):

import { addMonths, addQuarters, addYears } from 'date-fns';

function calculateNextRenewal(date: Date, billingCycle: string): Date {
  switch (billingCycle) {
    case 'monthly':   return addMonths(date, 1);
    case 'quarterly': return addQuarters(date, 1);
    case 'annual':    return addYears(date, 1);
    case 'weekly':    return addWeeks(date, 1);
    default: throw new Error(`Unknown billing cycle: ${billingCycle}`);
  }
}

addMonths correctly handles end-of-month edge cases (Jan 31 → Feb 28/29 → Mar 31).

Additional Locations to Fix

  • /backend/src/services/auto-expiry-service.ts — any date arithmetic for billing cycles
  • /backend/src/services/reminder-engine.ts — reminder date calculation
  • /client/lib/ — any client-side date math for renewal displays

Acceptance Criteria

  • All billing cycle math uses addMonths/addYears/addQuarters from date-fns
  • Unit tests for end-of-month edge cases (Jan 31, Feb 28/29, Mar 31)
  • Reminder dates recalculated for existing subscriptions after fix
  • Billing projections show correct calendar dates

Metadata

Metadata

Labels

BackendStellar WaveIssues in the Stellar wave programbugSomething isn't working

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions