Compare commits

...

23 Commits

Author SHA1 Message Date
Ahmed Bouhuolia
341bcbea7d feat: database backup script 2024-04-28 18:04:56 +02:00
Ahmed Bouhuolia
b7214044bb Merge branch 'main' into develop 2024-04-24 20:05:49 +02:00
Ahmed Bouhuolia
93cb3615c3 Merge branch 'main' into develop 2024-04-24 20:05:33 +02:00
Ahmed Bouhuolia
7abfa6a162 feat: ability to enable/disable the bank connect feature (#423) 2024-04-24 20:01:04 +02:00
Ahmed Bouhuolia
1372a1f0a8 hotfix: fix the subscription plan when subscribe on cloud (#422) 2024-04-24 15:30:36 +02:00
allcontributors[bot]
484024ec28 docs: add cloudsbird as a contributor for code (#418)
* docs: update README.md [skip ci]

* docs: update .all-contributorsrc [skip ci]

---------

Co-authored-by: allcontributors[bot] <46447321+allcontributors[bot]@users.noreply.github.com>
2024-04-23 19:37:47 +02:00
Vederis Leunardus
46639c7b86 feat: Update Docker Build-Push Action and Add ARM64 Support (#412)
* feat: build for arm64 platform

* fix: typo and add buildx and qemu

* feat: update the docker login-action version

* feat: update the docker login-action version

* feat: add the digest
2024-04-23 19:33:27 +02:00
allcontributors[bot]
d10d1654c1 docs: add benpsnyder as a contributor for code (#417)
* docs: update README.md [skip ci]

* docs: update .all-contributorsrc [skip ci]

---------

Co-authored-by: allcontributors[bot] <46447321+allcontributors[bot]@users.noreply.github.com>
2024-04-22 10:21:09 +02:00
Ahmed Bouhuolia
2f06070ecb Merge pull request #414 from benpsnyder/feat/upgrade-to-latest-lerna
feat(repo): upgrade to latest lerna v8 and pnpm v9
2024-04-22 10:16:50 +02:00
Ahmed Bouhuolia
deefdb9bfd fix: update pnpm-lock.yaml file 2024-04-22 10:04:18 +02:00
Ben Snyder
3cc62d80de fix(repo): replace usage of yarn with pnpm/pnpx 2024-04-21 20:34:35 -04:00
Ben Snyder
4962c5d4d3 feat(repo): upgrade to latest lerna v8 and pnpm v9 2024-04-21 20:29:38 -04:00
Ahmed Bouhuolia
571a332658 Merge pull request #410 from bigcapitalhq/seed-free-subscription-to-tenants
feat: seed free subscription to tenants that have no subscription.
2024-04-19 09:36:35 +02:00
Ahmed Bouhuolia
b44c318a5d feat: seed free subscription to tenants that have no subscription. 2024-04-19 09:34:47 +02:00
Ahmed Bouhuolia
bd9717f4dc chore: Add Bigcapital Cloud link on README.md file 2024-04-17 19:51:05 +02:00
Ahmed Bouhuolia
f48aea8e5a feat: add the new env variables to docker compose 2024-04-17 19:21:35 +02:00
Ahmed Bouhuolia
0ac3a5dea9 fix: add /imports directory to storage dir 2024-04-17 18:25:17 +02:00
Ahmed Bouhuolia
56b40ad4cb fix: TS and linit errors 2024-04-17 17:51:21 +02:00
Ahmed Bouhuolia
9b6f934990 fix: add @lemonsqueezy/lemonsqueezy package dependencies. 2024-04-17 17:44:35 +02:00
Ahmed Bouhuolia
80e3522f8a Merge pull request #408 from bigcapitalhq/fix-import-store-absolute-path
fix: absolute storage imports path.
2024-04-17 17:37:39 +02:00
Ahmed Bouhuolia
7975643765 fix: absolute storage imports path. 2024-04-17 17:36:35 +02:00
Ahmed Bouhuolia
2ac7f86bdb Merge pull request #407 from bigcapitalhq/auto-subscribe-free
chore: add default value to env variable
2024-04-16 21:24:49 +02:00
Ahmed Bouhuolia
60248ec3f6 Merge pull request #406 from bigcapitalhq/auto-subscribe-free
feat: auto subscribe to free plan once signup on community version.
2024-04-16 20:58:29 +02:00
37 changed files with 1609 additions and 41536 deletions

View File

@@ -105,6 +105,24 @@
"contributions": [
"bug"
]
},
{
"login": "benpsnyder",
"name": "Ben Snyder",
"avatar_url": "https://avatars.githubusercontent.com/u/707567?v=4",
"profile": "https://snyder.tech",
"contributions": [
"code"
]
},
{
"login": "cloudsbird",
"name": "Vederis Leunardus",
"avatar_url": "https://avatars.githubusercontent.com/u/13505006?v=4",
"profile": "http://vederis.id",
"contributions": [
"code"
]
}
],
"contributorsPerLine": 7,

View File

@@ -96,7 +96,6 @@ PLAID_LINK_WEBHOOK=
PLAID_SANDBOX_REDIRECT_URI=
PLAID_DEVELOPMENT_REDIRECT_URI=
# https://docs.lemonsqueezy.com/guides/developer-guide/getting-started#create-an-api-key
LEMONSQUEEZY_API_KEY=
LEMONSQUEEZY_STORE_ID=

View File

@@ -12,20 +12,37 @@ env:
jobs:
build-publish-webapp:
strategy:
fail-fast: false
matrix:
platform:
- linux/amd64
- linux/arm64
name: Build and deploy webapp container
runs-on: ubuntu-latest
environment: production
steps:
- name: Prepare
run: |
platform=${{ matrix.platform }}
echo "PLATFORM_PAIR=${platform//\//-}" >> $GITHUB_ENV
- name: Checkout
uses: actions/checkout@v2
uses: actions/checkout@v4
- name: Set up QEMU
uses: docker/setup-qemu-action@v3
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
# Login to Container registry.
- name: Log in to the Container registry
uses: docker/login-action@v1
uses: docker/login-action@v3
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GH_TOKEN }}
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GH_TOKEN }}
- name: Extract metadata (tags, labels) for Docker
id: meta
@@ -35,14 +52,29 @@ jobs:
# Builds and push the Docker image.
- name: Build and push Docker image
uses: docker/build-push-action@v2
uses: docker/build-push-action@v5
id: build
with:
context: .
file: ./packages/webapp/Dockerfile
push: true
tags: ghcr.io/bigcapitalhq/webapp:latest
labels: ${{ steps.meta.outputs.labels }}
context: .
file: ./packages/webapp/Dockerfile
platforms: ${{ matrix.platform }}
push: true
tags: ghcr.io/bigcapitalhq/webapp:latest
labels: ${{ steps.meta.outputs.labels }}
- name: Export digest
run: |
mkdir -p /tmp/digests
digest="${{ steps.build.outputs.digest }}"
touch "/tmp/digests/${digest#sha256:}"
- name: Upload digest
uses: actions/upload-artifact@v4
with:
name: digests-main-${{ env.PLATFORM_PAIR }}
path: /tmp/digests/*
if-no-files-found: error
retention-days: 1
# Send notification to Slack channel.
- name: Slack Notification built and published webapp container successfully.
uses: rtCamp/action-slack-notify@v2
@@ -53,12 +85,23 @@ jobs:
name: Build and deploy server container
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v2
- name: Prepare
run: |
platform=${{ matrix.platform }}
echo "PLATFORM_PAIR=${platform//\//-}" >> $GITHUB_ENV
- name: Checkout
uses: actions/checkout@v4
- name: Set up QEMU
uses: docker/setup-qemu-action@v3
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
# Login to Container registry.
- name: Log in to the Container registry
uses: docker/login-action@v1
uses: docker/login-action@v3
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
@@ -66,14 +109,30 @@ jobs:
# Builds and push the Docker image.
- name: Build and push Docker image
uses: docker/build-push-action@v2
uses: docker/build-push-action@v5
id: build
with:
context: ./
file: ./packages/server/Dockerfile
platforms: ${{ matrix.platform }}
push: true
tags: ghcr.io/bigcapitalhq/server:latest
labels: ${{ steps.meta.outputs.labels }}
- name: Export digest
run: |
mkdir -p /tmp/digests
digest="${{ steps.build.outputs.digest }}"
touch "/tmp/digests/${digest#sha256:}"
- name: Upload digest
uses: actions/upload-artifact@v4
with:
name: digests-main-${{ env.PLATFORM_PAIR }}
path: /tmp/digests/*
if-no-files-found: error
retention-days: 1
# Send notification to Slack channel.
- name: Slack Notification built and published server container successfully.
uses: rtCamp/action-slack-notify@v2

View File

@@ -8,14 +8,14 @@ on:
- '**.ts'
- '**.tsx'
- '**/tsconfig.json'
- 'yarn.lock'
- 'pnpm-lock.yaml'
- '.github/workflows/e2e.yml'
pull_request:
paths:
- '**.ts'
- '**.tsx'
- '**/tsconfig.json'
- 'yarn.lock'
- 'pnpm-lock.yaml'
- '.github/workflows/e2e.yml'
defaults:

View File

@@ -1,4 +1,4 @@
#!/usr/bin/env sh
. "$(dirname -- "$0")/_/husky.sh"
yarn commitlint --edit
pnpx commitlint --edit

View File

@@ -25,6 +25,10 @@
<img src="https://img.shields.io/twitter/follow/bigcapitalhq?style=social" alt="twitter" />
</a>
</p>
<p align="center">
<a href="https://app.bigcapital.ly">Bigcapital Cloud</a>
</p>
</p>
# What's Bigcapital?
@@ -118,6 +122,8 @@ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/d
<td align="center" valign="top" width="14.28%"><a href="https://github.com/ANasouf"><img src="https://avatars.githubusercontent.com/u/19536487?v=4?s=100" width="100px;" alt="ANasouf"/><br /><sub><b>ANasouf</b></sub></a><br /><a href="https://github.com/bigcapitalhq/bigcapital/commits?author=ANasouf" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://ragnarlaud.dev"><img src="https://avatars.githubusercontent.com/u/3042904?v=4?s=100" width="100px;" alt="Ragnar Laud"/><br /><sub><b>Ragnar Laud</b></sub></a><br /><a href="https://github.com/bigcapitalhq/bigcapital/issues?q=author%3Axprnio" title="Bug reports">🐛</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/asenawritescode"><img src="https://avatars.githubusercontent.com/u/67445192?v=4?s=100" width="100px;" alt="Asena"/><br /><sub><b>Asena</b></sub></a><br /><a href="https://github.com/bigcapitalhq/bigcapital/issues?q=author%3Aasenawritescode" title="Bug reports">🐛</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://snyder.tech"><img src="https://avatars.githubusercontent.com/u/707567?v=4?s=100" width="100px;" alt="Ben Snyder"/><br /><sub><b>Ben Snyder</b></sub></a><br /><a href="https://github.com/bigcapitalhq/bigcapital/commits?author=benpsnyder" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="http://vederis.id"><img src="https://avatars.githubusercontent.com/u/13505006?v=4?s=100" width="100px;" alt="Vederis Leunardus"/><br /><sub><b>Vederis Leunardus</b></sub></a><br /><a href="https://github.com/bigcapitalhq/bigcapital/commits?author=cloudsbird" title="Code">💻</a></td>
</tr>
</tbody>
</table>

