@company-manager/docs

Billing Cycles

Recurring billing, invoice generation, and payment processing diagrams

Billing Cycles

This page covers the recurring billing process including invoice generation, payment collection, and retry logic.

Billing Cycle Overview

flowchart TD
    subgraph "Billing Trigger"
        SCHEDULE[Scheduled Billing Date] --> CHECK[Check Active Subscriptions]
        CHECK --> DUE[Find Due Subscriptions]
    end

    subgraph "Invoice Generation"
        DUE --> CREATE[Create Invoice]
        CREATE --> CALCULATE[Calculate Amount]
        CALCULATE --> APPLY[Apply Discounts/Credits]
        APPLY --> FINALIZE[Finalize Invoice]
    end

    subgraph "Payment"
        FINALIZE --> CHARGE[Attempt Payment]
        CHARGE --> RESULT{Payment Result}
        RESULT -->|Success| PAID[Mark Paid]
        RESULT -->|Failure| RETRY[Schedule Retry]
    end

    subgraph "Post-Payment"
        PAID --> UPDATE[Update Subscription]
        UPDATE --> NEXT[Set Next Billing Date]
        NEXT --> NOTIFY[Send Receipt]
    end

    RETRY --> DUNNING[Enter Dunning Flow]

    style PAID fill:#e8f5e9
    style RETRY fill:#ffebee

Invoice Generation Sequence

sequenceDiagram
    participant Cron as Billing Scheduler
    participant Service as Billing Service
    participant DB as Database
    participant Stripe as Stripe API
    participant Email as Email Service

    Cron->>Service: runBillingCycle()

    Service->>DB: Get subscriptions due for billing
    Note over Service,DB: WHERE nextBillingDate <= NOW()
    DB-->>Service: Due subscriptions

    loop For each subscription
        Service->>Service: Calculate invoice amount
        Note over Service: Base price + add-ons - credits

        Service->>DB: Create SubscriptionInvoice (PENDING)
        DB-->>Service: Invoice created

        Service->>Stripe: Create invoice
        Note over Stripe: Linked to Stripe customer
        Stripe-->>Service: Stripe invoice

        Service->>Stripe: Finalize and pay invoice
        Stripe-->>Service: Payment result

        alt Payment successful
            Service->>DB: Update invoice (PAID)
            Service->>DB: Update nextBillingDate
            Service->>Email: sendReceipt(invoice)
        else Payment failed
            Service->>DB: Update invoice (FAILED)
            Service->>DB: Update subscription (PAST_DUE)
            Service->>DB: Schedule retry
        end
    end

    Service-->>Cron: Billing cycle complete

Invoice State Machine

stateDiagram-v2
    [*] --> DRAFT: Create Invoice

    DRAFT --> PENDING: Finalize
    DRAFT --> VOID: Cancel

    PENDING --> PAID: Payment Success
    PENDING --> FAILED: Payment Failed
    PENDING --> VOID: Cancel

    FAILED --> PENDING: Retry Payment
    FAILED --> PAID: Retry Success
    FAILED --> UNCOLLECTIBLE: Max Retries

    PAID --> REFUNDED: Full Refund
    PAID --> PARTIALLY_REFUNDED: Partial Refund

    VOID --> [*]
    PAID --> [*]
    UNCOLLECTIBLE --> [*]
    REFUNDED --> [*]

Amount Calculation Flow

flowchart TD
    START[Calculate Invoice] --> BASE[Get Base Plan Price]

    BASE --> ADDONS{Add-ons?}
    ADDONS -->|Yes| CALC_ADDONS[Calculate Add-on Amounts]
    ADDONS -->|No| SUBTOTAL1

    CALC_ADDONS --> SUBTOTAL1[Subtotal]

    SUBTOTAL1 --> DISCOUNTS{Discounts?}
    DISCOUNTS -->|Coupon| APPLY_COUPON[Apply Coupon Discount]
    DISCOUNTS -->|Promo| APPLY_PROMO[Apply Promo Code]
    DISCOUNTS -->|None| SUBTOTAL2

    APPLY_COUPON --> SUBTOTAL2[Subtotal After Discounts]
    APPLY_PROMO --> SUBTOTAL2

    SUBTOTAL2 --> CREDITS{Account Credits?}
    CREDITS -->|Yes| APPLY_CREDITS[Apply Credits]
    CREDITS -->|No| TAX

    APPLY_CREDITS --> TAX[Calculate Tax]
    TAX --> TOTAL[Final Total]

    subgraph "Example"
        EX_BASE[Plan: €29.00]
        EX_ADD[+ Add-on: €10.00]
        EX_SUB1[= €39.00]
        EX_DISC[- 20% coupon: €7.80]
        EX_SUB2[= €31.20]
        EX_CRED[- Credit: €5.00]
        EX_SUB3[= €26.20]
        EX_TAX[+ VAT 20%: €5.24]
        EX_TOTAL[Total: €31.44]
    end

    style TOTAL fill:#e8f5e9

Proration Calculation

flowchart TD
    CHANGE[Mid-Cycle Change] --> TYPE{Change Type}

    TYPE -->|Upgrade| UPGRADE[Calculate Upgrade Proration]
    TYPE -->|Downgrade| DOWNGRADE[Calculate Downgrade Proration]
    TYPE -->|Add-on Added| ADDON_ADD[Prorate Add-on]
    TYPE -->|Add-on Removed| ADDON_REM[Credit Remaining]

    subgraph "Upgrade Proration"
        UPGRADE --> DAYS_LEFT[Days Remaining in Cycle]
        DAYS_LEFT --> DIFF[Price Difference]
        DIFF --> PRORATE_CHARGE[Charge = (Diff / Total Days) × Days Left]
    end

    subgraph "Downgrade Proration"
        DOWNGRADE --> DAYS_LEFT2[Days Remaining]
        DAYS_LEFT2 --> DIFF2[Price Difference]
        DIFF2 --> PRORATE_CREDIT[Credit = (Diff / Total Days) × Days Left]
    end

    PRORATE_CHARGE --> APPLY[Apply to Next Invoice]
    PRORATE_CREDIT --> APPLY
    ADDON_ADD --> APPLY
    ADDON_REM --> APPLY

