diff --git a/packages/backend/src/config/app.ts b/packages/backend/src/config/app.ts index a18038b1..89cb8f9d 100644 --- a/packages/backend/src/config/app.ts +++ b/packages/backend/src/config/app.ts @@ -41,10 +41,6 @@ type AppConfig = { isCloud: boolean; paddleVendorId: number; paddleVendorAuthCode: string; - stripeSecretKey: string; - stripeSigningSecret: string; - stripeStarterPriceKey: string; - stripeGrowthPriceKey: string; licenseKey: string; sentryDsn: string; }; @@ -115,10 +111,6 @@ const appConfig: AppConfig = { isCloud: process.env.AUTOMATISCH_CLOUD === 'true', paddleVendorId: Number(process.env.PADDLE_VENDOR_ID), paddleVendorAuthCode: process.env.PADDLE_VENDOR_AUTH_CODE, - stripeSecretKey: process.env.STRIPE_SECRET_KEY, - stripeSigningSecret: process.env.STRIPE_SIGNING_SECRET, - stripeStarterPriceKey: process.env.STRIPE_STARTER_PRICE_KEY, - stripeGrowthPriceKey: process.env.STRIPE_GROWTH_PRICE_KEY, licenseKey: process.env.LICENSE_KEY, sentryDsn: process.env.SENTRY_DSN, }; diff --git a/packages/backend/src/controllers/stripe/webhooks.ee.ts b/packages/backend/src/controllers/stripe/webhooks.ee.ts deleted file mode 100644 index bd398dfe..00000000 --- a/packages/backend/src/controllers/stripe/webhooks.ee.ts +++ /dev/null @@ -1,27 +0,0 @@ -import { Response } from 'express'; -import { IRequest } from '@automatisch/types'; - -import * as Sentry from '../../helpers/sentry.ee'; -import Billing from '../../helpers/billing/index.ee'; -import appConfig from '../../config/app'; -import logger from '../../helpers/logger'; - -export default async (request: IRequest, response: Response) => { - const signature = request.headers['stripe-signature']; - - try { - const event = Billing.stripe.webhooks.constructEvent( - request.rawBody, - signature, - appConfig.stripeSigningSecret - ); - - await Billing.handleWebhooks(event); - return response.sendStatus(200); - } catch (error) { - logger.error(`Webhook Error: ${error.message}`); - - Sentry.captureException(error); - return response.sendStatus(400); - } -}; diff --git a/packages/backend/src/graphql/mutations/create-user.ee.ts b/packages/backend/src/graphql/mutations/create-user.ee.ts index 3f875ce7..a6f7d12a 100644 --- a/packages/backend/src/graphql/mutations/create-user.ee.ts +++ b/packages/backend/src/graphql/mutations/create-user.ee.ts @@ -1,6 +1,4 @@ import User from '../../models/user'; -import Billing from '../../helpers/billing/index.ee'; -import appConfig from '../../config/app'; type Params = { input: { @@ -26,10 +24,6 @@ const createUser = async (_parent: unknown, params: Params) => { role: 'user', }); - if (appConfig.isCloud) { - await Billing.createSubscription(user); - } - return user; }; diff --git a/packages/backend/src/graphql/queries/get-payment-portal-url.ee.ts b/packages/backend/src/graphql/queries/get-payment-portal-url.ee.ts deleted file mode 100644 index 9b17b00f..00000000 --- a/packages/backend/src/graphql/queries/get-payment-portal-url.ee.ts +++ /dev/null @@ -1,16 +0,0 @@ -import appConfig from '../../config/app'; -import Context from '../../types/express/context'; -import Billing from '../../helpers/billing/index.ee'; - -const getPaymentPortalUrl = async ( - _parent: unknown, - _params: unknown, - context: Context -) => { - if (!appConfig.isCloud) return; - - const url = Billing.createPaymentPortalUrl(context.currentUser); - return { url }; -}; - -export default getPaymentPortalUrl; diff --git a/packages/backend/src/graphql/query-resolvers.ts b/packages/backend/src/graphql/query-resolvers.ts index e8ae123f..1c16b8d0 100644 --- a/packages/backend/src/graphql/query-resolvers.ts +++ b/packages/backend/src/graphql/query-resolvers.ts @@ -14,7 +14,6 @@ import getCurrentUser from './queries/get-current-user'; import getUsageData from './queries/get-usage-data.ee'; import getPaymentPlans from './queries/get-payment-plans.ee'; import getPaddleInfo from './queries/get-paddle-info.ee'; -import getPaymentPortalUrl from './queries/get-payment-portal-url.ee'; import getAutomatischInfo from './queries/get-automatisch-info'; import healthcheck from './queries/healthcheck'; @@ -35,7 +34,6 @@ const queryResolvers = { getUsageData, getPaymentPlans, getPaddleInfo, - getPaymentPortalUrl, getAutomatischInfo, healthcheck, }; diff --git a/packages/backend/src/graphql/schema.graphql b/packages/backend/src/graphql/schema.graphql index 36f7de89..9d9abf6d 100644 --- a/packages/backend/src/graphql/schema.graphql +++ b/packages/backend/src/graphql/schema.graphql @@ -35,7 +35,6 @@ type Query { ): [SubstepArgument] getCurrentUser: User getUsageData: GetUsageData - getPaymentPortalUrl: GetPaymentPortalUrl getPaymentPlans: [PaymentPlan] getPaddleInfo: GetPaddleInfo getAutomatischInfo: GetAutomatischInfo @@ -479,10 +478,6 @@ type GetUsageData { nextResetAt: String } -type GetPaymentPortalUrl { - url: String -} - type GetPaddleInfo { sandbox: Boolean vendorId: Int diff --git a/packages/backend/src/helpers/billing/index.ee.ts b/packages/backend/src/helpers/billing/index.ee.ts index 6dc5b3dc..0e684efc 100644 --- a/packages/backend/src/helpers/billing/index.ee.ts +++ b/packages/backend/src/helpers/billing/index.ee.ts @@ -1,106 +1,12 @@ -import Stripe from 'stripe'; -import User from '../../models/user'; -import PaymentPlan from '../../models/payment-plan.ee'; -import UsageData from '../../models/usage-data.ee'; import appConfig from '../../config/app'; -import handleWebhooks from './webhooks.ee'; import paddlePlans from './plans.ee'; -const plans = [ - { - price: appConfig.stripeStarterPriceKey, - name: 'Starter', - taskCount: 1000, - default: true, - }, - { - price: appConfig.stripeGrowthPriceKey, - name: 'Growth', - taskCount: 10000, - default: false, - }, -]; - -const stripe = new Stripe(appConfig.stripeSecretKey, { - apiVersion: '2022-11-15', -}); - -const createStripeCustomer = async (user: User) => { - const params: Stripe.CustomerCreateParams = { - email: user.email, - name: user.fullName, - description: `User ID: ${user.id}`, - }; - - return await stripe.customers.create(params); -}; - -const defaultPlan = plans.find((plan) => plan.default); - -const createStripeSubscription = async ( - user: User, - stripeCustomer: Stripe.Customer -) => { - const params: Stripe.SubscriptionCreateParams = { - customer: stripeCustomer.id, - items: [{ price: defaultPlan.price }], - }; - - return await stripe.subscriptions.create(params); -}; - -const createSubscription = async (user: User) => { - const stripeCustomer = await createStripeCustomer(user); - const stripeSubscription = await createStripeSubscription( - user, - stripeCustomer - ); - - await PaymentPlan.query().insert({ - name: defaultPlan.name, - taskCount: defaultPlan.taskCount, - userId: user.id, - stripeCustomerId: stripeCustomer.id, - stripeSubscriptionId: stripeSubscription.id, - currentPeriodStartedAt: new Date( - stripeSubscription.current_period_start * 1000 - ).toISOString(), - currentPeriodEndsAt: new Date( - stripeSubscription.current_period_end * 1000 - ).toISOString(), - }); - - await UsageData.query().insert({ - userId: user.id, - consumedTaskCount: 0, - nextResetAt: new Date( - stripeSubscription.current_period_end * 1000 - ).toISOString(), - }); -}; - -const createPaymentPortalUrl = async (user: User) => { - const paymentPlan = await user.$relatedQuery('paymentPlan'); - - const userSession = await stripe.billingPortal.sessions.create({ - customer: paymentPlan.stripeCustomerId, - return_url: 'https://cloud.automatisch.io/settings/billing', - }); - - return userSession.url; -}; - const paddleInfo = { sandbox: appConfig.isDev ? true : false, vendorId: appConfig.paddleVendorId, }; const billing = { - createSubscription, - createPaymentPortalUrl, - handleWebhooks, - stripe, - plans, paddlePlans, paddleInfo, }; diff --git a/packages/backend/src/helpers/billing/webhooks.ee.ts b/packages/backend/src/helpers/billing/webhooks.ee.ts deleted file mode 100644 index 8ec18830..00000000 --- a/packages/backend/src/helpers/billing/webhooks.ee.ts +++ /dev/null @@ -1,42 +0,0 @@ -import Stripe from 'stripe'; -import PaymentPlan from '../../models/payment-plan.ee'; -import Billing from './index.ee'; - -const handleWebhooks = async (event: Stripe.Event) => { - const trackedWebhookTypes = [ - 'customer.subscription.created', - 'customer.subscription.updated', - 'customer.subscription.deleted', - ]; - - if (!trackedWebhookTypes.includes(event.type)) { - return; - } - - await updatePaymentPlan(event); -}; - -const updatePaymentPlan = async (event: Stripe.Event) => { - const subscription = event.data.object as Stripe.Subscription; - const priceKey = subscription.items.data[0].plan.id; - const plan = Billing.plans.find((plan) => plan.price === priceKey); - - const paymentPlan = await PaymentPlan.query().findOne({ - stripe_customer_id: subscription.customer, - }); - - await paymentPlan.$query().patchAndFetch({ - name: plan.name, - taskCount: plan.taskCount, - stripeSubscriptionId: subscription.id, - }); - - const user = await paymentPlan.$relatedQuery('user'); - const usageData = await user.$relatedQuery('usageData'); - - await usageData.$query().patchAndFetch({ - nextResetAt: new Date(subscription.current_period_end * 1000).toISOString(), - }); -}; - -export default handleWebhooks; diff --git a/packages/backend/src/routes/index.ts b/packages/backend/src/routes/index.ts index 853556ba..1cb26316 100644 --- a/packages/backend/src/routes/index.ts +++ b/packages/backend/src/routes/index.ts @@ -1,12 +1,10 @@ import { Router } from 'express'; import graphQLInstance from '../helpers/graphql-instance'; import webhooksRouter from './webhooks'; -import stripeRouter from './stripe.ee'; const router = Router(); router.use('/graphql', graphQLInstance); router.use('/webhooks', webhooksRouter); -router.use('/stripe', stripeRouter); export default router; diff --git a/packages/backend/src/routes/stripe.ee.ts b/packages/backend/src/routes/stripe.ee.ts deleted file mode 100644 index f6c71aef..00000000 --- a/packages/backend/src/routes/stripe.ee.ts +++ /dev/null @@ -1,23 +0,0 @@ -import express, { Router } from 'express'; -import multer from 'multer'; -import { IRequest } from '@automatisch/types'; -import appConfig from '../config/app'; -import stripeWebhooksAction from '../controllers/stripe/webhooks.ee'; - -const router = Router(); -const upload = multer(); - -router.use(upload.none()); - -router.use( - express.text({ - limit: appConfig.requestBodySizeLimit, - verify(req, res, buf) { - (req as IRequest).rawBody = buf; - }, - }) -); - -router.post('/webhooks', stripeWebhooksAction); - -export default router;