fix dashboard + payments

This commit is contained in:
Emily
2025-04-13 18:15:43 +02:00
parent 1d5dad44fa
commit 946f9d4d32
22 changed files with 272 additions and 521 deletions

View File

@@ -1,126 +0,0 @@
import { UserLimitModel } from "@schema/UserLimitSchema";
import { AIPlugin } from "../Plugin";
import { MAX_LOG_LIMIT_PERCENT } from "@data/broker/Limits";
import { ProjectModel } from "@schema/project/ProjectSchema";
import StripeService from "~/server/services/StripeService";
import { InvoiceData } from "~/server/api/pay/invoices";
export class AiBilling extends AIPlugin<[
'getBillingInfo',
'getLimits',
'getInvoices'
]> {
constructor() {
super({
'getInvoices': {
handler: async (data: { user_id: string }) => {
const project = await ProjectModel.findOne({ user_id: data.user_id });
if (!project) return { error: 'Project not found' };
const invoices = await StripeService.getInvoices(data.user_id);
if (!invoices) return [];
return invoices?.data.map(e => {
const result: InvoiceData = {
link: e.invoice_pdf || '',
id: e.number || '',
date: e.created * 1000,
status: e.status || 'NO_STATUS',
cost: e.amount_due
}
return result;
});
},
tool: {
type: 'function',
function: {
name: 'getInvoices',
description: 'Gets the invoices of the user project',
parameters: {}
}
}
},
'getBillingInfo': {
handler: async (data: { user_id: string }) => {
return { error: 'NOT IMPLEMENTED YET' }
// if (project.subscription_id === 'onetime') {
// const projectLimits = await ProjectLimitModel.findOne({ project_id: data.project_id });
// if (!projectLimits) return { error: 'Limits not found' }
// const result = {
// premium: project.premium,
// premium_type: project.premium_type,
// billing_start_at: projectLimits.billing_start_at,
// billing_expire_at: projectLimits.billing_expire_at,
// limit: projectLimits.limit,
// count: projectLimits.events + projectLimits.visits,
// subscription_status: StripeService.isDisabled() ? 'Disabled mode' : ('One time payment')
// }
// return result;
// }
// const subscription = await StripeService.getSubscription(project.subscription_id);
// const projectLimits = await ProjectLimitModel.findOne({ project_id: data.project_id });
// if (!projectLimits) return { error: 'Limits not found' }
// const result = {
// premium: project.premium,
// premium_type: project.premium_type,
// billing_start_at: projectLimits.billing_start_at,
// billing_expire_at: projectLimits.billing_expire_at,
// limit: projectLimits.limit,
// count: projectLimits.events + projectLimits.visits,
// subscription_status: StripeService.isDisabled() ? 'Disabled mode' : (subscription?.status ?? '?')
// }
// return result;
},
tool: {
type: 'function',
function: {
name: 'getBillingInfo',
description: 'Gets the informations about the billing of the user project, limits, count, subscription_status, is premium, premium type, billing start at, billing expire at',
parameters: {}
}
}
},
'getLimits': {
handler: async (data: { project_id: string }) => {
return { error: 'NOT IMPLEMENTED YET' }
// const projectLimits = await ProjectLimitModel.findOne({ project_id: data.project_id });
// if (!projectLimits) return { error: 'Project limits not found' };
// const TOTAL_COUNT = projectLimits.events + projectLimits.visits;
// const COUNT_LIMIT = projectLimits.limit;
// return {
// total: TOTAL_COUNT,
// limit: COUNT_LIMIT,
// limited: TOTAL_COUNT > COUNT_LIMIT * MAX_LOG_LIMIT_PERCENT,
// percent: Math.round(100 / COUNT_LIMIT * TOTAL_COUNT)
// }
},
tool: {
type: 'function',
function: {
name: 'getLimits',
description: 'Gets the informations about the limits of the user project',
parameters: {}
}
}
},
})
}
}
export const AiBillingInstance = new AiBilling();

View File