Payment Retry Flow (Dunning)

stateDiagram-v2
    [*] --> INITIAL_FAIL: Payment Fails

    INITIAL_FAIL --> RETRY_1: Wait 1 day
    RETRY_1 --> RETRY_2: Fail, wait 3 days
    RETRY_1 --> SUCCESS: Payment Success

    RETRY_2 --> RETRY_3: Fail, wait 5 days
    RETRY_2 --> SUCCESS: Payment Success

    RETRY_3 --> RETRY_4: Fail, wait 7 days
    RETRY_3 --> SUCCESS: Payment Success

    RETRY_4 --> CANCEL: Fail, max retries
    RETRY_4 --> SUCCESS: Payment Success

    SUCCESS --> ACTIVE: Subscription Active
    CANCEL --> CANCELLED: Subscription Cancelled

    note right of RETRY_1: Email: Payment failed
    note right of RETRY_2: Email: Action required
    note right of RETRY_3: Email: Final warning
    note right of RETRY_4: Email: Subscription cancelled

Dunning Email Sequence

sequenceDiagram
    participant System as Billing System
    participant Email as Email Service
    participant User

    Note over System: Payment fails

    System->>Email: Send payment failed email
    Email->>User: "Your payment failed"
    Note over User: Day 0

    System->>System: Wait 1 day, retry payment
    Note over System: Retry 1 fails

    System->>Email: Send reminder email
    Email->>User: "Please update payment method"
    Note over User: Day 1

    System->>System: Wait 3 days, retry payment
    Note over System: Retry 2 fails

    System->>Email: Send urgent email
    Email->>User: "Service may be interrupted"
    Note over User: Day 4

    System->>System: Wait 5 days, retry payment
    Note over System: Retry 3 fails

    System->>Email: Send final warning
    Email->>User: "Last chance to update payment"
    Note over User: Day 9

    System->>System: Wait 7 days, final retry
    Note over System: Final retry fails

    System->>Email: Send cancellation notice
    Email->>User: "Subscription cancelled"
    Note over User: Day 16

Billing Interval Types

flowchart LR
    subgraph "Interval Options"
        DAILY[Daily]
        WEEKLY[Weekly]
        MONTHLY[Monthly]
        QUARTERLY[Quarterly]
        YEARLY[Yearly]
    end

    subgraph "Next Billing Calculation"
        DAILY --> NEXT_DAY[+1 day]
        WEEKLY --> NEXT_WEEK[+7 days]
        MONTHLY --> NEXT_MONTH[+1 month]
        QUARTERLY --> NEXT_QUARTER[+3 months]
        YEARLY --> NEXT_YEAR[+1 year]
    end

Multi-Currency Billing

flowchart TD
    CUSTOMER[Customer Currency] --> DETERMINE{Determine Billing Currency}

    DETERMINE --> PLAN_CURR[Plan Default Currency]
    DETERMINE --> CUST_PREF[Customer Preference]
    DETERMINE --> GEO[Geographic Detection]

    PLAN_CURR --> SELECT[Select Currency]
    CUST_PREF --> SELECT
    GEO --> SELECT

    SELECT --> CONVERT{Conversion Needed?}

    CONVERT -->|Yes| RATE[Get Exchange Rate]
    CONVERT -->|No| CHARGE[Charge in Currency]

    RATE --> CALCULATE[Calculate Converted Amount]
    CALCULATE --> CHARGE

    CHARGE --> STRIPE[Process via Stripe]

Subscription Invoice ERD

erDiagram
    SUBSCRIPTION ||--o{ SUBSCRIPTION_INVOICE : generates
    SUBSCRIPTION_INVOICE ||--o{ INVOICE_LINE_ITEM : contains
    SUBSCRIPTION_INVOICE }o--o| PAYMENT_TRANSACTION : paid_by
    SUBSCRIPTION_INVOICE }o--o| COUPON : applies

    SUBSCRIPTION_INVOICE {
        string id PK
        string subscriptionId FK
        string invoiceNumber
        decimal subtotal
        decimal discount
        decimal tax
        decimal total
        string currency
        enum status
        timestamp periodStart
        timestamp periodEnd
        timestamp dueDate
        timestamp paidDate
        string stripeInvoiceId
        int retryCount
        timestamp nextRetryDate
    }

    INVOICE_LINE_ITEM {
        string id PK
        string invoiceId FK
        string description
        int quantity
        decimal unitPrice
        decimal amount
        enum itemType
    }

Billing Analytics

flowchart LR
    subgraph "Data Collection"
        INVOICES[Invoices]
        PAYMENTS[Payments]
        FAILURES[Failed Payments]
    end

    subgraph "Metrics"
        MRR[MRR Calculation]
        CHURN[Churn Rate]
        ARPU[ARPU]
        LTV[Customer LTV]
    end

    subgraph "Reports"
        REV[Revenue Report]
        COHORT[Cohort Analysis]
        FORECAST[Revenue Forecast]
    end

    INVOICES --> MRR
    INVOICES --> ARPU
    PAYMENTS --> MRR
    FAILURES --> CHURN

    MRR --> REV
    CHURN --> COHORT
    ARPU --> LTV
    LTV --> FORECAST