View File

@@ -21,16 +21,12 @@ services:
depends_on:
- server
- webapp
deploy:
restart_policy:
condition: unless-stopped
restart: on-failure
webapp:
container_name: bigcapital-webapp
image: ghcr.io/bigcapitalhq/webapp:latest
deploy:
restart_policy:
condition: unless-stopped
restart: on-failure
server:
container_name: bigcapital-server
@@ -45,9 +41,7 @@ services:
- mysql
- mongo
- redis
deploy:
restart_policy:
condition: unless-stopped
restart: on-failure
environment:
# Mail
- MAIL_HOST=${MAIL_HOST}
@@ -92,6 +86,22 @@ 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}
- LEMONSQUEEZY_WEBHOOK_SECRET=${LEMONSQUEEZY_WEBHOOK_SECRET}
- HOSTED_ON_BIGCAPITAL_CLOUD=${HOSTED_ON_BIGCAPITAL_CLOUD}
database_migration:
container_name: bigcapital-database-migration
build:
@@ -111,9 +121,7 @@ services:
mysql:
container_name: bigcapital-mysql
deploy:
restart_policy:
condition: unless-stopped
restart: on-failure
build:
context: ./docker/mariadb
environment:
@@ -128,9 +136,7 @@ services:
mongo:
container_name: bigcapital-mongo
deploy:
restart_policy:
condition: unless-stopped
restart: on-failure
build: ./docker/mongo
expose:
- '27017'
@@ -139,9 +145,7 @@ services:
redis:
container_name: bigcapital-redis
deploy:
restart_policy:
condition: unless-stopped
restart: on-failure
build:
context: ./docker/redis
expose:

View File

@@ -2,6 +2,7 @@
"$schema": "node_modules/lerna/schemas/lerna-schema.json",
"version": "independent",
"npmClient": "pnpm",
"useWorkspaces": true,
"packages": ["packages/*"]
}
"packages": [
"packages/*"
]
}

View File