@@ -2,7 +2,6 @@ import { ProjectModel } from "@schema/project/ProjectSchema";
import { ProjectCountModel } from "@schema/project/ProjectsCounts";
import { UserLimitModel } from "@schema/UserLimitSchema";
import { UserModel } from "@schema/UserSchema";
import StripeService from '~/server/services/StripeService';
import { PremiumModel } from "~/shared/schema/PremiumSchema";
export default defineEventHandler(async event => {
@@ -20,14 +19,18 @@ export default defineEventHandler(async event => {
const premium = await PremiumModel.findOne({ user_id: userData.id });
const subscription =
premium?.subscription_id ?
await StripeService.getSubscription(premium.subscription_id) : 'NONE';
// const subscription =
// premium?.subscription_id ?
// await StripeService.getSubscription(premium.subscription_id) : 'NONE';
const customer =
premium?.customer_id ?
await StripeService.getCustomer(premium.customer_id) : 'NONE';
// const customer =
// premium?.customer_id ?
// await StripeService.getCustomer(premium.customer_id) : 'NONE';
return { project, limits, counts, user, subscription, customer }
return {
project, limits, counts, user,
subscription: '',
customer: ''
}
});

View File

@@ -4,6 +4,7 @@ import { UserModel } from '@schema/UserSchema';
import { PasswordModel } from '@schema/PasswordSchema';
import { EmailService } from '@services/EmailService';
import { EmailServiceHelper } from '~/server/services/EmailServiceHelper';
import { PaymentServiceHelper } from '~/server/services/PaymentServiceHelper';
export default defineEventHandler(async event => {
@@ -13,15 +14,22 @@ export default defineEventHandler(async event => {
if (!data) return setResponseStatus(event, 400, 'Error decoding register_code');
try {
await PasswordModel.create({ email: data.email, password: data.password })
await UserModel.create({ email: data.email, given_name: '', name: 'EmailLogin', locale: '', picture: '', created_at: Date.now() });
await PasswordModel.updateOne({ email: data.email }, { password: data.password }, { upsert: true });
const user = await UserModel.create({ email: data.email, given_name: '', name: 'EmailLogin', locale: '', picture: '', created_at: Date.now() });
const [ok, error] = await PaymentServiceHelper.create_customer(user.id);
if (!ok) throw error;
setImmediate(() => {
const emailData = EmailService.getEmailServerInfo('welcome', { target: data.email });
EmailServiceHelper.sendEmail(emailData);
});
const jwt = createUserJwt({ email: data.email, name: 'EmailLogin' });
return sendRedirect(event, `https://dashboard.litlyx.com/jwt_login?jwt_login=${jwt}`);
} catch (ex) {
console.error(ex);
return setResponseStatus(event, 400, 'Error creating user');
}

View File

@@ -1,38 +1,38 @@
import { getPlanFromId } from "@data/PREMIUM";
import { getUserProjectFromId } from "~/server/LIVE_DEMO_DATA";
import StripeService from '~/server/services/StripeService';
// import StripeService from '~/server/services/StripeService';
export default defineEventHandler(async event => {
const data = await getRequestDataOld(event, { requireSchema: false, allowGuests: false, allowLitlyx: false });
if (!data) return;
// const data = await getRequestDataOld(event, { requireSchema: false, allowGuests: false, allowLitlyx: false });
// if (!data) return;
const { project, pid } = data;
// const { project, pid } = data;
const body = await readBody(event);
// const body = await readBody(event);
const { planId } = body;
// const { planId } = body;
const PLAN = getPlanFromId(planId);
// const PLAN = getPlanFromId(planId);
if (!PLAN) {
console.error('PLAN', planId, 'NOT EXIST');
return setResponseStatus(event, 400, 'Plan not exist');
}
// if (!PLAN) {
// console.error('PLAN', planId, 'NOT EXIST');
// return setResponseStatus(event, 400, 'Plan not exist');
// }
const intent = await StripeService.createOnetimePayment(
StripeService.testMode ? PLAN.PRICE_TEST : PLAN.PRICE,
'https://dashboard.litlyx.com/payment_ok',
pid,
project.customer_id
)
// const intent = await StripeService.createOnetimePayment(
// StripeService.testMode ? PLAN.PRICE_TEST : PLAN.PRICE,
// 'https://dashboard.litlyx.com/payment_ok',
// pid,
// project.customer_id
// )
if (!intent) {
console.error('Cannot create Intent', { plan: PLAN });
return setResponseStatus(event, 400, 'Cannot create intent');
}
// if (!intent) {
// console.error('Cannot create Intent', { plan: PLAN });
// return setResponseStatus(event, 400, 'Cannot create intent');
// }
return intent.url;
// return intent.url;
});

View File

@@ -1,5 +1,5 @@
import { getPlanFromId } from "@data/PREMIUM";
import StripeService from '~/server/services/StripeService';
// import StripeService from '~/server/services/StripeService';
export default defineEventHandler(async event => {
@@ -9,29 +9,30 @@ export default defineEventHandler(async event => {
const { project, pid } = data;
const body = await readBody(event);
// const body = await readBody(event);
const { planId } = body;
// const { planId } = body;
const PLAN = getPlanFromId(planId);
// const PLAN = getPlanFromId(planId);
if (!PLAN) {
console.error('PLAN', planId, 'NOT EXIST');
return setResponseStatus(event, 400, 'Plan not exist');
}
// if (!PLAN) {
// console.error('PLAN', planId, 'NOT EXIST');
// return setResponseStatus(event, 400, 'Plan not exist');
// }
const checkout = await StripeService.createPayment(
StripeService.testMode ? PLAN.PRICE_TEST : PLAN.PRICE,
'https://dashboard.litlyx.com/payment_ok',
pid,
project.customer_id
);
// const checkout = await StripeService.createPayment(
// StripeService.testMode ? PLAN.PRICE_TEST : PLAN.PRICE,
// 'https://dashboard.litlyx.com/payment_ok',
// pid,
// project.customer_id
// );
if (!checkout) {
console.error('Cannot create payment', { plan: PLAN });
return setResponseStatus(event, 400, 'Cannot create payment');
}
// if (!checkout) {
// console.error('Cannot create payment', { plan: PLAN });
// return setResponseStatus(event, 400, 'Cannot create payment');
// }
return checkout.url;
// return checkout.url;
return '';
});

View File

@@ -1,5 +1,5 @@
import StripeService from '~/server/services/StripeService';
import { PaymentServiceHelper } from '~/server/services/PaymentServiceHelper';
import { PremiumModel } from '~/shared/schema/PremiumSchema';
export default defineEventHandler(async event => {
@@ -10,9 +10,9 @@ export default defineEventHandler(async event => {
const premium = await PremiumModel.findOne({ user_id: data.user.id })
if (!premium) return;
const customer = await StripeService.getCustomer(premium.customer_id);
if (customer?.deleted) return;
const [ok, customerInfoOrError] = await PaymentServiceHelper.customer_info(data.user.id);
if (!ok) throw customerInfoOrError;
return customer?.address;
return customerInfoOrError;
});

View File

@@ -1,9 +1,7 @@
import { getUserProjectFromId } from "~/server/LIVE_DEMO_DATA";
import { Redis } from "~/server/services/CacheService";
import StripeService from '~/server/services/StripeService';
import { PaymentServiceHelper } from "~/server/services/PaymentServiceHelper";
import { PremiumModel } from "~/shared/schema/PremiumSchema";
export type InvoiceData = {
date: number,
cost: number,
@@ -21,11 +19,14 @@ export default defineEventHandler(async event => {
const premium = await PremiumModel.findOne({ user_id: data.user.id });
if (!premium) return [];
const invoices = await StripeService.getInvoices(premium.customer_id);
if (!invoices) return [];
return invoices?.data.map(e => {
const [ok, invoicesOrError] = await PaymentServiceHelper.invoices_list(data.user.id);
if (!ok) {
console.error(invoicesOrError);
return [];
}
return invoicesOrError.invoices.map(e => {
const result: InvoiceData = {
link: e.invoice_pdf || '',
id: e.number || '',
@@ -36,7 +37,6 @@ export default defineEventHandler(async event => {
return result;
});
});
});

View File

@@ -1,6 +1,6 @@
import { getPlanFromId, PREMIUM_PLAN } from "@data/PREMIUM";
import { canTryAppsumoCode, checkAppsumoCode, useAppsumoCode, useTryAppsumoCode } from "~/server/services/AppsumoService";
import StripeService from '~/server/services/StripeService';
function getPlanToActivate(current_plan_id: number) {
if (current_plan_id === PREMIUM_PLAN.FREE.ID) {
@@ -38,13 +38,13 @@ export default defineEventHandler(async event => {
const valid = await checkAppsumoCode(code);
if (!valid) return setResponseStatus(event, 400, 'Code not valid');
const currentPlan = getPlanFromId(project.premium_type);
if (!currentPlan) return setResponseStatus(event, 400, 'Current plan not found');
const planToActivate = getPlanToActivate(currentPlan.ID);
if (!planToActivate) return setResponseStatus(event, 400, 'Cannot use code on current plan');
// const currentPlan = getPlanFromId(project.premium_type);
// if (!currentPlan) return setResponseStatus(event, 400, 'Current plan not found');
// const planToActivate = getPlanToActivate(currentPlan.ID);
// if (!planToActivate) return setResponseStatus(event, 400, 'Cannot use code on current plan');
await StripeService.createSubscription(project.customer_id, planToActivate.ID);
// await StripeService.createSubscription(project.customer_id, planToActivate.ID);
await useAppsumoCode(pid, code);
// await useAppsumoCode(pid, code);
});

View File

@@ -1,19 +1,17 @@
import { getUserProjectFromId } from "~/server/LIVE_DEMO_DATA";
import StripeService from '~/server/services/StripeService';
import { PaymentServiceHelper } from '~/server/services/PaymentServiceHelper';
import { PremiumModel } from '~/shared/schema/PremiumSchema';
export default defineEventHandler(async event => {
const data = await getRequestData(event, []);
if (!data) return;
const { project } = data;
if (!project.customer_id) return setResponseStatus(event, 400, 'Project has no customer_id');
const premium = await PremiumModel.findOne({ user_id: data.user.id })
if (!premium) return;
const body = await readBody(event);
const res = await StripeService.setCustomerInfo(project.customer_id, body);
return { ok: true, data: res }
return await PaymentServiceHelper.update_customer_info(data.user.id, body);
});

View File

@@ -1,6 +1,5 @@
import { ProjectModel, TProject } from "@schema/project/ProjectSchema";
import { ProjectCountModel } from "@schema/project/ProjectsCounts";
import StripeService from '~/server/services/StripeService';
export default defineEventHandler(async event => {
@@ -19,57 +18,11 @@ export default defineEventHandler(async event => {
const existingUserProjects = await ProjectModel.countDocuments({ owner: userData.id });
if (existingUserProjects >= maxProjects) return setResponseStatus(event, 400, 'Already have max number of projects');
if (StripeService.isDisabled()) {
const project = await ProjectModel.create({ owner: userData.id, name: newProjectName });
const project = await ProjectModel.create({
owner: userData.id,
name: newProjectName,
premium: false,
premium_type: 0,
customer_id: 'DISABLED_MODE',
subscription_id: "DISABLED_MODE",
premium_expire_at: new Date(3000, 1, 1)
});
await ProjectCountModel.create({ project_id: project._id, events: 0, visits: 0, sessions: 0 });
await ProjectCountModel.create({
project_id: project._id,
events: 0,
visits: 0,
sessions: 0
});
return project.toJSON() as TProject;
} else {
const customer = await StripeService.createCustomer(userData.user.email);
if (!customer) return setResponseStatus(event, 400, 'Error creating customer');
const subscription = await StripeService.createFreeSubscription(customer.id);
if (!subscription) return setResponseStatus(event, 400, 'Error creating subscription');
const project = await ProjectModel.create({
owner: userData.id,
name: newProjectName,
premium: false,
premium_type: 0,
customer_id: customer.id,
subscription_id: subscription.id,
premium_expire_at: subscription.current_period_end * 1000
});
await ProjectCountModel.create({
project_id: project._id,
events: 0,
visits: 0,
sessions: 0
});
return project.toJSON() as TProject;
}
return project.toJSON() as TProject;

View File

@@ -1,5 +1,4 @@
import { UserLimitModel } from "@schema/UserLimitSchema";
import StripeService from '~/server/services/StripeService';
import { PremiumModel } from "~/shared/schema/PremiumSchema";
export default defineEventHandler(async event => {
@@ -22,14 +21,12 @@ export default defineEventHandler(async event => {
billing_expire_at: userLimits.billing_expire_at,
limit: userLimits.limit,
count: userLimits.events + userLimits.visits,
subscription_status: StripeService.isDisabled() ? 'Disabled mode' : ('One time payment')
subscription_status: 'One time'
}
return result;
}
const subscription = await StripeService.getSubscription(premium.subscription_id);
const userLimits = await UserLimitModel.findOne({ user_id: data.user.id });
if (!userLimits) return setResponseStatus(event, 400, 'User limits not found');
@@ -41,7 +38,7 @@ export default defineEventHandler(async event => {
billing_expire_at: userLimits.billing_expire_at,
limit: userLimits.limit,
count: userLimits.events + userLimits.visits,
subscription_status: StripeService.isDisabled() ? 'Disabled mode' : (subscription?.status ?? '?')
subscription_status: ''
}
return result;

View File

@@ -6,7 +6,6 @@ import { UserSettingsModel } from "@schema/UserSettings";
import { AiChatModel } from "@schema/ai/AiChatSchema";
import { LimitNotifyModel } from "@schema/broker/LimitNotifySchema";
import { SessionModel } from "@schema/metrics/SessionSchema";
import StripeService from "~/server/services/StripeService";
import { UserModel } from "@schema/UserSchema";
import { AddressBlacklistModel } from "~/shared/schema/shields/AddressBlacklistSchema";
import { DomainWhitelistModel } from "~/shared/schema/shields/DomainWhitelistSchema";
@@ -36,7 +35,7 @@ export default defineEventHandler(async event => {
const limitdeletation = await UserLimitModel.deleteMany({ user_id: userData.id });
const notifiesDeletation = await LimitNotifyModel.deleteMany({ user_id: userData.id });
await StripeService.deleteCustomer(premium.customer_id);
// await StripeService.deleteCustomer(premium.customer_id);
for (const project of projects) {
const project_id = project._id;
@@ -51,12 +50,11 @@ export default defineEventHandler(async event => {
const botTrafficOptionsDeletation = await BotTrafficOptionModel.deleteMany({ project_id });
const countryBlacklistDeletation = await CountryBlacklistModel.deleteMany({ project_id });
const domainWhitelistDeletation = await DomainWhitelistModel.deleteMany({ project_id });
const userDeletation = await UserModel.deleteOne({ _id: userData.id });
}
const userDeletation = await UserModel.deleteOne({ _id: userData.id });
return { ok: true };

View File

@@ -1,6 +1,5 @@
import mongoose from "mongoose";
import { Redis } from "~/server/services/CacheService";
import StripeService from '~/server/services/StripeService';
import { logger } from "./Logger";
@@ -13,16 +12,6 @@ export default async () => {
logger.info('[SERVER] Initializing');
if (config.STRIPE_SECRET) {
const TEST_MODE = config.MODE === 'TEST';
StripeService.init(config.STRIPE_SECRET, config.STRIPE_WH_SECRET, TEST_MODE);
logger.info('[STRIPE] Initialized');
} else {
StripeService.disable();
logger.warn('[STRIPE] No stripe key - Disabled mode');
}
if (!connection || connection.connection.readyState == mongoose.ConnectionStates.disconnected) {
logger.info('[DATABASE] Connecting');
connection = await mongoose.connect(config.MONGO_CONNECTION_STRING);

View File

@@ -6,7 +6,6 @@ import { AiChatModel } from '@schema/ai/AiChatSchema';
import { AiEventsInstance } from '../ai/functions/AI_Events';
import { AiVisitsInstance } from '../ai/functions/AI_Visits';
import { AiSessionsInstance } from '../ai/functions/AI_Sessions';
import { AiBillingInstance } from '../ai/functions/AI_Billing';
import { AiSnapshotInstance } from '../ai/functions/AI_Snapshots';
import { AiComposableChartInstance } from '../ai/functions/AI_ComposableChart';
@@ -20,7 +19,6 @@ const tools: OpenAI.Chat.Completions.ChatCompletionTool[] = [
...AiVisitsInstance.getTools(),
...AiEventsInstance.getTools(),
...AiSessionsInstance.getTools(),
...AiBillingInstance.getTools(),
...AiSnapshotInstance.getTools(),
...AiComposableChartInstance.getTools(),
]
@@ -30,7 +28,6 @@ const functions: any = {
...AiVisitsInstance.getHandlers(),
...AiEventsInstance.getHandlers(),
...AiSessionsInstance.getHandlers(),
...AiBillingInstance.getHandlers(),
...AiSnapshotInstance.getHandlers(),
...AiComposableChartInstance.getHandlers()
}

View File

@@ -0,0 +1,50 @@
const { PAYMENT_SECRET } = useRuntimeConfig();
type ErrorResponse = [false, Error];
type OkResponse<T> = [true, T];
type PaymentServiceResponse<T> = Promise<OkResponse<T> | ErrorResponse>
export class PaymentServiceHelper {
static BASE_URL = 'https://test-payments.litlyx.com/payment';
private static async send(endpoint: string, body: Record<string, any>): PaymentServiceResponse<any> {
try {
const res = await $fetch(`${this.BASE_URL}${endpoint}`, {
body: JSON.stringify(body),
method: 'POST',
headers: {
'Content-Type': 'application/json',
'x-litlyx-token': PAYMENT_SECRET
}
})
return [true, res];
} catch (ex: any) {
console.error(ex);
return [false, ex];
}
}
static async create_customer(user_id: string): PaymentServiceResponse<{ ok: true }> {
return await this.send('/create_customer', { user_id });
}
static async create_payment(user_id: string, plan_id: number): PaymentServiceResponse<{ url: string }> {
return await this.send('/create_payment', { user_id, plan_id });
}
static async invoices_list(user_id: string): PaymentServiceResponse<{ invoices: any[] }> {
return await this.send('/invoices_list', { user_id });
}
static async customer_info(user_id: string): PaymentServiceResponse<any> {
return await this.send('/customer_info', { user_id });
}
static async update_customer_info(user_id: string, address: { line1: string, line2: string, city: string, country: string, postal_code: string, state: string }): PaymentServiceResponse<{ ok: true }> {
return await this.send('/update_customer_info', { user_id, address });
}
}

View File

@@ -1,225 +0,0 @@
import { getPlanFromId, getPlanFromTag, PREMIUM_TAG } from '@data/PREMIUM';
import Stripe from 'stripe';
class StripeService {
private stripe?: Stripe;
private privateKey?: string;
private webhookSecret?: string;
public testMode?: boolean;
private disabledMode: boolean = false;
init(privateKey: string, webhookSecret: string, testMode: boolean = false) {
this.privateKey = privateKey;
this.webhookSecret = webhookSecret;
this.stripe = new Stripe(this.privateKey);
this.testMode = testMode;
}
disable() { this.disabledMode = true; }
enable() { this.disabledMode = false; }
isDisabled() { return this.disabledMode; }
parseWebhook(body: any, sig: string) {
if (this.disabledMode) return;
if (!this.stripe) throw Error('Stripe not initialized');
if (!this.webhookSecret) {
console.error('Stripe not initialized')
return;
}
return this.stripe.webhooks.constructEvent(body, sig, this.webhookSecret);
}
async createOnetimePayment(price: string, success_url: string, pid: string, customer?: string) {
if (this.disabledMode) return;
if (!this.stripe) throw Error('Stripe not initialized');
const checkout = await this.stripe.checkout.sessions.create({
allow_promotion_codes: true,
payment_method_types: ['card'],
invoice_creation: {
enabled: true,
},
line_items: [
{ price, quantity: 1 }
],
payment_intent_data: {
metadata: {
pid, price
}
},
customer,
success_url,
mode: 'payment'
});
return checkout;
}
async createPayment(price: string, success_url: string, pid: string, customer?: string) {
if (this.disabledMode) return;
if (!this.stripe) throw Error('Stripe not initialized');
const checkout = await this.stripe.checkout.sessions.create({
allow_promotion_codes: true,
payment_method_types: ['card'],
line_items: [
{ price, quantity: 1 }
],
subscription_data: {
metadata: { pid },
},
customer,
success_url,
mode: 'subscription'
});
return checkout;
}
async getPriceData(priceId: string) {
if (this.disabledMode) return;
if (!this.stripe) throw Error('Stripe not initialized');
const priceData = await this.stripe.prices.retrieve(priceId);
return priceData;
}
async deleteSubscription(subscriptionId: string) {
if (this.disabledMode) return;
if (!this.stripe) throw Error('Stripe not initialized');
const subscription = await this.stripe.subscriptions.cancel(subscriptionId);
return subscription;
}
async getSubscription(subscriptionId: string) {
if (this.disabledMode) return;
if (!this.stripe) throw Error('Stripe not initialized');
const subscription = await this.stripe.subscriptions.retrieve(subscriptionId);
return subscription;
}
async getAllSubscriptions(customer_id: string) {
if (this.disabledMode) return;
if (!this.stripe) throw Error('Stripe not initialized');
const subscriptions = await this.stripe.subscriptions.list({ customer: customer_id });
return subscriptions;
}
async getInvoices(customer_id: string) {
if (this.disabledMode) return;
if (!this.stripe) throw Error('Stripe not initialized');
const invoices = await this.stripe?.invoices.list({ customer: customer_id });
return invoices;
}
async getCustomer(customer_id: string) {
if (this.disabledMode) return;
if (!this.stripe) throw Error('Stripe not initialized');
const customer = await this.stripe.customers.retrieve(customer_id, { expand: [] })
return customer;
}
async createCustomer(email: string) {
if (this.disabledMode) return;
if (!this.stripe) throw Error('Stripe not initialized');
const customer = await this.stripe.customers.create({ email });
return customer;
}
async setCustomerInfo(customer_id: string, address: { line1: string, line2: string, city: string, country: string, postal_code: string, state: string }) {
if (this.disabledMode) return;
if (!this.stripe) throw Error('Stripe not initialized');
const customer = await this.stripe.customers.update(customer_id, {
address: {
line1: address.line1,
line2: address.line2,
city: address.city,
country: address.country,
postal_code: address.postal_code,
state: address.state
}
})
return customer.id;
}
async deleteCustomer(customer_id: string) {
if (this.disabledMode) return;
if (!this.stripe) throw Error('Stripe not initialized');
const { deleted } = await this.stripe.customers.del(customer_id);
return deleted;
}
async createStripeCode(plan: PREMIUM_TAG) {
if (this.disabledMode) return;
if (!this.stripe) throw Error('Stripe not initialized');
const INCUBATION_COUPON = 'sDD7Weh3';
if (plan === 'INCUBATION') {
await this.stripe.promotionCodes.create({
coupon: INCUBATION_COUPON,
active: true,
code: 'TESTCACCA1',
max_redemptions: 1,
})
return true;
}
return false;
}
async createSubscription(customer_id: string, planId: number) {
if (this.disabledMode) return;
if (!this.stripe) throw Error('Stripe not initialized');
const PLAN = getPlanFromId(planId);
if (!PLAN) throw Error('Plan not found');
const subscription = await this.stripe.subscriptions.create({
customer: customer_id,
items: [
{ price: this.testMode ? PLAN.PRICE_TEST : PLAN.PRICE, quantity: 1 }
],
});
return subscription;
}
async createOneTimeSubscriptionDummy(customer_id: string, planId: number) {
if (this.disabledMode) return;
if (!this.stripe) throw Error('Stripe not initialized');
const PLAN = getPlanFromId(planId);
if (!PLAN) throw Error('Plan not found');
const subscription = await this.stripe.subscriptions.create({
customer: customer_id,
items: [
{ price: this.testMode ? PLAN.PRICE_TEST : PLAN.PRICE, quantity: 1 }
],
});
return subscription;
}
async createFreeSubscription(customer_id: string) {
if (this.disabledMode) return;
if (!this.stripe) throw Error('Stripe not initialized');
const FREE_PLAN = getPlanFromTag('FREE');
const subscription = await this.stripe.subscriptions.create({
customer: customer_id,
items: [
{ price: this.testMode ? FREE_PLAN.PRICE_TEST : FREE_PLAN.PRICE, quantity: 1 }
]
});
return subscription;
}
}
const instance = new StripeService();
export default instance;