All files / src/services/stripe index.ts

0% Statements 0/19
0% Branches 0/4
0% Functions 0/7
0% Lines 0/19

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109                                                                                                                                                                                                                         
import Stripe from 'stripe';
import { stripeConfig } from '../../config/stripe';
import { Subscription } from '../../types';
 
export class StripeService {
  private client: Stripe;
  private prices: {
    STANDARD: {
      monthly?: string;
      yearly?: string;
    };
    UNLIMITED: {
      monthly?: string;
      yearly?: string;
    };
  };
 
  constructor() {
    this.client = new Stripe(stripeConfig.STRIPE_SECRET_KEY!);
    this.prices = {
      STANDARD: {
        monthly: process.env.STRIPE_STANDARD_SUBSCRIPTION_PRICE_ID,
        yearly: process.env.STRIPE_STANDARD_ANNUAL_SUBSCRIPTION_PRICE_ID
      },
      UNLIMITED: {
        monthly: process.env.STRIPE_UNLIMITED_SUBSCRIPTION_PRICE_ID,
        yearly: process.env.STRIPE_UNLIMITED_ANNUAL_SUBSCRIPTION_PRICE_ID
      }
    };
  }
 
  // Only for test
  async createTestSubscription(): Promise<{
    subscriptionId: string;
    customerId: string;
    status: string;
    priceId: string;
  }> {
    try {
      const customer = await this.client.customers.create({
        email: 'test@example.com',
        description: 'Client test',
        source: 'tok_visa'
      });
 
      const priceId = this.prices.STANDARD.monthly!;
      const price = await this.client.prices.retrieve(priceId);
 
      const subscription = await this.client.subscriptions.create({
        customer: customer.id,
        items: [{ price: price.id }],
        payment_behavior: 'default_incomplete',
        expand: ['latest_invoice.payment_intent']
      });
 
      return {
        subscriptionId: subscription.id,
        customerId: customer.id,
        status: subscription.status,
        priceId: price.id
      };
 
    } catch (error) {
      throw error;
    }
  }
 
  async createCheckoutSession(subscription: Subscription, frequency: 'monthly' | 'yearly'): Promise<Stripe.Checkout.Session> {
    const priceId = this.getPriceId(subscription.type, frequency);
 
    return await this.client.checkout.sessions.create({
      mode: 'subscription',
      payment_method_types: ['card', 'sepa_debit'],
      billing_address_collection: 'auto',
      line_items: [{
        price: priceId,
        quantity: subscription.type === 'STANDARD' ? subscription.seats || 1 : 1,
      }],
      success_url: `${stripeConfig.APP_HOST}/subscription/success`, // Success page (frontend)
      cancel_url: `${stripeConfig.APP_HOST}/subscription/error`, // Error page (frontend)
      metadata: {
        subscription: JSON.stringify(subscription),
      },
      allow_promotion_codes: true,
      automatic_tax: { enabled: true }
    });
  }
 
  getPriceId(type: 'STANDARD' | 'UNLIMITED', frequency: 'monthly' | 'yearly'): string {
    return this.prices[type][frequency]!;
  }
 
  async getSubscription(subscriptionId: string): Promise<Stripe.Subscription> {
    return await this.client.subscriptions.retrieve(subscriptionId);
  }
 
  async createPortalSession(subscriptionId: string): Promise<Stripe.BillingPortal.Session> {
    const subscription = await this.getSubscription(subscriptionId);
    return await this.client.billingPortal.sessions.create({
      customer: subscription.customer as string,
      return_url: `${stripeConfig.APP_HOST}/subscription/manage`
    });
  }
 
  getClient(): Stripe {
    return this.client;
  }
}