@@ -19,7 +19,8 @@
"@faker-js/faker": "^8.0.2",
"@playwright/test": "^1.32.3",
"husky": "^8.0.3",
"lerna": "^6.4.1"
"lerna": "^8.1.2",
"pnpm": "^9.0.5"
},
"engines": {
"node": "16.x || 17.x || 18.x"

View File

@@ -3,4 +3,6 @@
stdout.log
/dist
/build
/public/imports
/public/imports
dist

File diff suppressed because it is too large Load Diff

View File

@@ -22,6 +22,7 @@
"dependencies": {
"@casl/ability": "^5.4.3",
"@hapi/boom": "^7.4.3",
"@lemonsqueezy/lemonsqueezy.js": "^2.2.0",
"@types/i18n": "^0.8.7",
"@types/knex": "^0.16.1",
"@types/mathjs": "^6.0.12",
@@ -89,17 +90,17 @@
"objection-filter": "^4.0.1",
"objection-soft-delete": "^1.0.7",
"objection-unique": "^1.2.2",
"plaid": "^10.3.0",
"pluralize": "^8.0.0",
"pug": "^3.0.2",
"puppeteer": "^10.2.0",
"plaid": "^10.3.0",
"qim": "0.0.52",
"ramda": "^0.27.1",
"rate-limiter-flexible": "^2.1.14",
"reflect-metadata": "^0.1.13",
"rtl-detect": "^1.0.4",
"source-map-loader": "^4.0.1",
"socket.io": "^4.7.4",
"source-map-loader": "^4.0.1",
"tmp-promise": "^3.0.3",
"ts-transformer-keys": "^0.4.2",
"tsyringe": "^4.3.0",

View File

@@ -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

View File

@@ -1,5 +1,6 @@
import Multer from 'multer';
import { ServiceError } from '@/exceptions';
import { getImportsStoragePath } from '@/services/Import/_utils';
export function allowSheetExtensions(req, file, cb) {
if (
@@ -16,7 +17,8 @@ export function allowSheetExtensions(req, file, cb) {
const storage = Multer.diskStorage({
destination: function (req, file, cb) {
cb(null, './public/imports');
const path = getImportsStoragePath();
cb(null, path);
},
filename: function (req, file, cb) {
// Add the creation timestamp to clean up temp files later.

View File

@@ -180,6 +180,14 @@ module.exports = {
},
},
/**
* Bank Synchronization.
*/
bankSync: {
enabled: parseBoolean(defaultTo(process.env.BANKING_CONNECT, false), false),
provider: 'plaid',
},
/**
* Plaid.
*/

View File

@@ -1,6 +1,7 @@
export enum Features {
WAREHOUSES = 'warehouses',
BRANCHES = 'branches',
BankSyncing = 'BankSyncing'
}
export interface IFeatureAllItem {

View File

@@ -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;
}
/**

View File

@@ -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<void>}
*/
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<IFeatureAllItem[]>}
*/
public async all(tenantId: number): Promise<IFeatureAllItem[]> {
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);
}
}

View File

@@ -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;
}
/**

View File

@@ -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),
}
];

View File

@@ -38,8 +38,6 @@ export class ImportFileUploadService {
filename: string,
params: Record<string, number | string>
): Promise<ImportFileUploadPOJO> {
console.log(filename, 'filename');
try {
return await this.importUnhandled(
tenantId,

View File

@@ -3,6 +3,7 @@ import moment from 'moment';
import * as R from 'ramda';
import { Knex } from 'knex';
import fs from 'fs/promises';
import path from 'path';
import {
defaultTo,
upperFirst,
@@ -353,7 +354,6 @@ export const parseKey = R.curry(
_key = `${fieldKey}`;
}
}
console.log(_key);
return _key;
}
);
@@ -432,13 +432,19 @@ export const sanitizeSheetData = (json) => {
export const getMapToPath = (to: string, group = '') =>
group ? `${group}.${to}` : to;
export const getImportsStoragePath = () => {
return path.join(global.__storage_dir, `/imports`);
}
/**
* Deletes the imported file from the storage and database.
* @param {string} filename
*/
export const deleteImportFile = async (filename: string) => {
const filePath = getImportsStoragePath();
// Deletes the imported file.
await fs.unlink(`public/imports/${filename}`);
await fs.unlink(`${filePath}/${filename}`);
};
/**
@@ -447,5 +453,7 @@ export const deleteImportFile = async (filename: string) => {
* @returns {Promise<Buffer>}
*/
export const readImportFile = (filename: string) => {
return fs.readFile(`public/imports/${filename}`);
const filePath = getImportsStoragePath();
return fs.readFile(`${filePath}/${filename}`);
};

View File

@@ -70,7 +70,7 @@ export class LemonSqueezyWebhooks {
const variantId = attributes.variant_id as string;
// We assume that the Plan table is up to date.
const plan = await Plan.query().findOne('slug', 'essentials-yearly');
const plan = await Plan.query().findOne('slug', 'early-adaptor');
if (!plan) {
throw new Error(`Plan with variantId ${variantId} not found.`);

View File

@@ -1,4 +1,4 @@
import moment, { type unitOfTime } from 'moment';
import moment, { unitOfTime } from 'moment';
export default class SubscriptionPeriod {
private start: Date;

View File

@@ -0,0 +1,7 @@
exports.up = function (knex) {
return knex.seed.run({
specific: 'seed_tenants_free_subscription.js',
});
};
exports.down = function (knex) {};

View File

@@ -194,7 +194,12 @@ export default class Tenant extends BaseModel {
* @param {*} subscriptionSlug
* @returns
*/
public newSubscription(planId, invoiceInterval, invoicePeriod, subscriptionSlug) {
public newSubscription(
planId,
invoiceInterval,
invoicePeriod,
subscriptionSlug
) {
return Tenant.newSubscription(
this.id,
planId,
@@ -202,7 +207,6 @@ export default class Tenant extends BaseModel {
invoicePeriod,
subscriptionSlug
);
);
}
/**

View File

@@ -0,0 +1,26 @@
exports.seed = (knex) => {
// Deletes ALL existing entries
return knex('subscription_plan_subscriptions')
.then(async () => {
const tenants = await knex('tenants');
for (const tenant of tenants) {
const existingSubscription = await knex('subscription_plan_subscriptions')
.where('tenantId', tenant.id)
.first();
if (!existingSubscription) {
const freePlan = await knex('subscription_plans').where('slug', 'free').first();
await knex('subscription_plan_subscriptions').insert({
tenantId: tenant.id,
planId: freePlan.id,
slug: 'main',
startsAt: knex.fn.now(),
endsAt: null,
createdAt: knex.fn.now(),
});
}
}
});
};

View File

@@ -1,3 +1,4 @@
*
!pdf/
!imports/
!.gitignore

View File

@@ -0,0 +1,2 @@
*
!.gitignore

View File

@@ -20,4 +20,5 @@
.env.production.local
npm-debug.log*
yarn-debug.log*
dist

View File

@@ -5,5 +5,6 @@ export const Features = {
Warehouses: 'warehouses',
Branches: 'branches',
ManualJournal: 'manualJournal',
Projects:'Projects'
Projects:'Projects',
BankSyncing: 'BankSyncing',
}

View File

@@ -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({
</NavbarGroup>
<NavbarGroup align={Alignment.RIGHT}>
<Button
className={Classes.MINIMAL}
text={'Connect to Bank / Credit Card'}
onClick={handleConnectToBank}
/>
<FeatureCan feature={Features.BankSyncing}>
<Button
className={Classes.MINIMAL}
text={'Connect to Bank / Credit Card'}
onClick={handleConnectToBank}
/>
<NavbarDivider />
</FeatureCan>
<Button
className={Classes.MINIMAL}
icon={<Icon icon="refresh-16" iconSize={14} />}

2709
pnpm-lock.yaml generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,2 +0,0 @@
packages:
- "packages/*"

24
scripts/backup.sh Normal file
View File

@@ -0,0 +1,24 @@
# Takes a backup of database Docker volume and compress into one .tar.gz
# file and upload to s3 package through s3cmd.
S3_BUCKET="s3://bigcapital-backup"
# Generate the current date and time formatted as YYYY-MM-DD-HH-MM-SS
CURRENT_DATETIME=$(date +"%Y-%m-%d-%H-%M-%S")
# Define the filename with the current date and time
FILE_NAME="bigcapital-mariadb-${CURRENT_DATETIME}.tar.gz"
# Create a sample file (replace this with your actual file creation process)
echo "This is a sample file created on ${CURRENT_DATETIME}" > "$FILE_NAME"
docker run --rm \
--mount source=bigcapital_prod_mysql,target=/data/db \
-v $(pwd):/backup \
busybox \
tar -czvf "/backup/$FILE_NAME" /data/db
# Upload the file to S3 using s3cmd
s3cmd put "$FILE_NAME" "$S3_BUCKET/"
# Remove the temporary file
rm "$FILE_NAME"

7
scripts/store-backup.sh Normal file
View File

@@ -0,0 +1,7 @@
# Store the backup.
docker run --rm \
--mount source=bigcapital_dev_mysql,target=/data/db \
-v $(pwd):/backup \
busybox \
tar -xzvf /backup/bigcapital-mariadb-2024-04-24-15-14-40.tar.gz -C /

22315
yarn.lock

File diff suppressed because it is too large Load Diff