mirror of
https://github.com/bigcapitalhq/bigcapital.git
synced 2026-02-19 14:20:31 +00:00
Compare commits
2 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7e5c6b6487 | ||
|
|
7abfa6a162 |
@@ -86,6 +86,16 @@ services:
|
|||||||
- GOTENBERG_URL=${GOTENBERG_URL}
|
- GOTENBERG_URL=${GOTENBERG_URL}
|
||||||
- GOTENBERG_DOCS_URL=${GOTENBERG_DOCS_URL}
|
- GOTENBERG_DOCS_URL=${GOTENBERG_DOCS_URL}
|
||||||
|
|
||||||
|
# Bank Sync
|
||||||
|
- BANKING_CONNECT=${BANKING_CONNECT}
|
||||||
|
|
||||||
|
# Plaid
|
||||||
|
- PLAID_ENV=${PLAID_ENV}
|
||||||
|
- PLAID_CLIENT_ID=${PLAID_CLIENT_ID}
|
||||||
|
- PLAID_SECRET_DEVELOPMENT=${PLAID_SECRET_DEVELOPMENT}
|
||||||
|
- PLAID_SECRET_SANDBOX=${b8cf42b441e110451e2f69ad7e1e9f}
|
||||||
|
- PLAID_LINK_WEBHOOK=${PLAID_LINK_WEBHOOK}
|
||||||
|
|
||||||
# Lemon Squeez
|
# Lemon Squeez
|
||||||
- LEMONSQUEEZY_API_KEY=${LEMONSQUEEZY_API_KEY}
|
- LEMONSQUEEZY_API_KEY=${LEMONSQUEEZY_API_KEY}
|
||||||
- LEMONSQUEEZY_STORE_ID=${LEMONSQUEEZY_STORE_ID}
|
- LEMONSQUEEZY_STORE_ID=${LEMONSQUEEZY_STORE_ID}
|
||||||
|
|||||||
@@ -8,10 +8,10 @@ export default class DashboardMetaController {
|
|||||||
dashboardService: DashboardService;
|
dashboardService: DashboardService;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
* Constructor router.
|
||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
router() {
|
public router() {
|
||||||
const router = Router();
|
const router = Router();
|
||||||
|
|
||||||
router.get('/boot', this.getDashboardBoot);
|
router.get('/boot', this.getDashboardBoot);
|
||||||
@@ -25,7 +25,7 @@ export default class DashboardMetaController {
|
|||||||
* @param {Response} res -
|
* @param {Response} res -
|
||||||
* @param {NextFunction} next -
|
* @param {NextFunction} next -
|
||||||
*/
|
*/
|
||||||
getDashboardBoot = async (
|
private getDashboardBoot = async (
|
||||||
req: Request,
|
req: Request,
|
||||||
res: Response,
|
res: Response,
|
||||||
next: NextFunction
|
next: NextFunction
|
||||||
|
|||||||
@@ -55,7 +55,7 @@ module.exports = {
|
|||||||
mail: {
|
mail: {
|
||||||
host: process.env.MAIL_HOST,
|
host: process.env.MAIL_HOST,
|
||||||
port: process.env.MAIL_PORT,
|
port: process.env.MAIL_PORT,
|
||||||
secure: !!parseInt(process.env.MAIL_SECURE, 10),
|
secure: parseBoolean(defaultTo(process.env.MAIL_SECURE, false), false),
|
||||||
username: process.env.MAIL_USERNAME,
|
username: process.env.MAIL_USERNAME,
|
||||||
password: process.env.MAIL_PASSWORD,
|
password: process.env.MAIL_PASSWORD,
|
||||||
from: process.env.MAIL_FROM_ADDRESS,
|
from: process.env.MAIL_FROM_ADDRESS,
|
||||||
@@ -180,6 +180,14 @@ module.exports = {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Bank Synchronization.
|
||||||
|
*/
|
||||||
|
bankSync: {
|
||||||
|
enabled: parseBoolean(defaultTo(process.env.BANKING_CONNECT, false), false),
|
||||||
|
provider: 'plaid',
|
||||||
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Plaid.
|
* Plaid.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
export enum Features {
|
export enum Features {
|
||||||
WAREHOUSES = 'warehouses',
|
WAREHOUSES = 'warehouses',
|
||||||
BRANCHES = 'branches',
|
BRANCHES = 'branches',
|
||||||
|
BankSyncing = 'BankSyncing'
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IFeatureAllItem {
|
export interface IFeatureAllItem {
|
||||||
|
|||||||
@@ -62,13 +62,13 @@ export default class MetableStore implements IMetableStore {
|
|||||||
* @param {String} key -
|
* @param {String} key -
|
||||||
* @param {Mixied} defaultValue -
|
* @param {Mixied} defaultValue -
|
||||||
*/
|
*/
|
||||||
get(query: string | IMetaQuery, defaultValue: any): any | false {
|
get(query: string | IMetaQuery, defaultValue: any): any | null {
|
||||||
const metadata = this.find(query);
|
const metadata = this.find(query);
|
||||||
return metadata
|
return metadata
|
||||||
? metadata.value
|
? metadata.value
|
||||||
: typeof defaultValue !== 'undefined'
|
: typeof defaultValue !== 'undefined'
|
||||||
? defaultValue
|
? defaultValue
|
||||||
: false;
|
: null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -1,8 +1,5 @@
|
|||||||
import { defaultTo } from 'lodash';
|
|
||||||
import { Inject, Service } from 'typedi';
|
import { Inject, Service } from 'typedi';
|
||||||
import { omit } from 'lodash';
|
|
||||||
import { FeaturesSettingsDriver } from './FeaturesSettingsDriver';
|
import { FeaturesSettingsDriver } from './FeaturesSettingsDriver';
|
||||||
import { FeaturesConfigureManager } from './FeaturesConfigureManager';
|
|
||||||
import { IFeatureAllItem } from '@/interfaces';
|
import { IFeatureAllItem } from '@/interfaces';
|
||||||
|
|
||||||
@Service()
|
@Service()
|
||||||
@@ -10,9 +7,6 @@ export class FeaturesManager {
|
|||||||
@Inject()
|
@Inject()
|
||||||
private drive: FeaturesSettingsDriver;
|
private drive: FeaturesSettingsDriver;
|
||||||
|
|
||||||
@Inject()
|
|
||||||
private configure: FeaturesConfigureManager;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Turns-on the given feature name.
|
* Turns-on the given feature name.
|
||||||
* @param {number} tenantId
|
* @param {number} tenantId
|
||||||
@@ -40,35 +34,15 @@ export class FeaturesManager {
|
|||||||
* @returns {Promise<void>}
|
* @returns {Promise<void>}
|
||||||
*/
|
*/
|
||||||
public async accessible(tenantId: number, feature: string) {
|
public async accessible(tenantId: number, feature: string) {
|
||||||
// Retrieves the feature default accessible value.
|
return this.drive.accessible(tenantId, feature);
|
||||||
const defaultValue = this.configure.getFeatureConfigure(
|
|
||||||
feature,
|
|
||||||
'defaultValue'
|
|
||||||
);
|
|
||||||
const isAccessible = await this.drive.accessible(tenantId, feature);
|
|
||||||
|
|
||||||
return defaultTo(isAccessible, defaultValue);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieves the all features and their accessible value and default value.
|
* Retrieves the all features and their accessible value and default value.
|
||||||
* @param {number} tenantId
|
* @param {number} tenantId
|
||||||
* @returns
|
* @returns {Promise<IFeatureAllItem[]>}
|
||||||
*/
|
*/
|
||||||
public async all(tenantId: number): Promise<IFeatureAllItem[]> {
|
public async all(tenantId: number): Promise<IFeatureAllItem[]> {
|
||||||
const all = await this.drive.all(tenantId);
|
return this.drive.all(tenantId);
|
||||||
|
|
||||||
return all.map((feature: IFeatureAllItem) => {
|
|
||||||
const defaultAccessible = this.configure.getFeatureConfigure(
|
|
||||||
feature.name,
|
|
||||||
'defaultValue'
|
|
||||||
);
|
|
||||||
const isAccessible = feature.isAccessible;
|
|
||||||
|
|
||||||
return {
|
|
||||||
...feature,
|
|
||||||
isAccessible: defaultTo(isAccessible, defaultAccessible),
|
|
||||||
};
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,11 +2,15 @@ import { Service, Inject } from 'typedi';
|
|||||||
import HasTenancyService from '@/services/Tenancy/TenancyService';
|
import HasTenancyService from '@/services/Tenancy/TenancyService';
|
||||||
import { FeaturesConfigure } from './constants';
|
import { FeaturesConfigure } from './constants';
|
||||||
import { IFeatureAllItem } from '@/interfaces';
|
import { IFeatureAllItem } from '@/interfaces';
|
||||||
|
import { FeaturesConfigureManager } from './FeaturesConfigureManager';
|
||||||
|
|
||||||
@Service()
|
@Service()
|
||||||
export class FeaturesSettingsDriver {
|
export class FeaturesSettingsDriver {
|
||||||
@Inject()
|
@Inject()
|
||||||
tenancy: HasTenancyService;
|
private tenancy: HasTenancyService;
|
||||||
|
|
||||||
|
@Inject()
|
||||||
|
private configure: FeaturesConfigureManager;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Turns-on the given feature name.
|
* Turns-on the given feature name.
|
||||||
@@ -41,7 +45,15 @@ export class FeaturesSettingsDriver {
|
|||||||
async accessible(tenantId: number, feature: string) {
|
async accessible(tenantId: number, feature: string) {
|
||||||
const settings = this.tenancy.settings(tenantId);
|
const settings = this.tenancy.settings(tenantId);
|
||||||
|
|
||||||
return !!settings.get({ group: 'features', key: feature });
|
const defaultValue = this.configure.getFeatureConfigure(
|
||||||
|
feature,
|
||||||
|
'defaultValue'
|
||||||
|
);
|
||||||
|
const settingValue = settings.get(
|
||||||
|
{ group: 'features', key: feature },
|
||||||
|
defaultValue
|
||||||
|
);
|
||||||
|
return settingValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -1,4 +1,6 @@
|
|||||||
import { Features, IFeatureConfiugration } from '@/interfaces';
|
import { Features, IFeatureConfiugration } from '@/interfaces';
|
||||||
|
import config from '@/config';
|
||||||
|
import { defaultTo } from 'lodash';
|
||||||
|
|
||||||
export const FeaturesConfigure: IFeatureConfiugration[] = [
|
export const FeaturesConfigure: IFeatureConfiugration[] = [
|
||||||
{
|
{
|
||||||
@@ -9,4 +11,8 @@ export const FeaturesConfigure: IFeatureConfiugration[] = [
|
|||||||
name: Features.WAREHOUSES,
|
name: Features.WAREHOUSES,
|
||||||
defaultValue: false,
|
defaultValue: false,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: Features.BankSyncing,
|
||||||
|
defaultValue: defaultTo(config.bankSync.enabled, false),
|
||||||
|
}
|
||||||
];
|
];
|
||||||
|
|||||||
@@ -5,5 +5,6 @@ export const Features = {
|
|||||||
Warehouses: 'warehouses',
|
Warehouses: 'warehouses',
|
||||||
Branches: 'branches',
|
Branches: 'branches',
|
||||||
ManualJournal: 'manualJournal',
|
ManualJournal: 'manualJournal',
|
||||||
Projects:'Projects'
|
Projects:'Projects',
|
||||||
|
BankSyncing: 'BankSyncing',
|
||||||
}
|
}
|
||||||
@@ -12,6 +12,7 @@ import {
|
|||||||
Can,
|
Can,
|
||||||
Icon,
|
Icon,
|
||||||
FormattedMessage as T,
|
FormattedMessage as T,
|
||||||
|
FeatureCan,
|
||||||
} from '@/components';
|
} from '@/components';
|
||||||
import { useRefreshCashflowAccounts } from '@/hooks/query';
|
import { useRefreshCashflowAccounts } from '@/hooks/query';
|
||||||
import { CashflowAction, AbilitySubject } from '@/constants/abilityOption';
|
import { CashflowAction, AbilitySubject } from '@/constants/abilityOption';
|
||||||
@@ -21,7 +22,7 @@ import withCashflowAccountsTableActions from '../AccountTransactions/withCashflo
|
|||||||
|
|
||||||
import { AccountDialogAction } from '@/containers/Dialogs/AccountDialog/utils';
|
import { AccountDialogAction } from '@/containers/Dialogs/AccountDialog/utils';
|
||||||
|
|
||||||
import { ACCOUNT_TYPE } from '@/constants';
|
import { ACCOUNT_TYPE, Features } from '@/constants';
|
||||||
import { DialogsName } from '@/constants/dialogs';
|
import { DialogsName } from '@/constants/dialogs';
|
||||||
|
|
||||||
import { compose } from '@/utils';
|
import { compose } from '@/utils';
|
||||||
@@ -110,12 +111,14 @@ function CashFlowAccountsActionsBar({
|
|||||||
</NavbarGroup>
|
</NavbarGroup>
|
||||||
|
|
||||||
<NavbarGroup align={Alignment.RIGHT}>
|
<NavbarGroup align={Alignment.RIGHT}>
|
||||||
<Button
|
<FeatureCan feature={Features.BankSyncing}>
|
||||||
className={Classes.MINIMAL}
|
<Button
|
||||||
text={'Connect to Bank / Credit Card'}
|
className={Classes.MINIMAL}
|
||||||
onClick={handleConnectToBank}
|
text={'Connect to Bank / Credit Card'}
|
||||||
/>
|
onClick={handleConnectToBank}
|
||||||
|
/>
|
||||||
<NavbarDivider />
|
<NavbarDivider />
|
||||||
|
</FeatureCan>
|
||||||
<Button
|
<Button
|
||||||
className={Classes.MINIMAL}
|
className={Classes.MINIMAL}
|
||||||
icon={<Icon icon="refresh-16" iconSize={14} />}
|
icon={<Icon icon="refresh-16" iconSize={14} />}
|
||||||
|
|||||||
Reference in New Issue
Block a user