feat: Implement stripe webhooks

This commit is contained in:
Faruk AYDIN
2023-03-07 17:13:20 +01:00
parent 7676bc5836
commit b0b6b72b4c
7 changed files with 97 additions and 0 deletions

View File

@@ -40,6 +40,7 @@ type AppConfig = {
fromEmail: string;
isCloud: boolean;
stripeSecretKey: string;
stripeSigningSecret: string;
stripeStarterPriceKey: string;
stripeGrowthPriceKey: string;
licenseKey: string;
@@ -110,6 +111,7 @@ const appConfig: AppConfig = {
fromEmail: process.env.FROM_EMAIL,
isCloud: process.env.AUTOMATISCH_CLOUD === 'true',
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,

View File

@@ -0,0 +1,23 @@
import { Response } from 'express';
import { IRequest } from '@automatisch/types';
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}`);
return response.sendStatus(400);
}
};

View File

@@ -3,6 +3,7 @@ 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';
const plans = [
{
@@ -91,6 +92,9 @@ const createPaymentPortalUrl = async (user: User) => {
const billing = {
createSubscription,
createPaymentPortalUrl,
handleWebhooks,
stripe,
plans,
};
export default billing;

View File

@@ -0,0 +1,42 @@
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;

View File

@@ -10,6 +10,7 @@ class PaymentPlan extends Base {
stripeSubscriptionId!: string;
currentPeriodStartedAt!: string;
currentPeriodEndsAt!: string;
user?: User;
static tableName = 'payment_plans';

View File

@@ -1,10 +1,12 @@
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;

View File

@@ -0,0 +1,23 @@
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;