payment
parent
6eb711f673
commit
92f6782c21
|
@ -2,8 +2,8 @@ import { Request, Response } from "express";
|
|||
import logger, { userLogger } from "../logger/logger";
|
||||
import Stripe from "stripe";
|
||||
import {
|
||||
ACCOUNT_STATE,
|
||||
DASHBOARD_URL,
|
||||
PAYMENT_PLAN,
|
||||
PAYMENT_PLAN_SETTINGS,
|
||||
} from "../utils/constants";
|
||||
import UserPendingPayment from "../models/userPendingPayment";
|
||||
|
@ -12,10 +12,9 @@ import { getUserSession, stripe } from "../utils/utils";
|
|||
import Store from "../models/store";
|
||||
import Session from "../models/session";
|
||||
|
||||
const ZeitAdlerBasicMonthly = "zeitadler-basic-monthly";
|
||||
const ZeitAdlerBasicYearly = "zeitadler-basic-yearly";
|
||||
const ZeitAdlerPremiumMonthly = "zeitadler-premium-monthly";
|
||||
const ZeitAdlerPremiumYearly = "zeitadler-premium-yearly";
|
||||
const ZeitAdlerBasicMonthly = "za-basic-monthly";
|
||||
const ZeitAdlerBasicYearly = "za-basic-yearly";
|
||||
const lookupKeys = [ZeitAdlerBasicMonthly, ZeitAdlerBasicYearly];
|
||||
|
||||
let cachedPrices = [] as any[];
|
||||
|
||||
|
@ -28,12 +27,7 @@ export async function loadPrices() {
|
|||
|
||||
// load prices from stripe
|
||||
const prices = await stripe.prices.list({
|
||||
lookup_keys: [
|
||||
ZeitAdlerBasicMonthly,
|
||||
ZeitAdlerBasicYearly,
|
||||
ZeitAdlerPremiumMonthly,
|
||||
ZeitAdlerPremiumYearly,
|
||||
],
|
||||
lookup_keys: lookupKeys,
|
||||
expand: ["data.product"],
|
||||
});
|
||||
|
||||
|
@ -48,6 +42,66 @@ export async function loadPrices() {
|
|||
}
|
||||
}
|
||||
|
||||
export async function getUserPlanInfo(req: Request, res: Response) {
|
||||
try {
|
||||
const userSession = await getUserSession(req);
|
||||
|
||||
if (userSession === null) {
|
||||
return res.status(401).send({ err: "unauthorized" });
|
||||
}
|
||||
|
||||
await loadPrices();
|
||||
|
||||
const user = await User.findOne({
|
||||
where: {
|
||||
user_id: userSession.user_id,
|
||||
},
|
||||
attributes: [
|
||||
"payment_plan",
|
||||
"payment_plan_interval",
|
||||
"payment_plan_trial_end",
|
||||
"payment_plan_canceled_at",
|
||||
],
|
||||
});
|
||||
|
||||
if (user === null) {
|
||||
return res.status(400).send({ err: "invalid request" });
|
||||
}
|
||||
|
||||
let resData = {
|
||||
payment_plan: user.payment_plan,
|
||||
payment_plan_interval: user.payment_plan_interval,
|
||||
prices: cachedPrices
|
||||
.filter(
|
||||
(price) =>
|
||||
price.lookup_key === lookupKeys[0] ||
|
||||
price.lookup_key === lookupKeys[1]
|
||||
)
|
||||
.map((price) => {
|
||||
return {
|
||||
lookup_key: price.lookup_key,
|
||||
unit_amount: price.unit_amount,
|
||||
};
|
||||
}),
|
||||
} as any;
|
||||
|
||||
if (user.payment_plan_trial_end !== null) {
|
||||
resData["payment_plan_trial_end"] = user.payment_plan_trial_end;
|
||||
}
|
||||
|
||||
if (user.payment_plan_canceled_at !== null) {
|
||||
resData["payment_plan_canceled_at"] = user.payment_plan_canceled_at;
|
||||
}
|
||||
|
||||
userLogger.info(userSession.user_id, "GetUserPlanInfo");
|
||||
|
||||
res.status(200).send(resData);
|
||||
} catch (error) {
|
||||
logger.error("getUserPlanInfo", error as string);
|
||||
res.status(500).send({ err: "invalid request" });
|
||||
}
|
||||
}
|
||||
|
||||
export async function getPriceId(paymentPlan: number, interval: number) {
|
||||
await loadPrices();
|
||||
|
||||
|
@ -75,13 +129,7 @@ export async function GetPrices(req: Request, res: Response) {
|
|||
|
||||
await loadPrices();
|
||||
|
||||
let lookupKey: any[] = [];
|
||||
|
||||
if (productId === "0") {
|
||||
lookupKey = [ZeitAdlerBasicMonthly, ZeitAdlerBasicYearly];
|
||||
} else if (productId === "1") {
|
||||
lookupKey = [ZeitAdlerPremiumMonthly, ZeitAdlerPremiumYearly];
|
||||
}
|
||||
let lookupKey = [ZeitAdlerBasicMonthly, ZeitAdlerBasicYearly];
|
||||
|
||||
res.status(200).send({
|
||||
prices: cachedPrices
|
||||
|
@ -103,15 +151,88 @@ export async function GetPrices(req: Request, res: Response) {
|
|||
}
|
||||
}
|
||||
|
||||
export async function CreateCheckoutSession(priceId: string, userId: string) {
|
||||
export async function CreateCheckoutSession(req: Request, res: Response) {
|
||||
try {
|
||||
if (priceId === undefined || userId === undefined) {
|
||||
logger.error("CreateCheckoutSession: invalid request");
|
||||
return "";
|
||||
const { lookupKey } = req.body;
|
||||
|
||||
if (lookupKey === undefined) {
|
||||
return res.status(400).send({ err: "invalid request" });
|
||||
}
|
||||
|
||||
await loadPrices();
|
||||
|
||||
// check if lookupKey is valid
|
||||
|
||||
const priceId = cachedPrices.find(
|
||||
(price) => price.lookup_key === lookupKey
|
||||
)?.id;
|
||||
|
||||
if (priceId === undefined) {
|
||||
return res.status(400).send({ err: "invalid request" });
|
||||
}
|
||||
|
||||
const userSession = await getUserSession(req);
|
||||
|
||||
if (userSession === null) {
|
||||
return res.status(401).send({ err: "unauthorized" });
|
||||
}
|
||||
|
||||
const user = await User.findOne({
|
||||
where: {
|
||||
user_id: userSession.user_id,
|
||||
},
|
||||
attributes: ["user_id", "payment_plan_trial_end", "stripe_customer_id"],
|
||||
});
|
||||
|
||||
if (user === null) {
|
||||
return res.status(400).send({ err: "invalid request" });
|
||||
}
|
||||
|
||||
if (user.stripe_customer_id !== null && user.stripe_customer_id !== "") {
|
||||
const subscriptions = await stripe.subscriptions.list({
|
||||
customer: user.stripe_customer_id,
|
||||
limit: 1,
|
||||
});
|
||||
|
||||
if (
|
||||
subscriptions.data.length > 0 &&
|
||||
subscriptions.data[0].id !== priceId
|
||||
) {
|
||||
const latestSubscription = subscriptions.data[0];
|
||||
|
||||
await stripe.subscriptions.update(latestSubscription.id, {
|
||||
items: [
|
||||
{
|
||||
id: latestSubscription.items.data[0].id,
|
||||
price: priceId,
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
// update user
|
||||
|
||||
await User.update(
|
||||
{
|
||||
payment_plan_interval: lookupKey === ZeitAdlerBasicYearly ? 1 : 0,
|
||||
},
|
||||
{
|
||||
where: {
|
||||
user_id: userSession.user_id,
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
userLogger.info(
|
||||
userSession.user_id,
|
||||
`CreateCheckoutSession: update subscription ${latestSubscription.id} to ${priceId}`
|
||||
);
|
||||
|
||||
return res.status(200).json({ status: "ok" });
|
||||
}
|
||||
}
|
||||
|
||||
// create checkout session
|
||||
|
||||
const session = await stripe.checkout.sessions.create({
|
||||
payment_method_types: ["card"],
|
||||
line_items: [
|
||||
|
@ -123,31 +244,37 @@ export async function CreateCheckoutSession(priceId: string, userId: string) {
|
|||
billing_address_collection: "required",
|
||||
mode: "subscription",
|
||||
subscription_data: {
|
||||
trial_period_days: 7,
|
||||
trial_end: new Date(user.payment_plan_trial_end).getTime() / 1000,
|
||||
},
|
||||
success_url: `${DASHBOARD_URL}/checkout/success/{CHECKOUT_SESSION_ID}`,
|
||||
cancel_url: `${DASHBOARD_URL}/checkout/canceled/{CHECKOUT_SESSION_ID}`,
|
||||
success_url: `${DASHBOARD_URL}/payment-plan`,
|
||||
cancel_url: `${DASHBOARD_URL}/payment-plan`,
|
||||
metadata: {
|
||||
userId: userId,
|
||||
},
|
||||
userId: userSession.user_id,
|
||||
payment_plan_interval: lookupKey === ZeitAdlerBasicYearly ? 1 : 0,
|
||||
} /*
|
||||
automatic_tax: {
|
||||
// see https://dashboard.stripe.com/settings/tax
|
||||
enabled: true,
|
||||
},
|
||||
},*/,
|
||||
});
|
||||
|
||||
/*
|
||||
await UserPendingPayment.create({
|
||||
payment_session_id: session.id,
|
||||
user_id: userId,
|
||||
user_id: userSession.user_id,
|
||||
payment_session_url: session.url as string,
|
||||
}); */
|
||||
|
||||
userLogger.info(
|
||||
userSession.user_id,
|
||||
`CreateCheckoutSession: ${session.id}`
|
||||
);
|
||||
|
||||
res.status(200).send({
|
||||
url: session.url,
|
||||
});
|
||||
|
||||
logger.info(`CreateCheckoutSession: ${session.id}`);
|
||||
|
||||
return session.url;
|
||||
} catch (error) {
|
||||
logger.error("CreateCheckoutSession", error as string);
|
||||
return "";
|
||||
res.status(500).send({ err: "invalid request" });
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -263,14 +390,22 @@ export async function StripeWebhook(req: Request, res: Response) {
|
|||
return res.status(400).send(`Webhook Error: ${error}`);
|
||||
}
|
||||
|
||||
let user;
|
||||
let userId;
|
||||
let customerId;
|
||||
let user;
|
||||
|
||||
switch (event.type) {
|
||||
case "checkout.session.completed":
|
||||
userId = (event.data.object as Stripe.Checkout.Session)?.metadata
|
||||
?.userId;
|
||||
const session = event.data.object as Stripe.Checkout.Session;
|
||||
|
||||
if (session === undefined) {
|
||||
logger.error(
|
||||
"StripeWebhook: checkout.session.completed: session undefined"
|
||||
);
|
||||
break;
|
||||
}
|
||||
|
||||
userId = session.metadata?.userId;
|
||||
|
||||
if (userId === undefined) {
|
||||
logger.error(
|
||||
|
@ -279,52 +414,51 @@ export async function StripeWebhook(req: Request, res: Response) {
|
|||
break;
|
||||
}
|
||||
|
||||
// delete user pending payment
|
||||
const paymentPlanInterval = session.metadata?.payment_plan_interval;
|
||||
|
||||
const pendingPayment = await UserPendingPayment.findOne({
|
||||
if (paymentPlanInterval === undefined) {
|
||||
logger.error(
|
||||
"StripeWebhook: checkout.session.completed: paymentPlanInterval undefined"
|
||||
);
|
||||
break;
|
||||
}
|
||||
|
||||
user = await User.findOne({
|
||||
where: {
|
||||
payment_session_id: (event.data.object as Stripe.Checkout.Session)
|
||||
.id,
|
||||
user_id: userId,
|
||||
},
|
||||
});
|
||||
|
||||
if (pendingPayment !== null) {
|
||||
await pendingPayment.destroy();
|
||||
|
||||
let user = await User.findOne({
|
||||
where: {
|
||||
user_id: userId,
|
||||
if (user !== null) {
|
||||
await User.update(
|
||||
{
|
||||
payment_plan: PAYMENT_PLAN.BASIC,
|
||||
stripe_customer_id: (event.data.object as Stripe.Checkout.Session)
|
||||
.customer as string,
|
||||
payment_plan_interval: parseInt(paymentPlanInterval),
|
||||
},
|
||||
});
|
||||
|
||||
if (user !== null && user.state === ACCOUNT_STATE.INIT_PAYMENT) {
|
||||
// update user state
|
||||
await User.update(
|
||||
{
|
||||
state: ACCOUNT_STATE.ACTIVE,
|
||||
stripe_customer_id: (
|
||||
event.data.object as Stripe.Checkout.Session
|
||||
).customer as string,
|
||||
{
|
||||
where: {
|
||||
user_id: userId,
|
||||
},
|
||||
{
|
||||
where: {
|
||||
user_id: userId,
|
||||
},
|
||||
}
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
userLogger.info(
|
||||
userId as string,
|
||||
"StripeWebhook: user state updated to ACTIVE"
|
||||
);
|
||||
}
|
||||
logger.info(
|
||||
`StripeWebhook: checkout.session.completed: ${userId} ${JSON.stringify(
|
||||
event.data.object
|
||||
)}`
|
||||
);
|
||||
} else {
|
||||
logger.error(
|
||||
`StripeWebhook: checkout.session.completed: user not found for userId: ${userId}`
|
||||
);
|
||||
}
|
||||
break;
|
||||
case "checkout.session.expired":
|
||||
logger.info(
|
||||
`StripeWebhook: checkout.session.expired: ${event.data.object.id}`
|
||||
);
|
||||
|
||||
break;
|
||||
case "billing_portal.session.created":
|
||||
customerId = event.data.object.customer as string;
|
||||
|
@ -375,21 +509,23 @@ export async function StripeWebhook(req: Request, res: Response) {
|
|||
|
||||
let updateData: any = {
|
||||
payment_plan_status: status,
|
||||
payment_plan_trial_end: trialEnd !== null ? trialEnd : null,
|
||||
payment_plan_canceled_at: canceledAt !== null ? canceledAt : null,
|
||||
/*payment_plan_trial_end:
|
||||
trialEnd !== null ? new Date(trialEnd * 1000) : null, */
|
||||
payment_plan_canceled_at:
|
||||
canceledAt !== null ? new Date(canceledAt * 1000) : null,
|
||||
};
|
||||
|
||||
logger.info(
|
||||
`StripeWebhook: customer.subscription.updated: updating user: ${
|
||||
user.user_id
|
||||
} ${JSON.stringify(updateData)}`
|
||||
);
|
||||
|
||||
await User.update(updateData, {
|
||||
where: {
|
||||
stripe_customer_id: customerId,
|
||||
},
|
||||
});
|
||||
|
||||
logger.info(
|
||||
`StripeWebhook: customer.subscription.updated: updating user: ${
|
||||
user.user_id
|
||||
} ${JSON.stringify(updateData)}`
|
||||
);
|
||||
break;
|
||||
default:
|
||||
logger.warn(`StripeWebhook: Ignoring unknown event: ${event.type}`);
|
||||
|
@ -480,6 +616,8 @@ export async function GetBillingPortal(req: Request, res: Response) {
|
|||
return_url: `${DASHBOARD_URL}/payment-plan`,
|
||||
});
|
||||
|
||||
userLogger.info(userSession.user_id, "GetBillingPortal");
|
||||
|
||||
res.status(200).send({
|
||||
url: session.url,
|
||||
});
|
||||
|
|
|
@ -18,6 +18,7 @@ import {
|
|||
CALENDAR_MAX_SERVICE_DURATION,
|
||||
CALENDAR_MIN_EARLIEST_BOOKING_TIME,
|
||||
EMAIL_VERIFICATION_STATE,
|
||||
PAYMENT_DEMO_TRAILING_DAYS,
|
||||
PAYMENT_PLAN,
|
||||
PAYMENT_PLAN_SETTINGS,
|
||||
Roles,
|
||||
|
@ -132,7 +133,8 @@ export async function SignUp(req: Request, res: Response) {
|
|||
owner_user_id: userId,
|
||||
name: companyName,
|
||||
calendar_max_future_booking_days:
|
||||
PAYMENT_PLAN_SETTINGS[PAYMENT_PLAN.DEMO].calendarMaxFutureBookingDays,
|
||||
PAYMENT_PLAN_SETTINGS[PAYMENT_PLAN.TRAILING]
|
||||
.calendarMaxFutureBookingDays,
|
||||
calendar_min_earliest_booking_time: CALENDAR_MIN_EARLIEST_BOOKING_TIME,
|
||||
calendar_max_service_duration: CALENDAR_MAX_SERVICE_DURATION,
|
||||
address: companyAddress,
|
||||
|
@ -164,9 +166,9 @@ export async function SignUp(req: Request, res: Response) {
|
|||
password: hashedPassword,
|
||||
language: language,
|
||||
analytics_enabled: USER_ANALYTICS_ENABLED_DEFAULT,
|
||||
state: ACCOUNT_STATE.INIT_PAYMENT,
|
||||
payment_plan: PAYMENT_PLAN.DEMO,
|
||||
// payment_plan_status: PAYMENT_PLAN_STATUS.TRAILING,
|
||||
state: ACCOUNT_STATE.ACTIVE,
|
||||
payment_plan: PAYMENT_PLAN.TRAILING,
|
||||
payment_plan_trial_end: new Date(Date.now() + PAYMENT_DEMO_TRAILING_DAYS),
|
||||
});
|
||||
/*
|
||||
const checkoutSessionUrl = await CreateCheckoutSession(
|
||||
|
@ -471,7 +473,6 @@ export async function GetUser(req: Request, res: Response) {
|
|||
"language",
|
||||
"analytics_enabled",
|
||||
"payment_plan",
|
||||
"payment_plan_status",
|
||||
"payment_plan_trial_end",
|
||||
"payment_plan_canceled_at",
|
||||
"created_at",
|
||||
|
@ -495,21 +496,29 @@ export async function GetUser(req: Request, res: Response) {
|
|||
|
||||
let respData = {
|
||||
user: {
|
||||
user_id: user.user_id,
|
||||
// user_id: user.user_id,
|
||||
username: user.username,
|
||||
//store_id: user.store_id,
|
||||
language: user.language,
|
||||
analytics_enabled: user.analytics_enabled,
|
||||
payment_plan: user.payment_plan,
|
||||
// payment_plan_status: user.payment_plan_status,
|
||||
payment_plan_trial_end: user.payment_plan_trial_end,
|
||||
payment_plan_canceled_at: user.payment_plan_canceled_at,
|
||||
},
|
||||
stores: stores,
|
||||
// only temporary until we have a proper permissions system
|
||||
permissions: [] as string[],
|
||||
paymentPlanSettings: PAYMENT_PLAN_SETTINGS[user.payment_plan],
|
||||
};
|
||||
} as any;
|
||||
|
||||
if (user.payment_plan_canceled_at !== null) {
|
||||
user["payment_plan_canceled_at"] = user.payment_plan_canceled_at;
|
||||
}
|
||||
|
||||
if (
|
||||
user.payment_plan === PAYMENT_PLAN.TRAILING ||
|
||||
user.payment_plan_canceled_at !== null
|
||||
) {
|
||||
respData.user["payment_plan_trial_end"] = user.payment_plan_trial_end;
|
||||
}
|
||||
|
||||
// if user is not a store master, then check if user is a worker
|
||||
if (!stores || stores.length === 0) {
|
||||
|
@ -528,7 +537,6 @@ export async function GetUser(req: Request, res: Response) {
|
|||
stores.push(store);
|
||||
|
||||
respData.stores = stores;
|
||||
|
||||
respData.permissions.push("calendar");
|
||||
} else {
|
||||
// user is a store owner
|
||||
|
|
|
@ -43,7 +43,19 @@ class MyTransport extends Transport {
|
|||
setImmediate(() => this.emit("logged", info));
|
||||
|
||||
const currentDate = new Date();
|
||||
const formattedDate = `${currentDate.getHours()}:${currentDate.getMinutes()}:${currentDate.getSeconds()}:${currentDate.getMilliseconds()}`;
|
||||
const formattedDate = `${currentDate
|
||||
.getHours()
|
||||
.toString()
|
||||
.padStart(2, "0")}:${currentDate
|
||||
.getMinutes()
|
||||
.toString()
|
||||
.padStart(2, "0")}:${currentDate
|
||||
.getSeconds()
|
||||
.toString()
|
||||
.padStart(2, "0")}:${currentDate
|
||||
.getMilliseconds()
|
||||
.toString()
|
||||
.padStart(3, "0")}`;
|
||||
|
||||
let logLevel;
|
||||
|
||||
|
|
|
@ -18,9 +18,9 @@ interface UserAttributes {
|
|||
google_account_picture?: string;
|
||||
analytics_enabled: boolean;
|
||||
payment_plan: number;
|
||||
// payment_plan_status?: string;
|
||||
payment_plan_trial_end?: number;
|
||||
payment_plan_canceled_at?: number;
|
||||
payment_plan_interval?: number;
|
||||
payment_plan_trial_end?: Date;
|
||||
payment_plan_canceled_at?: Date;
|
||||
stripe_customer_id?: string;
|
||||
}
|
||||
|
||||
|
@ -40,9 +40,9 @@ class User extends Model<UserAttributes> implements UserAttributes {
|
|||
declare google_account_picture: string;
|
||||
declare analytics_enabled: boolean;
|
||||
declare payment_plan: number;
|
||||
// declare payment_plan_status: string;
|
||||
declare payment_plan_trial_end: number;
|
||||
declare payment_plan_canceled_at: number;
|
||||
declare payment_plan_interval: number;
|
||||
declare payment_plan_trial_end: Date;
|
||||
declare payment_plan_canceled_at: Date;
|
||||
declare stripe_customer_id: string;
|
||||
declare created_at: Date;
|
||||
}
|
||||
|
@ -111,16 +111,16 @@ User.init(
|
|||
type: DataTypes.TINYINT,
|
||||
allowNull: false,
|
||||
},
|
||||
/*payment_plan_status: {
|
||||
type: DataTypes.STRING,
|
||||
allowNull: true,
|
||||
}, */
|
||||
payment_plan_trial_end: {
|
||||
payment_plan_interval: {
|
||||
type: DataTypes.INTEGER,
|
||||
allowNull: true,
|
||||
},
|
||||
payment_plan_trial_end: {
|
||||
type: DataTypes.DATE,
|
||||
allowNull: true,
|
||||
},
|
||||
payment_plan_canceled_at: {
|
||||
type: DataTypes.INTEGER,
|
||||
type: DataTypes.DATE,
|
||||
allowNull: true,
|
||||
},
|
||||
stripe_customer_id: {
|
||||
|
|
|
@ -2,10 +2,14 @@ import express from "express";
|
|||
const router = express.Router();
|
||||
|
||||
import * as paymentController from "../controllers/paymentController";
|
||||
import { sessionProtection } from "../middleware/authMiddleware";
|
||||
|
||||
router.get("/", sessionProtection, paymentController.getUserPlanInfo);
|
||||
|
||||
router.get("/prices/:productId", paymentController.GetPrices);
|
||||
// webhook is registered in server.ts as it needs registered before the body parser
|
||||
|
||||
router.post("/checkout", paymentController.CreateCheckoutSession);
|
||||
router.post("/checkout/success", paymentController.CheckoutSuccess);
|
||||
router.post("/checkout/canceled", paymentController.CheckoutCanceled);
|
||||
router.get("/portal", paymentController.GetBillingPortal);
|
||||
|
|
|
@ -59,7 +59,6 @@ export enum ACCOUNT_STATE {
|
|||
INIT_LOGIN = 2, // account is created but password is not set yet
|
||||
BANNED = 3, // account is banned, cannot login
|
||||
PENDING_EMAIL_VERIFICATION = 4, // account is created but email is not verified yet
|
||||
INIT_PAYMENT = 5, // account is created but payment is not set yet
|
||||
}
|
||||
|
||||
export const FEEDBACK_MIN_LENGTH = 3;
|
||||
|
@ -88,33 +87,29 @@ export const PASSPORT_SUCCESS_REDIRECT_URL = `${DASHBOARD_URL}/store/calendar/au
|
|||
export const ACCOUNT_EXPORT_URL = `${DASHBOARD_URL}/api/v1/user/profile/export/`;
|
||||
export const TERMIN_PLANNER_URL = process.env.TERMIN_PLANNER_URL;
|
||||
|
||||
export const PAYMENT_DEMO_TRAILING_DAYS = 7 * 24 * 60 * 60 * 1000; // 7 days
|
||||
|
||||
export enum PAYMENT_PLAN {
|
||||
DEMO = 0,
|
||||
TRAILING = 0,
|
||||
BASIC = 1,
|
||||
PREMIUM = 2,
|
||||
}
|
||||
|
||||
export const PAYMENT_PLAN_SETTINGS = [
|
||||
{
|
||||
id: "demo", // used in the backend for identifiying the stripe pricing product
|
||||
name: "Demo", // used in the frontend
|
||||
id: "trailing", // used in the backend for identifiying the stripe pricing product
|
||||
name: "Trailing", // used in the frontend
|
||||
maxEmployees: 5,
|
||||
calendarMaxFutureBookingDays: 7,
|
||||
},
|
||||
{
|
||||
id: "basic", // used in the backend for identifiying the stripe pricing product
|
||||
name: "Basic", // used in the frontend
|
||||
maxEmployees: 15,
|
||||
calendarMaxFutureBookingDays: 60,
|
||||
},
|
||||
{
|
||||
id: "premium", // used in the backend for identifiying the stripe pricing product
|
||||
name: "Premium", // used in the frontend
|
||||
maxEmployees: 20,
|
||||
calendarMaxFutureBookingDays: 90,
|
||||
calendarMaxFutureBookingDays: 30,
|
||||
},
|
||||
];
|
||||
|
||||
/*
|
||||
export enum PAYMENT_PLAN_STATUS {
|
||||
TRAILING = "trailing",
|
||||
}
|
||||
*/
|
||||
|
|
|
@ -183,13 +183,7 @@ export function isCalendarMinEarliestBookingTimeValid(
|
|||
}
|
||||
|
||||
export function isPaymentPlanValid(paymentPlan: number) {
|
||||
return (
|
||||
paymentPlan >= PAYMENT_PLAN.BASIC && paymentPlan <= PAYMENT_PLAN.PREMIUM
|
||||
);
|
||||
}
|
||||
|
||||
export function isPaymentIntervalValid(paymentInterval: number) {
|
||||
return paymentInterval === 0 || paymentInterval === 1;
|
||||
return paymentPlan >= PAYMENT_PLAN.BASIC && paymentPlan <= PAYMENT_PLAN.BASIC;
|
||||
}
|
||||
|
||||
export function isCompanyNameValid(companyName: string) {
|
||||
|
|
Loading…
Reference in New Issue