diff --git a/front/admin/init_plans.ts b/front/admin/init_plans.ts index a5d643c703a4..777c6e3721da 100644 --- a/front/admin/init_plans.ts +++ b/front/admin/init_plans.ts @@ -1,7 +1,9 @@ import { upsertFreePlans } from "@app/lib/plans/free_plans"; +import { upsertProPlans } from "@app/lib/plans/pro_plans"; async function main() { await upsertFreePlans(); + await upsertProPlans(); process.exit(0); } diff --git a/front/lib/models/plan.ts b/front/lib/models/plan.ts index 2e5138ebaf53..2a06d5306ae1 100644 --- a/front/lib/models/plan.ts +++ b/front/lib/models/plan.ts @@ -22,6 +22,7 @@ export class Plan extends Model< declare code: string; // unique declare name: string; + declare stripeProductId: string | null; // workspace limitations declare maxMessages: number; @@ -60,6 +61,10 @@ Plan.init( type: DataTypes.STRING, allowNull: false, }, + stripeProductId: { + type: DataTypes.STRING, + allowNull: true, + }, maxMessages: { type: DataTypes.INTEGER, allowNull: false, diff --git a/front/lib/plans/enterprise_plans.ts b/front/lib/plans/enterprise_plans.ts new file mode 100644 index 000000000000..11d5a9edd21b --- /dev/null +++ b/front/lib/plans/enterprise_plans.ts @@ -0,0 +1,38 @@ +import { Attributes } from "sequelize"; + +import { Plan } from "@app/lib/models"; + +export type PlanAttributes = Omit< + Attributes, + "id" | "createdAt" | "updatedAt" +>; + +/** + * We have 3 categories of plans: + * - Free: plans with no paid subscription. + * - Pro: plans with a paid subscription, not tailored. -> i.e. the same plan is used by all Pro workspaces. + * - Entreprise: plans with a paid subscription, tailored to the needs of the entreprise. -> i.e. we will have one plan per "Entreprise". + * + * This file about Entreprise plans. + * As entreprise plans are custom, we won't create them in this file, but directly from Poké. + */ + +/** + * ENT_PLAN_FAKE is not subscribable and is only used to display the Enterprise plan in the UI (hence it's not stored on the db). + */ +export const ENT_PLAN_FAKE_CODE = "ENT_PLAN_FAKE_CODE"; +export const ENT_PLAN_FAKE_DATA: PlanAttributes = { + code: ENT_PLAN_FAKE_CODE, + name: "Entreprise", + stripeProductId: null, + maxMessages: -1, + maxUsersInWorkspace: -1, + isSlackbotAllowed: true, + isManagedSlackAllowed: true, + isManagedNotionAllowed: true, + isManagedGoogleDriveAllowed: true, + isManagedGithubAllowed: true, + maxNbStaticDataSources: -1, + maxNbStaticDocuments: -1, + maxSizeStaticDataSources: 2, // 2MB +}; diff --git a/front/lib/plans/free_plans.ts b/front/lib/plans/free_plans.ts index af28ffbbc0b3..4304122f370b 100644 --- a/front/lib/plans/free_plans.ts +++ b/front/lib/plans/free_plans.ts @@ -8,19 +8,26 @@ export type PlanAttributes = Omit< >; /** - * We have 2 FREE plans: - * - The FREE_TEST plan, a free plan with strong limitations, used until the user subscribes to a paid plan. - * - The FREE_UPGRADED plan, a free plan with no limitations that won't be users for users that are not Dust once we have paid plans. + * We have 3 categories of plans: + * - Free: plans with no paid subscription. + * - Pro: plans with a paid subscription, not tailored. -> i.e. the same plan is used by all Pro workspaces. + * - Entreprise: plans with a paid subscription, tailored to the needs of the entreprise. -> i.e. we will have one plan per "Entreprise". + * + * This file about Free plans. */ +// Current free plans: +export const FREE_TEST_PLAN_CODE = "FREE_TEST_PLAN"; +export const FREE_UPGRADED_PLAN_CODE = "FREE_UPGRADED_PLAN"; + /** - * Our TEST plan is our default plan, when no subscription is ON. - * It is the only plan not stored in the database. + * FREE_TEST plan is our default plan: this is the plan used by all workspaces until they subscribe to a plan. + * It is not stored in the database (as we don't create a subsription). */ -export const FREE_TEST_PLAN_CODE = "FREE_TEST_PLAN"; export const FREE_TEST_PLAN_DATA: PlanAttributes = { code: FREE_TEST_PLAN_CODE, name: "Test", + stripeProductId: null, maxMessages: 100, maxUsersInWorkspace: 1, isSlackbotAllowed: false, @@ -35,13 +42,13 @@ export const FREE_TEST_PLAN_DATA: PlanAttributes = { /** * Other FREE plans are stored in the database. - * We never remove anything from this list, we only add new plans and run a migration to create new subscriptions for them. + * We can update existing plans or add new one but never remove anything from this list. */ -export const FREE_UPGRADED_PLAN_CODE = "FREE_UPGRADED_PLAN"; const FREE_PLANS_DATA: PlanAttributes[] = [ { code: FREE_UPGRADED_PLAN_CODE, name: "Free Trial", + stripeProductId: null, maxMessages: -1, maxUsersInWorkspace: -1, isSlackbotAllowed: true, diff --git a/front/lib/plans/pro_plans.ts b/front/lib/plans/pro_plans.ts new file mode 100644 index 000000000000..a5d66da6ebec --- /dev/null +++ b/front/lib/plans/pro_plans.ts @@ -0,0 +1,79 @@ +import { Attributes } from "sequelize"; + +import { Plan } from "@app/lib/models"; + +export type PlanAttributes = Omit< + Attributes, + "id" | "createdAt" | "updatedAt" +>; + +/** + * We have 3 categories of plans: + * - Free: plans with no paid subscription. + * - Pro: plans with a paid subscription, not tailored. -> i.e. the same plan is used by all Pro workspaces. + * - Entreprise: plans with a paid subscription, tailored to the needs of the entreprise. -> i.e. we will have one plan per "Entreprise". + * + * This file about Pro plans. + */ + +// Current pro plans: +export const PRO_PLAN_MAU_29_CODE = "PRO_PLAN_MAU_29"; +export const PRO_PLAN_FIXED_1000_CODE = "PRO_PLAN_FIXED_1000"; + +/** + * Paid plans are stored in the database. + * We can update existing plans or add new one but never remove anything from this list. + * Entreprise custom plans will be created from Poké. + */ +const PRO_PLANS_DATA: PlanAttributes[] = [ + { + code: "PRO_PLAN_MAU_29", + name: "Pro", + stripeProductId: "prod_OtB9SOIwFyiQnl", + maxMessages: -1, + maxUsersInWorkspace: 500, + isSlackbotAllowed: true, + isManagedSlackAllowed: true, + isManagedNotionAllowed: true, + isManagedGoogleDriveAllowed: true, + isManagedGithubAllowed: true, + maxNbStaticDataSources: -1, + maxNbStaticDocuments: -1, + maxSizeStaticDataSources: 2, // 2MB + }, + { + code: "PRO_PLAN_FIXED_1000", + name: "Pro Fixed", + stripeProductId: "prod_OtBhelMswszehT", + maxMessages: -1, + maxUsersInWorkspace: 50, + isSlackbotAllowed: true, + isManagedSlackAllowed: true, + isManagedNotionAllowed: true, + isManagedGoogleDriveAllowed: true, + isManagedGithubAllowed: true, + maxNbStaticDataSources: -1, + maxNbStaticDocuments: -1, + maxSizeStaticDataSources: 2, // 2MB + }, +]; + +/** + * Function to call when we edit something in FREE_PLANS_DATA to update the database. It will create or update the plans. + */ +export const upsertProPlans = async () => { + for (const planData of PRO_PLANS_DATA) { + const plan = await Plan.findOne({ + where: { + code: planData.code, + }, + }); + if (plan === null) { + await Plan.create(planData); + console.log(`Pro plan ${planData.code} created.`); + } else { + await plan.update(planData); + console.log(`Pro plan ${planData.code} updated.`); + } + } +};