From 7abfa6a162a992859bdfb826214abd63fe6c2dc7 Mon Sep 17 00:00:00 2001 From: Ahmed Bouhuolia Date: Wed, 24 Apr 2024 20:01:04 +0200 Subject: [PATCH] feat: ability to enable/disable the bank connect feature (#423) --- docker-compose.prod.yml | 10 ++++++ .../src/api/controllers/Dashboard/index.ts | 6 ++-- packages/server/src/config/index.ts | 8 +++++ packages/server/src/interfaces/Features.ts | 1 + .../server/src/lib/Metable/MetableStore.ts | 4 +-- .../src/services/Features/FeaturesManager.ts | 32 ++----------------- .../Features/FeaturesSettingsDriver.ts | 16 ++++++++-- .../server/src/services/Features/constants.ts | 6 ++++ packages/webapp/src/constants/features.tsx | 3 +- .../CashFlowAccountsActionsBar.tsx | 15 +++++---- 10 files changed, 58 insertions(+), 43 deletions(-) diff --git a/docker-compose.prod.yml b/docker-compose.prod.yml index 5d2cc174d..fa873e7de 100644 --- a/docker-compose.prod.yml +++ b/docker-compose.prod.yml @@ -86,6 +86,16 @@ services: - GOTENBERG_URL=${GOTENBERG_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 - LEMONSQUEEZY_API_KEY=${LEMONSQUEEZY_API_KEY} - LEMONSQUEEZY_STORE_ID=${LEMONSQUEEZY_STORE_ID} diff --git a/packages/server/src/api/controllers/Dashboard/index.ts b/packages/server/src/api/controllers/Dashboard/index.ts index 4102fcbe8..027f151ac 100644 --- a/packages/server/src/api/controllers/Dashboard/index.ts +++ b/packages/server/src/api/controllers/Dashboard/index.ts @@ -8,10 +8,10 @@ export default class DashboardMetaController { dashboardService: DashboardService; /** - * + * Constructor router. * @returns */ - router() { + public router() { const router = Router(); router.get('/boot', this.getDashboardBoot); @@ -25,7 +25,7 @@ export default class DashboardMetaController { * @param {Response} res - * @param {NextFunction} next - */ - getDashboardBoot = async ( + private getDashboardBoot = async ( req: Request, res: Response, next: NextFunction diff --git a/packages/server/src/config/index.ts b/packages/server/src/config/index.ts index 77726997a..6a61da3ca 100644 --- a/packages/server/src/config/index.ts +++ b/packages/server/src/config/index.ts @@ -180,6 +180,14 @@ module.exports = { }, }, + /** + * Bank Synchronization. + */ + bankSync: { + enabled: parseBoolean(defaultTo(process.env.BANKING_CONNECT, false), false), + provider: 'plaid', + }, + /** * Plaid. */ diff --git a/packages/server/src/interfaces/Features.ts b/packages/server/src/interfaces/Features.ts index 691cf76af..05b5247d2 100644 --- a/packages/server/src/interfaces/Features.ts +++ b/packages/server/src/interfaces/Features.ts @@ -1,6 +1,7 @@ export enum Features { WAREHOUSES = 'warehouses', BRANCHES = 'branches', + BankSyncing = 'BankSyncing' } export interface IFeatureAllItem { diff --git a/packages/server/src/lib/Metable/MetableStore.ts b/packages/server/src/lib/Metable/MetableStore.ts index 3d9400361..0dd7861d0 100644 --- a/packages/server/src/lib/Metable/MetableStore.ts +++ b/packages/server/src/lib/Metable/MetableStore.ts @@ -62,13 +62,13 @@ export default class MetableStore implements IMetableStore { * @param {String} key - * @param {Mixied} defaultValue - */ - get(query: string | IMetaQuery, defaultValue: any): any | false { + get(query: string | IMetaQuery, defaultValue: any): any | null { const metadata = this.find(query); return metadata ? metadata.value : typeof defaultValue !== 'undefined' ? defaultValue - : false; + : null; } /** diff --git a/packages/server/src/services/Features/FeaturesManager.ts b/packages/server/src/services/Features/FeaturesManager.ts index 2ee0265be..e355d1944 100644 --- a/packages/server/src/services/Features/FeaturesManager.ts +++ b/packages/server/src/services/Features/FeaturesManager.ts @@ -1,8 +1,5 @@ -import { defaultTo } from 'lodash'; import { Inject, Service } from 'typedi'; -import { omit } from 'lodash'; import { FeaturesSettingsDriver } from './FeaturesSettingsDriver'; -import { FeaturesConfigureManager } from './FeaturesConfigureManager'; import { IFeatureAllItem } from '@/interfaces'; @Service() @@ -10,9 +7,6 @@ export class FeaturesManager { @Inject() private drive: FeaturesSettingsDriver; - @Inject() - private configure: FeaturesConfigureManager; - /** * Turns-on the given feature name. * @param {number} tenantId @@ -40,35 +34,15 @@ export class FeaturesManager { * @returns {Promise} */ public async accessible(tenantId: number, feature: string) { - // Retrieves the feature default accessible value. - const defaultValue = this.configure.getFeatureConfigure( - feature, - 'defaultValue' - ); - const isAccessible = await this.drive.accessible(tenantId, feature); - - return defaultTo(isAccessible, defaultValue); + return this.drive.accessible(tenantId, feature); } /** * Retrieves the all features and their accessible value and default value. * @param {number} tenantId - * @returns + * @returns {Promise} */ public async all(tenantId: number): Promise { - const all = await 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), - }; - }); + return this.drive.all(tenantId); } } diff --git a/packages/server/src/services/Features/FeaturesSettingsDriver.ts b/packages/server/src/services/Features/FeaturesSettingsDriver.ts index dd0c98022..cf4900d05 100644 --- a/packages/server/src/services/Features/FeaturesSettingsDriver.ts +++ b/packages/server/src/services/Features/FeaturesSettingsDriver.ts @@ -2,11 +2,15 @@ import { Service, Inject } from 'typedi'; import HasTenancyService from '@/services/Tenancy/TenancyService'; import { FeaturesConfigure } from './constants'; import { IFeatureAllItem } from '@/interfaces'; +import { FeaturesConfigureManager } from './FeaturesConfigureManager'; @Service() export class FeaturesSettingsDriver { @Inject() - tenancy: HasTenancyService; + private tenancy: HasTenancyService; + + @Inject() + private configure: FeaturesConfigureManager; /** * Turns-on the given feature name. @@ -41,7 +45,15 @@ export class FeaturesSettingsDriver { async accessible(tenantId: number, feature: string) { 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; } /** diff --git a/packages/server/src/services/Features/constants.ts b/packages/server/src/services/Features/constants.ts index 5e2b807f6..2d8fb76e3 100644 --- a/packages/server/src/services/Features/constants.ts +++ b/packages/server/src/services/Features/constants.ts @@ -1,4 +1,6 @@ import { Features, IFeatureConfiugration } from '@/interfaces'; +import config from '@/config'; +import { defaultTo } from 'lodash'; export const FeaturesConfigure: IFeatureConfiugration[] = [ { @@ -9,4 +11,8 @@ export const FeaturesConfigure: IFeatureConfiugration[] = [ name: Features.WAREHOUSES, defaultValue: false, }, + { + name: Features.BankSyncing, + defaultValue: defaultTo(config.bankSync.enabled, false), + } ]; diff --git a/packages/webapp/src/constants/features.tsx b/packages/webapp/src/constants/features.tsx index ef391f3ef..b2db20da7 100644 --- a/packages/webapp/src/constants/features.tsx +++ b/packages/webapp/src/constants/features.tsx @@ -5,5 +5,6 @@ export const Features = { Warehouses: 'warehouses', Branches: 'branches', ManualJournal: 'manualJournal', - Projects:'Projects' + Projects:'Projects', + BankSyncing: 'BankSyncing', } \ No newline at end of file diff --git a/packages/webapp/src/containers/CashFlow/CashFlowAccounts/CashFlowAccountsActionsBar.tsx b/packages/webapp/src/containers/CashFlow/CashFlowAccounts/CashFlowAccountsActionsBar.tsx index 66298dc8b..6d6c4bbbe 100644 --- a/packages/webapp/src/containers/CashFlow/CashFlowAccounts/CashFlowAccountsActionsBar.tsx +++ b/packages/webapp/src/containers/CashFlow/CashFlowAccounts/CashFlowAccountsActionsBar.tsx @@ -12,6 +12,7 @@ import { Can, Icon, FormattedMessage as T, + FeatureCan, } from '@/components'; import { useRefreshCashflowAccounts } from '@/hooks/query'; import { CashflowAction, AbilitySubject } from '@/constants/abilityOption'; @@ -21,7 +22,7 @@ import withCashflowAccountsTableActions from '../AccountTransactions/withCashflo import { AccountDialogAction } from '@/containers/Dialogs/AccountDialog/utils'; -import { ACCOUNT_TYPE } from '@/constants'; +import { ACCOUNT_TYPE, Features } from '@/constants'; import { DialogsName } from '@/constants/dialogs'; import { compose } from '@/utils'; @@ -110,12 +111,14 @@ function CashFlowAccountsActionsBar({ -