Skip to content

Commit

Permalink
馃搫 Add Commercial License for ee folder (#1532)
Browse files Browse the repository at this point in the history
  • Loading branch information
baptisteArno committed May 23, 2024
1 parent 5680829 commit 0eacbeb
Show file tree
Hide file tree
Showing 246 changed files with 1,472 additions and 1,588 deletions.
8 changes: 8 additions & 0 deletions LICENSE
Original file line number Diff line number Diff line change
@@ -1,3 +1,11 @@
Copyright (c) 2020-present Typebot

Portions of this software are licensed as follows:

- All content that resides under https://github.com/baptisteArno/typebot.io/tree/main/ee directory of this repository is licensed under the license defined in [ee/LICENSE](./ee/LICENSE).
- Content outside of the above mentioned directories or restrictions above is available under the "AGPLv3" license as defined below.


GNU AFFERO GENERAL PUBLIC LICENSE
Version 3, 19 November 2007

Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -110,4 +110,4 @@ Made with [contrib.rocks](https://contrib.rocks).

## License

Typebot is open-source under the GNU Affero General Public License Version 3 (AGPLv3). You will find more information about the license and how to comply with it [here](https://docs.typebot.io/self-hosting#license-requirements).
Most of Typebot's code is open-source under the GNU Affero General Public License Version 3 (AGPLv3). You will find more information about the license and how to comply with it [here](https://docs.typebot.io/self-hosting#license-requirements).
134 changes: 3 additions & 131 deletions apps/builder/src/features/billing/api/createCheckoutSession.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,7 @@
import prisma from '@typebot.io/lib/prisma'
import { authenticatedProcedure } from '@/helpers/server/trpc'
import { TRPCError } from '@trpc/server'
import { Plan } from '@typebot.io/prisma'
import Stripe from 'stripe'
import { z } from 'zod'
import { isAdminWriteWorkspaceForbidden } from '@/features/workspace/helpers/isAdminWriteWorkspaceForbidden'
import { env } from '@typebot.io/env'
import { createCheckoutSession as createCheckoutSessionHandler } from '@typebot.io/billing/api/createCheckoutSession'

export const createCheckoutSession = authenticatedProcedure
.meta({
Expand Down Expand Up @@ -38,130 +34,6 @@ export const createCheckoutSession = authenticatedProcedure
checkoutUrl: z.string(),
})
)
.mutation(
async ({
input: { vat, email, company, workspaceId, currency, plan, returnUrl },
ctx: { user },
}) => {
if (!env.STRIPE_SECRET_KEY)
throw new TRPCError({
code: 'INTERNAL_SERVER_ERROR',
message: 'Stripe environment variables are missing',
})
const workspace = await prisma.workspace.findFirst({
where: {
id: workspaceId,
},
select: {
stripeId: true,
members: {
select: {
userId: true,
role: true,
},
},
},
})

if (!workspace || isAdminWriteWorkspaceForbidden(workspace, user))
throw new TRPCError({
code: 'NOT_FOUND',
message: 'Workspace not found',
})
if (workspace.stripeId)
throw new TRPCError({
code: 'BAD_REQUEST',
message: 'Customer already exists, use updateSubscription endpoint.',
})

const stripe = new Stripe(env.STRIPE_SECRET_KEY, {
apiVersion: '2022-11-15',
})

await prisma.user.updateMany({
where: {
id: user.id,
},
data: {
company,
},
})

const customer = await stripe.customers.create({
email,
name: company,
metadata: { workspaceId },
tax_id_data: vat
? [vat as Stripe.CustomerCreateParams.TaxIdDatum]
: undefined,
})

const checkoutUrl = await createCheckoutSessionUrl(stripe)({
customerId: customer.id,
userId: user.id,
workspaceId,
currency,
plan,
returnUrl,
})

if (!checkoutUrl)
throw new TRPCError({
code: 'INTERNAL_SERVER_ERROR',
message: 'Stripe checkout session creation failed',
})

return {
checkoutUrl,
}
}
.mutation(async ({ input, ctx: { user } }) =>
createCheckoutSessionHandler({ ...input, user })
)

type Props = {
customerId: string
workspaceId: string
currency: 'usd' | 'eur'
plan: 'STARTER' | 'PRO'
returnUrl: string
userId: string
}

export const createCheckoutSessionUrl =
(stripe: Stripe) =>
async ({ customerId, workspaceId, currency, plan, returnUrl }: Props) => {
const session = await stripe.checkout.sessions.create({
success_url: `${returnUrl}?stripe=${plan}&success=true`,
cancel_url: `${returnUrl}?stripe=cancel`,
allow_promotion_codes: true,
customer: customerId,
customer_update: {
address: 'auto',
name: 'never',
},
mode: 'subscription',
metadata: {
workspaceId,
plan,
},
currency,
billing_address_collection: 'required',
automatic_tax: { enabled: true },
line_items: [
{
price:
plan === 'STARTER'
? env.STRIPE_STARTER_PRICE_ID
: env.STRIPE_PRO_PRICE_ID,
quantity: 1,
},
{
price:
plan === 'STARTER'
? env.STRIPE_STARTER_CHATS_PRICE_ID
: env.STRIPE_PRO_CHATS_PRICE_ID,
},
],
})

return session.url
}
162 changes: 6 additions & 156 deletions apps/builder/src/features/billing/api/createCustomCheckoutSession.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,6 @@
import prisma from '@typebot.io/lib/prisma'
import { authenticatedProcedure } from '@/helpers/server/trpc'
import { TRPCError } from '@trpc/server'
import { Plan } from '@typebot.io/prisma'
import Stripe from 'stripe'
import { z } from 'zod'
import { isAdminWriteWorkspaceForbidden } from '@/features/workspace/helpers/isAdminWriteWorkspaceForbidden'
import { env } from '@typebot.io/env'
import { createCustomCheckoutSession as createCustomCheckoutSessionHandler } from '@typebot.io/billing/api/createCustomCheckoutSession'

export const createCustomCheckoutSession = authenticatedProcedure
.meta({
Expand All @@ -30,154 +25,9 @@ export const createCustomCheckoutSession = authenticatedProcedure
checkoutUrl: z.string(),
})
)
.mutation(
async ({ input: { email, workspaceId, returnUrl }, ctx: { user } }) => {
if (!env.STRIPE_SECRET_KEY)
throw new TRPCError({
code: 'INTERNAL_SERVER_ERROR',
message: 'Stripe environment variables are missing',
})
const workspace = await prisma.workspace.findFirst({
where: {
id: workspaceId,
},
select: {
stripeId: true,
claimableCustomPlan: true,
name: true,
members: {
select: {
userId: true,
role: true,
},
},
},
})
if (
!workspace?.claimableCustomPlan ||
workspace.claimableCustomPlan.claimedAt ||
isAdminWriteWorkspaceForbidden(workspace, user)
)
throw new TRPCError({
code: 'NOT_FOUND',
message: 'Custom plan not found',
})
const stripe = new Stripe(env.STRIPE_SECRET_KEY, {
apiVersion: '2022-11-15',
})

const vat =
workspace.claimableCustomPlan.vatValue &&
workspace.claimableCustomPlan.vatType
? ({
type: workspace.claimableCustomPlan.vatType,
value: workspace.claimableCustomPlan.vatValue,
} as Stripe.CustomerCreateParams.TaxIdDatum)
: undefined

const customer = workspace.stripeId
? await stripe.customers.retrieve(workspace.stripeId)
: await stripe.customers.create({
email,
name: workspace.claimableCustomPlan.companyName ?? workspace.name,
metadata: { workspaceId },
tax_id_data: vat ? [vat] : undefined,
})

const session = await stripe.checkout.sessions.create({
success_url: `${returnUrl}?stripe=${Plan.CUSTOM}&success=true`,
cancel_url: `${returnUrl}?stripe=cancel`,
allow_promotion_codes: true,
customer: customer.id,
customer_update: {
address: 'auto',
name: 'never',
},
mode: 'subscription',
metadata: {
claimableCustomPlanId: workspace.claimableCustomPlan.id,
},
currency: workspace.claimableCustomPlan.currency,
billing_address_collection: 'required',
automatic_tax: { enabled: true },
line_items: [
{
price_data: {
currency: workspace.claimableCustomPlan.currency,
tax_behavior: 'exclusive',
recurring: {
interval: workspace.claimableCustomPlan.isYearly
? 'year'
: 'month',
},
product_data: {
name: workspace.claimableCustomPlan.name,
description:
workspace.claimableCustomPlan.description ?? undefined,
},
unit_amount: workspace.claimableCustomPlan.price * 100,
},
quantity: 1,
},
{
price_data: {
currency: workspace.claimableCustomPlan.currency,
tax_behavior: 'exclusive',
recurring: {
interval: workspace.claimableCustomPlan.isYearly
? 'year'
: 'month',
},
product_data: {
name: 'Included chats per month',
},
unit_amount: 0,
},
quantity: workspace.claimableCustomPlan.chatsLimit,
},
{
price_data: {
currency: workspace.claimableCustomPlan.currency,
tax_behavior: 'exclusive',
recurring: {
interval: workspace.claimableCustomPlan.isYearly
? 'year'
: 'month',
},
product_data: {
name: 'Included storage per month',
},
unit_amount: 0,
},
quantity: workspace.claimableCustomPlan.storageLimit,
},
{
price_data: {
currency: workspace.claimableCustomPlan.currency,
tax_behavior: 'exclusive',
recurring: {
interval: workspace.claimableCustomPlan.isYearly
? 'year'
: 'month',
},
product_data: {
name: 'Included seats',
},
unit_amount: 0,
},
quantity: workspace.claimableCustomPlan.seatsLimit,
},
],
})

if (!session.url)
throw new TRPCError({
code: 'INTERNAL_SERVER_ERROR',
message: 'Stripe checkout session creation failed',
})

return {
checkoutUrl: session.url,
}
}
.mutation(async ({ input, ctx: { user } }) =>
createCustomCheckoutSessionHandler({
...input,
user,
})
)
45 changes: 4 additions & 41 deletions apps/builder/src/features/billing/api/getBillingPortalUrl.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,6 @@
import prisma from '@typebot.io/lib/prisma'
import { authenticatedProcedure } from '@/helpers/server/trpc'
import { TRPCError } from '@trpc/server'
import Stripe from 'stripe'
import { z } from 'zod'
import { isAdminWriteWorkspaceForbidden } from '@/features/workspace/helpers/isAdminWriteWorkspaceForbidden'
import { env } from '@typebot.io/env'
import { getBillingPortalUrl as getBillingPortalUrlHandler } from '@typebot.io/billing/api/getBillingPortalUrl'

export const getBillingPortalUrl = authenticatedProcedure
.meta({
Expand All @@ -26,39 +22,6 @@ export const getBillingPortalUrl = authenticatedProcedure
billingPortalUrl: z.string(),
})
)
.query(async ({ input: { workspaceId }, ctx: { user } }) => {
if (!env.STRIPE_SECRET_KEY)
throw new TRPCError({
code: 'INTERNAL_SERVER_ERROR',
message: 'STRIPE_SECRET_KEY var is missing',
})
const workspace = await prisma.workspace.findFirst({
where: {
id: workspaceId,
},
select: {
stripeId: true,
members: {
select: {
userId: true,
role: true,
},
},
},
})
if (!workspace?.stripeId || isAdminWriteWorkspaceForbidden(workspace, user))
throw new TRPCError({
code: 'NOT_FOUND',
message: 'Workspace not found',
})
const stripe = new Stripe(env.STRIPE_SECRET_KEY, {
apiVersion: '2022-11-15',
})
const portalSession = await stripe.billingPortal.sessions.create({
customer: workspace.stripeId,
return_url: `${env.NEXTAUTH_URL}/typebots`,
})
return {
billingPortalUrl: portalSession.url,
}
})
.query(async ({ input: { workspaceId }, ctx: { user } }) =>
getBillingPortalUrlHandler({ workspaceId, user })
)
Loading

0 comments on commit 0eacbeb

Please sign in to comment.