mirror of
https://github.com/Litlyx/litlyx
synced 2025-12-10 07:48:37 +01:00
fix dashboard + payments
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
<script lang="ts" setup>
|
||||
import dayjs from 'dayjs';
|
||||
import type { SettingsTemplateEntry } from './Template.vue';
|
||||
import { getPlanFromId, PREMIUM_PLAN, type PREMIUM_TAG } from '@data/PREMIUM';
|
||||
import { getPlanFromId, PREMIUM_PLAN, type PLAN_TAG } from '@data/PREMIUM';
|
||||
|
||||
const { projectId, isGuest } = useProject();
|
||||
|
||||
@@ -53,10 +53,10 @@ function openInvoice(link: string) {
|
||||
window.open(link, '_blank');
|
||||
}
|
||||
|
||||
function getPremiumName(type: number) {
|
||||
function getTagName(type: number) {
|
||||
|
||||
return Object.keys(PREMIUM_PLAN).map(e => ({
|
||||
...PREMIUM_PLAN[e as PREMIUM_TAG], name: e
|
||||
...PREMIUM_PLAN[e as PLAN_TAG], name: e
|
||||
})).find(e => e.ID == type)?.name;
|
||||
|
||||
}
|
||||
@@ -168,7 +168,7 @@ const { showDrawer } = useDrawer();
|
||||
</div>
|
||||
<div
|
||||
class="flex lato text-[.7rem] bg-transparent border-[#262626] border-[1px] px-[.6rem] rounded-sm">
|
||||
{{ planData.premium ? getPremiumName(planData.premium_type) : 'FREE' }}
|
||||
{{ planData.premium ? getTagName(planData.premium_type) : 'FREE' }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -187,9 +187,6 @@ const { showDrawer } = useDrawer();
|
||||
</div>
|
||||
<div class="poppins"> {{ daysLeft }} days left </div>
|
||||
</div>
|
||||
<div class="flex justify-center">
|
||||
Subscription: {{ planData.subscription_status }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="my-4 w-full bg-gray-400/30 h-[1px]">
|
||||
|
||||
@@ -45,15 +45,12 @@ export default defineNuxtConfig({
|
||||
AI_PROJECT: process.env.AI_PROJECT,
|
||||
AI_KEY: process.env.AI_KEY,
|
||||
EMAIL_SECRET: process.env.EMAIL_SECRET,
|
||||
PAYMENT_SECRET: process.env.PAYMENT_SECRET,
|
||||
AUTH_JWT_SECRET: process.env.AUTH_JWT_SECRET,
|
||||
GOOGLE_AUTH_CLIENT_ID: process.env.GOOGLE_AUTH_CLIENT_ID,
|
||||
GOOGLE_AUTH_CLIENT_SECRET: process.env.GOOGLE_AUTH_CLIENT_SECRET,
|
||||
GITHUB_AUTH_CLIENT_ID: process.env.GITHUB_AUTH_CLIENT_ID,
|
||||
GITHUB_AUTH_CLIENT_SECRET: process.env.GITHUB_AUTH_CLIENT_SECRET,
|
||||
STRIPE_SECRET: process.env.STRIPE_SECRET,
|
||||
STRIPE_WH_SECRET: process.env.STRIPE_WH_SECRET,
|
||||
STRIPE_SECRET_TEST: process.env.STRIPE_SECRET_TEST,
|
||||
STRIPE_WH_SECRET_TEST: process.env.STRIPE_WH_SECRET_TEST,
|
||||
NOAUTH_USER_EMAIL: process.env.NOAUTH_USER_EMAIL,
|
||||
NOAUTH_USER_PASS: process.env.NOAUTH_USER_PASS,
|
||||
MODE: process.env.MODE || 'NONE',
|
||||
|
||||
8
dashboard/pnpm-lock.yaml
generated
8
dashboard/pnpm-lock.yaml
generated
@@ -5255,8 +5255,8 @@ packages:
|
||||
peerDependencies:
|
||||
vue: ^3.2.0
|
||||
|
||||
vue3-google-signin@2.0.1:
|
||||
resolution: {integrity: sha512-vZTlVrG56JERtqQ+6YI8e92wqfhAMDyNONCsLgKKXxzCNCWEfSkZcAvz7COm9V4bvzmGsebZ8KC3ljol2qsIcg==}
|
||||
vue3-google-signin@2.1.1:
|
||||
resolution: {integrity: sha512-RwlwyeCv8+PZjK35C/UyJN4/9MH+Fsz4bJDO7IjtmRuOaTMrvmMmI6SP5qkJgD7w9MIKOCj5rYVFMAL7+NCM0A==}
|
||||
peerDependencies:
|
||||
vue: ^3
|
||||
|
||||
@@ -9868,7 +9868,7 @@ snapshots:
|
||||
dependencies:
|
||||
'@nuxt/kit': 3.11.2(rollup@4.18.0)
|
||||
unimport: 3.7.2(rollup@4.18.0)
|
||||
vue3-google-signin: 2.0.1(vue@3.4.27(typescript@5.4.2))
|
||||
vue3-google-signin: 2.1.1(vue@3.4.27(typescript@5.4.2))
|
||||
transitivePeerDependencies:
|
||||
- rollup
|
||||
- supports-color
|
||||
@@ -11525,7 +11525,7 @@ snapshots:
|
||||
vue-observe-visibility: 2.0.0-alpha.1(vue@3.4.27(typescript@5.4.2))
|
||||
vue-resize: 2.0.0-alpha.1(vue@3.4.27(typescript@5.4.2))
|
||||
|
||||
vue3-google-signin@2.0.1(vue@3.4.27(typescript@5.4.2)):
|
||||
vue3-google-signin@2.1.1(vue@3.4.27(typescript@5.4.2)):
|
||||
dependencies:
|
||||
vue: 3.4.27(typescript@5.4.2)
|
||||
|
||||
|
||||
@@ -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();
|
||||
@@ -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: ''
|
||||
}
|
||||
|
||||
});
|
||||
@@ -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');
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
});
|
||||
@@ -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 '';
|
||||
|
||||
});
|
||||
@@ -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;
|
||||
|
||||
});
|
||||
@@ -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,
|
||||
@@ -22,10 +20,13 @@ 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 [];
|
||||
const [ok, invoicesOrError] = await PaymentServiceHelper.invoices_list(data.user.id);
|
||||
if (!ok) {
|
||||
console.error(invoicesOrError);
|
||||
return [];
|
||||
}
|
||||
|
||||
return invoices?.data.map(e => {
|
||||
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;
|
||||
});
|
||||
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
@@ -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);
|
||||
|
||||
});
|
||||
@@ -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);
|
||||
|
||||
|
||||
});
|
||||
@@ -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,58 +18,12 @@ 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;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
});
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
@@ -52,11 +51,10 @@ export default defineEventHandler(async event => {
|
||||
const countryBlacklistDeletation = await CountryBlacklistModel.deleteMany({ project_id });
|
||||
const domainWhitelistDeletation = await DomainWhitelistModel.deleteMany({ project_id });
|
||||
|
||||
}
|
||||
|
||||
const userDeletation = await UserModel.deleteOne({ _id: userData.id });
|
||||
|
||||
}
|
||||
|
||||
return { ok: true };
|
||||
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
|
||||
50
dashboard/server/services/PaymentServiceHelper.ts
Normal file
50
dashboard/server/services/PaymentServiceHelper.ts
Normal 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 });
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
@@ -80,7 +80,10 @@ export async function onPaymentSuccess(event: Event.InvoicePaidEvent) {
|
||||
}
|
||||
}
|
||||
|
||||
await addSubscriptionToUser(premiumData.user_id.toString(), plan, subscription_id, event.data.object.period_start, event.data.object.period_end);
|
||||
await addSubscriptionToUser(premiumData.user_id.toString(), plan, subscription_id,
|
||||
event.data.object.lines.data[0].period.start,
|
||||
event.data.object.lines.data[0].period.end
|
||||
);
|
||||
|
||||
setTimeout(() => {
|
||||
if (plan.ID == 0) return;
|
||||
|
||||
@@ -17,6 +17,12 @@ console.log('Stripe started in', STRIPE_TESTMODE ? 'TESTMODE' : 'LIVEMODE');
|
||||
|
||||
const app = express();
|
||||
|
||||
|
||||
app.use((req, res, next) => {
|
||||
console.log(req.path);
|
||||
next();
|
||||
})
|
||||
|
||||
app.use('/webhook', webhookRouter);
|
||||
app.use('/payment', paymentRouter);
|
||||
|
||||
|
||||
@@ -5,14 +5,41 @@ import StripeService from '../services/StripeService';
|
||||
import { sendJson } from '../Utils';
|
||||
import { PremiumModel } from '../shared/schema/PremiumSchema';
|
||||
import { Types } from 'mongoose';
|
||||
import { UserModel } from '../shared/schema/UserSchema';
|
||||
|
||||
export const paymentRouter = Router();
|
||||
|
||||
export const ZBodyCreateCustomer = z.object({
|
||||
user_id: z.string()
|
||||
});
|
||||
|
||||
paymentRouter.post('/create_customer', json(), async (req, res) => {
|
||||
try {
|
||||
const createCustomerData = ZBodyCreateCustomer.parse(req.body);
|
||||
const user = await UserModel.findOne({ _id: createCustomerData.user_id });
|
||||
if (!user) return sendJson(res, 400, { error: 'user not found' });
|
||||
|
||||
const customer = await StripeService.createCustomer(user.email);
|
||||
const freesub = await StripeService.createFreeSubscription(customer.id);
|
||||
|
||||
await PremiumModel.create({
|
||||
user_id: user.id,
|
||||
customer_id: customer.id,
|
||||
premium_type: 0,
|
||||
subscription_id: freesub.id
|
||||
})
|
||||
|
||||
return sendJson(res, 200, { ok: true });
|
||||
} catch (ex) {
|
||||
res.status(500).json({ error: ex.message });
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
export const ZBodyCreatePayment = z.object({
|
||||
user_id: z.string(),
|
||||
plan_id: z.number()
|
||||
})
|
||||
});
|
||||
|
||||
paymentRouter.post('/create', json(), async (req, res) => {
|
||||
try {
|
||||
@@ -42,3 +69,81 @@ paymentRouter.post('/create', json(), async (req, res) => {
|
||||
res.status(500).json({ error: ex.message });
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
export const ZBodyInvoicesList = z.object({
|
||||
user_id: z.string()
|
||||
});
|
||||
|
||||
paymentRouter.post('/invoices_list', json(), async (req, res) => {
|
||||
try {
|
||||
const invoicesListData = ZBodyInvoicesList.parse(req.body);
|
||||
|
||||
const premiumData = await PremiumModel.findOne({ user_id: invoicesListData.user_id });
|
||||
if (!premiumData) return sendJson(res, 400, { error: 'user not found' });
|
||||
if (!premiumData.customer_id) return sendJson(res, 400, { error: 'user have no customer_id' });
|
||||
|
||||
const invoices = await StripeService.getInvoices(premiumData.customer_id);
|
||||
return sendJson(res, 200, { invoices: invoices.data });
|
||||
|
||||
} catch (ex) {
|
||||
res.status(500).json({ error: ex.message });
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
export const ZBodyCustomerInfo = z.object({
|
||||
user_id: z.string()
|
||||
});
|
||||
|
||||
paymentRouter.post('/customer_info', json(), async (req, res) => {
|
||||
try {
|
||||
const customerInfoData = ZBodyCustomerInfo.parse(req.body);
|
||||
|
||||
const premiumData = await PremiumModel.findOne({ user_id: customerInfoData.user_id });
|
||||
if (!premiumData) return sendJson(res, 400, { error: 'user not found' });
|
||||
if (!premiumData.customer_id) return sendJson(res, 400, { error: 'user have no customer_id' });
|
||||
|
||||
const customer = await StripeService.getCustomer(premiumData.customer_id);
|
||||
if (!customer) return sendJson(res, 200, {});
|
||||
if (customer.deleted === true) return sendJson(res, 200, {});
|
||||
return sendJson(res, 200, customer.address);
|
||||
|
||||
} catch (ex) {
|
||||
console.error(ex);
|
||||
res.status(500).json({ error: ex.message });
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
|
||||
|
||||
export const ZBodyUpdateCustomerInfo = z.object({
|
||||
user_id: z.string(),
|
||||
address: z.object({
|
||||
line1: z.string(),
|
||||
line2: z.string(),
|
||||
city: z.string(),
|
||||
country: z.string(),
|
||||
postal_code: z.string(),
|
||||
state: z.string()
|
||||
})
|
||||
});
|
||||
|
||||
paymentRouter.post('/update_customer_info', json(), async (req, res) => {
|
||||
try {
|
||||
const updateCustomerInfoData = ZBodyUpdateCustomerInfo.parse(req.body);
|
||||
|
||||
const premiumData = await PremiumModel.findOne({ user_id: updateCustomerInfoData.user_id });
|
||||
if (!premiumData) return sendJson(res, 400, { error: 'user not found' });
|
||||
if (!premiumData.customer_id) return sendJson(res, 400, { error: 'user have no customer_id' });
|
||||
await StripeService.setCustomerInfo(
|
||||
premiumData.customer_id,
|
||||
updateCustomerInfoData.address as any
|
||||
);
|
||||
return sendJson(res, 200, { ok: true });
|
||||
|
||||
} catch (ex) {
|
||||
res.status(500).json({ error: ex.message });
|
||||
}
|
||||
});
|
||||
Reference in New Issue
Block a user