mirror of
https://github.com/bigcapitalhq/bigcapital.git
synced 2026-02-17 05:10:31 +00:00
feat: WIP advanced filter.
This commit is contained in:
@@ -1,7 +1,6 @@
|
||||
import { Service, Inject } from 'typedi';
|
||||
import { Router, Request, Response, NextFunction } from 'express';
|
||||
import { param, query } from 'express-validator';
|
||||
import asyncMiddleware from 'api/middleware/asyncMiddleware';
|
||||
import { param } from 'express-validator';
|
||||
import BaseController from './BaseController';
|
||||
import { ServiceError } from 'exceptions';
|
||||
import ResourceService from 'services/Resource/ResourceService';
|
||||
@@ -19,32 +18,15 @@ export default class ResourceController extends BaseController {
|
||||
|
||||
router.get(
|
||||
'/:resource_model/meta',
|
||||
[...this.resourceModelParamSchema],
|
||||
[
|
||||
param('resource_model').exists().trim().escape()
|
||||
],
|
||||
this.asyncMiddleware(this.resourceMeta.bind(this)),
|
||||
this.handleServiceErrors
|
||||
);
|
||||
|
||||
router.get(
|
||||
'/:resource_model/fields',
|
||||
[...this.resourceModelParamSchema],
|
||||
this.validationResult,
|
||||
asyncMiddleware(this.resourceFields.bind(this)),
|
||||
this.handleServiceErrors
|
||||
);
|
||||
router.get(
|
||||
'/:resource_model/data',
|
||||
[...this.resourceModelParamSchema],
|
||||
this.validationResult,
|
||||
asyncMiddleware(this.resourceData.bind(this)),
|
||||
this.handleServiceErrors
|
||||
);
|
||||
return router;
|
||||
}
|
||||
|
||||
get resourceModelParamSchema() {
|
||||
return [param('resource_model').exists().trim().escape()];
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve resource model meta.
|
||||
* @param {Request} req -
|
||||
@@ -52,7 +34,7 @@ export default class ResourceController extends BaseController {
|
||||
* @param {NextFunction} next -
|
||||
* @returns {Response}
|
||||
*/
|
||||
private resourceMeta = (
|
||||
public resourceMeta = (
|
||||
req: Request,
|
||||
res: Response,
|
||||
next: NextFunction
|
||||
@@ -73,56 +55,6 @@ export default class ResourceController extends BaseController {
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Retrieve resource fields of the given resource.
|
||||
* @param {Request} req
|
||||
* @param {Response} res
|
||||
* @param {NextFunction} next
|
||||
*/
|
||||
resourceFields(req: Request, res: Response, next: NextFunction) {
|
||||
const { tenantId } = req;
|
||||
const { resource_model: resourceModel } = req.params;
|
||||
|
||||
try {
|
||||
// const resourceFields = this.resourcesService.getResourceFields(
|
||||
// tenantId,
|
||||
// resourceModel
|
||||
// );
|
||||
|
||||
return res.status(200).send({
|
||||
resource_fields: [],
|
||||
});
|
||||
} catch (error) {
|
||||
next(error);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve resource data of the give resource based on the given query.
|
||||
* @param {Request} req
|
||||
* @param {Response} res
|
||||
* @param {NextFunction} next
|
||||
*/
|
||||
async resourceData(req: Request, res: Response, next: NextFunction) {
|
||||
const { tenantId } = req;
|
||||
const { resource_model: resourceModel } = req.params;
|
||||
const filter = req.query;
|
||||
|
||||
try {
|
||||
const resourceData = await this.resourcesService.getResourceData(
|
||||
tenantId,
|
||||
resourceModel,
|
||||
filter
|
||||
);
|
||||
|
||||
return res.status(200).send({
|
||||
resource_data: this.transfromToResponse(resourceData),
|
||||
});
|
||||
} catch (error) {
|
||||
next(error);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles service errors.
|
||||
* @param {Error} error
|
||||
|
||||
@@ -23,6 +23,7 @@ export default {
|
||||
column: 'slug',
|
||||
fieldType: 'text',
|
||||
columnable: false,
|
||||
filterable: false,
|
||||
},
|
||||
code: {
|
||||
name: 'Account code',
|
||||
@@ -76,6 +77,7 @@ export default {
|
||||
name: 'Currency',
|
||||
column: 'currency_code',
|
||||
fieldType: 'text',
|
||||
filterable: false,
|
||||
},
|
||||
created_at: {
|
||||
name: 'Created at',
|
||||
|
||||
@@ -48,12 +48,12 @@ export default {
|
||||
fieldType: 'enumeration',
|
||||
columnable: true,
|
||||
options: [
|
||||
{ name: 'Paid', key: 'paid' },
|
||||
{ name: 'Partially paid', key: 'partially-paid' },
|
||||
{ name: 'Overdue', key: 'overdue' },
|
||||
{ name: 'Unpaid', key: 'unpaid' },
|
||||
{ name: 'Opened', key: 'opened' },
|
||||
{ name: 'Draft', key: 'draft' },
|
||||
{ label: 'Paid', key: 'paid' },
|
||||
{ label: 'Partially paid', key: 'partially-paid' },
|
||||
{ label: 'Overdue', key: 'overdue' },
|
||||
{ label: 'Unpaid', key: 'unpaid' },
|
||||
{ label: 'Opened', key: 'opened' },
|
||||
{ label: 'Draft', key: 'draft' },
|
||||
],
|
||||
filterCustomQuery: StatusFieldFilterQuery,
|
||||
sortCustomQuery: StatusFieldSortQuery,
|
||||
|
||||
@@ -43,6 +43,7 @@ export default {
|
||||
created_at: {
|
||||
name: 'Created at',
|
||||
column: 'created_at',
|
||||
fieldType: 'date',
|
||||
},
|
||||
balance: {
|
||||
name: 'Balance',
|
||||
@@ -61,11 +62,13 @@ export default {
|
||||
fieldType: 'date',
|
||||
},
|
||||
currency_code: {
|
||||
name: 'Curreny',
|
||||
column: 'currency_code',
|
||||
fieldType: 'text',
|
||||
},
|
||||
status: {
|
||||
label: 'Status',
|
||||
name: 'Status',
|
||||
fieldType: 'enumeration',
|
||||
options: [
|
||||
{ key: 'active', label: 'Active' },
|
||||
{ key: 'inactive', label: 'Inactive' },
|
||||
|
||||
@@ -48,8 +48,8 @@ export default {
|
||||
name: 'Status',
|
||||
fieldType: 'enumeration',
|
||||
options: [
|
||||
{ key: 'draft', name: 'Draft' },
|
||||
{ key: 'published', name: 'Published' },
|
||||
{ key: 'draft', label: 'Draft' },
|
||||
{ key: 'published', label: 'Published' },
|
||||
],
|
||||
filterCustomQuery: StatusFieldFilterQuery,
|
||||
sortCustomQuery: StatusFieldSortQuery,
|
||||
|
||||
@@ -6,23 +6,23 @@ export default {
|
||||
},
|
||||
fields: {
|
||||
name: {
|
||||
label: 'Name',
|
||||
name: 'Name',
|
||||
column: 'name',
|
||||
fieldType: 'text',
|
||||
},
|
||||
description: {
|
||||
label: 'Description',
|
||||
name: 'Description',
|
||||
column: 'description',
|
||||
fieldType: 'text',
|
||||
},
|
||||
count: {
|
||||
label: 'Count',
|
||||
name: 'Count',
|
||||
column: 'count',
|
||||
fieldType: 'number',
|
||||
virtualColumn: true,
|
||||
},
|
||||
created_at: {
|
||||
label: 'Created at',
|
||||
name: 'Created at',
|
||||
column: 'created_at',
|
||||
columnType: 'date',
|
||||
},
|
||||
|
||||
@@ -6,43 +6,47 @@ export default {
|
||||
},
|
||||
fields: {
|
||||
'date': {
|
||||
label: 'Date',
|
||||
name: 'Date',
|
||||
column: 'date',
|
||||
fieldType: 'date',
|
||||
},
|
||||
'journal_number': {
|
||||
label: 'Journal number',
|
||||
name: 'Journal number',
|
||||
column: 'journal_number',
|
||||
fieldType: 'text',
|
||||
},
|
||||
'reference': {
|
||||
label: 'Reference No.',
|
||||
name: 'Reference No.',
|
||||
column: 'reference',
|
||||
fieldType: 'text',
|
||||
},
|
||||
'journal_type': {
|
||||
label: 'Journal type',
|
||||
name: 'Journal type',
|
||||
column: 'journal_type',
|
||||
fieldType: 'text',
|
||||
},
|
||||
'amount': {
|
||||
label: 'Amount',
|
||||
name: 'Amount',
|
||||
column: 'amount',
|
||||
columnType: 'number',
|
||||
fieldType: 'number',
|
||||
},
|
||||
'description': {
|
||||
label: 'Description',
|
||||
name: 'Description',
|
||||
column: 'description',
|
||||
fieldType: 'text',
|
||||
},
|
||||
'status': {
|
||||
label: 'Status',
|
||||
name: 'Status',
|
||||
column: 'status',
|
||||
fieldType: 'enumeration',
|
||||
options: [
|
||||
{ key: 'draft', label: 'Draft' },
|
||||
{ key: 'published', label: 'published' }
|
||||
],
|
||||
sortCustomQuery: StatusFieldSortQuery,
|
||||
},
|
||||
'created_at': {
|
||||
label: 'Created at',
|
||||
name: 'Created at',
|
||||
column: 'created_at',
|
||||
fieldType: 'date',
|
||||
},
|
||||
|
||||
@@ -26,8 +26,8 @@ export default (Model) =>
|
||||
* @param {string} key
|
||||
* @returns
|
||||
*/
|
||||
public static getMeta(key: string) {
|
||||
return get(this.meta, key);
|
||||
public static getMeta(key?: string) {
|
||||
return key ? get(this.meta, key): this.meta;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -55,11 +55,11 @@ export default {
|
||||
name: 'Status',
|
||||
fieldType: 'enumeration',
|
||||
options: [
|
||||
{ name: 'Delivered', key: 'delivered' },
|
||||
{ name: 'Rejected', key: 'rejected' },
|
||||
{ name: 'Approved', key: 'approved' },
|
||||
{ name: 'Delivered', key: 'delivered' },
|
||||
{ name: 'Draft', key: 'draft' },
|
||||
{ label: 'Delivered', key: 'delivered' },
|
||||
{ label: 'Rejected', key: 'rejected' },
|
||||
{ label: 'Approved', key: 'approved' },
|
||||
{ label: 'Delivered', key: 'delivered' },
|
||||
{ label: 'Draft', key: 'draft' },
|
||||
],
|
||||
filterCustomQuery: StatusFieldFilterQuery,
|
||||
sortCustomQuery: StatusFieldSortQuery,
|
||||
|
||||
@@ -64,15 +64,14 @@ export default {
|
||||
},
|
||||
status: {
|
||||
name: 'Status',
|
||||
columnable: true,
|
||||
fieldType: 'enumeration',
|
||||
options: [
|
||||
{ key: 'draft', name: 'Draft' },
|
||||
{ key: 'delivered', name: 'Delivered' },
|
||||
{ key: 'unpaid', name: 'Unpaid' },
|
||||
{ key: 'overdue', name: 'Overdue' },
|
||||
{ key: 'partially-paid', name: 'Partially paid' },
|
||||
{ key: 'paid', name: 'Paid' },
|
||||
{ key: 'draft', label: 'Draft' },
|
||||
{ key: 'delivered', label: 'Delivered' },
|
||||
{ key: 'unpaid', label: 'Unpaid' },
|
||||
{ key: 'overdue', label: 'Overdue' },
|
||||
{ key: 'partially-paid', label: 'Partially paid' },
|
||||
{ key: 'paid', label: 'Paid' },
|
||||
],
|
||||
filterCustomQuery: StatusFieldFilterQuery,
|
||||
sortCustomQuery: StatusFieldSortQuery,
|
||||
@@ -97,4 +96,4 @@ function StatusFieldFilterQuery(query, role) {
|
||||
*/
|
||||
function StatusFieldSortQuery(query, role) {
|
||||
query.modify('sortByStatus', role.order);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,8 +22,8 @@ export default {
|
||||
relationEntityKey: 'slug',
|
||||
},
|
||||
'customer': {
|
||||
name: 'Customer',
|
||||
column: 'customer_id',
|
||||
label: 'Customer',
|
||||
name: 'customer_id',
|
||||
fieldType: 'relation',
|
||||
|
||||
relationType: 'enumeration',
|
||||
@@ -67,8 +67,8 @@ export default {
|
||||
name: 'Status',
|
||||
fieldType: 'enumeration',
|
||||
options: [
|
||||
{ key: 'draft', name: 'Draft' },
|
||||
{ key: 'closed', name: 'Closed' },
|
||||
{ key: 'draft', label: 'Draft' },
|
||||
{ key: 'closed', label: 'Closed' },
|
||||
],
|
||||
filterCustomQuery: StatusFieldFilterQuery,
|
||||
sortCustomQuery: StatusFieldSortQuery,
|
||||
|
||||
@@ -71,7 +71,8 @@ export default {
|
||||
fieldType: 'text',
|
||||
},
|
||||
'status': {
|
||||
label: 'Status',
|
||||
name: 'Status',
|
||||
type: 'enumeration',
|
||||
options: [
|
||||
{ key: 'overdue', label: 'Overdue' },
|
||||
{ key: 'unpaid', label: 'Unpaid' },
|
||||
|
||||
@@ -3,9 +3,6 @@ import { camelCase, upperFirst } from 'lodash';
|
||||
import pluralize from 'pluralize';
|
||||
import { buildFilter } from 'objection-filter';
|
||||
import { IModel, IModelMeta } from 'interfaces';
|
||||
import {
|
||||
getModelFields,
|
||||
} from 'lib/ViewRolesBuilder'
|
||||
import TenancyService from 'services/Tenancy/TenancyService';
|
||||
import { ServiceError } from 'exceptions';
|
||||
|
||||
@@ -20,62 +17,12 @@ export default class ResourceService {
|
||||
|
||||
/**
|
||||
* Transform resource to model name.
|
||||
* @param {string} resourceName
|
||||
* @param {string} resourceName
|
||||
*/
|
||||
private resourceToModelName(resourceName: string): string {
|
||||
return upperFirst(camelCase(pluralize.singular(resourceName)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve model fields.
|
||||
* @param {number} tenantId
|
||||
* @param {IModel} Model
|
||||
*/
|
||||
private getModelFields(tenantId: number, Model: IModel) {
|
||||
const { __ } = this.tenancy.i18n(tenantId);
|
||||
const fields = getModelFields(Model);
|
||||
|
||||
return fields.map((field) => ({
|
||||
label: __(field.label),
|
||||
key: field.key,
|
||||
dataType: field.columnType,
|
||||
fieldType: field.fieldType,
|
||||
|
||||
...(field.options) ? {
|
||||
options: field.options.map((option) => ({
|
||||
...option, label: __(option.label),
|
||||
})),
|
||||
} : {},
|
||||
|
||||
...(field.optionsResource) ? {
|
||||
optionsResource: field.optionsResource,
|
||||
optionsKey: field.optionsKey,
|
||||
optionsLabel: field.optionsLabel,
|
||||
} : {},
|
||||
}));
|
||||
}
|
||||
|
||||
/**
|
||||
* Should model be resource-able or throw service error.
|
||||
* @param {IModel} model
|
||||
*/
|
||||
private shouldModelBeResourceable(model: IModel) {
|
||||
if (!model.resourceable) {
|
||||
throw new ServiceError(ERRORS.RESOURCE_MODEL_NOT_FOUND);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve resource fields from resource model name.
|
||||
* @param {string} resourceName
|
||||
*/
|
||||
public getResourceFields(tenantId: number, modelName: string) {
|
||||
const resourceModel = this.getResourceModel(tenantId, modelName);
|
||||
this.shouldModelBeResourceable(resourceModel);
|
||||
|
||||
return this.getModelFields(tenantId, resourceModel);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve resource model object.
|
||||
* @param {number} tenantId -
|
||||
@@ -91,29 +38,18 @@ export default class ResourceService {
|
||||
return Models[modelName];
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve resource data from the storage based on the given query.
|
||||
* @param {number} tenantId
|
||||
* @param {string} modelName
|
||||
*/
|
||||
public async getResourceData(tenantId: number, modelName: string, filter: any) {
|
||||
const resourceModel = this.getResourceModel(tenantId, modelName);
|
||||
this.shouldModelBeResourceable(resourceModel);
|
||||
|
||||
return buildFilter(resourceModel).build(filter);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the resource meta.
|
||||
* @param {number} tenantId
|
||||
* @param {string} modelName
|
||||
* @param {number} tenantId
|
||||
* @param {string} modelName
|
||||
* @returns {IModelMeta}
|
||||
*/
|
||||
public getResourceMeta(tenantId: number, modelName: string): IModelMeta {
|
||||
public getResourceMeta(
|
||||
tenantId: number,
|
||||
modelName: string,
|
||||
metakey?: string
|
||||
): IModelMeta {
|
||||
const resourceModel = this.getResourceModel(tenantId, modelName);
|
||||
|
||||
const settings = resourceModel.meta();
|
||||
|
||||
return settings;
|
||||
return resourceModel.getMeta(metakey);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user