mirror of
https://github.com/bigcapitalhq/bigcapital.git
synced 2026-02-20 14:50:32 +00:00
feat: remove other payment methods
This commit is contained in:
@@ -1,31 +0,0 @@
|
|||||||
import { Inject } from 'typedi';
|
|
||||||
import { Request, Response } from 'express';
|
|
||||||
import { Plan } from '@/system/models';
|
|
||||||
import BaseController from '@/api/controllers/BaseController';
|
|
||||||
import SubscriptionService from '@/services/Subscription/SubscriptionService';
|
|
||||||
|
|
||||||
export default class PaymentMethodController extends BaseController {
|
|
||||||
@Inject()
|
|
||||||
subscriptionService: SubscriptionService;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Validate the given plan slug exists on the storage.
|
|
||||||
*
|
|
||||||
* @param {Request} req
|
|
||||||
* @param {Response} res
|
|
||||||
* @param {NextFunction} next
|
|
||||||
*
|
|
||||||
* @return {Response|void}
|
|
||||||
*/
|
|
||||||
async validatePlanSlugExistance(req: Request, res: Response, next: Function) {
|
|
||||||
const { planSlug } = this.matchedBodyData(req);
|
|
||||||
const foundPlan = await Plan.query().where('slug', planSlug).first();
|
|
||||||
|
|
||||||
if (!foundPlan) {
|
|
||||||
return res.status(400).send({
|
|
||||||
errors: [{ type: 'PLAN.SLUG.NOT.EXISTS', code: 110 }],
|
|
||||||
});
|
|
||||||
}
|
|
||||||
next();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,88 @@
|
|||||||
|
import { Router, Request, Response, NextFunction } from 'express';
|
||||||
|
import { Service, Inject } from 'typedi';
|
||||||
|
import { body } from 'express-validator';
|
||||||
|
import JWTAuth from '@/api/middleware/jwtAuth';
|
||||||
|
import TenancyMiddleware from '@/api/middleware/TenancyMiddleware';
|
||||||
|
import AttachCurrentTenantUser from '@/api/middleware/AttachCurrentTenantUser';
|
||||||
|
import SubscriptionService from '@/services/Subscription/SubscriptionService';
|
||||||
|
import asyncMiddleware from '@/api/middleware/asyncMiddleware';
|
||||||
|
import BaseController from '../BaseController';
|
||||||
|
import { LemonSqueezyService } from '@/services/Subscription/LemonSqueezyService';
|
||||||
|
|
||||||
|
@Service()
|
||||||
|
export class SubscriptionController extends BaseController {
|
||||||
|
@Inject()
|
||||||
|
private subscriptionService: SubscriptionService;
|
||||||
|
|
||||||
|
@Inject()
|
||||||
|
private lemonSqueezyService: LemonSqueezyService;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Router constructor.
|
||||||
|
*/
|
||||||
|
router() {
|
||||||
|
const router = Router();
|
||||||
|
|
||||||
|
router.use(JWTAuth);
|
||||||
|
router.use(AttachCurrentTenantUser);
|
||||||
|
router.use(TenancyMiddleware);
|
||||||
|
|
||||||
|
router.post(
|
||||||
|
'/lemon/checkout_url',
|
||||||
|
[body('variantId').exists().trim()],
|
||||||
|
this.validationResult,
|
||||||
|
this.getCheckoutUrl.bind(this)
|
||||||
|
);
|
||||||
|
router.get('/', asyncMiddleware(this.getSubscriptions.bind(this)));
|
||||||
|
|
||||||
|
return router;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieve all subscriptions of the authenticated user's tenant.
|
||||||
|
* @param {Request} req
|
||||||
|
* @param {Response} res
|
||||||
|
* @param {NextFunction} next
|
||||||
|
*/
|
||||||
|
private async getSubscriptions(
|
||||||
|
req: Request,
|
||||||
|
res: Response,
|
||||||
|
next: NextFunction
|
||||||
|
) {
|
||||||
|
const { tenantId } = req;
|
||||||
|
|
||||||
|
try {
|
||||||
|
const subscriptions = await this.subscriptionService.getSubscriptions(
|
||||||
|
tenantId
|
||||||
|
);
|
||||||
|
return res.status(200).send({ subscriptions });
|
||||||
|
} catch (error) {
|
||||||
|
next(error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves the LemonSqueezy checkout url.
|
||||||
|
* @param {Request} req
|
||||||
|
* @param {Response} res
|
||||||
|
* @param {NextFunction} next
|
||||||
|
*/
|
||||||
|
private async getCheckoutUrl(
|
||||||
|
req: Request,
|
||||||
|
res: Response,
|
||||||
|
next: NextFunction
|
||||||
|
) {
|
||||||
|
const { variantId } = this.matchedBodyData(req);
|
||||||
|
const { user } = req;
|
||||||
|
|
||||||
|
try {
|
||||||
|
const checkout = await this.lemonSqueezyService.getCheckout(
|
||||||
|
variantId,
|
||||||
|
user
|
||||||
|
);
|
||||||
|
return res.status(200).send(checkout);
|
||||||
|
} catch (error) {
|
||||||
|
next(error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,88 +1 @@
|
|||||||
import { Router, Request, Response, NextFunction } from 'express';
|
export * from './SubscriptionController';
|
||||||
import { Service, Inject } from 'typedi';
|
|
||||||
import { body } from 'express-validator';
|
|
||||||
import JWTAuth from '@/api/middleware/jwtAuth';
|
|
||||||
import TenancyMiddleware from '@/api/middleware/TenancyMiddleware';
|
|
||||||
import AttachCurrentTenantUser from '@/api/middleware/AttachCurrentTenantUser';
|
|
||||||
import SubscriptionService from '@/services/Subscription/SubscriptionService';
|
|
||||||
import asyncMiddleware from '@/api/middleware/asyncMiddleware';
|
|
||||||
import BaseController from '../BaseController';
|
|
||||||
import { LemonSqueezyService } from '@/services/Subscription/LemonSqueezyService';
|
|
||||||
|
|
||||||
@Service()
|
|
||||||
export default class SubscriptionController extends BaseController {
|
|
||||||
@Inject()
|
|
||||||
private subscriptionService: SubscriptionService;
|
|
||||||
|
|
||||||
@Inject()
|
|
||||||
private lemonSqueezyService: LemonSqueezyService;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Router constructor.
|
|
||||||
*/
|
|
||||||
router() {
|
|
||||||
const router = Router();
|
|
||||||
|
|
||||||
router.use(JWTAuth);
|
|
||||||
router.use(AttachCurrentTenantUser);
|
|
||||||
router.use(TenancyMiddleware);
|
|
||||||
|
|
||||||
router.post(
|
|
||||||
'/lemon/checkout_url',
|
|
||||||
[body('variantId').exists().trim()],
|
|
||||||
this.validationResult,
|
|
||||||
this.getCheckoutUrl.bind(this)
|
|
||||||
);
|
|
||||||
router.get('/', asyncMiddleware(this.getSubscriptions.bind(this)));
|
|
||||||
|
|
||||||
return router;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Retrieve all subscriptions of the authenticated user's tenant.
|
|
||||||
* @param {Request} req
|
|
||||||
* @param {Response} res
|
|
||||||
* @param {NextFunction} next
|
|
||||||
*/
|
|
||||||
private async getSubscriptions(
|
|
||||||
req: Request,
|
|
||||||
res: Response,
|
|
||||||
next: NextFunction
|
|
||||||
) {
|
|
||||||
const { tenantId } = req;
|
|
||||||
|
|
||||||
try {
|
|
||||||
const subscriptions = await this.subscriptionService.getSubscriptions(
|
|
||||||
tenantId
|
|
||||||
);
|
|
||||||
return res.status(200).send({ subscriptions });
|
|
||||||
} catch (error) {
|
|
||||||
next(error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Retrieves the LemonSqueezy checkout url.
|
|
||||||
* @param {Request} req
|
|
||||||
* @param {Response} res
|
|
||||||
* @param {NextFunction} next
|
|
||||||
*/
|
|
||||||
private async getCheckoutUrl(
|
|
||||||
req: Request,
|
|
||||||
res: Response,
|
|
||||||
next: NextFunction
|
|
||||||
) {
|
|
||||||
const { variantId } = this.matchedBodyData(req);
|
|
||||||
const { user } = req;
|
|
||||||
|
|
||||||
try {
|
|
||||||
const checkout = await this.lemonSqueezyService.getCheckout(
|
|
||||||
variantId,
|
|
||||||
user
|
|
||||||
);
|
|
||||||
return res.status(200).send(checkout);
|
|
||||||
} catch (error) {
|
|
||||||
next(error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -37,7 +37,7 @@ import Resources from './controllers/Resources';
|
|||||||
import ExchangeRates from '@/api/controllers/ExchangeRates';
|
import ExchangeRates from '@/api/controllers/ExchangeRates';
|
||||||
import Media from '@/api/controllers/Media';
|
import Media from '@/api/controllers/Media';
|
||||||
import Ping from '@/api/controllers/Ping';
|
import Ping from '@/api/controllers/Ping';
|
||||||
import Subscription from '@/api/controllers/Subscription';
|
import { SubscriptionController } from '@/api/controllers/Subscription';
|
||||||
import InventoryAdjustments from '@/api/controllers/Inventory/InventoryAdjustments';
|
import InventoryAdjustments from '@/api/controllers/Inventory/InventoryAdjustments';
|
||||||
import asyncRenderMiddleware from './middleware/AsyncRenderMiddleware';
|
import asyncRenderMiddleware from './middleware/AsyncRenderMiddleware';
|
||||||
import Jobs from './controllers/Jobs';
|
import Jobs from './controllers/Jobs';
|
||||||
@@ -72,7 +72,7 @@ export default () => {
|
|||||||
|
|
||||||
app.use('/auth', Container.get(Authentication).router());
|
app.use('/auth', Container.get(Authentication).router());
|
||||||
app.use('/invite', Container.get(InviteUsers).nonAuthRouter());
|
app.use('/invite', Container.get(InviteUsers).nonAuthRouter());
|
||||||
app.use('/subscription', Container.get(Subscription).router());
|
app.use('/subscription', Container.get(SubscriptionController).router());
|
||||||
app.use('/organization', Container.get(Organization).router());
|
app.use('/organization', Container.get(Organization).router());
|
||||||
app.use('/ping', Container.get(Ping).router());
|
app.use('/ping', Container.get(Ping).router());
|
||||||
app.use('/jobs', Container.get(Jobs).router());
|
app.use('/jobs', Container.get(Jobs).router());
|
||||||
@@ -140,12 +140,10 @@ export default () => {
|
|||||||
dashboard.use('/warehouses', Container.get(WarehousesController).router());
|
dashboard.use('/warehouses', Container.get(WarehousesController).router());
|
||||||
dashboard.use('/projects', Container.get(ProjectsController).router());
|
dashboard.use('/projects', Container.get(ProjectsController).router());
|
||||||
dashboard.use('/tax-rates', Container.get(TaxRatesController).router());
|
dashboard.use('/tax-rates', Container.get(TaxRatesController).router());
|
||||||
|
|
||||||
dashboard.use('/import', Container.get(ImportController).router());
|
dashboard.use('/import', Container.get(ImportController).router());
|
||||||
|
|
||||||
dashboard.use('/', Container.get(ProjectTasksController).router());
|
dashboard.use('/', Container.get(ProjectTasksController).router());
|
||||||
dashboard.use('/', Container.get(ProjectTimesController).router());
|
dashboard.use('/', Container.get(ProjectTimesController).router());
|
||||||
|
|
||||||
dashboard.use('/', Container.get(WarehousesItemController).router());
|
dashboard.use('/', Container.get(WarehousesItemController).router());
|
||||||
|
|
||||||
dashboard.use('/dashboard', Container.get(DashboardController).router());
|
dashboard.use('/dashboard', Container.get(DashboardController).router());
|
||||||
|
|||||||
@@ -49,16 +49,17 @@ export class LemonSqueezyWebhooks {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* This action will process a webhook event in the database.
|
* This action will process a webhook event in the database.
|
||||||
|
* @param {unknown} eventBody -
|
||||||
|
* @returns {Promise<void>}
|
||||||
*/
|
*/
|
||||||
private async processWebhookEvent(eventBody) {
|
private async processWebhookEvent(eventBody): Promise<void> {
|
||||||
let processingError = '';
|
|
||||||
const webhookEvent = eventBody.meta.event_name;
|
const webhookEvent = eventBody.meta.event_name;
|
||||||
|
|
||||||
const userId = eventBody.meta.custom_data?.user_id;
|
const userId = eventBody.meta.custom_data?.user_id;
|
||||||
const tenantId = eventBody.meta.custom_data?.tenant_id;
|
const tenantId = eventBody.meta.custom_data?.tenant_id;
|
||||||
|
|
||||||
if (!webhookHasMeta(eventBody)) {
|
if (!webhookHasMeta(eventBody)) {
|
||||||
processingError = "Event body is missing the 'meta' property.";
|
throw new Error("Event body is missing the 'meta' property.");
|
||||||
} else if (webhookHasData(eventBody)) {
|
} else if (webhookHasData(eventBody)) {
|
||||||
if (webhookEvent.startsWith('subscription_payment_')) {
|
if (webhookEvent.startsWith('subscription_payment_')) {
|
||||||
// Save subscription invoices; eventBody is a SubscriptionInvoice
|
// Save subscription invoices; eventBody is a SubscriptionInvoice
|
||||||
@@ -72,7 +73,7 @@ export class LemonSqueezyWebhooks {
|
|||||||
const plan = await Plan.query().findOne('slug', 'essentials-yearly');
|
const plan = await Plan.query().findOne('slug', 'essentials-yearly');
|
||||||
|
|
||||||
if (!plan) {
|
if (!plan) {
|
||||||
processingError = `Plan with variantId ${variantId} not found.`;
|
throw new Error(`Plan with variantId ${variantId} not found.`);
|
||||||
} else {
|
} else {
|
||||||
// Update the subscription in the database.
|
// Update the subscription in the database.
|
||||||
const priceId = attributes.first_subscription_item.price_id;
|
const priceId = attributes.first_subscription_item.price_id;
|
||||||
@@ -81,7 +82,9 @@ export class LemonSqueezyWebhooks {
|
|||||||
const priceData = await getPrice(priceId);
|
const priceData = await getPrice(priceId);
|
||||||
|
|
||||||
if (priceData.error) {
|
if (priceData.error) {
|
||||||
processingError = `Failed to get the price data for the subscription ${eventBody.data.id}.`;
|
throw new Error(
|
||||||
|
`Failed to get the price data for the subscription ${eventBody.data.id}.`
|
||||||
|
);
|
||||||
}
|
}
|
||||||
const isUsageBased =
|
const isUsageBased =
|
||||||
attributes.first_subscription_item.is_usage_based;
|
attributes.first_subscription_item.is_usage_based;
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
// @ts-nocheck
|
// @ts-nocheck
|
||||||
import { useMutation, useQueryClient } from 'react-query';
|
import { useMutation, useQueryClient } from 'react-query';
|
||||||
import { batch } from 'react-redux';
|
import { batch } from 'react-redux';
|
||||||
|
import { omit } from 'lodash';
|
||||||
import t from './types';
|
import t from './types';
|
||||||
import useApiRequest from '../useRequest';
|
import useApiRequest from '../useRequest';
|
||||||
import { useRequestQuery } from '../useQueryRequest';
|
import { useRequestQuery } from '../useQueryRequest';
|
||||||
import { useSetOrganizations, useSetSubscriptions } from '../state';
|
import { useSetOrganizations, useSetSubscriptions } from '../state';
|
||||||
import { omit } from 'lodash';
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieve organizations of the authenticated user.
|
* Retrieve organizations of the authenticated user.
|
||||||
|
|||||||
Reference in New Issue
Block a user