Compare commits

...

11 Commits

Author SHA1 Message Date
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
14 changed files with 84 additions and 30 deletions

View File

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

View File

@@ -25,6 +25,10 @@
<img src="https://img.shields.io/twitter/follow/bigcapitalhq?style=social" alt="twitter" /> <img src="https://img.shields.io/twitter/follow/bigcapitalhq?style=social" alt="twitter" />
</a> </a>
</p> </p>
<p align="center">
<a href="https://app.bigcapital.ly">Bigcapital Cloud</a>
</p>
</p> </p>
# What's Bigcapital? # What's Bigcapital?

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -1,4 +1,4 @@
import moment, { type unitOfTime } from 'moment'; import moment, { unitOfTime } from 'moment';
export default class SubscriptionPeriod { export default class SubscriptionPeriod {
private start: Date; 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 * @param {*} subscriptionSlug
* @returns * @returns
*/ */
public newSubscription(planId, invoiceInterval, invoicePeriod, subscriptionSlug) { public newSubscription(
planId,
invoiceInterval,
invoicePeriod,
subscriptionSlug
) {
return Tenant.newSubscription( return Tenant.newSubscription(
this.id, this.id,
planId, planId,
@@ -202,7 +207,6 @@ export default class Tenant extends BaseModel {
invoicePeriod, invoicePeriod,
subscriptionSlug 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/ !pdf/
!imports/
!.gitignore !.gitignore

View File

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

8
pnpm-lock.yaml generated
View File

@@ -38,6 +38,9 @@ importers:
'@hapi/boom': '@hapi/boom':
specifier: ^7.4.3 specifier: ^7.4.3
version: 7.4.11 version: 7.4.11
'@lemonsqueezy/lemonsqueezy.js':
specifier: ^2.2.0
version: 2.2.0
'@types/i18n': '@types/i18n':
specifier: ^0.8.7 specifier: ^0.8.7
version: 0.8.8 version: 0.8.8
@@ -4623,6 +4626,11 @@ packages:
resolution: {integrity: sha512-Hcv+nVC0kZnQ3tD9GVu5xSMR4VVYOteQIr/hwFPVEvPdlXqgGEuRjiheChHgdM+JyqdgNcmzZOX/tnl0JOiI7A==} resolution: {integrity: sha512-Hcv+nVC0kZnQ3tD9GVu5xSMR4VVYOteQIr/hwFPVEvPdlXqgGEuRjiheChHgdM+JyqdgNcmzZOX/tnl0JOiI7A==}
dev: false dev: false
/@lemonsqueezy/lemonsqueezy.js@2.2.0:
resolution: {integrity: sha512-DsZTeowehSLTESUZ6xxoYPDhoE8BYepWsj3TCqibG7FvB8X1HERPXQlc6E/IeGj22SOfIM997b7GfFkeLWY8pA==}
engines: {node: '>=18'}
dev: false
/@lerna/add@6.4.1: /@lerna/add@6.4.1:
resolution: {integrity: sha512-YSRnMcsdYnQtQQK0NSyrS9YGXvB3jzvx183o+JTH892MKzSlBqwpBHekCknSibyxga1HeZ0SNKQXgsHAwWkrRw==} resolution: {integrity: sha512-YSRnMcsdYnQtQQK0NSyrS9YGXvB3jzvx183o+JTH892MKzSlBqwpBHekCknSibyxga1HeZ0SNKQXgsHAwWkrRw==}
engines: {node: ^14.15.0 || >=16.0.0} engines: {node: ^14.15.0 || >=16.0.0}