mirror of
https://github.com/bigcapitalhq/bigcapital.git
synced 2026-02-21 23:30:32 +00:00
Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
882fc20ac1 |
@@ -132,33 +132,6 @@
|
|||||||
"contributions": [
|
"contributions": [
|
||||||
"bug"
|
"bug"
|
||||||
]
|
]
|
||||||
},
|
|
||||||
{
|
|
||||||
"login": "oleynikd",
|
|
||||||
"name": "Denis",
|
|
||||||
"avatar_url": "https://avatars.githubusercontent.com/u/3976868?v=4",
|
|
||||||
"profile": "https://github.com/oleynikd",
|
|
||||||
"contributions": [
|
|
||||||
"bug"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"login": "mittalsam98",
|
|
||||||
"name": "Sachin Mittal",
|
|
||||||
"avatar_url": "https://avatars.githubusercontent.com/u/42431274?v=4",
|
|
||||||
"profile": "https://myself.vercel.app/",
|
|
||||||
"contributions": [
|
|
||||||
"bug"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"login": "Champetaman",
|
|
||||||
"name": "Camilo Oviedo",
|
|
||||||
"avatar_url": "https://avatars.githubusercontent.com/u/64604272?v=4",
|
|
||||||
"profile": "https://www.camilooviedo.com/",
|
|
||||||
"contributions": [
|
|
||||||
"code"
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"contributorsPerLine": 7,
|
"contributorsPerLine": 7,
|
||||||
|
|||||||
@@ -89,7 +89,3 @@ S3_ACCESS_KEY_ID=
|
|||||||
S3_SECRET_ACCESS_KEY=
|
S3_SECRET_ACCESS_KEY=
|
||||||
S3_ENDPOINT=
|
S3_ENDPOINT=
|
||||||
S3_BUCKET=
|
S3_BUCKET=
|
||||||
|
|
||||||
# PostHog
|
|
||||||
POSTHOG_API_KEY=
|
|
||||||
POSTHOG_HOST=
|
|
||||||
29
CHANGELOG.md
29
CHANGELOG.md
@@ -2,35 +2,6 @@
|
|||||||
|
|
||||||
All notable changes to Bigcapital server-side will be in this file.
|
All notable changes to Bigcapital server-side will be in this file.
|
||||||
|
|
||||||
## [0.19.4] - 18-08-2024
|
|
||||||
|
|
||||||
* fix: Allow multi-lines to statements transactions by @abouolia in https://github.com/bigcapitalhq/bigcapital/pull/594
|
|
||||||
* feat: Add amount comparators to amount bank rule field by @abouolia in https://github.com/bigcapitalhq/bigcapital/pull/595
|
|
||||||
* fix: Transaction type and description do not show in general ledger. by @abouolia in https://github.com/bigcapitalhq/bigcapital/pull/596
|
|
||||||
* fix: Refresh accounts and account transactions. by @abouolia in https://github.com/bigcapitalhq/bigcapital/pull/597
|
|
||||||
* fix: Typo payments made by @abouolia in https://github.com/bigcapitalhq/bigcapital/pull/598
|
|
||||||
* fix: Typo categories list by @abouolia in https://github.com/bigcapitalhq/bigcapital/pull/600
|
|
||||||
* fix: Autofill the quick created customer/vendor by @abouolia in https://github.com/bigcapitalhq/bigcapital/pull/601
|
|
||||||
* fix: Remove views tabs from receipts list by @abouolia in https://github.com/bigcapitalhq/bigcapital/pull/602
|
|
||||||
* fix: Typo payment receive messages by @abouolia in https://github.com/bigcapitalhq/bigcapital/pull/599
|
|
||||||
* fix: Enhance Dropzone visual of accept and reject modes by @Champetaman in https://github.com/bigcapitalhq/bigcapital/pull/603
|
|
||||||
* fix: Matching bank transactions should create associate payment transactions by @abouolia in https://github.com/bigcapitalhq/bigcapital/pull/606
|
|
||||||
* fix: Change Dropzone title and subtitle by @abouolia in https://github.com/bigcapitalhq/bigcapital/pull/607
|
|
||||||
* fix: Inconsistance page size of paginated data tables by @abouolia in https://github.com/bigcapitalhq/bigcapital/pull/604
|
|
||||||
* fix: Database connection lost error by @abouolia in https://github.com/bigcapitalhq/bigcapital/pull/611
|
|
||||||
* fix: Language typos by @abouolia in https://github.com/bigcapitalhq/bigcapital/pull/613
|
|
||||||
* Fix: Correctly display Date, Published At, and Created At in ExpenseDrawerHeader by @Champetaman in https://github.com/bigcapitalhq/bigcapital/pull/612
|
|
||||||
* fix: Delete bank account with uncategorized transactions by @abouolia in https://github.com/bigcapitalhq/bigcapital/pull/614
|
|
||||||
* feat: activate/inactivate account from drawer details by @abouolia in https://github.com/bigcapitalhq/bigcapital/pull/615
|
|
||||||
|
|
||||||
## [v0.18.0] - 10-08-2024
|
|
||||||
|
|
||||||
* feat: Bank rules for automated categorization by @abouolia in https://github.com/bigcapitalhq/bigcapital/pull/511
|
|
||||||
* feat: Categorize & match bank transaction by @abouolia in https://github.com/bigcapitalhq/bigcapital/pull/511
|
|
||||||
* feat: Reconcile match transactions by @abouolia in https://github.com/bigcapitalhq/bigcapital/pull/522
|
|
||||||
* fix: Issues in matching transactions by @abouolia in https://github.com/bigcapitalhq/bigcapital/pull/523
|
|
||||||
* fix: Cashflow transactions types by @abouolia in https://github.com/bigcapitalhq/bigcapital/pull/524
|
|
||||||
|
|
||||||
## [v0.17.5] - 17-06-2024
|
## [v0.17.5] - 17-06-2024
|
||||||
|
|
||||||
* fix: Balance sheet and P/L nested accounts by @abouolia in https://github.com/bigcapitalhq/bigcapital/pull/501
|
* fix: Balance sheet and P/L nested accounts by @abouolia in https://github.com/bigcapitalhq/bigcapital/pull/501
|
||||||
|
|||||||
@@ -126,11 +126,6 @@ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/d
|
|||||||
<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>
|
<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>
|
||||||
<td align="center" valign="top" width="14.28%"><a href="http://www.pivoten.com"><img src="https://avatars.githubusercontent.com/u/104120598?v=4?s=100" width="100px;" alt="Chris Cantrell"/><br /><sub><b>Chris Cantrell</b></sub></a><br /><a href="https://github.com/bigcapitalhq/bigcapital/issues?q=author%3Accantrell72" title="Bug reports">🐛</a></td>
|
<td align="center" valign="top" width="14.28%"><a href="http://www.pivoten.com"><img src="https://avatars.githubusercontent.com/u/104120598?v=4?s=100" width="100px;" alt="Chris Cantrell"/><br /><sub><b>Chris Cantrell</b></sub></a><br /><a href="https://github.com/bigcapitalhq/bigcapital/issues?q=author%3Accantrell72" title="Bug reports">🐛</a></td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/oleynikd"><img src="https://avatars.githubusercontent.com/u/3976868?v=4?s=100" width="100px;" alt="Denis"/><br /><sub><b>Denis</b></sub></a><br /><a href="https://github.com/bigcapitalhq/bigcapital/issues?q=author%3Aoleynikd" title="Bug reports">🐛</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://myself.vercel.app/"><img src="https://avatars.githubusercontent.com/u/42431274?v=4?s=100" width="100px;" alt="Sachin Mittal"/><br /><sub><b>Sachin Mittal</b></sub></a><br /><a href="https://github.com/bigcapitalhq/bigcapital/issues?q=author%3Amittalsam98" title="Bug reports">🐛</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://www.camilooviedo.com/"><img src="https://avatars.githubusercontent.com/u/64604272?v=4?s=100" width="100px;" alt="Camilo Oviedo"/><br /><sub><b>Camilo Oviedo</b></sub></a><br /><a href="https://github.com/bigcapitalhq/bigcapital/commits?author=Champetaman" title="Code">💻</a></td>
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
|
|
||||||
|
|||||||
@@ -37,7 +37,6 @@
|
|||||||
"agendash": "^3.1.0",
|
"agendash": "^3.1.0",
|
||||||
"app-root-path": "^3.0.0",
|
"app-root-path": "^3.0.0",
|
||||||
"async": "^3.2.0",
|
"async": "^3.2.0",
|
||||||
"async-mutex": "^0.5.0",
|
|
||||||
"axios": "^1.6.0",
|
"axios": "^1.6.0",
|
||||||
"babel-loader": "^9.1.2",
|
"babel-loader": "^9.1.2",
|
||||||
"bcryptjs": "^2.4.3",
|
"bcryptjs": "^2.4.3",
|
||||||
@@ -70,8 +69,9 @@
|
|||||||
"is-my-json-valid": "^2.20.5",
|
"is-my-json-valid": "^2.20.5",
|
||||||
"js-money": "^0.6.3",
|
"js-money": "^0.6.3",
|
||||||
"jsonwebtoken": "^8.5.1",
|
"jsonwebtoken": "^8.5.1",
|
||||||
"knex": "^3.1.0",
|
"knex": "^0.95.15",
|
||||||
"knex-cleaner": "^1.3.0",
|
"knex-cleaner": "^1.3.0",
|
||||||
|
"knex-db-manager": "^0.6.1",
|
||||||
"libphonenumber-js": "^1.9.6",
|
"libphonenumber-js": "^1.9.6",
|
||||||
"lodash": "^4.17.15",
|
"lodash": "^4.17.15",
|
||||||
"lru-cache": "^6.0.0",
|
"lru-cache": "^6.0.0",
|
||||||
@@ -99,7 +99,6 @@
|
|||||||
"objection-unique": "^1.2.2",
|
"objection-unique": "^1.2.2",
|
||||||
"plaid": "^10.3.0",
|
"plaid": "^10.3.0",
|
||||||
"pluralize": "^8.0.0",
|
"pluralize": "^8.0.0",
|
||||||
"posthog-node": "^4.2.0",
|
|
||||||
"pug": "^3.0.2",
|
"pug": "^3.0.2",
|
||||||
"puppeteer": "^10.2.0",
|
"puppeteer": "^10.2.0",
|
||||||
"qim": "0.0.52",
|
"qim": "0.0.52",
|
||||||
|
|||||||
@@ -103,20 +103,24 @@ export default class AccountsController extends BaseController {
|
|||||||
check('name')
|
check('name')
|
||||||
.exists()
|
.exists()
|
||||||
.isLength({ min: 3, max: DATATYPES_LENGTH.STRING })
|
.isLength({ min: 3, max: DATATYPES_LENGTH.STRING })
|
||||||
.trim(),
|
.trim()
|
||||||
|
.escape(),
|
||||||
check('code')
|
check('code')
|
||||||
.optional({ nullable: true })
|
.optional({ nullable: true })
|
||||||
.isLength({ min: 3, max: 6 })
|
.isLength({ min: 3, max: 6 })
|
||||||
.trim(),
|
.trim()
|
||||||
|
.escape(),
|
||||||
check('currency_code').optional(),
|
check('currency_code').optional(),
|
||||||
check('account_type')
|
check('account_type')
|
||||||
.exists()
|
.exists()
|
||||||
.isLength({ min: 3, max: DATATYPES_LENGTH.STRING })
|
.isLength({ min: 3, max: DATATYPES_LENGTH.STRING })
|
||||||
.trim(),
|
.trim()
|
||||||
|
.escape(),
|
||||||
check('description')
|
check('description')
|
||||||
.optional({ nullable: true })
|
.optional({ nullable: true })
|
||||||
.isLength({ max: DATATYPES_LENGTH.TEXT })
|
.isLength({ max: DATATYPES_LENGTH.TEXT })
|
||||||
.trim(),
|
.trim()
|
||||||
|
.escape(),
|
||||||
check('parent_account_id')
|
check('parent_account_id')
|
||||||
.optional({ nullable: true })
|
.optional({ nullable: true })
|
||||||
.isInt({ min: 0, max: DATATYPES_LENGTH.INT_10 })
|
.isInt({ min: 0, max: DATATYPES_LENGTH.INT_10 })
|
||||||
@@ -132,19 +136,23 @@ export default class AccountsController extends BaseController {
|
|||||||
check('name')
|
check('name')
|
||||||
.exists()
|
.exists()
|
||||||
.isLength({ min: 3, max: DATATYPES_LENGTH.STRING })
|
.isLength({ min: 3, max: DATATYPES_LENGTH.STRING })
|
||||||
.trim(),
|
.trim()
|
||||||
|
.escape(),
|
||||||
check('code')
|
check('code')
|
||||||
.optional({ nullable: true })
|
.optional({ nullable: true })
|
||||||
.isLength({ min: 3, max: 6 })
|
.isLength({ min: 3, max: 6 })
|
||||||
.trim(),
|
.trim()
|
||||||
|
.escape(),
|
||||||
check('account_type')
|
check('account_type')
|
||||||
.exists()
|
.exists()
|
||||||
.isLength({ min: 3, max: DATATYPES_LENGTH.STRING })
|
.isLength({ min: 3, max: DATATYPES_LENGTH.STRING })
|
||||||
.trim(),
|
.trim()
|
||||||
|
.escape(),
|
||||||
check('description')
|
check('description')
|
||||||
.optional({ nullable: true })
|
.optional({ nullable: true })
|
||||||
.isLength({ max: DATATYPES_LENGTH.TEXT })
|
.isLength({ max: DATATYPES_LENGTH.TEXT })
|
||||||
.trim(),
|
.trim()
|
||||||
|
.escape(),
|
||||||
check('parent_account_id')
|
check('parent_account_id')
|
||||||
.optional({ nullable: true })
|
.optional({ nullable: true })
|
||||||
.isInt({ min: 0, max: DATATYPES_LENGTH.INT_10 })
|
.isInt({ min: 0, max: DATATYPES_LENGTH.INT_10 })
|
||||||
|
|||||||
@@ -250,12 +250,10 @@ export class AttachmentsController extends BaseController {
|
|||||||
res: Response,
|
res: Response,
|
||||||
next: NextFunction
|
next: NextFunction
|
||||||
): Promise<Response | void> {
|
): Promise<Response | void> {
|
||||||
const { tenantId } = req;
|
|
||||||
const { id: documentKey } = req.params;
|
const { id: documentKey } = req.params;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const presignedUrl = await this.attachmentsApplication.getPresignedUrl(
|
const presignedUrl = await this.attachmentsApplication.getPresignedUrl(
|
||||||
tenantId,
|
|
||||||
documentKey
|
documentKey
|
||||||
);
|
);
|
||||||
return res.status(200).send({ presignedUrl });
|
return res.status(200).send({ presignedUrl });
|
||||||
|
|||||||
@@ -90,23 +90,27 @@ export default class AuthenticationController extends BaseController {
|
|||||||
.exists()
|
.exists()
|
||||||
.isString()
|
.isString()
|
||||||
.trim()
|
.trim()
|
||||||
|
.escape()
|
||||||
.isLength({ max: DATATYPES_LENGTH.STRING }),
|
.isLength({ max: DATATYPES_LENGTH.STRING }),
|
||||||
check('last_name')
|
check('last_name')
|
||||||
.exists()
|
.exists()
|
||||||
.isString()
|
.isString()
|
||||||
.trim()
|
.trim()
|
||||||
|
.escape()
|
||||||
.isLength({ max: DATATYPES_LENGTH.STRING }),
|
.isLength({ max: DATATYPES_LENGTH.STRING }),
|
||||||
check('email')
|
check('email')
|
||||||
.exists()
|
.exists()
|
||||||
.isString()
|
.isString()
|
||||||
.isEmail()
|
.isEmail()
|
||||||
.trim()
|
.trim()
|
||||||
|
.escape()
|
||||||
.isLength({ max: DATATYPES_LENGTH.STRING }),
|
.isLength({ max: DATATYPES_LENGTH.STRING }),
|
||||||
check('password')
|
check('password')
|
||||||
.exists()
|
.exists()
|
||||||
.isString()
|
.isString()
|
||||||
.isLength({ min: 6 })
|
.isLength({ min: 6 })
|
||||||
.trim()
|
.trim()
|
||||||
|
.escape()
|
||||||
.isLength({ max: DATATYPES_LENGTH.STRING }),
|
.isLength({ max: DATATYPES_LENGTH.STRING }),
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
@@ -146,7 +150,7 @@ export default class AuthenticationController extends BaseController {
|
|||||||
* @returns {ValidationChain[]}
|
* @returns {ValidationChain[]}
|
||||||
*/
|
*/
|
||||||
private get sendResetPasswordSchema(): ValidationChain[] {
|
private get sendResetPasswordSchema(): ValidationChain[] {
|
||||||
return [check('email').exists().isEmail().trim()];
|
return [check('email').exists().isEmail().trim().escape()];
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -154,11 +158,7 @@ export default class AuthenticationController extends BaseController {
|
|||||||
* @param {Request} req
|
* @param {Request} req
|
||||||
* @param {Response} res
|
* @param {Response} res
|
||||||
*/
|
*/
|
||||||
private async login(
|
private async login(req: Request, res: Response, next: Function): Response {
|
||||||
req: Request,
|
|
||||||
res: Response,
|
|
||||||
next: Function
|
|
||||||
): Promise<Response | null> {
|
|
||||||
const userDTO: ILoginDTO = this.matchedBodyData(req);
|
const userDTO: ILoginDTO = this.matchedBodyData(req);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|||||||
@@ -1,218 +0,0 @@
|
|||||||
import { Inject, Service } from 'typedi';
|
|
||||||
import { NextFunction, Request, Response, Router } from 'express';
|
|
||||||
import { param, query } from 'express-validator';
|
|
||||||
import BaseController from '@/api/controllers/BaseController';
|
|
||||||
import { GetBankAccountSummary } from '@/services/Banking/BankAccounts/GetBankAccountSummary';
|
|
||||||
import { BankAccountsApplication } from '@/services/Banking/BankAccounts/BankAccountsApplication';
|
|
||||||
import { GetPendingBankAccountTransactions } from '@/services/Cashflow/GetPendingBankAccountTransaction';
|
|
||||||
|
|
||||||
@Service()
|
|
||||||
export class BankAccountsController extends BaseController {
|
|
||||||
@Inject()
|
|
||||||
private getBankAccountSummaryService: GetBankAccountSummary;
|
|
||||||
|
|
||||||
@Inject()
|
|
||||||
private bankAccountsApp: BankAccountsApplication;
|
|
||||||
|
|
||||||
@Inject()
|
|
||||||
private getPendingTransactionsService: GetPendingBankAccountTransactions;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Router constructor.
|
|
||||||
*/
|
|
||||||
router() {
|
|
||||||
const router = Router();
|
|
||||||
|
|
||||||
router.get('/:bankAccountId/meta', this.getBankAccountSummary.bind(this));
|
|
||||||
router.get(
|
|
||||||
'/pending_transactions',
|
|
||||||
[
|
|
||||||
query('account_id').optional().isNumeric().toInt(),
|
|
||||||
query('page').optional().isNumeric().toInt(),
|
|
||||||
query('page_size').optional().isNumeric().toInt(),
|
|
||||||
],
|
|
||||||
this.validationResult,
|
|
||||||
this.getBankAccountsPendingTransactions.bind(this)
|
|
||||||
);
|
|
||||||
router.post(
|
|
||||||
'/:bankAccountId/disconnect',
|
|
||||||
this.disconnectBankAccount.bind(this)
|
|
||||||
);
|
|
||||||
router.post('/:bankAccountId/update', this.refreshBankAccount.bind(this));
|
|
||||||
router.post(
|
|
||||||
'/:bankAccountId/pause_feeds',
|
|
||||||
[param('bankAccountId').exists().isNumeric().toInt()],
|
|
||||||
this.validationResult,
|
|
||||||
this.pauseBankAccountFeeds.bind(this)
|
|
||||||
);
|
|
||||||
router.post(
|
|
||||||
'/:bankAccountId/resume_feeds',
|
|
||||||
[param('bankAccountId').exists().isNumeric().toInt()],
|
|
||||||
this.validationResult,
|
|
||||||
this.resumeBankAccountFeeds.bind(this)
|
|
||||||
);
|
|
||||||
|
|
||||||
return router;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Retrieves the bank account meta summary.
|
|
||||||
* @param {Request} req
|
|
||||||
* @param {Response} res
|
|
||||||
* @param {NextFunction} next
|
|
||||||
* @returns {Promise<Response|null>}
|
|
||||||
*/
|
|
||||||
async getBankAccountSummary(
|
|
||||||
req: Request<{ bankAccountId: number }>,
|
|
||||||
res: Response,
|
|
||||||
next: NextFunction
|
|
||||||
) {
|
|
||||||
const { bankAccountId } = req.params;
|
|
||||||
const { tenantId } = req;
|
|
||||||
|
|
||||||
try {
|
|
||||||
const data =
|
|
||||||
await this.getBankAccountSummaryService.getBankAccountSummary(
|
|
||||||
tenantId,
|
|
||||||
bankAccountId
|
|
||||||
);
|
|
||||||
return res.status(200).send({ data });
|
|
||||||
} catch (error) {
|
|
||||||
next(error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Retrieves the bank account pending transactions.
|
|
||||||
* @param {Request} req
|
|
||||||
* @param {Response} res
|
|
||||||
* @param {NextFunction} next
|
|
||||||
*/
|
|
||||||
async getBankAccountsPendingTransactions(
|
|
||||||
req: Request,
|
|
||||||
res: Response,
|
|
||||||
next: NextFunction
|
|
||||||
) {
|
|
||||||
const { tenantId } = req;
|
|
||||||
const query = this.matchedQueryData(req);
|
|
||||||
|
|
||||||
try {
|
|
||||||
const data =
|
|
||||||
await this.getPendingTransactionsService.getPendingTransactions(
|
|
||||||
tenantId,
|
|
||||||
query
|
|
||||||
);
|
|
||||||
return res.status(200).send(data);
|
|
||||||
} catch (error) {
|
|
||||||
next(error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Disonnect the given bank account.
|
|
||||||
* @param {Request} req
|
|
||||||
* @param {Response} res
|
|
||||||
* @param {NextFunction} next
|
|
||||||
* @returns {Promise<Response|null>}
|
|
||||||
*/
|
|
||||||
async disconnectBankAccount(
|
|
||||||
req: Request<{ bankAccountId: number }>,
|
|
||||||
res: Response,
|
|
||||||
next: NextFunction
|
|
||||||
) {
|
|
||||||
const { bankAccountId } = req.params;
|
|
||||||
const { tenantId } = req;
|
|
||||||
|
|
||||||
try {
|
|
||||||
await this.bankAccountsApp.disconnectBankAccount(tenantId, bankAccountId);
|
|
||||||
|
|
||||||
return res.status(200).send({
|
|
||||||
id: bankAccountId,
|
|
||||||
message: 'The bank account has been disconnected.',
|
|
||||||
});
|
|
||||||
} catch (error) {
|
|
||||||
next(error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Refresh the given bank account.
|
|
||||||
* @param {Request} req
|
|
||||||
* @param {Response} res
|
|
||||||
* @param {NextFunction} next
|
|
||||||
* @returns {Promise<Response|null>}
|
|
||||||
*/
|
|
||||||
async refreshBankAccount(
|
|
||||||
req: Request<{ bankAccountId: number }>,
|
|
||||||
res: Response,
|
|
||||||
next: NextFunction
|
|
||||||
) {
|
|
||||||
const { bankAccountId } = req.params;
|
|
||||||
const { tenantId } = req;
|
|
||||||
|
|
||||||
try {
|
|
||||||
await this.bankAccountsApp.refreshBankAccount(tenantId, bankAccountId);
|
|
||||||
|
|
||||||
return res.status(200).send({
|
|
||||||
id: bankAccountId,
|
|
||||||
message: 'The bank account has been disconnected.',
|
|
||||||
});
|
|
||||||
} catch (error) {
|
|
||||||
next(error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Resumes the bank account feeds sync.
|
|
||||||
* @param {Request} req
|
|
||||||
* @param {Response} res
|
|
||||||
* @param {NextFunction} next
|
|
||||||
* @returns {Promise<Response | void>}
|
|
||||||
*/
|
|
||||||
async resumeBankAccountFeeds(
|
|
||||||
req: Request<{ bankAccountId: number }>,
|
|
||||||
res: Response,
|
|
||||||
next: NextFunction
|
|
||||||
) {
|
|
||||||
const { bankAccountId } = req.params;
|
|
||||||
const { tenantId } = req;
|
|
||||||
|
|
||||||
try {
|
|
||||||
await this.bankAccountsApp.resumeBankAccount(tenantId, bankAccountId);
|
|
||||||
|
|
||||||
return res.status(200).send({
|
|
||||||
message: 'The bank account feeds syncing has been resumed.',
|
|
||||||
id: bankAccountId,
|
|
||||||
});
|
|
||||||
} catch (error) {
|
|
||||||
next(error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Pauses the bank account feeds sync.
|
|
||||||
* @param {Request} req
|
|
||||||
* @param {Response} res
|
|
||||||
* @param {NextFunction} next
|
|
||||||
* @returns {Promise<Response | void>}
|
|
||||||
*/
|
|
||||||
async pauseBankAccountFeeds(
|
|
||||||
req: Request<{ bankAccountId: number }>,
|
|
||||||
res: Response,
|
|
||||||
next: NextFunction
|
|
||||||
) {
|
|
||||||
const { bankAccountId } = req.params;
|
|
||||||
const { tenantId } = req;
|
|
||||||
|
|
||||||
try {
|
|
||||||
await this.bankAccountsApp.pauseBankAccount(tenantId, bankAccountId);
|
|
||||||
|
|
||||||
return res.status(200).send({
|
|
||||||
message: 'The bank account feeds syncing has been paused.',
|
|
||||||
id: bankAccountId,
|
|
||||||
});
|
|
||||||
} catch (error) {
|
|
||||||
next(error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,101 +0,0 @@
|
|||||||
import { Inject, Service } from 'typedi';
|
|
||||||
import { body, param } from 'express-validator';
|
|
||||||
import { NextFunction, Request, Response, Router } from 'express';
|
|
||||||
import BaseController from '@/api/controllers/BaseController';
|
|
||||||
import { MatchBankTransactionsApplication } from '@/services/Banking/Matching/MatchBankTransactionsApplication';
|
|
||||||
|
|
||||||
@Service()
|
|
||||||
export class BankTransactionsMatchingController extends BaseController {
|
|
||||||
@Inject()
|
|
||||||
private bankTransactionsMatchingApp: MatchBankTransactionsApplication;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Router constructor.
|
|
||||||
*/
|
|
||||||
public router() {
|
|
||||||
const router = Router();
|
|
||||||
|
|
||||||
router.post(
|
|
||||||
'/unmatch/:transactionId',
|
|
||||||
[param('transactionId').exists()],
|
|
||||||
this.validationResult,
|
|
||||||
this.unmatchMatchedBankTransaction.bind(this)
|
|
||||||
);
|
|
||||||
router.post(
|
|
||||||
'/match',
|
|
||||||
[
|
|
||||||
body('uncategorizedTransactions').exists().isArray({ min: 1 }),
|
|
||||||
body('uncategorizedTransactions.*').isNumeric().toInt(),
|
|
||||||
|
|
||||||
body('matchedTransactions').isArray({ min: 1 }),
|
|
||||||
body('matchedTransactions.*.reference_type').exists(),
|
|
||||||
body('matchedTransactions.*.reference_id').isNumeric().toInt(),
|
|
||||||
],
|
|
||||||
this.validationResult,
|
|
||||||
this.matchBankTransaction.bind(this)
|
|
||||||
);
|
|
||||||
return router;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Matches the given bank transaction.
|
|
||||||
* @param {Request} req
|
|
||||||
* @param {Response} res
|
|
||||||
* @param {NextFunction} next
|
|
||||||
* @returns {Promise<Response|null>}
|
|
||||||
*/
|
|
||||||
private async matchBankTransaction(
|
|
||||||
req: Request<{ transactionId: number }>,
|
|
||||||
res: Response,
|
|
||||||
next: NextFunction
|
|
||||||
): Promise<Response | null> {
|
|
||||||
const { tenantId } = req;
|
|
||||||
const bodyData = this.matchedBodyData(req);
|
|
||||||
|
|
||||||
const uncategorizedTransactions = bodyData?.uncategorizedTransactions;
|
|
||||||
const matchedTransactions = bodyData?.matchedTransactions;
|
|
||||||
|
|
||||||
try {
|
|
||||||
await this.bankTransactionsMatchingApp.matchTransaction(
|
|
||||||
tenantId,
|
|
||||||
uncategorizedTransactions,
|
|
||||||
matchedTransactions
|
|
||||||
);
|
|
||||||
return res.status(200).send({
|
|
||||||
ids: uncategorizedTransactions,
|
|
||||||
message: 'The bank transaction has been matched.',
|
|
||||||
});
|
|
||||||
} catch (error) {
|
|
||||||
next(error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Unmatches the matched bank transaction.
|
|
||||||
* @param {Request} req
|
|
||||||
* @param {Response} res
|
|
||||||
* @param {NextFunction} next
|
|
||||||
* @returns {Promise<Response|null>}
|
|
||||||
*/
|
|
||||||
private async unmatchMatchedBankTransaction(
|
|
||||||
req: Request<{ transactionId: number }>,
|
|
||||||
res: Response,
|
|
||||||
next: NextFunction
|
|
||||||
) {
|
|
||||||
const { tenantId } = req;
|
|
||||||
const { transactionId } = req.params;
|
|
||||||
|
|
||||||
try {
|
|
||||||
await this.bankTransactionsMatchingApp.unmatchMatchedTransaction(
|
|
||||||
tenantId,
|
|
||||||
transactionId
|
|
||||||
);
|
|
||||||
return res.status(200).send({
|
|
||||||
id: transactionId,
|
|
||||||
message: 'The bank matched transaction has been unmatched.',
|
|
||||||
});
|
|
||||||
} catch (error) {
|
|
||||||
next(error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -2,38 +2,17 @@ import Container, { Inject, Service } from 'typedi';
|
|||||||
import { Router } from 'express';
|
import { Router } from 'express';
|
||||||
import BaseController from '@/api/controllers/BaseController';
|
import BaseController from '@/api/controllers/BaseController';
|
||||||
import { PlaidBankingController } from './PlaidBankingController';
|
import { PlaidBankingController } from './PlaidBankingController';
|
||||||
import { BankingRulesController } from './BankingRulesController';
|
|
||||||
import { BankTransactionsMatchingController } from './BankTransactionsMatchingController';
|
|
||||||
import { RecognizedTransactionsController } from './RecognizedTransactionsController';
|
|
||||||
import { BankAccountsController } from './BankAccountsController';
|
|
||||||
import { BankingUncategorizedController } from './BankingUncategorizedController';
|
|
||||||
|
|
||||||
@Service()
|
@Service()
|
||||||
export class BankingController extends BaseController {
|
export class BankingController extends BaseController {
|
||||||
/**
|
/**
|
||||||
* Router constructor.
|
* Router constructor.
|
||||||
*/
|
*/
|
||||||
public router() {
|
router() {
|
||||||
const router = Router();
|
const router = Router();
|
||||||
|
|
||||||
router.use('/plaid', Container.get(PlaidBankingController).router());
|
router.use('/plaid', Container.get(PlaidBankingController).router());
|
||||||
router.use('/rules', Container.get(BankingRulesController).router());
|
|
||||||
router.use(
|
|
||||||
'/matches',
|
|
||||||
Container.get(BankTransactionsMatchingController).router()
|
|
||||||
);
|
|
||||||
router.use(
|
|
||||||
'/recognized',
|
|
||||||
Container.get(RecognizedTransactionsController).router()
|
|
||||||
);
|
|
||||||
router.use(
|
|
||||||
'/bank_accounts',
|
|
||||||
Container.get(BankAccountsController).router()
|
|
||||||
);
|
|
||||||
router.use(
|
|
||||||
'/categorize',
|
|
||||||
Container.get(BankingUncategorizedController).router()
|
|
||||||
);
|
|
||||||
return router;
|
return router;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,214 +0,0 @@
|
|||||||
import { Inject, Service } from 'typedi';
|
|
||||||
import { NextFunction, Request, Response, Router } from 'express';
|
|
||||||
import BaseController from '@/api/controllers/BaseController';
|
|
||||||
import { BankRulesApplication } from '@/services/Banking/Rules/BankRulesApplication';
|
|
||||||
import { body, param } from 'express-validator';
|
|
||||||
import {
|
|
||||||
ICreateBankRuleDTO,
|
|
||||||
IEditBankRuleDTO,
|
|
||||||
} from '@/services/Banking/Rules/types';
|
|
||||||
|
|
||||||
@Service()
|
|
||||||
export class BankingRulesController extends BaseController {
|
|
||||||
@Inject()
|
|
||||||
private bankRulesApplication: BankRulesApplication;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Bank rule DTO validation schema.
|
|
||||||
*/
|
|
||||||
private get bankRuleValidationSchema() {
|
|
||||||
return [
|
|
||||||
body('name').isString().exists(),
|
|
||||||
body('order').isInt({ min: 0 }),
|
|
||||||
|
|
||||||
// Apply to if transaction is.
|
|
||||||
body('apply_if_account_id')
|
|
||||||
.isInt({ min: 0 })
|
|
||||||
.optional({ nullable: true }),
|
|
||||||
body('apply_if_transaction_type').isIn(['deposit', 'withdrawal']),
|
|
||||||
|
|
||||||
// Conditions
|
|
||||||
body('conditions_type').isString().isIn(['and', 'or']).default('and'),
|
|
||||||
body('conditions').isArray({ min: 1 }),
|
|
||||||
body('conditions.*.field').exists().isIn(['description', 'amount']),
|
|
||||||
body('conditions.*.comparator')
|
|
||||||
.exists()
|
|
||||||
.isIn([
|
|
||||||
'equals',
|
|
||||||
'equal',
|
|
||||||
'contains',
|
|
||||||
'not_contain',
|
|
||||||
'bigger',
|
|
||||||
'bigger_or_equal',
|
|
||||||
'smaller',
|
|
||||||
'smaller_or_equal',
|
|
||||||
])
|
|
||||||
.default('contain')
|
|
||||||
.trim(),
|
|
||||||
body('conditions.*.value').exists().trim(),
|
|
||||||
|
|
||||||
// Assign
|
|
||||||
body('assign_category').isString(),
|
|
||||||
body('assign_account_id').isInt({ min: 0 }),
|
|
||||||
body('assign_payee').isString().optional({ nullable: true }),
|
|
||||||
body('assign_memo').isString().optional({ nullable: true }),
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Router constructor.
|
|
||||||
*/
|
|
||||||
public router() {
|
|
||||||
const router = Router();
|
|
||||||
|
|
||||||
router.post(
|
|
||||||
'/',
|
|
||||||
[...this.bankRuleValidationSchema],
|
|
||||||
this.validationResult,
|
|
||||||
this.createBankRule.bind(this)
|
|
||||||
);
|
|
||||||
router.post(
|
|
||||||
'/:id',
|
|
||||||
[param('id').toInt().exists(), ...this.bankRuleValidationSchema],
|
|
||||||
this.validationResult,
|
|
||||||
this.editBankRule.bind(this)
|
|
||||||
);
|
|
||||||
router.delete(
|
|
||||||
'/:id',
|
|
||||||
[param('id').toInt().exists()],
|
|
||||||
this.validationResult,
|
|
||||||
this.deleteBankRule.bind(this)
|
|
||||||
);
|
|
||||||
router.get(
|
|
||||||
'/:id',
|
|
||||||
[param('id').toInt().exists()],
|
|
||||||
this.validationResult,
|
|
||||||
this.getBankRule.bind(this)
|
|
||||||
);
|
|
||||||
router.get(
|
|
||||||
'/',
|
|
||||||
[param('id').toInt().exists()],
|
|
||||||
this.validationResult,
|
|
||||||
this.getBankRules.bind(this)
|
|
||||||
);
|
|
||||||
return router;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a new bank rule.
|
|
||||||
* @param {Request} req
|
|
||||||
* @param {Response} res
|
|
||||||
* @param {NextFunction} next
|
|
||||||
*/
|
|
||||||
private async createBankRule(
|
|
||||||
req: Request,
|
|
||||||
res: Response,
|
|
||||||
next: NextFunction
|
|
||||||
) {
|
|
||||||
const { tenantId } = req;
|
|
||||||
const createBankRuleDTO = this.matchedBodyData(req) as ICreateBankRuleDTO;
|
|
||||||
|
|
||||||
try {
|
|
||||||
const bankRule = await this.bankRulesApplication.createBankRule(
|
|
||||||
tenantId,
|
|
||||||
createBankRuleDTO
|
|
||||||
);
|
|
||||||
return res.status(200).send({
|
|
||||||
id: bankRule.id,
|
|
||||||
message: 'The bank rule has been created successfully.',
|
|
||||||
});
|
|
||||||
} catch (error) {
|
|
||||||
next(error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Edits the given bank rule.
|
|
||||||
* @param {Request} req
|
|
||||||
* @param {Response} res
|
|
||||||
* @param {NextFunction} next
|
|
||||||
*/
|
|
||||||
private async editBankRule(req: Request, res: Response, next: NextFunction) {
|
|
||||||
const { tenantId } = req;
|
|
||||||
const { id: ruleId } = req.params;
|
|
||||||
const editBankRuleDTO = this.matchedBodyData(req) as IEditBankRuleDTO;
|
|
||||||
|
|
||||||
try {
|
|
||||||
await this.bankRulesApplication.editBankRule(
|
|
||||||
tenantId,
|
|
||||||
ruleId,
|
|
||||||
editBankRuleDTO
|
|
||||||
);
|
|
||||||
return res.status(200).send({
|
|
||||||
id: ruleId,
|
|
||||||
message: 'The bank rule has been updated successfully.',
|
|
||||||
});
|
|
||||||
} catch (error) {
|
|
||||||
next(error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Deletes the given bank rule.
|
|
||||||
* @param {Request} req
|
|
||||||
* @param {Response} res
|
|
||||||
* @param {NextFunction} next
|
|
||||||
*/
|
|
||||||
private async deleteBankRule(
|
|
||||||
req: Request<{ id: number }>,
|
|
||||||
res: Response,
|
|
||||||
next: NextFunction
|
|
||||||
) {
|
|
||||||
const { id: ruleId } = req.params;
|
|
||||||
const { tenantId } = req;
|
|
||||||
|
|
||||||
try {
|
|
||||||
await this.bankRulesApplication.deleteBankRule(tenantId, ruleId);
|
|
||||||
|
|
||||||
return res
|
|
||||||
.status(200)
|
|
||||||
.send({ message: 'The bank rule has been deleted.', id: ruleId });
|
|
||||||
} catch (error) {
|
|
||||||
next(error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Retrieve the given bank rule.
|
|
||||||
* @param {Request} req
|
|
||||||
* @param {Response} res
|
|
||||||
* @param {NextFunction} next
|
|
||||||
*/
|
|
||||||
private async getBankRule(req: Request, res: Response, next: NextFunction) {
|
|
||||||
const { id: ruleId } = req.params;
|
|
||||||
const { tenantId } = req;
|
|
||||||
|
|
||||||
try {
|
|
||||||
const bankRule = await this.bankRulesApplication.getBankRule(
|
|
||||||
tenantId,
|
|
||||||
ruleId
|
|
||||||
);
|
|
||||||
|
|
||||||
return res.status(200).send({ bankRule });
|
|
||||||
} catch (error) {
|
|
||||||
next(error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Retrieves the bank rules.
|
|
||||||
* @param {Request} req
|
|
||||||
* @param {Response} res
|
|
||||||
* @param {NextFunction} next
|
|
||||||
*/
|
|
||||||
private async getBankRules(req: Request, res: Response, next: NextFunction) {
|
|
||||||
const { tenantId } = req;
|
|
||||||
|
|
||||||
try {
|
|
||||||
const bankRules = await this.bankRulesApplication.getBankRules(tenantId);
|
|
||||||
return res.status(200).send({ bankRules });
|
|
||||||
} catch (error) {
|
|
||||||
next(error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,57 +0,0 @@
|
|||||||
import { Inject, Service } from 'typedi';
|
|
||||||
import { NextFunction, Request, Response, Router } from 'express';
|
|
||||||
import { query } from 'express-validator';
|
|
||||||
import BaseController from '../BaseController';
|
|
||||||
import { GetAutofillCategorizeTransaction } from '@/services/Banking/RegonizeTranasctions/GetAutofillCategorizeTransaction';
|
|
||||||
|
|
||||||
@Service()
|
|
||||||
export class BankingUncategorizedController extends BaseController {
|
|
||||||
@Inject()
|
|
||||||
private getAutofillCategorizeTransactionService: GetAutofillCategorizeTransaction;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Router constructor.
|
|
||||||
*/
|
|
||||||
router() {
|
|
||||||
const router = Router();
|
|
||||||
|
|
||||||
router.get(
|
|
||||||
'/autofill',
|
|
||||||
[
|
|
||||||
query('uncategorizedTransactionIds').isArray({ min: 1 }),
|
|
||||||
query('uncategorizedTransactionIds.*').isNumeric().toInt(),
|
|
||||||
],
|
|
||||||
this.validationResult,
|
|
||||||
this.getAutofillCategorizeTransaction.bind(this)
|
|
||||||
);
|
|
||||||
return router;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Retrieves the autofill values of the categorize form of the given
|
|
||||||
* uncategorized transactions.
|
|
||||||
* @param {Request} req
|
|
||||||
* @param {Response} res
|
|
||||||
* @param {NextFunction} next
|
|
||||||
* @returns {Promise<Response | null>}
|
|
||||||
*/
|
|
||||||
public async getAutofillCategorizeTransaction(
|
|
||||||
req: Request,
|
|
||||||
res: Response,
|
|
||||||
next: NextFunction
|
|
||||||
) {
|
|
||||||
const { tenantId } = req;
|
|
||||||
const uncategorizedTransactionIds = req.query.uncategorizedTransactionIds;
|
|
||||||
|
|
||||||
try {
|
|
||||||
const data =
|
|
||||||
await this.getAutofillCategorizeTransactionService.getAutofillCategorizeTransaction(
|
|
||||||
tenantId,
|
|
||||||
uncategorizedTransactionIds
|
|
||||||
);
|
|
||||||
return res.status(200).send({ data });
|
|
||||||
} catch (error) {
|
|
||||||
next(error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,201 +0,0 @@
|
|||||||
import { Inject, Service } from 'typedi';
|
|
||||||
import { body, param, query } from 'express-validator';
|
|
||||||
import { NextFunction, Request, Response, Router } from 'express';
|
|
||||||
import BaseController from '../BaseController';
|
|
||||||
import { ExcludeBankTransactionsApplication } from '@/services/Banking/Exclude/ExcludeBankTransactionsApplication';
|
|
||||||
import { map, parseInt, trim } from 'lodash';
|
|
||||||
|
|
||||||
@Service()
|
|
||||||
export class ExcludeBankTransactionsController extends BaseController {
|
|
||||||
@Inject()
|
|
||||||
private excludeBankTransactionApp: ExcludeBankTransactionsApplication;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Router constructor.
|
|
||||||
*/
|
|
||||||
public router() {
|
|
||||||
const router = Router();
|
|
||||||
|
|
||||||
router.put(
|
|
||||||
'/transactions/exclude',
|
|
||||||
[body('ids').exists()],
|
|
||||||
this.validationResult,
|
|
||||||
this.excludeBulkBankTransactions.bind(this)
|
|
||||||
);
|
|
||||||
router.put(
|
|
||||||
'/transactions/unexclude',
|
|
||||||
[body('ids').exists()],
|
|
||||||
this.validationResult,
|
|
||||||
this.unexcludeBulkBankTransactins.bind(this)
|
|
||||||
);
|
|
||||||
router.put(
|
|
||||||
'/transactions/:transactionId/exclude',
|
|
||||||
[param('transactionId').exists().toInt()],
|
|
||||||
this.validationResult,
|
|
||||||
this.excludeBankTransaction.bind(this)
|
|
||||||
);
|
|
||||||
router.put(
|
|
||||||
'/transactions/:transactionId/unexclude',
|
|
||||||
[param('transactionId').exists()],
|
|
||||||
this.validationResult,
|
|
||||||
this.unexcludeBankTransaction.bind(this)
|
|
||||||
);
|
|
||||||
router.get(
|
|
||||||
'/excluded',
|
|
||||||
[
|
|
||||||
query('account_id').optional().isNumeric().toInt(),
|
|
||||||
query('page').optional().isNumeric().toInt(),
|
|
||||||
query('page_size').optional().isNumeric().toInt(),
|
|
||||||
query('min_date').optional({ nullable: true }).isISO8601().toDate(),
|
|
||||||
query('max_date').optional({ nullable: true }).isISO8601().toDate(),
|
|
||||||
query('min_amount').optional({ nullable: true }).isFloat().toFloat(),
|
|
||||||
query('max_amount').optional({ nullable: true }).isFloat().toFloat(),
|
|
||||||
],
|
|
||||||
this.validationResult,
|
|
||||||
this.getExcludedBankTransactions.bind(this)
|
|
||||||
);
|
|
||||||
return router;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Marks a bank transaction as excluded.
|
|
||||||
* @param {Request} req
|
|
||||||
* @param {Response} res
|
|
||||||
* @param {NextFunction} next
|
|
||||||
* @returns
|
|
||||||
*/
|
|
||||||
private async excludeBankTransaction(
|
|
||||||
req: Request,
|
|
||||||
res: Response,
|
|
||||||
next: NextFunction
|
|
||||||
): Promise<Response | void> {
|
|
||||||
const { tenantId } = req;
|
|
||||||
const { transactionId } = req.params;
|
|
||||||
|
|
||||||
try {
|
|
||||||
await this.excludeBankTransactionApp.excludeBankTransaction(
|
|
||||||
tenantId,
|
|
||||||
transactionId
|
|
||||||
);
|
|
||||||
return res.status(200).send({
|
|
||||||
message: 'The bank transaction has been excluded.',
|
|
||||||
id: transactionId,
|
|
||||||
});
|
|
||||||
} catch (error) {
|
|
||||||
next(error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Marks a bank transaction as not excluded.
|
|
||||||
* @param {Request} req
|
|
||||||
* @param {Response} res
|
|
||||||
* @param {NextFunction} next
|
|
||||||
* @returns {Promise<Response|void>}
|
|
||||||
*/
|
|
||||||
private async unexcludeBankTransaction(
|
|
||||||
req: Request,
|
|
||||||
res: Response,
|
|
||||||
next: NextFunction
|
|
||||||
): Promise<Response | void> {
|
|
||||||
const { tenantId } = req;
|
|
||||||
const { transactionId } = req.params;
|
|
||||||
|
|
||||||
try {
|
|
||||||
await this.excludeBankTransactionApp.unexcludeBankTransaction(
|
|
||||||
tenantId,
|
|
||||||
transactionId
|
|
||||||
);
|
|
||||||
return res.status(200).send({
|
|
||||||
message: 'The bank transaction has been unexcluded.',
|
|
||||||
id: transactionId,
|
|
||||||
});
|
|
||||||
} catch (error) {
|
|
||||||
next(error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Exclude bank transactions in bulk.
|
|
||||||
* @param {Request} req
|
|
||||||
* @param {Response} res
|
|
||||||
* @param {NextFunction} next
|
|
||||||
*/
|
|
||||||
private async excludeBulkBankTransactions(
|
|
||||||
req: Request,
|
|
||||||
res: Response,
|
|
||||||
next: NextFunction
|
|
||||||
) {
|
|
||||||
const { tenantId } = req;
|
|
||||||
const { ids } = this.matchedBodyData(req);
|
|
||||||
|
|
||||||
try {
|
|
||||||
await this.excludeBankTransactionApp.excludeBankTransactions(
|
|
||||||
tenantId,
|
|
||||||
ids
|
|
||||||
);
|
|
||||||
return res.status(200).send({
|
|
||||||
message: 'The given bank transactions have been excluded',
|
|
||||||
ids,
|
|
||||||
});
|
|
||||||
} catch (error) {
|
|
||||||
next(error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Unexclude the given bank transactions in bulk.
|
|
||||||
* @param {Request} req
|
|
||||||
* @param {Response} res
|
|
||||||
* @param {NextFunction} next
|
|
||||||
* @returns {Promise<Response | null>}
|
|
||||||
*/
|
|
||||||
private async unexcludeBulkBankTransactins(
|
|
||||||
req: Request,
|
|
||||||
res: Response,
|
|
||||||
next: NextFunction
|
|
||||||
): Promise<Response | null> {
|
|
||||||
const { tenantId } = req;
|
|
||||||
const { ids } = this.matchedBodyData(req);
|
|
||||||
|
|
||||||
try {
|
|
||||||
await this.excludeBankTransactionApp.unexcludeBankTransactions(
|
|
||||||
tenantId,
|
|
||||||
ids
|
|
||||||
);
|
|
||||||
return res.status(200).send({
|
|
||||||
message: 'The given bank transactions have been excluded',
|
|
||||||
ids,
|
|
||||||
});
|
|
||||||
} catch (error) {
|
|
||||||
next(error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Retrieves the excluded uncategorized bank transactions.
|
|
||||||
* @param {Request} req
|
|
||||||
* @param {Response} res
|
|
||||||
* @param {NextFunction} next
|
|
||||||
* @returns {Promise<Response|null>}
|
|
||||||
*/
|
|
||||||
private async getExcludedBankTransactions(
|
|
||||||
req: Request,
|
|
||||||
res: Response,
|
|
||||||
next: NextFunction
|
|
||||||
): Promise<Response | void> {
|
|
||||||
const { tenantId } = req;
|
|
||||||
const filter = this.matchedQueryData(req);
|
|
||||||
|
|
||||||
try {
|
|
||||||
const data =
|
|
||||||
await this.excludeBankTransactionApp.getExcludedBankTransactions(
|
|
||||||
tenantId,
|
|
||||||
filter
|
|
||||||
);
|
|
||||||
return res.status(200).send(data);
|
|
||||||
} catch (error) {
|
|
||||||
next(error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,91 +0,0 @@
|
|||||||
import { Inject, Service } from 'typedi';
|
|
||||||
import { NextFunction, Request, Response, Router } from 'express';
|
|
||||||
import { query } from 'express-validator';
|
|
||||||
import BaseController from '@/api/controllers/BaseController';
|
|
||||||
import { CashflowApplication } from '@/services/Cashflow/CashflowApplication';
|
|
||||||
|
|
||||||
@Service()
|
|
||||||
export class RecognizedTransactionsController extends BaseController {
|
|
||||||
@Inject()
|
|
||||||
private cashflowApplication: CashflowApplication;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Router constructor.
|
|
||||||
*/
|
|
||||||
router() {
|
|
||||||
const router = Router();
|
|
||||||
|
|
||||||
router.get(
|
|
||||||
'/',
|
|
||||||
[
|
|
||||||
query('page').optional().isNumeric().toInt(),
|
|
||||||
query('page_size').optional().isNumeric().toInt(),
|
|
||||||
query('account_id').optional().isNumeric().toInt(),
|
|
||||||
query('min_date').optional({ nullable: true }).isISO8601().toDate(),
|
|
||||||
query('max_date').optional({ nullable: true }).isISO8601().toDate(),
|
|
||||||
query('min_amount').optional({ nullable: true }).isFloat().toFloat(),
|
|
||||||
query('max_amount').optional({ nullable: true }).isFloat().isFloat(),
|
|
||||||
],
|
|
||||||
this.validationResult,
|
|
||||||
this.getRecognizedTransactions.bind(this)
|
|
||||||
);
|
|
||||||
router.get(
|
|
||||||
'/transactions/:uncategorizedTransactionId',
|
|
||||||
this.getRecognizedTransaction.bind(this)
|
|
||||||
);
|
|
||||||
|
|
||||||
return router;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Retrieves the recognized bank transactions.
|
|
||||||
* @param {Request} req
|
|
||||||
* @param {Response} res
|
|
||||||
* @param {NextFunction} next
|
|
||||||
* @returns {Promise<Response|null>}
|
|
||||||
*/
|
|
||||||
async getRecognizedTransactions(
|
|
||||||
req: Request<{ accountId: number }>,
|
|
||||||
res: Response,
|
|
||||||
next: NextFunction
|
|
||||||
) {
|
|
||||||
const filter = this.matchedQueryData(req);
|
|
||||||
const { tenantId } = req;
|
|
||||||
|
|
||||||
try {
|
|
||||||
const data = await this.cashflowApplication.getRecognizedTransactions(
|
|
||||||
tenantId,
|
|
||||||
filter
|
|
||||||
);
|
|
||||||
return res.status(200).send(data);
|
|
||||||
} catch (error) {
|
|
||||||
next(error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Retrieves the recognized transaction of the ginen uncategorized transaction.
|
|
||||||
* @param {Request} req
|
|
||||||
* @param {Response} res
|
|
||||||
* @param {NextFunction} next
|
|
||||||
* @returns {Promise<Response|null>}
|
|
||||||
*/
|
|
||||||
async getRecognizedTransaction(
|
|
||||||
req: Request<{ uncategorizedTransactionId: number }>,
|
|
||||||
res: Response,
|
|
||||||
next: NextFunction
|
|
||||||
) {
|
|
||||||
const { tenantId } = req;
|
|
||||||
const { uncategorizedTransactionId } = req.params;
|
|
||||||
|
|
||||||
try {
|
|
||||||
const data = await this.cashflowApplication.getRecognizedTransaction(
|
|
||||||
tenantId,
|
|
||||||
uncategorizedTransactionId
|
|
||||||
);
|
|
||||||
return res.status(200).send({ data });
|
|
||||||
} catch (error) {
|
|
||||||
next(error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -4,7 +4,6 @@ import CommandCashflowTransaction from './NewCashflowTransaction';
|
|||||||
import DeleteCashflowTransaction from './DeleteCashflowTransaction';
|
import DeleteCashflowTransaction from './DeleteCashflowTransaction';
|
||||||
import GetCashflowTransaction from './GetCashflowTransaction';
|
import GetCashflowTransaction from './GetCashflowTransaction';
|
||||||
import GetCashflowAccounts from './GetCashflowAccounts';
|
import GetCashflowAccounts from './GetCashflowAccounts';
|
||||||
import { ExcludeBankTransactionsController } from '../Banking/ExcludeBankTransactionsController';
|
|
||||||
|
|
||||||
@Service()
|
@Service()
|
||||||
export default class CashflowController {
|
export default class CashflowController {
|
||||||
@@ -15,7 +14,6 @@ export default class CashflowController {
|
|||||||
const router = Router();
|
const router = Router();
|
||||||
|
|
||||||
router.use(Container.get(CommandCashflowTransaction).router());
|
router.use(Container.get(CommandCashflowTransaction).router());
|
||||||
router.use(Container.get(ExcludeBankTransactionsController).router());
|
|
||||||
router.use(Container.get(GetCashflowTransaction).router());
|
router.use(Container.get(GetCashflowTransaction).router());
|
||||||
router.use(Container.get(GetCashflowAccounts).router());
|
router.use(Container.get(GetCashflowAccounts).router());
|
||||||
router.use(Container.get(DeleteCashflowTransaction).router());
|
router.use(Container.get(DeleteCashflowTransaction).router());
|
||||||
|
|||||||
@@ -31,6 +31,7 @@ export default class GetCashflowAccounts extends BaseController {
|
|||||||
query('search_keyword').optional({ nullable: true }).isString().trim(),
|
query('search_keyword').optional({ nullable: true }).isString().trim(),
|
||||||
],
|
],
|
||||||
this.asyncMiddleware(this.getCashflowAccounts),
|
this.asyncMiddleware(this.getCashflowAccounts),
|
||||||
|
this.catchServiceErrors
|
||||||
);
|
);
|
||||||
return router;
|
return router;
|
||||||
}
|
}
|
||||||
@@ -66,4 +67,22 @@ export default class GetCashflowAccounts extends BaseController {
|
|||||||
next(error);
|
next(error);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Catches the service errors.
|
||||||
|
* @param {Error} error - Error.
|
||||||
|
* @param {Request} req - Request.
|
||||||
|
* @param {Response} res - Response.
|
||||||
|
* @param {NextFunction} next -
|
||||||
|
*/
|
||||||
|
private catchServiceErrors(
|
||||||
|
error,
|
||||||
|
req: Request,
|
||||||
|
res: Response,
|
||||||
|
next: NextFunction
|
||||||
|
) {
|
||||||
|
if (error instanceof ServiceError) {
|
||||||
|
}
|
||||||
|
next(error);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,37 +1,23 @@
|
|||||||
import { Service, Inject } from 'typedi';
|
import { Service, Inject } from 'typedi';
|
||||||
import { Router, Request, Response, NextFunction } from 'express';
|
import { Router, Request, Response, NextFunction } from 'express';
|
||||||
import { param, query } from 'express-validator';
|
import { param } from 'express-validator';
|
||||||
import BaseController from '../BaseController';
|
import BaseController from '../BaseController';
|
||||||
import { ServiceError } from '@/exceptions';
|
import { ServiceError } from '@/exceptions';
|
||||||
import CheckPolicies from '@/api/middleware/CheckPolicies';
|
import CheckPolicies from '@/api/middleware/CheckPolicies';
|
||||||
import { AbilitySubject, CashflowAction } from '@/interfaces';
|
import { AbilitySubject, CashflowAction } from '@/interfaces';
|
||||||
import { CashflowApplication } from '@/services/Cashflow/CashflowApplication';
|
import { CashflowApplication } from '@/services/Cashflow/CashflowApplication';
|
||||||
import { GetMatchedTransactionsFilter } from '@/services/Banking/Matching/types';
|
|
||||||
import { MatchBankTransactionsApplication } from '@/services/Banking/Matching/MatchBankTransactionsApplication';
|
|
||||||
|
|
||||||
@Service()
|
@Service()
|
||||||
export default class GetCashflowAccounts extends BaseController {
|
export default class GetCashflowAccounts extends BaseController {
|
||||||
@Inject()
|
@Inject()
|
||||||
private cashflowApplication: CashflowApplication;
|
private cashflowApplication: CashflowApplication;
|
||||||
|
|
||||||
@Inject()
|
|
||||||
private bankTransactionsMatchingApp: MatchBankTransactionsApplication;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Controller router.
|
* Controller router.
|
||||||
*/
|
*/
|
||||||
public router() {
|
public router() {
|
||||||
const router = Router();
|
const router = Router();
|
||||||
|
|
||||||
router.get(
|
|
||||||
'/transactions/matches',
|
|
||||||
[
|
|
||||||
query('uncategorizeTransactionsIds').exists().isArray({ min: 1 }),
|
|
||||||
query('uncategorizeTransactionsIds.*').exists().isNumeric().toInt(),
|
|
||||||
],
|
|
||||||
this.validationResult,
|
|
||||||
this.getMatchedTransactions.bind(this)
|
|
||||||
);
|
|
||||||
router.get(
|
router.get(
|
||||||
'/transactions/:transactionId',
|
'/transactions/:transactionId',
|
||||||
CheckPolicies(CashflowAction.View, AbilitySubject.Cashflow),
|
CheckPolicies(CashflowAction.View, AbilitySubject.Cashflow),
|
||||||
@@ -49,7 +35,7 @@ export default class GetCashflowAccounts extends BaseController {
|
|||||||
* @param {NextFunction} next
|
* @param {NextFunction} next
|
||||||
*/
|
*/
|
||||||
private getCashflowTransaction = async (
|
private getCashflowTransaction = async (
|
||||||
req: Request<{ transactionId: number }>,
|
req: Request,
|
||||||
res: Response,
|
res: Response,
|
||||||
next: NextFunction
|
next: NextFunction
|
||||||
) => {
|
) => {
|
||||||
@@ -61,6 +47,7 @@ export default class GetCashflowAccounts extends BaseController {
|
|||||||
tenantId,
|
tenantId,
|
||||||
transactionId
|
transactionId
|
||||||
);
|
);
|
||||||
|
|
||||||
return res.status(200).send({
|
return res.status(200).send({
|
||||||
cashflow_transaction: this.transfromToResponse(cashflowTransaction),
|
cashflow_transaction: this.transfromToResponse(cashflowTransaction),
|
||||||
});
|
});
|
||||||
@@ -69,39 +56,6 @@ export default class GetCashflowAccounts extends BaseController {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
|
||||||
* Retrieves the matched transactions.
|
|
||||||
* @param {Request} req
|
|
||||||
* @param {Response} res
|
|
||||||
* @param {NextFunction} next
|
|
||||||
*/
|
|
||||||
private async getMatchedTransactions(
|
|
||||||
req: Request<
|
|
||||||
{ transactionId: number },
|
|
||||||
null,
|
|
||||||
null,
|
|
||||||
{ uncategorizeTransactionsIds: Array<number> }
|
|
||||||
>,
|
|
||||||
res: Response,
|
|
||||||
next: NextFunction
|
|
||||||
) {
|
|
||||||
const { tenantId } = req;
|
|
||||||
const uncategorizeTransactionsIds = req.query.uncategorizeTransactionsIds;
|
|
||||||
const filter = this.matchedQueryData(req) as GetMatchedTransactionsFilter;
|
|
||||||
|
|
||||||
try {
|
|
||||||
const data =
|
|
||||||
await this.bankTransactionsMatchingApp.getMatchedTransactions(
|
|
||||||
tenantId,
|
|
||||||
uncategorizeTransactionsIds,
|
|
||||||
filter
|
|
||||||
);
|
|
||||||
return res.status(200).send(data);
|
|
||||||
} catch (error) {
|
|
||||||
next(error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Catches the service errors.
|
* Catches the service errors.
|
||||||
* @param {Error} error - Error.
|
* @param {Error} error - Error.
|
||||||
|
|||||||
@@ -1,15 +1,10 @@
|
|||||||
import { Service, Inject } from 'typedi';
|
import { Service, Inject } from 'typedi';
|
||||||
import { ValidationChain, body, check, param, query } from 'express-validator';
|
import { ValidationChain, check, param, query } from 'express-validator';
|
||||||
import { Router, Request, Response, NextFunction } from 'express';
|
import { Router, Request, Response, NextFunction } from 'express';
|
||||||
import { omit } from 'lodash';
|
|
||||||
import BaseController from '../BaseController';
|
import BaseController from '../BaseController';
|
||||||
import { ServiceError } from '@/exceptions';
|
import { ServiceError } from '@/exceptions';
|
||||||
import CheckPolicies from '@/api/middleware/CheckPolicies';
|
import CheckPolicies from '@/api/middleware/CheckPolicies';
|
||||||
import {
|
import { AbilitySubject, CashflowAction } from '@/interfaces';
|
||||||
AbilitySubject,
|
|
||||||
CashflowAction,
|
|
||||||
ICategorizeCashflowTransactioDTO,
|
|
||||||
} from '@/interfaces';
|
|
||||||
import { CashflowApplication } from '@/services/Cashflow/CashflowApplication';
|
import { CashflowApplication } from '@/services/Cashflow/CashflowApplication';
|
||||||
|
|
||||||
@Service()
|
@Service()
|
||||||
@@ -43,23 +38,13 @@ export default class NewCashflowTransactionController extends BaseController {
|
|||||||
this.asyncMiddleware(this.newCashflowTransaction),
|
this.asyncMiddleware(this.newCashflowTransaction),
|
||||||
this.catchServiceErrors
|
this.catchServiceErrors
|
||||||
);
|
);
|
||||||
router.post(
|
|
||||||
'/transactions/uncategorize/bulk',
|
|
||||||
[
|
|
||||||
body('ids').isArray({ min: 1 }),
|
|
||||||
body('ids.*').exists().isNumeric().toInt(),
|
|
||||||
],
|
|
||||||
this.validationResult,
|
|
||||||
this.uncategorizeBulkTransactions.bind(this),
|
|
||||||
this.catchServiceErrors
|
|
||||||
);
|
|
||||||
router.post(
|
router.post(
|
||||||
'/transactions/:id/uncategorize',
|
'/transactions/:id/uncategorize',
|
||||||
this.revertCategorizedCashflowTransaction,
|
this.revertCategorizedCashflowTransaction,
|
||||||
this.catchServiceErrors
|
this.catchServiceErrors
|
||||||
);
|
);
|
||||||
router.post(
|
router.post(
|
||||||
'/transactions/categorize',
|
'/transactions/:id/categorize',
|
||||||
this.categorizeCashflowTransactionValidationSchema,
|
this.categorizeCashflowTransactionValidationSchema,
|
||||||
this.validationResult,
|
this.validationResult,
|
||||||
this.categorizeCashflowTransaction,
|
this.categorizeCashflowTransaction,
|
||||||
@@ -84,10 +69,6 @@ export default class NewCashflowTransactionController extends BaseController {
|
|||||||
param('id').exists().isNumeric().toInt(),
|
param('id').exists().isNumeric().toInt(),
|
||||||
query('page').optional().isNumeric().toInt(),
|
query('page').optional().isNumeric().toInt(),
|
||||||
query('page_size').optional().isNumeric().toInt(),
|
query('page_size').optional().isNumeric().toInt(),
|
||||||
query('min_date').optional({ nullable: true }).isISO8601().toDate(),
|
|
||||||
query('max_date').optional({ nullable: true }).isISO8601().toDate(),
|
|
||||||
query('min_amount').optional({ nullable: true }).isFloat().toFloat(),
|
|
||||||
query('max_amount').optional({ nullable: true }).isFloat().toFloat(),
|
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -108,7 +89,6 @@ export default class NewCashflowTransactionController extends BaseController {
|
|||||||
*/
|
*/
|
||||||
public get categorizeCashflowTransactionValidationSchema() {
|
public get categorizeCashflowTransactionValidationSchema() {
|
||||||
return [
|
return [
|
||||||
check('uncategorized_transaction_ids').exists().isArray({ min: 1 }),
|
|
||||||
check('date').exists().isISO8601().toDate(),
|
check('date').exists().isISO8601().toDate(),
|
||||||
check('credit_account_id').exists().isInt().toInt(),
|
check('credit_account_id').exists().isInt().toInt(),
|
||||||
check('transaction_number').optional(),
|
check('transaction_number').optional(),
|
||||||
@@ -126,11 +106,12 @@ export default class NewCashflowTransactionController extends BaseController {
|
|||||||
public get newTransactionValidationSchema() {
|
public get newTransactionValidationSchema() {
|
||||||
return [
|
return [
|
||||||
check('date').exists().isISO8601().toDate(),
|
check('date').exists().isISO8601().toDate(),
|
||||||
check('reference_no').optional({ nullable: true }).trim(),
|
check('reference_no').optional({ nullable: true }).trim().escape(),
|
||||||
check('description')
|
check('description')
|
||||||
.optional({ nullable: true })
|
.optional({ nullable: true })
|
||||||
.isLength({ min: 3 })
|
.isLength({ min: 3 })
|
||||||
.trim(),
|
.trim()
|
||||||
|
.escape(),
|
||||||
check('transaction_type').exists(),
|
check('transaction_type').exists(),
|
||||||
|
|
||||||
check('amount').exists().isFloat().toFloat(),
|
check('amount').exists().isFloat().toFloat(),
|
||||||
@@ -180,7 +161,7 @@ export default class NewCashflowTransactionController extends BaseController {
|
|||||||
* @param {NextFunction} next
|
* @param {NextFunction} next
|
||||||
*/
|
*/
|
||||||
private revertCategorizedCashflowTransaction = async (
|
private revertCategorizedCashflowTransaction = async (
|
||||||
req: Request<{ id: number }>,
|
req: Request,
|
||||||
res: Response,
|
res: Response,
|
||||||
next: NextFunction
|
next: NextFunction
|
||||||
) => {
|
) => {
|
||||||
@@ -198,34 +179,6 @@ export default class NewCashflowTransactionController extends BaseController {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
|
||||||
* Uncategorize the given transactions in bulk.
|
|
||||||
* @param {Request<{}>} req
|
|
||||||
* @param {Response} res
|
|
||||||
* @param {NextFunction} next
|
|
||||||
* @returns {Promise<Response | null>}
|
|
||||||
*/
|
|
||||||
private uncategorizeBulkTransactions = async (
|
|
||||||
req: Request<{}>,
|
|
||||||
res: Response,
|
|
||||||
next: NextFunction
|
|
||||||
) => {
|
|
||||||
const { tenantId } = req;
|
|
||||||
const { ids: uncategorizedTransactionIds } = this.matchedBodyData(req);
|
|
||||||
|
|
||||||
try {
|
|
||||||
await this.cashflowApplication.uncategorizeTransactions(
|
|
||||||
tenantId,
|
|
||||||
uncategorizedTransactionIds
|
|
||||||
);
|
|
||||||
return res.status(200).send({
|
|
||||||
message: 'The given transactions have been uncategorized successfully.',
|
|
||||||
});
|
|
||||||
} catch (error) {
|
|
||||||
next(error);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Categorize the cashflow transaction.
|
* Categorize the cashflow transaction.
|
||||||
* @param {Request} req
|
* @param {Request} req
|
||||||
@@ -238,19 +191,14 @@ export default class NewCashflowTransactionController extends BaseController {
|
|||||||
next: NextFunction
|
next: NextFunction
|
||||||
) => {
|
) => {
|
||||||
const { tenantId } = req;
|
const { tenantId } = req;
|
||||||
const matchedObject = this.matchedBodyData(req);
|
const { id: cashflowTransactionId } = req.params;
|
||||||
const categorizeDTO = omit(matchedObject, [
|
const cashflowTransaction = this.matchedBodyData(req);
|
||||||
'uncategorizedTransactionIds',
|
|
||||||
]) as ICategorizeCashflowTransactioDTO;
|
|
||||||
|
|
||||||
const uncategorizedTransactionIds =
|
|
||||||
matchedObject.uncategorizedTransactionIds;
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await this.cashflowApplication.categorizeTransaction(
|
await this.cashflowApplication.categorizeTransaction(
|
||||||
tenantId,
|
tenantId,
|
||||||
uncategorizedTransactionIds,
|
cashflowTransactionId,
|
||||||
categorizeDTO
|
cashflowTransaction
|
||||||
);
|
);
|
||||||
return res.status(200).send({
|
return res.status(200).send({
|
||||||
message: 'The cashflow transaction has been created successfully.',
|
message: 'The cashflow transaction has been created successfully.',
|
||||||
@@ -321,7 +269,7 @@ export default class NewCashflowTransactionController extends BaseController {
|
|||||||
* @param {NextFunction} next
|
* @param {NextFunction} next
|
||||||
*/
|
*/
|
||||||
public getUncategorizedCashflowTransactions = async (
|
public getUncategorizedCashflowTransactions = async (
|
||||||
req: Request<{ id: number }>,
|
req: Request,
|
||||||
res: Response,
|
res: Response,
|
||||||
next: NextFunction
|
next: NextFunction
|
||||||
) => {
|
) => {
|
||||||
|
|||||||
@@ -56,7 +56,7 @@ export default class ContactsController extends BaseController {
|
|||||||
*/
|
*/
|
||||||
get autocompleteQuerySchema() {
|
get autocompleteQuerySchema() {
|
||||||
return [
|
return [
|
||||||
query('column_sort_by').optional().trim(),
|
query('column_sort_by').optional().trim().escape(),
|
||||||
query('sort_order').optional().isIn(['desc', 'asc']),
|
query('sort_order').optional().isIn(['desc', 'asc']),
|
||||||
|
|
||||||
query('stringified_filter_roles').optional().isJSON(),
|
query('stringified_filter_roles').optional().isJSON(),
|
||||||
@@ -122,27 +122,32 @@ export default class ContactsController extends BaseController {
|
|||||||
.optional({ nullable: true })
|
.optional({ nullable: true })
|
||||||
.isString()
|
.isString()
|
||||||
.trim()
|
.trim()
|
||||||
|
.escape()
|
||||||
.isLength({ max: DATATYPES_LENGTH.STRING }),
|
.isLength({ max: DATATYPES_LENGTH.STRING }),
|
||||||
check('first_name')
|
check('first_name')
|
||||||
.optional({ nullable: true })
|
.optional({ nullable: true })
|
||||||
.isString()
|
.isString()
|
||||||
.trim()
|
.trim()
|
||||||
|
.escape()
|
||||||
.isLength({ max: DATATYPES_LENGTH.STRING }),
|
.isLength({ max: DATATYPES_LENGTH.STRING }),
|
||||||
check('last_name')
|
check('last_name')
|
||||||
.optional({ nullable: true })
|
.optional({ nullable: true })
|
||||||
.isString()
|
.isString()
|
||||||
.trim()
|
.trim()
|
||||||
|
.escape()
|
||||||
.isLength({ max: DATATYPES_LENGTH.STRING }),
|
.isLength({ max: DATATYPES_LENGTH.STRING }),
|
||||||
check('company_name')
|
check('company_name')
|
||||||
.optional({ nullable: true })
|
.optional({ nullable: true })
|
||||||
.isString()
|
.isString()
|
||||||
.trim()
|
.trim()
|
||||||
|
.escape()
|
||||||
.isLength({ max: DATATYPES_LENGTH.STRING }),
|
.isLength({ max: DATATYPES_LENGTH.STRING }),
|
||||||
|
|
||||||
check('display_name')
|
check('display_name')
|
||||||
.exists()
|
.exists()
|
||||||
.isString()
|
.isString()
|
||||||
.trim()
|
.trim()
|
||||||
|
.escape()
|
||||||
.isLength({ max: DATATYPES_LENGTH.STRING }),
|
.isLength({ max: DATATYPES_LENGTH.STRING }),
|
||||||
|
|
||||||
check('email')
|
check('email')
|
||||||
@@ -160,101 +165,120 @@ export default class ContactsController extends BaseController {
|
|||||||
.optional({ nullable: true })
|
.optional({ nullable: true })
|
||||||
.isString()
|
.isString()
|
||||||
.trim()
|
.trim()
|
||||||
|
.escape()
|
||||||
.isLength({ max: DATATYPES_LENGTH.STRING }),
|
.isLength({ max: DATATYPES_LENGTH.STRING }),
|
||||||
check('personal_phone')
|
check('personal_phone')
|
||||||
.optional({ nullable: true })
|
.optional({ nullable: true })
|
||||||
.isString()
|
.isString()
|
||||||
.trim()
|
.trim()
|
||||||
|
.escape()
|
||||||
.isLength({ max: DATATYPES_LENGTH.STRING }),
|
.isLength({ max: DATATYPES_LENGTH.STRING }),
|
||||||
|
|
||||||
check('billing_address_1')
|
check('billing_address_1')
|
||||||
.optional({ nullable: true })
|
.optional({ nullable: true })
|
||||||
.isString()
|
.isString()
|
||||||
.trim()
|
.trim()
|
||||||
|
.escape()
|
||||||
.isLength({ max: DATATYPES_LENGTH.STRING }),
|
.isLength({ max: DATATYPES_LENGTH.STRING }),
|
||||||
check('billing_address_2')
|
check('billing_address_2')
|
||||||
.optional({ nullable: true })
|
.optional({ nullable: true })
|
||||||
.isString()
|
.isString()
|
||||||
.trim()
|
.trim()
|
||||||
|
.escape()
|
||||||
.isLength({ max: DATATYPES_LENGTH.STRING }),
|
.isLength({ max: DATATYPES_LENGTH.STRING }),
|
||||||
check('billing_address_city')
|
check('billing_address_city')
|
||||||
.optional({ nullable: true })
|
.optional({ nullable: true })
|
||||||
.isString()
|
.isString()
|
||||||
.trim()
|
.trim()
|
||||||
|
.escape()
|
||||||
.isLength({ max: DATATYPES_LENGTH.STRING }),
|
.isLength({ max: DATATYPES_LENGTH.STRING }),
|
||||||
check('billing_address_country')
|
check('billing_address_country')
|
||||||
.optional({ nullable: true })
|
.optional({ nullable: true })
|
||||||
.isString()
|
.isString()
|
||||||
.trim()
|
.trim()
|
||||||
|
.escape()
|
||||||
.isLength({ max: DATATYPES_LENGTH.STRING }),
|
.isLength({ max: DATATYPES_LENGTH.STRING }),
|
||||||
check('billing_address_email')
|
check('billing_address_email')
|
||||||
.optional({ nullable: true })
|
.optional({ nullable: true })
|
||||||
.isString()
|
.isString()
|
||||||
.isEmail()
|
.isEmail()
|
||||||
.trim()
|
.trim()
|
||||||
|
.escape()
|
||||||
.isLength({ max: DATATYPES_LENGTH.STRING }),
|
.isLength({ max: DATATYPES_LENGTH.STRING }),
|
||||||
check('billing_address_postcode')
|
check('billing_address_postcode')
|
||||||
.optional({ nullable: true })
|
.optional({ nullable: true })
|
||||||
.isString()
|
.isString()
|
||||||
.trim()
|
.trim()
|
||||||
|
.escape()
|
||||||
.isLength({ max: DATATYPES_LENGTH.STRING }),
|
.isLength({ max: DATATYPES_LENGTH.STRING }),
|
||||||
check('billing_address_phone')
|
check('billing_address_phone')
|
||||||
.optional({ nullable: true })
|
.optional({ nullable: true })
|
||||||
.isString()
|
.isString()
|
||||||
.trim()
|
.trim()
|
||||||
|
.escape()
|
||||||
.isLength({ max: DATATYPES_LENGTH.STRING }),
|
.isLength({ max: DATATYPES_LENGTH.STRING }),
|
||||||
check('billing_address_state')
|
check('billing_address_state')
|
||||||
.optional({ nullable: true })
|
.optional({ nullable: true })
|
||||||
.isString()
|
.isString()
|
||||||
.trim()
|
.trim()
|
||||||
|
.escape()
|
||||||
.isLength({ max: DATATYPES_LENGTH.STRING }),
|
.isLength({ max: DATATYPES_LENGTH.STRING }),
|
||||||
|
|
||||||
check('shipping_address_1')
|
check('shipping_address_1')
|
||||||
.optional({ nullable: true })
|
.optional({ nullable: true })
|
||||||
.isString()
|
.isString()
|
||||||
.trim()
|
.trim()
|
||||||
|
.escape()
|
||||||
.isLength({ max: DATATYPES_LENGTH.STRING }),
|
.isLength({ max: DATATYPES_LENGTH.STRING }),
|
||||||
check('shipping_address_2')
|
check('shipping_address_2')
|
||||||
.optional({ nullable: true })
|
.optional({ nullable: true })
|
||||||
.isString()
|
.isString()
|
||||||
.trim()
|
.trim()
|
||||||
|
.escape()
|
||||||
.isLength({ max: DATATYPES_LENGTH.STRING }),
|
.isLength({ max: DATATYPES_LENGTH.STRING }),
|
||||||
check('shipping_address_city')
|
check('shipping_address_city')
|
||||||
.optional({ nullable: true })
|
.optional({ nullable: true })
|
||||||
.isString()
|
.isString()
|
||||||
.trim()
|
.trim()
|
||||||
|
.escape()
|
||||||
.isLength({ max: DATATYPES_LENGTH.STRING }),
|
.isLength({ max: DATATYPES_LENGTH.STRING }),
|
||||||
check('shipping_address_country')
|
check('shipping_address_country')
|
||||||
.optional({ nullable: true })
|
.optional({ nullable: true })
|
||||||
.isString()
|
.isString()
|
||||||
.trim()
|
.trim()
|
||||||
|
.escape()
|
||||||
.isLength({ max: DATATYPES_LENGTH.STRING }),
|
.isLength({ max: DATATYPES_LENGTH.STRING }),
|
||||||
check('shipping_address_email')
|
check('shipping_address_email')
|
||||||
.optional({ nullable: true })
|
.optional({ nullable: true })
|
||||||
.isString()
|
.isString()
|
||||||
.isEmail()
|
.isEmail()
|
||||||
.trim()
|
.trim()
|
||||||
|
.escape()
|
||||||
.isLength({ max: DATATYPES_LENGTH.STRING }),
|
.isLength({ max: DATATYPES_LENGTH.STRING }),
|
||||||
check('shipping_address_postcode')
|
check('shipping_address_postcode')
|
||||||
.optional({ nullable: true })
|
.optional({ nullable: true })
|
||||||
.isString()
|
.isString()
|
||||||
.trim()
|
.trim()
|
||||||
|
.escape()
|
||||||
.isLength({ max: DATATYPES_LENGTH.STRING }),
|
.isLength({ max: DATATYPES_LENGTH.STRING }),
|
||||||
check('shipping_address_phone')
|
check('shipping_address_phone')
|
||||||
.optional({ nullable: true })
|
.optional({ nullable: true })
|
||||||
.isString()
|
.isString()
|
||||||
.trim()
|
.trim()
|
||||||
|
.escape()
|
||||||
.isLength({ max: DATATYPES_LENGTH.STRING }),
|
.isLength({ max: DATATYPES_LENGTH.STRING }),
|
||||||
check('shipping_address_state')
|
check('shipping_address_state')
|
||||||
.optional({ nullable: true })
|
.optional({ nullable: true })
|
||||||
.isString()
|
.isString()
|
||||||
.trim()
|
.trim()
|
||||||
|
.escape()
|
||||||
.isLength({ max: DATATYPES_LENGTH.STRING }),
|
.isLength({ max: DATATYPES_LENGTH.STRING }),
|
||||||
|
|
||||||
check('note')
|
check('note')
|
||||||
.optional({ nullable: true })
|
.optional({ nullable: true })
|
||||||
.isString()
|
.isString()
|
||||||
.trim()
|
.trim()
|
||||||
|
.escape()
|
||||||
.isLength({ max: DATATYPES_LENGTH.TEXT }),
|
.isLength({ max: DATATYPES_LENGTH.TEXT }),
|
||||||
check('active').optional().isBoolean().toBoolean(),
|
check('active').optional().isBoolean().toBoolean(),
|
||||||
];
|
];
|
||||||
|
|||||||
@@ -106,7 +106,11 @@ export default class CustomersController extends ContactsController {
|
|||||||
*/
|
*/
|
||||||
get customerDTOSchema() {
|
get customerDTOSchema() {
|
||||||
return [
|
return [
|
||||||
check('customer_type').exists().isIn(['business', 'individual']).trim(),
|
check('customer_type')
|
||||||
|
.exists()
|
||||||
|
.isIn(['business', 'individual'])
|
||||||
|
.trim()
|
||||||
|
.escape(),
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -119,6 +123,7 @@ export default class CustomersController extends ContactsController {
|
|||||||
.optional({ nullable: true })
|
.optional({ nullable: true })
|
||||||
.isString()
|
.isString()
|
||||||
.trim()
|
.trim()
|
||||||
|
.escape()
|
||||||
.isLength({ max: 3 }),
|
.isLength({ max: 3 }),
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
@@ -128,7 +133,7 @@ export default class CustomersController extends ContactsController {
|
|||||||
*/
|
*/
|
||||||
get validateListQuerySchema() {
|
get validateListQuerySchema() {
|
||||||
return [
|
return [
|
||||||
query('column_sort_by').optional().trim(),
|
query('column_sort_by').optional().trim().escape(),
|
||||||
query('sort_order').optional().isIn(['desc', 'asc']),
|
query('sort_order').optional().isIn(['desc', 'asc']),
|
||||||
|
|
||||||
query('page').optional().isNumeric().toInt(),
|
query('page').optional().isNumeric().toInt(),
|
||||||
|
|||||||
@@ -106,6 +106,7 @@ export default class VendorsController extends ContactsController {
|
|||||||
.optional({ nullable: true })
|
.optional({ nullable: true })
|
||||||
.isString()
|
.isString()
|
||||||
.trim()
|
.trim()
|
||||||
|
.escape()
|
||||||
.isLength({ min: 3, max: 3 }),
|
.isLength({ min: 3, max: 3 }),
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -67,7 +67,7 @@ export default class CurrenciesController extends BaseController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
get currencyParamSchema(): ValidationChain[] {
|
get currencyParamSchema(): ValidationChain[] {
|
||||||
return [param('currency_code').exists().trim()];
|
return [param('currency_code').exists().trim().escape()];
|
||||||
}
|
}
|
||||||
|
|
||||||
get listSchema(): ValidationChain[] {
|
get listSchema(): ValidationChain[] {
|
||||||
@@ -187,13 +187,11 @@ export default class CurrenciesController extends BaseController {
|
|||||||
}
|
}
|
||||||
if (error.errorType === 'currency_code_exists') {
|
if (error.errorType === 'currency_code_exists') {
|
||||||
return res.boom.badRequest(null, {
|
return res.boom.badRequest(null, {
|
||||||
errors: [
|
errors: [{
|
||||||
{
|
type: 'CURRENCY_CODE_EXISTS',
|
||||||
type: 'CURRENCY_CODE_EXISTS',
|
message: 'The given currency code is already exists.',
|
||||||
message: 'The given currency code is already exists.',
|
code: 200,
|
||||||
code: 200,
|
}],
|
||||||
},
|
|
||||||
],
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
if (error.errorType === 'CANNOT_DELETE_BASE_CURRENCY') {
|
if (error.errorType === 'CANNOT_DELETE_BASE_CURRENCY') {
|
||||||
|
|||||||
@@ -89,6 +89,7 @@ export class ExpensesController extends BaseController {
|
|||||||
check('reference_no')
|
check('reference_no')
|
||||||
.optional({ nullable: true })
|
.optional({ nullable: true })
|
||||||
.trim()
|
.trim()
|
||||||
|
.escape()
|
||||||
.isLength({ max: DATATYPES_LENGTH.STRING }),
|
.isLength({ max: DATATYPES_LENGTH.STRING }),
|
||||||
check('payment_date').exists().isISO8601().toDate(),
|
check('payment_date').exists().isISO8601().toDate(),
|
||||||
check('payment_account_id')
|
check('payment_account_id')
|
||||||
@@ -122,6 +123,7 @@ export class ExpensesController extends BaseController {
|
|||||||
check('categories.*.description')
|
check('categories.*.description')
|
||||||
.optional()
|
.optional()
|
||||||
.trim()
|
.trim()
|
||||||
|
.escape()
|
||||||
.isLength({ max: DATATYPES_LENGTH.STRING }),
|
.isLength({ max: DATATYPES_LENGTH.STRING }),
|
||||||
check('categories.*.landed_cost').optional().isBoolean().toBoolean(),
|
check('categories.*.landed_cost').optional().isBoolean().toBoolean(),
|
||||||
check('categories.*.project_id')
|
check('categories.*.project_id')
|
||||||
@@ -142,6 +144,7 @@ export class ExpensesController extends BaseController {
|
|||||||
check('reference_no')
|
check('reference_no')
|
||||||
.optional({ nullable: true })
|
.optional({ nullable: true })
|
||||||
.trim()
|
.trim()
|
||||||
|
.escape()
|
||||||
.isLength({ max: DATATYPES_LENGTH.STRING }),
|
.isLength({ max: DATATYPES_LENGTH.STRING }),
|
||||||
check('payment_date').exists().isISO8601().toDate(),
|
check('payment_date').exists().isISO8601().toDate(),
|
||||||
check('payment_account_id')
|
check('payment_account_id')
|
||||||
@@ -176,6 +179,7 @@ export class ExpensesController extends BaseController {
|
|||||||
check('categories.*.description')
|
check('categories.*.description')
|
||||||
.optional()
|
.optional()
|
||||||
.trim()
|
.trim()
|
||||||
|
.escape()
|
||||||
.isLength({ max: DATATYPES_LENGTH.STRING }),
|
.isLength({ max: DATATYPES_LENGTH.STRING }),
|
||||||
check('categories.*.landed_cost').optional().isBoolean().toBoolean(),
|
check('categories.*.landed_cost').optional().isBoolean().toBoolean(),
|
||||||
check('categories.*.project_id')
|
check('categories.*.project_id')
|
||||||
|
|||||||
@@ -1,7 +1,9 @@
|
|||||||
import { query } from 'express-validator';
|
import { query } from 'express-validator';
|
||||||
import BaseController from '../BaseController';
|
import BaseController from "../BaseController";
|
||||||
|
|
||||||
export default class BaseFinancialReportController extends BaseController {
|
export default class BaseFinancialReportController extends BaseController {
|
||||||
|
|
||||||
|
|
||||||
get sheetNumberFormatValidationSchema() {
|
get sheetNumberFormatValidationSchema() {
|
||||||
return [
|
return [
|
||||||
query('number_format.precision')
|
query('number_format.precision')
|
||||||
@@ -17,7 +19,8 @@ export default class BaseFinancialReportController extends BaseController {
|
|||||||
query('number_format.negative_format')
|
query('number_format.negative_format')
|
||||||
.optional()
|
.optional()
|
||||||
.isIn(['parentheses', 'mines'])
|
.isIn(['parentheses', 'mines'])
|
||||||
.trim(),
|
.trim()
|
||||||
|
.escape(),
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -51,7 +51,8 @@ export default class InventoryDetailsController extends BaseController {
|
|||||||
query('number_format.negative_format')
|
query('number_format.negative_format')
|
||||||
.optional()
|
.optional()
|
||||||
.isIn(['parentheses', 'mines'])
|
.isIn(['parentheses', 'mines'])
|
||||||
.trim(),
|
.trim()
|
||||||
|
.escape(),
|
||||||
query('from_date').optional(),
|
query('from_date').optional(),
|
||||||
query('to_date').optional(),
|
query('to_date').optional(),
|
||||||
|
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ export default class JournalSheetController extends BaseFinancialReportControlle
|
|||||||
return [
|
return [
|
||||||
query('from_date').optional().isISO8601(),
|
query('from_date').optional().isISO8601(),
|
||||||
query('to_date').optional().isISO8601(),
|
query('to_date').optional().isISO8601(),
|
||||||
query('transaction_type').optional().trim(),
|
query('transaction_type').optional().trim().escape(),
|
||||||
query('transaction_id').optional().isInt().toInt(),
|
query('transaction_id').optional().isInt().toInt(),
|
||||||
oneOf(
|
oneOf(
|
||||||
[
|
[
|
||||||
|
|||||||
@@ -40,7 +40,8 @@ export default class TransactionsByReferenceController extends BaseController {
|
|||||||
query('number_format.negative_format')
|
query('number_format.negative_format')
|
||||||
.optional()
|
.optional()
|
||||||
.isIn(['parentheses', 'mines'])
|
.isIn(['parentheses', 'mines'])
|
||||||
.trim(),
|
.trim()
|
||||||
|
.escape(),
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -86,7 +86,7 @@ export default class InventoryAdjustmentsController extends BaseController {
|
|||||||
*/
|
*/
|
||||||
get validateListQuerySchema() {
|
get validateListQuerySchema() {
|
||||||
return [
|
return [
|
||||||
query('column_sort_by').optional().trim(),
|
query('column_sort_by').optional().trim().escape(),
|
||||||
query('sort_order').optional().isIn(['desc', 'asc']),
|
query('sort_order').optional().isIn(['desc', 'asc']),
|
||||||
|
|
||||||
query('page').optional().isNumeric().toInt(),
|
query('page').optional().isNumeric().toInt(),
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ export default class InviteUsersController extends BaseController {
|
|||||||
router.post(
|
router.post(
|
||||||
'/send',
|
'/send',
|
||||||
[
|
[
|
||||||
body('email').exists().trim(),
|
body('email').exists().trim().escape(),
|
||||||
body('role_id').exists().isNumeric().toInt(),
|
body('role_id').exists().isNumeric().toInt(),
|
||||||
],
|
],
|
||||||
this.validationResult,
|
this.validationResult,
|
||||||
@@ -57,7 +57,7 @@ export default class InviteUsersController extends BaseController {
|
|||||||
);
|
);
|
||||||
router.get(
|
router.get(
|
||||||
'/invited/:token',
|
'/invited/:token',
|
||||||
[param('token').exists().trim()],
|
[param('token').exists().trim().escape()],
|
||||||
this.validationResult,
|
this.validationResult,
|
||||||
asyncMiddleware(this.invited.bind(this)),
|
asyncMiddleware(this.invited.bind(this)),
|
||||||
this.handleServicesError
|
this.handleServicesError
|
||||||
@@ -72,10 +72,10 @@ export default class InviteUsersController extends BaseController {
|
|||||||
*/
|
*/
|
||||||
private get inviteUserDTO() {
|
private get inviteUserDTO() {
|
||||||
return [
|
return [
|
||||||
check('first_name').exists().trim(),
|
check('first_name').exists().trim().escape(),
|
||||||
check('last_name').exists().trim(),
|
check('last_name').exists().trim().escape(),
|
||||||
check('password').exists().trim().isLength({ min: 5 }),
|
check('password').exists().trim().escape().isLength({ min: 5 }),
|
||||||
param('token').exists().trim(),
|
param('token').exists().trim().escape(),
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -73,11 +73,13 @@ export default class ItemsCategoriesController extends BaseController {
|
|||||||
check('name')
|
check('name')
|
||||||
.exists()
|
.exists()
|
||||||
.trim()
|
.trim()
|
||||||
|
.escape()
|
||||||
.isLength({ min: 0, max: DATATYPES_LENGTH.STRING }),
|
.isLength({ min: 0, max: DATATYPES_LENGTH.STRING }),
|
||||||
check('description')
|
check('description')
|
||||||
.optional({ nullable: true })
|
.optional({ nullable: true })
|
||||||
.isString()
|
.isString()
|
||||||
.trim()
|
.trim()
|
||||||
|
.escape()
|
||||||
.isLength({ max: DATATYPES_LENGTH.TEXT }),
|
.isLength({ max: DATATYPES_LENGTH.TEXT }),
|
||||||
check('sell_account_id')
|
check('sell_account_id')
|
||||||
.optional({ nullable: true })
|
.optional({ nullable: true })
|
||||||
@@ -99,8 +101,9 @@ export default class ItemsCategoriesController extends BaseController {
|
|||||||
*/
|
*/
|
||||||
get categoriesListValidationSchema() {
|
get categoriesListValidationSchema() {
|
||||||
return [
|
return [
|
||||||
query('column_sort_by').optional().trim(),
|
query('column_sort_by').optional().trim().escape(),
|
||||||
query('sort_order').optional().trim().isIn(['desc', 'asc']),
|
query('sort_order').optional().trim().escape().isIn(['desc', 'asc']),
|
||||||
|
|
||||||
query('stringified_filter_roles').optional().isJSON(),
|
query('stringified_filter_roles').optional().isJSON(),
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
@@ -204,12 +207,14 @@ export default class ItemsCategoriesController extends BaseController {
|
|||||||
};
|
};
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const { itemCategories, filterMeta } =
|
const {
|
||||||
await this.itemCategoriesService.getItemCategoriesList(
|
itemCategories,
|
||||||
tenantId,
|
filterMeta,
|
||||||
itemCategoriesFilter,
|
} = await this.itemCategoriesService.getItemCategoriesList(
|
||||||
user
|
tenantId,
|
||||||
);
|
itemCategoriesFilter,
|
||||||
|
user
|
||||||
|
);
|
||||||
return res.status(200).send({
|
return res.status(200).send({
|
||||||
item_categories: itemCategories,
|
item_categories: itemCategories,
|
||||||
filter_meta: this.transfromToResponse(filterMeta),
|
filter_meta: this.transfromToResponse(filterMeta),
|
||||||
|
|||||||
@@ -96,11 +96,13 @@ export default class ItemsController extends BaseController {
|
|||||||
.exists()
|
.exists()
|
||||||
.isString()
|
.isString()
|
||||||
.trim()
|
.trim()
|
||||||
|
.escape()
|
||||||
.isIn(['service', 'non-inventory', 'inventory']),
|
.isIn(['service', 'non-inventory', 'inventory']),
|
||||||
check('code')
|
check('code')
|
||||||
.optional({ nullable: true })
|
.optional({ nullable: true })
|
||||||
.isString()
|
.isString()
|
||||||
.trim()
|
.trim()
|
||||||
|
.escape()
|
||||||
.isLength({ max: DATATYPES_LENGTH.STRING }),
|
.isLength({ max: DATATYPES_LENGTH.STRING }),
|
||||||
// Purchase attributes.
|
// Purchase attributes.
|
||||||
check('purchasable').optional().isBoolean().toBoolean(),
|
check('purchasable').optional().isBoolean().toBoolean(),
|
||||||
@@ -139,11 +141,13 @@ export default class ItemsController extends BaseController {
|
|||||||
.optional({ nullable: true })
|
.optional({ nullable: true })
|
||||||
.isString()
|
.isString()
|
||||||
.trim()
|
.trim()
|
||||||
|
.escape()
|
||||||
.isLength({ max: DATATYPES_LENGTH.TEXT }),
|
.isLength({ max: DATATYPES_LENGTH.TEXT }),
|
||||||
check('purchase_description')
|
check('purchase_description')
|
||||||
.optional({ nullable: true })
|
.optional({ nullable: true })
|
||||||
.isString()
|
.isString()
|
||||||
.trim()
|
.trim()
|
||||||
|
.escape()
|
||||||
.isLength({ max: DATATYPES_LENGTH.TEXT }),
|
.isLength({ max: DATATYPES_LENGTH.TEXT }),
|
||||||
check('sell_tax_rate_id').optional({ nullable: true }).isInt().toInt(),
|
check('sell_tax_rate_id').optional({ nullable: true }).isInt().toInt(),
|
||||||
check('purchase_tax_rate_id')
|
check('purchase_tax_rate_id')
|
||||||
@@ -158,6 +162,7 @@ export default class ItemsController extends BaseController {
|
|||||||
.optional()
|
.optional()
|
||||||
.isString()
|
.isString()
|
||||||
.trim()
|
.trim()
|
||||||
|
.escape()
|
||||||
.isLength({ max: DATATYPES_LENGTH.TEXT }),
|
.isLength({ max: DATATYPES_LENGTH.TEXT }),
|
||||||
check('active').optional().isBoolean().toBoolean(),
|
check('active').optional().isBoolean().toBoolean(),
|
||||||
|
|
||||||
@@ -179,7 +184,7 @@ export default class ItemsController extends BaseController {
|
|||||||
*/
|
*/
|
||||||
private get validateListQuerySchema() {
|
private get validateListQuerySchema() {
|
||||||
return [
|
return [
|
||||||
query('column_sort_by').optional().trim(),
|
query('column_sort_by').optional().trim().escape(),
|
||||||
query('sort_order').optional().isIn(['desc', 'asc']),
|
query('sort_order').optional().isIn(['desc', 'asc']),
|
||||||
|
|
||||||
query('page').optional().isNumeric().toInt(),
|
query('page').optional().isNumeric().toInt(),
|
||||||
|
|||||||
@@ -94,21 +94,25 @@ export default class ManualJournalsController extends BaseController {
|
|||||||
.optional()
|
.optional()
|
||||||
.isString()
|
.isString()
|
||||||
.trim()
|
.trim()
|
||||||
|
.escape()
|
||||||
.isLength({ max: DATATYPES_LENGTH.STRING }),
|
.isLength({ max: DATATYPES_LENGTH.STRING }),
|
||||||
check('journal_type')
|
check('journal_type')
|
||||||
.optional({ nullable: true })
|
.optional({ nullable: true })
|
||||||
.isString()
|
.isString()
|
||||||
.trim()
|
.trim()
|
||||||
|
.escape()
|
||||||
.isLength({ max: DATATYPES_LENGTH.STRING }),
|
.isLength({ max: DATATYPES_LENGTH.STRING }),
|
||||||
check('reference')
|
check('reference')
|
||||||
.optional({ nullable: true })
|
.optional({ nullable: true })
|
||||||
.isString()
|
.isString()
|
||||||
.trim()
|
.trim()
|
||||||
|
.escape()
|
||||||
.isLength({ max: DATATYPES_LENGTH.STRING }),
|
.isLength({ max: DATATYPES_LENGTH.STRING }),
|
||||||
check('description')
|
check('description')
|
||||||
.optional({ nullable: true })
|
.optional({ nullable: true })
|
||||||
.isString()
|
.isString()
|
||||||
.trim()
|
.trim()
|
||||||
|
.escape()
|
||||||
.isLength({ max: DATATYPES_LENGTH.TEXT }),
|
.isLength({ max: DATATYPES_LENGTH.TEXT }),
|
||||||
check('branch_id').optional({ nullable: true }).isNumeric().toInt(),
|
check('branch_id').optional({ nullable: true }).isNumeric().toInt(),
|
||||||
check('publish').optional().isBoolean().toBoolean(),
|
check('publish').optional().isBoolean().toBoolean(),
|
||||||
@@ -159,7 +163,7 @@ export default class ManualJournalsController extends BaseController {
|
|||||||
query('page_size').optional().isNumeric().toInt(),
|
query('page_size').optional().isNumeric().toInt(),
|
||||||
query('custom_view_id').optional().isNumeric().toInt(),
|
query('custom_view_id').optional().isNumeric().toInt(),
|
||||||
|
|
||||||
query('column_sort_by').optional().trim(),
|
query('column_sort_by').optional().trim().escape(),
|
||||||
query('sort_order').optional().isIn(['desc', 'asc']),
|
query('sort_order').optional().isIn(['desc', 'asc']),
|
||||||
|
|
||||||
query('stringified_filter_roles').optional().isJSON(),
|
query('stringified_filter_roles').optional().isJSON(),
|
||||||
|
|||||||
@@ -61,14 +61,15 @@ export default class MediaController extends BaseController {
|
|||||||
|
|
||||||
get uploadValidationSchema() {
|
get uploadValidationSchema() {
|
||||||
return [
|
return [
|
||||||
check('model_name').optional().trim(),
|
// check('attachment'),
|
||||||
check('model_id').optional().isNumeric(),
|
check('model_name').optional().trim().escape(),
|
||||||
|
check('model_id').optional().isNumeric().toInt(),
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
get linkValidationSchema() {
|
get linkValidationSchema() {
|
||||||
return [
|
return [
|
||||||
check('model_name').exists().trim(),
|
check('model_name').exists().trim().escape(),
|
||||||
check('model_id').exists().isNumeric().toInt(),
|
check('model_id').exists().isNumeric().toInt(),
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,87 +0,0 @@
|
|||||||
import { Router, Request, Response, NextFunction } from 'express';
|
|
||||||
import { Service, Inject } from 'typedi';
|
|
||||||
import { body } from 'express-validator';
|
|
||||||
import asyncMiddleware from '@/api/middleware/asyncMiddleware';
|
|
||||||
import BaseController from '@/api/controllers/BaseController';
|
|
||||||
import { OneClickDemoApplication } from '@/services/OneClickDemo/OneClickDemoApplication';
|
|
||||||
import config from '@/config';
|
|
||||||
@Service()
|
|
||||||
export class OneClickDemoController extends BaseController {
|
|
||||||
@Inject()
|
|
||||||
private oneClickDemoApp: OneClickDemoApplication;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Router constructor method.
|
|
||||||
*/
|
|
||||||
router() {
|
|
||||||
const router = Router();
|
|
||||||
|
|
||||||
// Protects the endpoints if the feature is not enabled.
|
|
||||||
const protectMiddleware = (
|
|
||||||
req: Request,
|
|
||||||
res: Response,
|
|
||||||
next: NextFunction
|
|
||||||
) => {
|
|
||||||
// Add your protection logic here
|
|
||||||
if (config.oneClickDemoAccounts) {
|
|
||||||
next();
|
|
||||||
} else {
|
|
||||||
res.status(403).send({ message: 'Forbidden' });
|
|
||||||
}
|
|
||||||
};
|
|
||||||
router.post(
|
|
||||||
'/one_click',
|
|
||||||
protectMiddleware,
|
|
||||||
asyncMiddleware(this.oneClickDemo.bind(this))
|
|
||||||
);
|
|
||||||
router.post(
|
|
||||||
'/one_click_signin',
|
|
||||||
[body('demo_id').exists()],
|
|
||||||
this.validationResult,
|
|
||||||
protectMiddleware,
|
|
||||||
asyncMiddleware(this.oneClickSignIn.bind(this))
|
|
||||||
);
|
|
||||||
return router;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* One-click demo application.
|
|
||||||
* @param {Request} req -
|
|
||||||
* @param {Response} res -
|
|
||||||
* @param {NextFunction} next -
|
|
||||||
*/
|
|
||||||
private async oneClickDemo(req: Request, res: Response, next: NextFunction) {
|
|
||||||
try {
|
|
||||||
const data = await this.oneClickDemoApp.createOneClick();
|
|
||||||
|
|
||||||
return res.status(200).send({
|
|
||||||
data,
|
|
||||||
message: 'The one-click demo has been created successfully.',
|
|
||||||
});
|
|
||||||
} catch (error) {
|
|
||||||
next(error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sign-in to one-click demo account.
|
|
||||||
* @param {Request} req
|
|
||||||
* @param {Response} res
|
|
||||||
* @param {NextFunction} next
|
|
||||||
*/
|
|
||||||
private async oneClickSignIn(
|
|
||||||
req: Request,
|
|
||||||
res: Response,
|
|
||||||
next: NextFunction
|
|
||||||
) {
|
|
||||||
const { demoId } = this.matchedBodyData(req);
|
|
||||||
|
|
||||||
try {
|
|
||||||
const data = await this.oneClickDemoApp.autoSignIn(demoId);
|
|
||||||
|
|
||||||
return res.status(200).send(data);
|
|
||||||
} catch (error) {
|
|
||||||
next(error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -62,7 +62,7 @@ export default class OrganizationController extends BaseController {
|
|||||||
private get commonOrganizationValidationSchema(): ValidationChain[] {
|
private get commonOrganizationValidationSchema(): ValidationChain[] {
|
||||||
return [
|
return [
|
||||||
check('name').exists().trim(),
|
check('name').exists().trim(),
|
||||||
check('industry').optional({ nullable: true }).isString().trim(),
|
check('industry').optional({ nullable: true }).isString().trim().escape(),
|
||||||
check('location').exists().isString().isISO31661Alpha2(),
|
check('location').exists().isString().isISO31661Alpha2(),
|
||||||
check('base_currency').exists().isISO4217(),
|
check('base_currency').exists().isISO4217(),
|
||||||
check('timezone').exists().isIn(moment.tz.names()),
|
check('timezone').exists().isIn(moment.tz.names()),
|
||||||
@@ -87,7 +87,11 @@ export default class OrganizationController extends BaseController {
|
|||||||
private get updateOrganizationValidationSchema(): ValidationChain[] {
|
private get updateOrganizationValidationSchema(): ValidationChain[] {
|
||||||
return [
|
return [
|
||||||
...this.commonOrganizationValidationSchema,
|
...this.commonOrganizationValidationSchema,
|
||||||
check('tax_number').optional({ nullable: true }).isString().trim(),
|
check('tax_number')
|
||||||
|
.optional({ nullable: true })
|
||||||
|
.isString()
|
||||||
|
.trim()
|
||||||
|
.escape(),
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -100,8 +100,8 @@ export default class BillsController extends BaseController {
|
|||||||
*/
|
*/
|
||||||
private get billValidationSchema() {
|
private get billValidationSchema() {
|
||||||
return [
|
return [
|
||||||
check('bill_number').exists().trim(),
|
check('bill_number').exists().trim().escape(),
|
||||||
check('reference_no').optional().trim(),
|
check('reference_no').optional().trim().escape(),
|
||||||
check('bill_date').exists().isISO8601(),
|
check('bill_date').exists().isISO8601(),
|
||||||
check('due_date').optional().isISO8601(),
|
check('due_date').optional().isISO8601(),
|
||||||
|
|
||||||
@@ -112,7 +112,7 @@ export default class BillsController extends BaseController {
|
|||||||
check('branch_id').optional({ nullable: true }).isNumeric().toInt(),
|
check('branch_id').optional({ nullable: true }).isNumeric().toInt(),
|
||||||
check('project_id').optional({ nullable: true }).isNumeric().toInt(),
|
check('project_id').optional({ nullable: true }).isNumeric().toInt(),
|
||||||
|
|
||||||
check('note').optional().trim(),
|
check('note').optional().trim().escape(),
|
||||||
check('open').default(false).isBoolean().toBoolean(),
|
check('open').default(false).isBoolean().toBoolean(),
|
||||||
|
|
||||||
check('is_inclusive_tax').default(false).isBoolean().toBoolean(),
|
check('is_inclusive_tax').default(false).isBoolean().toBoolean(),
|
||||||
@@ -126,7 +126,10 @@ export default class BillsController extends BaseController {
|
|||||||
.optional({ nullable: true })
|
.optional({ nullable: true })
|
||||||
.isNumeric()
|
.isNumeric()
|
||||||
.toFloat(),
|
.toFloat(),
|
||||||
check('entries.*.description').optional({ nullable: true }).trim(),
|
check('entries.*.description')
|
||||||
|
.optional({ nullable: true })
|
||||||
|
.trim()
|
||||||
|
.escape(),
|
||||||
check('entries.*.landed_cost')
|
check('entries.*.landed_cost')
|
||||||
.optional({ nullable: true })
|
.optional({ nullable: true })
|
||||||
.isBoolean()
|
.isBoolean()
|
||||||
@@ -138,6 +141,7 @@ export default class BillsController extends BaseController {
|
|||||||
check('entries.*.tax_code')
|
check('entries.*.tax_code')
|
||||||
.optional({ nullable: true })
|
.optional({ nullable: true })
|
||||||
.trim()
|
.trim()
|
||||||
|
.escape()
|
||||||
.isString(),
|
.isString(),
|
||||||
check('entries.*.tax_rate_id')
|
check('entries.*.tax_rate_id')
|
||||||
.optional({ nullable: true })
|
.optional({ nullable: true })
|
||||||
@@ -154,8 +158,8 @@ export default class BillsController extends BaseController {
|
|||||||
*/
|
*/
|
||||||
private get billEditValidationSchema() {
|
private get billEditValidationSchema() {
|
||||||
return [
|
return [
|
||||||
check('bill_number').optional().trim(),
|
check('bill_number').optional().trim().escape(),
|
||||||
check('reference_no').optional().trim(),
|
check('reference_no').optional().trim().escape(),
|
||||||
check('bill_date').exists().isISO8601(),
|
check('bill_date').exists().isISO8601(),
|
||||||
check('due_date').optional().isISO8601(),
|
check('due_date').optional().isISO8601(),
|
||||||
|
|
||||||
@@ -166,7 +170,7 @@ export default class BillsController extends BaseController {
|
|||||||
check('branch_id').optional({ nullable: true }).isNumeric().toInt(),
|
check('branch_id').optional({ nullable: true }).isNumeric().toInt(),
|
||||||
check('project_id').optional({ nullable: true }).isNumeric().toInt(),
|
check('project_id').optional({ nullable: true }).isNumeric().toInt(),
|
||||||
|
|
||||||
check('note').optional().trim(),
|
check('note').optional().trim().escape(),
|
||||||
check('open').default(false).isBoolean().toBoolean(),
|
check('open').default(false).isBoolean().toBoolean(),
|
||||||
|
|
||||||
check('entries').isArray({ min: 1 }),
|
check('entries').isArray({ min: 1 }),
|
||||||
@@ -180,7 +184,10 @@ export default class BillsController extends BaseController {
|
|||||||
.optional({ nullable: true })
|
.optional({ nullable: true })
|
||||||
.isNumeric()
|
.isNumeric()
|
||||||
.toFloat(),
|
.toFloat(),
|
||||||
check('entries.*.description').optional({ nullable: true }).trim(),
|
check('entries.*.description')
|
||||||
|
.optional({ nullable: true })
|
||||||
|
.trim()
|
||||||
|
.escape(),
|
||||||
check('entries.*.landed_cost')
|
check('entries.*.landed_cost')
|
||||||
.optional({ nullable: true })
|
.optional({ nullable: true })
|
||||||
.isBoolean()
|
.isBoolean()
|
||||||
@@ -215,8 +222,8 @@ export default class BillsController extends BaseController {
|
|||||||
|
|
||||||
private get dueBillsListingValidationSchema() {
|
private get dueBillsListingValidationSchema() {
|
||||||
return [
|
return [
|
||||||
query('vendor_id').optional().trim(),
|
query('vendor_id').optional().trim().escape(),
|
||||||
query('payment_made_id').optional().trim(),
|
query('payment_made_id').optional().trim().escape(),
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -111,15 +111,14 @@ export default class BillsPayments extends BaseController {
|
|||||||
check('vendor_id').exists().isNumeric().toInt(),
|
check('vendor_id').exists().isNumeric().toInt(),
|
||||||
check('exchange_rate').optional().isFloat({ gt: 0 }).toFloat(),
|
check('exchange_rate').optional().isFloat({ gt: 0 }).toFloat(),
|
||||||
|
|
||||||
check('amount').exists().isNumeric().toFloat(),
|
|
||||||
check('payment_account_id').exists().isNumeric().toInt(),
|
check('payment_account_id').exists().isNumeric().toInt(),
|
||||||
check('payment_number').optional({ nullable: true }).trim(),
|
check('payment_number').optional({ nullable: true }).trim().escape(),
|
||||||
check('payment_date').exists(),
|
check('payment_date').exists(),
|
||||||
check('statement').optional().trim(),
|
check('statement').optional().trim().escape(),
|
||||||
check('reference').optional().trim(),
|
check('reference').optional().trim().escape(),
|
||||||
check('branch_id').optional({ nullable: true }).isNumeric().toInt(),
|
check('branch_id').optional({ nullable: true }).isNumeric().toInt(),
|
||||||
|
|
||||||
check('entries').exists().isArray(),
|
check('entries').exists().isArray({ min: 1 }),
|
||||||
check('entries.*.index').optional().isNumeric().toInt(),
|
check('entries.*.index').optional().isNumeric().toInt(),
|
||||||
check('entries.*.bill_id').exists().isNumeric().toInt(),
|
check('entries.*.bill_id').exists().isNumeric().toInt(),
|
||||||
check('entries.*.payment_amount').exists().isNumeric().toFloat(),
|
check('entries.*.payment_amount').exists().isNumeric().toFloat(),
|
||||||
|
|||||||
@@ -156,10 +156,13 @@ export default class VendorCreditController extends BaseController {
|
|||||||
check('vendor_id').exists().isNumeric().toInt(),
|
check('vendor_id').exists().isNumeric().toInt(),
|
||||||
check('exchange_rate').optional().isFloat({ gt: 0 }).toFloat(),
|
check('exchange_rate').optional().isFloat({ gt: 0 }).toFloat(),
|
||||||
|
|
||||||
check('vendor_credit_number').optional({ nullable: true }).trim(),
|
check('vendor_credit_number')
|
||||||
check('reference_no').optional().trim(),
|
.optional({ nullable: true })
|
||||||
|
.trim()
|
||||||
|
.escape(),
|
||||||
|
check('reference_no').optional().trim().escape(),
|
||||||
check('vendor_credit_date').exists().isISO8601().toDate(),
|
check('vendor_credit_date').exists().isISO8601().toDate(),
|
||||||
check('note').optional().trim(),
|
check('note').optional().trim().escape(),
|
||||||
check('open').default(false).isBoolean().toBoolean(),
|
check('open').default(false).isBoolean().toBoolean(),
|
||||||
|
|
||||||
check('warehouse_id').optional({ nullable: true }).isNumeric().toInt(),
|
check('warehouse_id').optional({ nullable: true }).isNumeric().toInt(),
|
||||||
@@ -175,7 +178,10 @@ export default class VendorCreditController extends BaseController {
|
|||||||
.optional({ nullable: true })
|
.optional({ nullable: true })
|
||||||
.isNumeric()
|
.isNumeric()
|
||||||
.toFloat(),
|
.toFloat(),
|
||||||
check('entries.*.description').optional({ nullable: true }).trim(),
|
check('entries.*.description')
|
||||||
|
.optional({ nullable: true })
|
||||||
|
.trim()
|
||||||
|
.escape(),
|
||||||
check('entries.*.warehouse_id')
|
check('entries.*.warehouse_id')
|
||||||
.optional({ nullable: true })
|
.optional({ nullable: true })
|
||||||
.isNumeric()
|
.isNumeric()
|
||||||
@@ -196,10 +202,13 @@ export default class VendorCreditController extends BaseController {
|
|||||||
check('vendor_id').exists().isNumeric().toInt(),
|
check('vendor_id').exists().isNumeric().toInt(),
|
||||||
check('exchange_rate').optional().isFloat({ gt: 0 }).toFloat(),
|
check('exchange_rate').optional().isFloat({ gt: 0 }).toFloat(),
|
||||||
|
|
||||||
check('vendor_credit_number').optional({ nullable: true }).trim(),
|
check('vendor_credit_number')
|
||||||
check('reference_no').optional().trim(),
|
.optional({ nullable: true })
|
||||||
|
.trim()
|
||||||
|
.escape(),
|
||||||
|
check('reference_no').optional().trim().escape(),
|
||||||
check('vendor_credit_date').exists().isISO8601().toDate(),
|
check('vendor_credit_date').exists().isISO8601().toDate(),
|
||||||
check('note').optional().trim(),
|
check('note').optional().trim().escape(),
|
||||||
|
|
||||||
check('warehouse_id').optional({ nullable: true }).isNumeric().toInt(),
|
check('warehouse_id').optional({ nullable: true }).isNumeric().toInt(),
|
||||||
check('branch_id').optional({ nullable: true }).isNumeric().toInt(),
|
check('branch_id').optional({ nullable: true }).isNumeric().toInt(),
|
||||||
@@ -214,7 +223,10 @@ export default class VendorCreditController extends BaseController {
|
|||||||
.optional({ nullable: true })
|
.optional({ nullable: true })
|
||||||
.isNumeric()
|
.isNumeric()
|
||||||
.toFloat(),
|
.toFloat(),
|
||||||
check('entries.*.description').optional({ nullable: true }).trim(),
|
check('entries.*.description')
|
||||||
|
.optional({ nullable: true })
|
||||||
|
.trim()
|
||||||
|
.escape(),
|
||||||
check('entries.*.warehouse_id')
|
check('entries.*.warehouse_id')
|
||||||
.optional({ nullable: true })
|
.optional({ nullable: true })
|
||||||
.isNumeric()
|
.isNumeric()
|
||||||
|
|||||||
@@ -18,7 +18,9 @@ export default class ResourceController extends BaseController {
|
|||||||
|
|
||||||
router.get(
|
router.get(
|
||||||
'/:resource_model/meta',
|
'/:resource_model/meta',
|
||||||
[param('resource_model').exists().trim()],
|
[
|
||||||
|
param('resource_model').exists().trim().escape()
|
||||||
|
],
|
||||||
this.asyncMiddleware(this.resourceMeta.bind(this)),
|
this.asyncMiddleware(this.resourceMeta.bind(this)),
|
||||||
this.handleServiceErrors
|
this.handleServiceErrors
|
||||||
);
|
);
|
||||||
@@ -46,7 +48,9 @@ export default class ResourceController extends BaseController {
|
|||||||
resourceModel
|
resourceModel
|
||||||
);
|
);
|
||||||
return res.status(200).send({
|
return res.status(200).send({
|
||||||
resource_meta: this.transfromToResponse(resourceMeta),
|
resource_meta: this.transfromToResponse(
|
||||||
|
resourceMeta,
|
||||||
|
),
|
||||||
});
|
});
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
next(error);
|
next(error);
|
||||||
|
|||||||
@@ -210,9 +210,9 @@ export default class PaymentReceivesController extends BaseController {
|
|||||||
|
|
||||||
check('credit_note_date').exists().isISO8601().toDate(),
|
check('credit_note_date').exists().isISO8601().toDate(),
|
||||||
check('reference_no').optional(),
|
check('reference_no').optional(),
|
||||||
check('credit_note_number').optional({ nullable: true }).trim(),
|
check('credit_note_number').optional({ nullable: true }).trim().escape(),
|
||||||
check('note').optional().trim(),
|
check('note').optional().trim().escape(),
|
||||||
check('terms_conditions').optional().trim(),
|
check('terms_conditions').optional().trim().escape(),
|
||||||
check('open').default(false).isBoolean().toBoolean(),
|
check('open').default(false).isBoolean().toBoolean(),
|
||||||
|
|
||||||
check('warehouse_id').optional({ nullable: true }).isNumeric().toInt(),
|
check('warehouse_id').optional({ nullable: true }).isNumeric().toInt(),
|
||||||
@@ -228,7 +228,10 @@ export default class PaymentReceivesController extends BaseController {
|
|||||||
.optional({ nullable: true })
|
.optional({ nullable: true })
|
||||||
.isNumeric()
|
.isNumeric()
|
||||||
.toFloat(),
|
.toFloat(),
|
||||||
check('entries.*.description').optional({ nullable: true }).trim(),
|
check('entries.*.description')
|
||||||
|
.optional({ nullable: true })
|
||||||
|
.trim()
|
||||||
|
.escape(),
|
||||||
check('entries.*.warehouse_id')
|
check('entries.*.warehouse_id')
|
||||||
.optional({ nullable: true })
|
.optional({ nullable: true })
|
||||||
.isNumeric()
|
.isNumeric()
|
||||||
|
|||||||
@@ -9,9 +9,9 @@ import {
|
|||||||
} from '@/interfaces';
|
} from '@/interfaces';
|
||||||
import BaseController from '@/api/controllers/BaseController';
|
import BaseController from '@/api/controllers/BaseController';
|
||||||
import asyncMiddleware from '@/api/middleware/asyncMiddleware';
|
import asyncMiddleware from '@/api/middleware/asyncMiddleware';
|
||||||
import PaymentsReceivedPages from '@/services/Sales/PaymentReceived/PaymentsReceivedPages';
|
import PaymentReceivesPages from '@/services/Sales/PaymentReceives/PaymentReceivesPages';
|
||||||
import { PaymentReceivesApplication } from '@/services/Sales/PaymentReceived/PaymentReceivedApplication';
|
|
||||||
import DynamicListingService from '@/services/DynamicListing/DynamicListService';
|
import DynamicListingService from '@/services/DynamicListing/DynamicListService';
|
||||||
|
import { PaymentReceivesApplication } from '@/services/Sales/PaymentReceives/PaymentReceivesApplication';
|
||||||
import CheckPolicies from '@/api/middleware/CheckPolicies';
|
import CheckPolicies from '@/api/middleware/CheckPolicies';
|
||||||
import { ServiceError } from '@/exceptions';
|
import { ServiceError } from '@/exceptions';
|
||||||
import { ACCEPT_TYPE } from '@/interfaces/Http';
|
import { ACCEPT_TYPE } from '@/interfaces/Http';
|
||||||
@@ -22,7 +22,7 @@ export default class PaymentReceivesController extends BaseController {
|
|||||||
private paymentReceiveApplication: PaymentReceivesApplication;
|
private paymentReceiveApplication: PaymentReceivesApplication;
|
||||||
|
|
||||||
@Inject()
|
@Inject()
|
||||||
private PaymentsReceivedPages: PaymentsReceivedPages;
|
private PaymentReceivesPages: PaymentReceivesPages;
|
||||||
|
|
||||||
@Inject()
|
@Inject()
|
||||||
private dynamicListService: DynamicListingService;
|
private dynamicListService: DynamicListingService;
|
||||||
@@ -150,16 +150,16 @@ export default class PaymentReceivesController extends BaseController {
|
|||||||
check('customer_id').exists().isNumeric().toInt(),
|
check('customer_id').exists().isNumeric().toInt(),
|
||||||
check('exchange_rate').optional().isFloat({ gt: 0 }).toFloat(),
|
check('exchange_rate').optional().isFloat({ gt: 0 }).toFloat(),
|
||||||
|
|
||||||
check('amount').exists().isNumeric().toFloat(),
|
|
||||||
check('payment_date').exists(),
|
check('payment_date').exists(),
|
||||||
check('reference_no').optional(),
|
check('reference_no').optional(),
|
||||||
check('deposit_account_id').exists().isNumeric().toInt(),
|
check('deposit_account_id').exists().isNumeric().toInt(),
|
||||||
check('payment_receive_no').optional({ nullable: true }).trim(),
|
check('payment_receive_no').optional({ nullable: true }).trim().escape(),
|
||||||
check('statement').optional().trim(),
|
check('statement').optional().trim().escape(),
|
||||||
|
|
||||||
check('branch_id').optional({ nullable: true }).isNumeric().toInt(),
|
check('branch_id').optional({ nullable: true }).isNumeric().toInt(),
|
||||||
|
|
||||||
check('entries').isArray({}),
|
check('entries').isArray({ min: 1 }),
|
||||||
|
|
||||||
check('entries.*.id').optional({ nullable: true }).isNumeric().toInt(),
|
check('entries.*.id').optional({ nullable: true }).isNumeric().toInt(),
|
||||||
check('entries.*.index').optional().isNumeric().toInt(),
|
check('entries.*.index').optional().isNumeric().toInt(),
|
||||||
check('entries.*.invoice_id').exists().isNumeric().toInt(),
|
check('entries.*.invoice_id').exists().isNumeric().toInt(),
|
||||||
@@ -176,6 +176,7 @@ export default class PaymentReceivesController extends BaseController {
|
|||||||
private get validatePaymentReceiveList(): ValidationChain[] {
|
private get validatePaymentReceiveList(): ValidationChain[] {
|
||||||
return [
|
return [
|
||||||
query('stringified_filter_roles').optional().isJSON(),
|
query('stringified_filter_roles').optional().isJSON(),
|
||||||
|
|
||||||
query('view_slug').optional({ nullable: true }).isString().trim(),
|
query('view_slug').optional({ nullable: true }).isString().trim(),
|
||||||
|
|
||||||
query('column_sort_by').optional(),
|
query('column_sort_by').optional(),
|
||||||
@@ -229,7 +230,7 @@ export default class PaymentReceivesController extends BaseController {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
const storedPaymentReceive =
|
const storedPaymentReceive =
|
||||||
await this.paymentReceiveApplication.createPaymentReceived(
|
await this.paymentReceiveApplication.createPaymentReceive(
|
||||||
tenantId,
|
tenantId,
|
||||||
paymentReceive,
|
paymentReceive,
|
||||||
user
|
user
|
||||||
@@ -376,7 +377,7 @@ export default class PaymentReceivesController extends BaseController {
|
|||||||
const { customerId } = this.matchedQueryData(req);
|
const { customerId } = this.matchedQueryData(req);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const entries = await this.PaymentsReceivedPages.getNewPageEntries(
|
const entries = await this.PaymentReceivesPages.getNewPageEntries(
|
||||||
tenantId,
|
tenantId,
|
||||||
customerId
|
customerId
|
||||||
);
|
);
|
||||||
@@ -404,7 +405,7 @@ export default class PaymentReceivesController extends BaseController {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
const { paymentReceive, entries } =
|
const { paymentReceive, entries } =
|
||||||
await this.PaymentsReceivedPages.getPaymentReceiveEditPage(
|
await this.PaymentReceivesPages.getPaymentReceiveEditPage(
|
||||||
tenantId,
|
tenantId,
|
||||||
paymentReceiveId,
|
paymentReceiveId,
|
||||||
user
|
user
|
||||||
|
|||||||
@@ -155,7 +155,7 @@ export default class SalesEstimatesController extends BaseController {
|
|||||||
check('estimate_date').exists().isISO8601().toDate(),
|
check('estimate_date').exists().isISO8601().toDate(),
|
||||||
check('expiration_date').exists().isISO8601().toDate(),
|
check('expiration_date').exists().isISO8601().toDate(),
|
||||||
check('reference').optional(),
|
check('reference').optional(),
|
||||||
check('estimate_number').optional().trim(),
|
check('estimate_number').optional().trim().escape(),
|
||||||
check('delivered').default(false).isBoolean().toBoolean(),
|
check('delivered').default(false).isBoolean().toBoolean(),
|
||||||
|
|
||||||
check('exchange_rate').optional().isFloat({ gt: 0 }).toFloat(),
|
check('exchange_rate').optional().isFloat({ gt: 0 }).toFloat(),
|
||||||
@@ -170,7 +170,8 @@ export default class SalesEstimatesController extends BaseController {
|
|||||||
check('entries.*.rate').exists().isNumeric().toFloat(),
|
check('entries.*.rate').exists().isNumeric().toFloat(),
|
||||||
check('entries.*.description')
|
check('entries.*.description')
|
||||||
.optional({ nullable: true })
|
.optional({ nullable: true })
|
||||||
.trim(),
|
.trim()
|
||||||
|
.escape(),
|
||||||
check('entries.*.discount')
|
check('entries.*.discount')
|
||||||
.optional({ nullable: true })
|
.optional({ nullable: true })
|
||||||
.isNumeric()
|
.isNumeric()
|
||||||
@@ -180,9 +181,9 @@ export default class SalesEstimatesController extends BaseController {
|
|||||||
.isNumeric()
|
.isNumeric()
|
||||||
.toInt(),
|
.toInt(),
|
||||||
|
|
||||||
check('note').optional().trim(),
|
check('note').optional().trim().escape(),
|
||||||
check('terms_conditions').optional().trim(),
|
check('terms_conditions').optional().trim().escape(),
|
||||||
check('send_to_email').optional().trim(),
|
check('send_to_email').optional().trim().escape(),
|
||||||
|
|
||||||
check('attachments').isArray().optional(),
|
check('attachments').isArray().optional(),
|
||||||
check('attachments.*.key').exists().isString(),
|
check('attachments.*.key').exists().isString(),
|
||||||
|
|||||||
@@ -200,12 +200,12 @@ export default class SaleInvoicesController extends BaseController {
|
|||||||
check('customer_id').exists().isNumeric().toInt(),
|
check('customer_id').exists().isNumeric().toInt(),
|
||||||
check('invoice_date').exists().isISO8601().toDate(),
|
check('invoice_date').exists().isISO8601().toDate(),
|
||||||
check('due_date').exists().isISO8601().toDate(),
|
check('due_date').exists().isISO8601().toDate(),
|
||||||
check('invoice_no').optional().trim(),
|
check('invoice_no').optional().trim().escape(),
|
||||||
check('reference_no').optional().trim(),
|
check('reference_no').optional().trim().escape(),
|
||||||
check('delivered').default(false).isBoolean().toBoolean(),
|
check('delivered').default(false).isBoolean().toBoolean(),
|
||||||
|
|
||||||
check('invoice_message').optional().trim(),
|
check('invoice_message').optional().trim().escape(),
|
||||||
check('terms_conditions').optional().trim(),
|
check('terms_conditions').optional().trim().escape(),
|
||||||
|
|
||||||
check('exchange_rate').optional().isFloat({ gt: 0 }).toFloat(),
|
check('exchange_rate').optional().isFloat({ gt: 0 }).toFloat(),
|
||||||
|
|
||||||
@@ -226,10 +226,12 @@ export default class SaleInvoicesController extends BaseController {
|
|||||||
.toFloat(),
|
.toFloat(),
|
||||||
check('entries.*.description')
|
check('entries.*.description')
|
||||||
.optional({ nullable: true })
|
.optional({ nullable: true })
|
||||||
.trim(),
|
.trim()
|
||||||
|
.escape(),
|
||||||
check('entries.*.tax_code')
|
check('entries.*.tax_code')
|
||||||
.optional({ nullable: true })
|
.optional({ nullable: true })
|
||||||
.trim()
|
.trim()
|
||||||
|
.escape()
|
||||||
.isString(),
|
.isString(),
|
||||||
check('entries.*.tax_rate_id')
|
check('entries.*.tax_rate_id')
|
||||||
.optional({ nullable: true })
|
.optional({ nullable: true })
|
||||||
|
|||||||
@@ -130,8 +130,8 @@ export default class SalesReceiptsController extends BaseController {
|
|||||||
|
|
||||||
check('deposit_account_id').exists().isNumeric().toInt(),
|
check('deposit_account_id').exists().isNumeric().toInt(),
|
||||||
check('receipt_date').exists().isISO8601(),
|
check('receipt_date').exists().isISO8601(),
|
||||||
check('receipt_number').optional().trim(),
|
check('receipt_number').optional().trim().escape(),
|
||||||
check('reference_no').optional().trim(),
|
check('reference_no').optional().trim().escape(),
|
||||||
check('closed').default(false).isBoolean().toBoolean(),
|
check('closed').default(false).isBoolean().toBoolean(),
|
||||||
|
|
||||||
check('warehouse_id').optional({ nullable: true }).isNumeric().toInt(),
|
check('warehouse_id').optional({ nullable: true }).isNumeric().toInt(),
|
||||||
@@ -150,13 +150,14 @@ export default class SalesReceiptsController extends BaseController {
|
|||||||
.toInt(),
|
.toInt(),
|
||||||
check('entries.*.description')
|
check('entries.*.description')
|
||||||
.optional({ nullable: true })
|
.optional({ nullable: true })
|
||||||
.trim(),
|
.trim()
|
||||||
|
.escape(),
|
||||||
check('entries.*.warehouse_id')
|
check('entries.*.warehouse_id')
|
||||||
.optional({ nullable: true })
|
.optional({ nullable: true })
|
||||||
.isNumeric()
|
.isNumeric()
|
||||||
.toInt(),
|
.toInt(),
|
||||||
check('receipt_message').optional().trim(),
|
check('receipt_message').optional().trim().escape(),
|
||||||
check('statement').optional().trim(),
|
check('statement').optional().trim().escape(),
|
||||||
check('attachments').isArray().optional(),
|
check('attachments').isArray().optional(),
|
||||||
check('attachments.*.key').exists().isString(),
|
check('attachments.*.key').exists().isString(),
|
||||||
];
|
];
|
||||||
|
|||||||
@@ -52,7 +52,10 @@ export default class SettingsController extends BaseController {
|
|||||||
* Retrieve the application options from the storage.
|
* Retrieve the application options from the storage.
|
||||||
*/
|
*/
|
||||||
private get getSettingsSchema() {
|
private get getSettingsSchema() {
|
||||||
return [query('key').optional().trim(), query('group').optional().trim()];
|
return [
|
||||||
|
query('key').optional().trim().escape(),
|
||||||
|
query('group').optional().trim().escape(),
|
||||||
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -8,7 +8,6 @@ import SubscriptionService from '@/services/Subscription/SubscriptionService';
|
|||||||
import asyncMiddleware from '@/api/middleware/asyncMiddleware';
|
import asyncMiddleware from '@/api/middleware/asyncMiddleware';
|
||||||
import BaseController from '../BaseController';
|
import BaseController from '../BaseController';
|
||||||
import { LemonSqueezyService } from '@/services/Subscription/LemonSqueezyService';
|
import { LemonSqueezyService } from '@/services/Subscription/LemonSqueezyService';
|
||||||
import { SubscriptionApplication } from '@/services/Subscription/SubscriptionApplication';
|
|
||||||
|
|
||||||
@Service()
|
@Service()
|
||||||
export class SubscriptionController extends BaseController {
|
export class SubscriptionController extends BaseController {
|
||||||
@@ -18,9 +17,6 @@ export class SubscriptionController extends BaseController {
|
|||||||
@Inject()
|
@Inject()
|
||||||
private lemonSqueezyService: LemonSqueezyService;
|
private lemonSqueezyService: LemonSqueezyService;
|
||||||
|
|
||||||
@Inject()
|
|
||||||
private subscriptionApp: SubscriptionApplication;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Router constructor.
|
* Router constructor.
|
||||||
*/
|
*/
|
||||||
@@ -37,14 +33,6 @@ export class SubscriptionController extends BaseController {
|
|||||||
this.validationResult,
|
this.validationResult,
|
||||||
this.getCheckoutUrl.bind(this)
|
this.getCheckoutUrl.bind(this)
|
||||||
);
|
);
|
||||||
router.post('/cancel', asyncMiddleware(this.cancelSubscription.bind(this)));
|
|
||||||
router.post('/resume', asyncMiddleware(this.resumeSubscription.bind(this)));
|
|
||||||
router.post(
|
|
||||||
'/change',
|
|
||||||
[body('variant_id').exists().trim()],
|
|
||||||
this.validationResult,
|
|
||||||
asyncMiddleware(this.changeSubscriptionPlan.bind(this))
|
|
||||||
);
|
|
||||||
router.get('/', asyncMiddleware(this.getSubscriptions.bind(this)));
|
router.get('/', asyncMiddleware(this.getSubscriptions.bind(this)));
|
||||||
|
|
||||||
return router;
|
return router;
|
||||||
@@ -97,84 +85,4 @@ export class SubscriptionController extends BaseController {
|
|||||||
next(error);
|
next(error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Cancels the subscription of the current organization.
|
|
||||||
* @param {Request} req
|
|
||||||
* @param {Response} res
|
|
||||||
* @param {NextFunction} next
|
|
||||||
* @returns {Promise<Response|null>}
|
|
||||||
*/
|
|
||||||
private async cancelSubscription(
|
|
||||||
req: Request,
|
|
||||||
res: Response,
|
|
||||||
next: NextFunction
|
|
||||||
) {
|
|
||||||
const { tenantId } = req;
|
|
||||||
|
|
||||||
try {
|
|
||||||
await this.subscriptionApp.cancelSubscription(tenantId);
|
|
||||||
|
|
||||||
return res.status(200).send({
|
|
||||||
status: 200,
|
|
||||||
message: 'The organization subscription has been canceled.',
|
|
||||||
});
|
|
||||||
} catch (error) {
|
|
||||||
next(error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Resumes the subscription of the current organization.
|
|
||||||
* @param {Request} req
|
|
||||||
* @param {Response} res
|
|
||||||
* @param {NextFunction} next
|
|
||||||
* @returns {Promise<Response | null>}
|
|
||||||
*/
|
|
||||||
private async resumeSubscription(
|
|
||||||
req: Request,
|
|
||||||
res: Response,
|
|
||||||
next: NextFunction
|
|
||||||
) {
|
|
||||||
const { tenantId } = req;
|
|
||||||
|
|
||||||
try {
|
|
||||||
await this.subscriptionApp.resumeSubscription(tenantId);
|
|
||||||
|
|
||||||
return res.status(200).send({
|
|
||||||
status: 200,
|
|
||||||
message: 'The organization subscription has been resumed.',
|
|
||||||
});
|
|
||||||
} catch (error) {
|
|
||||||
next(error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Changes the main subscription plan of the current organization.
|
|
||||||
* @param {Request} req
|
|
||||||
* @param {Response} res
|
|
||||||
* @param {NextFunction} next
|
|
||||||
* @returns {Promise<Response | null>}
|
|
||||||
*/
|
|
||||||
public async changeSubscriptionPlan(
|
|
||||||
req: Request,
|
|
||||||
res: Response,
|
|
||||||
next: NextFunction
|
|
||||||
) {
|
|
||||||
const { tenantId } = req;
|
|
||||||
const body = this.matchedBodyData(req);
|
|
||||||
|
|
||||||
try {
|
|
||||||
await this.subscriptionApp.changeSubscriptionPlan(
|
|
||||||
tenantId,
|
|
||||||
body.variantId
|
|
||||||
);
|
|
||||||
return res.status(200).send({
|
|
||||||
message: 'The subscription plan has been changed.',
|
|
||||||
});
|
|
||||||
} catch (error) {
|
|
||||||
next(error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ export default class ViewsController extends BaseController {
|
|||||||
* Custom views list validation schema.
|
* Custom views list validation schema.
|
||||||
*/
|
*/
|
||||||
get viewsListSchemaValidation() {
|
get viewsListSchemaValidation() {
|
||||||
return [param('resource_model').exists().trim()];
|
return [param('resource_model').exists().trim().escape()];
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ export class Webhooks extends BaseController {
|
|||||||
*/
|
*/
|
||||||
public async lemonWebhooks(req: Request, res: Response, next: NextFunction) {
|
public async lemonWebhooks(req: Request, res: Response, next: NextFunction) {
|
||||||
const data = req.body;
|
const data = req.body;
|
||||||
const signature = req.headers['x-signature'] as string ?? '';
|
const signature = req.headers['x-signature'] ?? '';
|
||||||
const rawBody = req.rawBody;
|
const rawBody = req.rawBody;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|||||||
@@ -63,7 +63,6 @@ import { BankingController } from './controllers/Banking/BankingController';
|
|||||||
import { Webhooks } from './controllers/Webhooks/Webhooks';
|
import { Webhooks } from './controllers/Webhooks/Webhooks';
|
||||||
import { ExportController } from './controllers/Export/ExportController';
|
import { ExportController } from './controllers/Export/ExportController';
|
||||||
import { AttachmentsController } from './controllers/Attachments/AttachmentsController';
|
import { AttachmentsController } from './controllers/Attachments/AttachmentsController';
|
||||||
import { OneClickDemoController } from './controllers/OneClickDemo/OneClickDemoController';
|
|
||||||
|
|
||||||
export default () => {
|
export default () => {
|
||||||
const app = Router();
|
const app = Router();
|
||||||
@@ -81,7 +80,6 @@ export default () => {
|
|||||||
app.use('/jobs', Container.get(Jobs).router());
|
app.use('/jobs', Container.get(Jobs).router());
|
||||||
app.use('/account', Container.get(Account).router());
|
app.use('/account', Container.get(Account).router());
|
||||||
app.use('/webhooks', Container.get(Webhooks).router());
|
app.use('/webhooks', Container.get(Webhooks).router());
|
||||||
app.use('/demo', Container.get(OneClickDemoController).router())
|
|
||||||
|
|
||||||
// - Dashboard routes.
|
// - Dashboard routes.
|
||||||
// ---------------------------
|
// ---------------------------
|
||||||
|
|||||||
@@ -1,21 +1,11 @@
|
|||||||
import { Container } from 'typedi';
|
|
||||||
import { Request, Response, NextFunction } from 'express';
|
import { Request, Response, NextFunction } from 'express';
|
||||||
|
import { Container } from 'typedi';
|
||||||
import SettingsStore from '@/services/Settings/SettingsStore';
|
import SettingsStore from '@/services/Settings/SettingsStore';
|
||||||
|
|
||||||
export default async (req: Request, res: Response, next: NextFunction) => {
|
export default async (req: Request, res: Response, next: NextFunction) => {
|
||||||
const { tenantId } = req.user;
|
const { tenantId } = req.user;
|
||||||
|
|
||||||
const settings = await initializeTenantSettings(tenantId);
|
const Logger = Container.get('logger');
|
||||||
req.settings = settings;
|
|
||||||
|
|
||||||
res.on('finish', async () => {
|
|
||||||
await settings.save();
|
|
||||||
});
|
|
||||||
next();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
export const initializeTenantSettings = async (tenantId: number) => {
|
|
||||||
const tenantContainer = Container.of(`tenant-${tenantId}`);
|
const tenantContainer = Container.of(`tenant-${tenantId}`);
|
||||||
|
|
||||||
if (tenantContainer && !tenantContainer.has('settings')) {
|
if (tenantContainer && !tenantContainer.has('settings')) {
|
||||||
@@ -28,5 +18,10 @@ export const initializeTenantSettings = async (tenantId: number) => {
|
|||||||
|
|
||||||
await settings.load();
|
await settings.load();
|
||||||
|
|
||||||
return settings;
|
req.settings = settings;
|
||||||
|
|
||||||
|
res.on('finish', async () => {
|
||||||
|
await settings.save();
|
||||||
|
});
|
||||||
|
next();
|
||||||
}
|
}
|
||||||
@@ -1,8 +1,6 @@
|
|||||||
import { Container } from 'typedi';
|
import { Container } from 'typedi';
|
||||||
import { Request, Response, NextFunction } from 'express';
|
import { Request, Response, NextFunction } from 'express';
|
||||||
|
|
||||||
const SupportedMethods = ['POST', 'PUT'];
|
|
||||||
|
|
||||||
export default (subscriptionSlug = 'main') =>
|
export default (subscriptionSlug = 'main') =>
|
||||||
async (req: Request, res: Response, next: NextFunction) => {
|
async (req: Request, res: Response, next: NextFunction) => {
|
||||||
const { tenant, tenantId } = req;
|
const { tenant, tenantId } = req;
|
||||||
@@ -21,10 +19,8 @@ export default (subscriptionSlug = 'main') =>
|
|||||||
errors: [{ type: 'TENANT.HAS.NO.SUBSCRIPTION' }],
|
errors: [{ type: 'TENANT.HAS.NO.SUBSCRIPTION' }],
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
const isMethodSupported = SupportedMethods.includes(req.method);
|
// Validate in case the subscription is inactive.
|
||||||
const isSubscriptionInactive = subscription.inactive();
|
else if (subscription.inactive()) {
|
||||||
|
|
||||||
if (isMethodSupported && isSubscriptionInactive) {
|
|
||||||
return res.boom.badRequest(null, {
|
return res.boom.badRequest(null, {
|
||||||
errors: [{ type: 'ORGANIZATION.SUBSCRIPTION.INACTIVE' }],
|
errors: [{ type: 'ORGANIZATION.SUBSCRIPTION.INACTIVE' }],
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -4,7 +4,6 @@ import { Request } from 'express';
|
|||||||
import TenancyService from '@/services/Tenancy/TenancyService';
|
import TenancyService from '@/services/Tenancy/TenancyService';
|
||||||
import TenantsManagerService from '@/services/Tenancy/TenantsManager';
|
import TenantsManagerService from '@/services/Tenancy/TenantsManager';
|
||||||
import rtlDetect from 'rtl-detect';
|
import rtlDetect from 'rtl-detect';
|
||||||
import { Tenant } from '@/system/models';
|
|
||||||
|
|
||||||
export default (req: Request, tenant: ITenant) => {
|
export default (req: Request, tenant: ITenant) => {
|
||||||
const { id: tenantId, organizationId } = tenant;
|
const { id: tenantId, organizationId } = tenant;
|
||||||
@@ -17,7 +16,7 @@ export default (req: Request, tenant: ITenant) => {
|
|||||||
|
|
||||||
const tenantContainer = tenantServices.tenantContainer(tenantId);
|
const tenantContainer = tenantServices.tenantContainer(tenantId);
|
||||||
|
|
||||||
tenantContainer.set('i18n', injectI18nUtils());
|
tenantContainer.set('i18n', injectI18nUtils(req));
|
||||||
|
|
||||||
const knexInstance = tenantServices.knex(tenantId);
|
const knexInstance = tenantServices.knex(tenantId);
|
||||||
const models = tenantServices.models(tenantId);
|
const models = tenantServices.models(tenantId);
|
||||||
@@ -34,35 +33,14 @@ export default (req: Request, tenant: ITenant) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const injectI18nUtils = (req) => {
|
export const injectI18nUtils = (req) => {
|
||||||
const globalI18n = Container.get('i18n');
|
const locale = req.getLocale();
|
||||||
const locale = globalI18n.getLocale();
|
|
||||||
const direction = rtlDetect.getLangDir(locale);
|
const direction = rtlDetect.getLangDir(locale);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
locale,
|
locale,
|
||||||
__: globalI18n.__,
|
__: req.__,
|
||||||
direction,
|
direction,
|
||||||
isRtl: direction === 'rtl',
|
isRtl: direction === 'rtl',
|
||||||
isLtr: direction === 'ltr',
|
isLtr: direction === 'ltr',
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
export const initalizeTenantServices = async (tenantId: number) => {
|
|
||||||
const tenant = await Tenant.query()
|
|
||||||
.findById(tenantId)
|
|
||||||
.withGraphFetched('metadata');
|
|
||||||
|
|
||||||
const tenantServices = Container.get(TenancyService);
|
|
||||||
const tenantsManager = Container.get(TenantsManagerService);
|
|
||||||
|
|
||||||
// Initialize the knex instance.
|
|
||||||
tenantsManager.setupKnexInstance(tenant);
|
|
||||||
|
|
||||||
const tenantContainer = tenantServices.tenantContainer(tenantId);
|
|
||||||
tenantContainer.set('i18n', injectI18nUtils());
|
|
||||||
|
|
||||||
tenantServices.knex(tenantId);
|
|
||||||
tenantServices.models(tenantId);
|
|
||||||
tenantServices.repositories(tenantId);
|
|
||||||
tenantServices.cache(tenantId);
|
|
||||||
};
|
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ module.exports = {
|
|||||||
*/
|
*/
|
||||||
tenant: {
|
tenant: {
|
||||||
db_client: process.env.TENANT_DB_CLIENT || process.env.DB_CLIENT || 'mysql',
|
db_client: process.env.TENANT_DB_CLIENT || process.env.DB_CLIENT || 'mysql',
|
||||||
db_name_prefix: process.env.TENANT_DB_NAME_PERFIX || 'bigcapital_tenant_',
|
db_name_prefix: process.env.TENANT_DB_NAME_PERFIX,
|
||||||
db_host: process.env.TENANT_DB_HOST || process.env.DB_HOST,
|
db_host: process.env.TENANT_DB_HOST || process.env.DB_HOST,
|
||||||
db_user: process.env.TENANT_DB_USER || process.env.DB_USER,
|
db_user: process.env.TENANT_DB_USER || process.env.DB_USER,
|
||||||
db_password: process.env.TENANT_DB_PASSWORD || process.env.DB_PASSWORD,
|
db_password: process.env.TENANT_DB_PASSWORD || process.env.DB_PASSWORD,
|
||||||
@@ -236,29 +236,5 @@ module.exports = {
|
|||||||
secretAccessKey: process.env.S3_SECRET_ACCESS_KEY,
|
secretAccessKey: process.env.S3_SECRET_ACCESS_KEY,
|
||||||
endpoint: process.env.S3_ENDPOINT,
|
endpoint: process.env.S3_ENDPOINT,
|
||||||
bucket: process.env.S3_BUCKET || 'bigcapital-documents',
|
bucket: process.env.S3_BUCKET || 'bigcapital-documents',
|
||||||
forcePathStyle: parseBoolean(
|
|
||||||
defaultTo(process.env.S3_FORCE_PATH_STYLE, false),
|
|
||||||
false
|
|
||||||
),
|
|
||||||
},
|
},
|
||||||
|
|
||||||
loops: {
|
|
||||||
apiKey: process.env.LOOPS_API_KEY,
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* One-click demo accounts.
|
|
||||||
*/
|
|
||||||
oneClickDemoAccounts: {
|
|
||||||
enable: parseBoolean(process.env.ONE_CLICK_DEMO_ACCOUNTS, false),
|
|
||||||
demoUrl: process.env.ONE_CLICK_DEMO_ACCOUNTS_URL || '',
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* PostHog
|
|
||||||
*/
|
|
||||||
posthog: {
|
|
||||||
apiKey: process.env.POSTHOG_API_KEY,
|
|
||||||
host: process.env.POSTHOG_HOST
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,67 +0,0 @@
|
|||||||
export const SALE_INVOICE_CREATED = 'Sale invoice created';
|
|
||||||
export const SALE_INVOICE_EDITED = 'Sale invoice d';
|
|
||||||
export const SALE_INVOICE_DELETED = 'Sale invoice deleted';
|
|
||||||
export const SALE_INVOICE_MAIL_DELIVERED = 'Sale invoice mail delivered';
|
|
||||||
|
|
||||||
export const SALE_ESTIMATE_CREATED = 'Sale estimate created';
|
|
||||||
export const SALE_ESTIMATE_EDITED = 'Sale estimate edited';
|
|
||||||
export const SALE_ESTIMATE_DELETED = 'Sale estimate deleted';
|
|
||||||
|
|
||||||
export const PAYMENT_RECEIVED_CREATED = 'Payment received created';
|
|
||||||
export const PAYMENT_RECEIVED_EDITED = 'payment received edited';
|
|
||||||
export const PAYMENT_RECEIVED_DELETED = 'Payment received deleted';
|
|
||||||
|
|
||||||
export const BILL_CREATED = 'Bill created';
|
|
||||||
export const BILL_EDITED = 'Bill edited';
|
|
||||||
export const BILL_DELETED = 'Bill deleted';
|
|
||||||
|
|
||||||
export const PAYMENT_MADE_CREATED = 'Payment made created';
|
|
||||||
export const PAYMENT_MADE_EDITED = 'Payment made edited';
|
|
||||||
export const PAYMENT_MADE_DELETED = 'Payment made deleted';
|
|
||||||
|
|
||||||
export const EXPENSE_CREATED = 'Expense created';
|
|
||||||
export const EXPENSE_EDITED = 'Expense edited';
|
|
||||||
export const EXPENSE_DELETED = 'Expense deleted';
|
|
||||||
|
|
||||||
export const ACCOUNT_CREATED = 'Account created';
|
|
||||||
export const ACCOUNT_EDITED = 'Account Edited';
|
|
||||||
export const ACCOUNT_DELETED = 'Account deleted';
|
|
||||||
|
|
||||||
export const ITEM_EVENT_CREATED = 'Item created';
|
|
||||||
export const ITEM_EVENT_EDITED = 'Item edited';
|
|
||||||
export const ITEM_EVENT_DELETED = 'Item deleted';
|
|
||||||
|
|
||||||
export const AUTH_SIGNED_UP = 'Auth Signed-up';
|
|
||||||
export const AUTH_RESET_PASSWORD = 'Auth reset password';
|
|
||||||
|
|
||||||
export const BANK_TRANSACTION_MATCHED = 'Bank transaction matching deleted';
|
|
||||||
export const BANK_TRANSACTION_EXCLUDED = 'Bank transaction excluded';
|
|
||||||
export const BANK_TRANSACTION_CATEGORIZED = 'Bank transaction categorized';
|
|
||||||
export const BANK_TRANSACTION_UNCATEGORIZED = 'Bank transaction uncategorized';
|
|
||||||
export const BANK_ACCOUNT_DISCONNECTED = 'Bank account disconnected';
|
|
||||||
|
|
||||||
export const ACCOUNT_GROUP = 'Account';
|
|
||||||
export const ITEM_GROUP = 'Item';
|
|
||||||
export const AUTH_GROUP = 'Auth';
|
|
||||||
export const SALE_GROUP = 'Sale';
|
|
||||||
export const PAYMENT_GROUP = 'Payment';
|
|
||||||
export const BILL_GROUP = 'Bill';
|
|
||||||
export const EXPENSE_GROUP = 'Expense';
|
|
||||||
|
|
||||||
export const MANUAL_JOURNAL_CREATED = 'Manual journal created';
|
|
||||||
export const MANUAL_JOURNAL_EDITED = 'Manual journal edited';
|
|
||||||
export const MANUAL_JOURNAL_DELETED = 'Manual journal deleted';
|
|
||||||
export const MANUAL_JOURNAL_PUBLISHED = 'Manual journal published';
|
|
||||||
|
|
||||||
export const CUSTOMER_CREATED = 'Customer created';
|
|
||||||
export const CUSTOMER_EDITED = 'Customer edited';
|
|
||||||
export const CUSTOMER_DELETED = 'Customer deleted';
|
|
||||||
|
|
||||||
export const VENDOR_CREATED = 'Vendor created';
|
|
||||||
export const VENDOR_EDITED = 'Vendor edited';
|
|
||||||
export const VENDOR_DELETED = 'Vendor deleted';
|
|
||||||
|
|
||||||
export const BANK_RULE_CREATED = 'Bank rule created';
|
|
||||||
export const BANK_RULE_EDITED = 'Bank rule edited';
|
|
||||||
export const BANK_RULE_DELETED = 'Bank rule deleted';
|
|
||||||
|
|
||||||
@@ -1,16 +1,7 @@
|
|||||||
export const CashflowTransactionTypes = {
|
|
||||||
OtherIncome: 'Other income',
|
|
||||||
OtherExpense: 'Other expense',
|
|
||||||
OwnerDrawing: 'Owner drawing',
|
|
||||||
OwnerContribution: 'Owner contribution',
|
|
||||||
TransferToAccount: 'Transfer to account',
|
|
||||||
TransferFromAccount: 'Transfer from account',
|
|
||||||
};
|
|
||||||
|
|
||||||
export const TransactionTypes = {
|
export const TransactionTypes = {
|
||||||
SaleInvoice: 'Sale invoice',
|
SaleInvoice: 'Sale invoice',
|
||||||
SaleReceipt: 'Sale receipt',
|
SaleReceipt: 'Sale receipt',
|
||||||
PaymentReceive: 'Payment received',
|
PaymentReceive: 'Payment receive',
|
||||||
Bill: 'Bill',
|
Bill: 'Bill',
|
||||||
BillPayment: 'Payment made',
|
BillPayment: 'Payment made',
|
||||||
VendorOpeningBalance: 'Vendor opening balance',
|
VendorOpeningBalance: 'Vendor opening balance',
|
||||||
@@ -26,10 +17,12 @@ export const TransactionTypes = {
|
|||||||
OtherExpense: 'Other expense',
|
OtherExpense: 'Other expense',
|
||||||
OwnerDrawing: 'Owner drawing',
|
OwnerDrawing: 'Owner drawing',
|
||||||
InvoiceWriteOff: 'Invoice write-off',
|
InvoiceWriteOff: 'Invoice write-off',
|
||||||
|
|
||||||
CreditNote: 'transaction_type.credit_note',
|
CreditNote: 'transaction_type.credit_note',
|
||||||
VendorCredit: 'transaction_type.vendor_credit',
|
VendorCredit: 'transaction_type.vendor_credit',
|
||||||
|
|
||||||
RefundCreditNote: 'transaction_type.refund_credit_note',
|
RefundCreditNote: 'transaction_type.refund_credit_note',
|
||||||
RefundVendorCredit: 'transaction_type.refund_vendor_credit',
|
RefundVendorCredit: 'transaction_type.refund_vendor_credit',
|
||||||
|
|
||||||
LandedCost: 'transaction_type.landed_cost',
|
LandedCost: 'transaction_type.landed_cost',
|
||||||
CashflowTransaction: CashflowTransactionTypes,
|
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,45 +0,0 @@
|
|||||||
exports.up = function (knex) {
|
|
||||||
return knex.schema
|
|
||||||
.createTable('bank_rules', (table) => {
|
|
||||||
table.increments('id').primary();
|
|
||||||
table.string('name');
|
|
||||||
table.integer('order').unsigned();
|
|
||||||
|
|
||||||
table
|
|
||||||
.integer('apply_if_account_id')
|
|
||||||
.unsigned()
|
|
||||||
.references('id')
|
|
||||||
.inTable('accounts');
|
|
||||||
table.string('apply_if_transaction_type');
|
|
||||||
|
|
||||||
table.string('assign_category');
|
|
||||||
table
|
|
||||||
.integer('assign_account_id')
|
|
||||||
.unsigned()
|
|
||||||
.references('id')
|
|
||||||
.inTable('accounts');
|
|
||||||
table.string('assign_payee');
|
|
||||||
table.string('assign_memo');
|
|
||||||
|
|
||||||
table.string('conditions_type');
|
|
||||||
|
|
||||||
table.timestamps();
|
|
||||||
})
|
|
||||||
.createTable('bank_rule_conditions', (table) => {
|
|
||||||
table.increments('id').primary();
|
|
||||||
table
|
|
||||||
.integer('rule_id')
|
|
||||||
.unsigned()
|
|
||||||
.references('id')
|
|
||||||
.inTable('bank_rules');
|
|
||||||
table.string('field');
|
|
||||||
table.string('comparator');
|
|
||||||
table.string('value');
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
exports.down = function (knex) {
|
|
||||||
return knex.schema
|
|
||||||
.dropTableIfExists('bank_rules')
|
|
||||||
.dropTableIfExists('bank_rule_conditions');
|
|
||||||
};
|
|
||||||
@@ -1,31 +0,0 @@
|
|||||||
exports.up = function (knex) {
|
|
||||||
return knex.schema.createTable('recognized_bank_transactions', (table) => {
|
|
||||||
table.increments('id');
|
|
||||||
table
|
|
||||||
.integer('uncategorized_transaction_id')
|
|
||||||
.unsigned()
|
|
||||||
.references('id')
|
|
||||||
.inTable('uncategorized_cashflow_transactions')
|
|
||||||
.withKeyName('recognizedBankTransactionsUncategorizedTransIdForeign');
|
|
||||||
table
|
|
||||||
.integer('bank_rule_id')
|
|
||||||
.unsigned()
|
|
||||||
.references('id')
|
|
||||||
.inTable('bank_rules');
|
|
||||||
|
|
||||||
table.string('assigned_category');
|
|
||||||
table
|
|
||||||
.integer('assigned_account_id')
|
|
||||||
.unsigned()
|
|
||||||
.references('id')
|
|
||||||
.inTable('accounts');
|
|
||||||
table.string('assigned_payee');
|
|
||||||
table.string('assigned_memo');
|
|
||||||
|
|
||||||
table.timestamps();
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
exports.down = function (knex) {
|
|
||||||
return knex.schema.dropTableIfExists('recognized_bank_transactions');
|
|
||||||
};
|
|
||||||
@@ -1,16 +0,0 @@
|
|||||||
exports.up = function (knex) {
|
|
||||||
return knex.schema.table('uncategorized_cashflow_transactions', (table) => {
|
|
||||||
table
|
|
||||||
.integer('recognized_transaction_id')
|
|
||||||
.unsigned()
|
|
||||||
.references('id')
|
|
||||||
.inTable('recognized_bank_transactions')
|
|
||||||
.withKeyName('uncategorizedCashflowTransRecognizedTranIdForeign');
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
exports.down = function (knex) {
|
|
||||||
return knex.schema.table('uncategorized_cashflow_transactions', (table) => {
|
|
||||||
table.dropColumn('recognized_transaction_id');
|
|
||||||
});
|
|
||||||
};
|
|
||||||
@@ -1,18 +0,0 @@
|
|||||||
exports.up = function (knex) {
|
|
||||||
return knex.schema.createTable('matched_bank_transactions', (table) => {
|
|
||||||
table.increments('id');
|
|
||||||
table
|
|
||||||
.integer('uncategorized_transaction_id')
|
|
||||||
.unsigned()
|
|
||||||
.references('id')
|
|
||||||
.inTable('uncategorized_cashflow_transactions');
|
|
||||||
table.string('reference_type');
|
|
||||||
table.integer('reference_id').unsigned();
|
|
||||||
table.decimal('amount');
|
|
||||||
table.timestamps();
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
exports.down = function (knex) {
|
|
||||||
return knex.schema.dropTableIfExists('matched_bank_transactions');
|
|
||||||
};
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
exports.up = function (knex) {
|
|
||||||
return knex.schema.table('uncategorized_cashflow_transactions', (table) => {
|
|
||||||
table.datetime('excluded_at');
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
exports.down = function (knex) {
|
|
||||||
return knex.schema.table('uncategorized_cashflow_transactions', (table) => {
|
|
||||||
table.dropColumn('excluded_at');
|
|
||||||
});
|
|
||||||
};
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
exports.up = function (knex) {
|
|
||||||
return knex.schema.table('uncategorized_cashflow_transactions', (table) => {
|
|
||||||
table.string('batch');
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
exports.down = function (knex) {
|
|
||||||
return knex.schema.table('uncategorized_cashflow_transactions', (table) => {
|
|
||||||
table.dropColumn('batch');
|
|
||||||
});
|
|
||||||
};
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
exports.up = function (knex) {
|
|
||||||
return knex.schema.table('settings', (table) => {
|
|
||||||
table.text('value').alter();
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
exports.down = (knex) => {
|
|
||||||
return knex.schema.table('settings', (table) => {
|
|
||||||
table.string('value').alter();
|
|
||||||
});
|
|
||||||
};
|
|
||||||
@@ -1,60 +0,0 @@
|
|||||||
exports.up = function (knex) {
|
|
||||||
return knex('accounts_transactions')
|
|
||||||
.whereIn('referenceType', [
|
|
||||||
'OtherIncome',
|
|
||||||
'OtherExpense',
|
|
||||||
'OwnerDrawing',
|
|
||||||
'OwnerContribution',
|
|
||||||
'TransferToAccount',
|
|
||||||
'TransferFromAccount',
|
|
||||||
])
|
|
||||||
.update({
|
|
||||||
transactionType: knex.raw(`
|
|
||||||
CASE
|
|
||||||
WHEN REFERENCE_TYPE = 'OtherIncome' THEN 'OtherIncome'
|
|
||||||
WHEN REFERENCE_TYPE = 'OtherExpense' THEN 'OtherExpense'
|
|
||||||
WHEN REFERENCE_TYPE = 'OwnerDrawing' THEN 'OwnerDrawing'
|
|
||||||
WHEN REFERENCE_TYPE = 'OwnerContribution' THEN 'OwnerContribution'
|
|
||||||
WHEN REFERENCE_TYPE = 'TransferToAccount' THEN 'TransferToAccount'
|
|
||||||
WHEN REFERENCE_TYPE = 'TransferFromAccount' THEN 'TransferFromAccount'
|
|
||||||
END
|
|
||||||
`),
|
|
||||||
referenceType: knex.raw(`
|
|
||||||
CASE
|
|
||||||
WHEN REFERENCE_TYPE IN ('OtherIncome', 'OtherExpense', 'OwnerDrawing', 'OwnerContribution', 'TransferToAccount', 'TransferFromAccount') THEN 'CashflowTransaction'
|
|
||||||
ELSE REFERENCE_TYPE
|
|
||||||
END
|
|
||||||
`),
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
exports.down = function (knex) {
|
|
||||||
return knex('accounts_transactions')
|
|
||||||
.whereIn('transactionType', [
|
|
||||||
'OtherIncome',
|
|
||||||
'OtherExpense',
|
|
||||||
'OwnerDrawing',
|
|
||||||
'OwnerContribution',
|
|
||||||
'TransferToAccount',
|
|
||||||
'TransferFromAccount',
|
|
||||||
])
|
|
||||||
.update({
|
|
||||||
referenceType: knex.raw(`
|
|
||||||
CASE
|
|
||||||
WHEN TRANSACTION_TYPE = 'OtherIncome' THEN 'OtherIncome'
|
|
||||||
WHEN TRANSACTION_TYPE = 'OtherExpense' THEN 'OtherExpense'
|
|
||||||
WHEN TRANSACTION_TYPE = 'OwnerDrawing' THEN 'OwnerDrawing'
|
|
||||||
WHEN TRANSACTION_TYPE = 'OwnerContribution' THEN 'OwnerContribution'
|
|
||||||
WHEN TRANSACTION_TYPE = 'TransferToAccount' THEN 'TransferToAccount'
|
|
||||||
WHEN TRANSACTION_TYPE = 'TransferFromAccount' THEN 'TransferFromAccount'
|
|
||||||
ELSE REFERENCE_TYPE
|
|
||||||
END
|
|
||||||
`),
|
|
||||||
transactionType: knex.raw(`
|
|
||||||
CASE
|
|
||||||
WHEN TRANSACTION_TYPE IN ('OtherIncome', 'OtherExpense', 'OwnerDrawing', 'OwnerContribution', 'TransferToAccount', 'TransferFromAccount') THEN NULL
|
|
||||||
ELSE TRANSACTION_TYPE
|
|
||||||
END
|
|
||||||
`),
|
|
||||||
});
|
|
||||||
};
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
exports.up = function (knex) {
|
|
||||||
return knex.schema.table('accounts', (table) => {
|
|
||||||
table.string('plaid_item_id').nullable();
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
exports.down = function (knex) {
|
|
||||||
return knex.schema.table('accounts', (table) => {
|
|
||||||
table.dropColumn('plaid_item_id');
|
|
||||||
});
|
|
||||||
};
|
|
||||||
@@ -1,19 +0,0 @@
|
|||||||
exports.up = function (knex) {
|
|
||||||
return knex.schema
|
|
||||||
.table('accounts', (table) => {
|
|
||||||
table
|
|
||||||
.boolean('is_syncing_owner')
|
|
||||||
.defaultTo(false)
|
|
||||||
.after('is_feeds_active');
|
|
||||||
})
|
|
||||||
.then(() => {
|
|
||||||
return knex('accounts')
|
|
||||||
.whereNotNull('plaid_item_id')
|
|
||||||
.orWhereNotNull('plaid_account_id')
|
|
||||||
.update('is_syncing_owner', true);
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
exports.down = function (knex) {
|
|
||||||
table.dropColumn('is_syncing_owner');
|
|
||||||
};
|
|
||||||
@@ -1,18 +0,0 @@
|
|||||||
// This migration changes the precision of the tax_amount_withheld column in the bills and sales_invoices tables from 8, 2 to 13, 2.
|
|
||||||
// This migration is necessary to allow tax_amount_withheld filed to store values bigger than 999,999.99.
|
|
||||||
|
|
||||||
exports.up = function(knex) {
|
|
||||||
return knex.schema.alterTable('bills', function (table) {
|
|
||||||
table.decimal('tax_amount_withheld', 13, 2).alter();
|
|
||||||
}).alterTable('sales_invoices', function (table) {
|
|
||||||
table.decimal('tax_amount_withheld', 13, 2).alter();
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
exports.down = function(knex) {
|
|
||||||
return knex.schema.alterTable('bills', function (table) {
|
|
||||||
table.decimal('tax_amount_withheld', 8, 2).alter();
|
|
||||||
}).alterTable('sales_invoices', function (table) {
|
|
||||||
table.decimal('tax_amount_withheld', 8, 2).alter();
|
|
||||||
});
|
|
||||||
};
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
exports.up = function (knex) {
|
|
||||||
return knex.schema.table('plaid_items', (table) => {
|
|
||||||
table.datetime('paused_at');
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
exports.down = function (knex) {
|
|
||||||
return knex.schema.table('plaid_items', (table) => {
|
|
||||||
table.dropColumn('paused_at');
|
|
||||||
});
|
|
||||||
};
|
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
exports.up = function (knex) {
|
|
||||||
return knex.schema.table('uncategorized_cashflow_transactions', (table) => {
|
|
||||||
table.boolean('pending').defaultTo(false);
|
|
||||||
table.string('pending_plaid_transaction_id').nullable();
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
exports.down = function (knex) {
|
|
||||||
return knex.schema.table('uncategorized_cashflow_transactions', (table) => {
|
|
||||||
table.dropColumn('pending');
|
|
||||||
table.dropColumn('pending_plaid_transaction_id');
|
|
||||||
});
|
|
||||||
};
|
|
||||||
@@ -12,7 +12,8 @@ export default class SeedAccounts extends TenantSeeder {
|
|||||||
description: this.i18n.__(account.description),
|
description: this.i18n.__(account.description),
|
||||||
currencyCode: this.tenant.metadata.baseCurrency,
|
currencyCode: this.tenant.metadata.baseCurrency,
|
||||||
seededAt: new Date(),
|
seededAt: new Date(),
|
||||||
}));
|
})
|
||||||
|
);
|
||||||
return knex('accounts').then(async () => {
|
return knex('accounts').then(async () => {
|
||||||
// Inserts seed entries.
|
// Inserts seed entries.
|
||||||
return knex('accounts').insert(data);
|
return knex('accounts').insert(data);
|
||||||
|
|||||||
@@ -15,7 +15,6 @@ export default class SeedSettings extends TenantSeeder {
|
|||||||
|
|
||||||
// Manual journals settings.
|
// Manual journals settings.
|
||||||
{ group: 'manual_journals', key: 'next_number', value: '00001' },
|
{ group: 'manual_journals', key: 'next_number', value: '00001' },
|
||||||
{ group: 'manual_journals', key: 'number_prefix', value: 'J-' },
|
|
||||||
{ group: 'manual_journals', key: 'auto_increment', value: true },
|
{ group: 'manual_journals', key: 'auto_increment', value: true },
|
||||||
|
|
||||||
// Sale invoices settings.
|
// Sale invoices settings.
|
||||||
|
|||||||
@@ -9,28 +9,6 @@ export const TaxPayableAccount = {
|
|||||||
predefined: 1,
|
predefined: 1,
|
||||||
};
|
};
|
||||||
|
|
||||||
export const UnearnedRevenueAccount = {
|
|
||||||
name: 'Unearned Revenue',
|
|
||||||
slug: 'unearned-revenue',
|
|
||||||
account_type: 'other-current-liability',
|
|
||||||
parent_account_id: null,
|
|
||||||
code: '50005',
|
|
||||||
active: true,
|
|
||||||
index: 1,
|
|
||||||
predefined: true,
|
|
||||||
};
|
|
||||||
|
|
||||||
export const PrepardExpenses = {
|
|
||||||
name: 'Prepaid Expenses',
|
|
||||||
slug: 'prepaid-expenses',
|
|
||||||
account_type: 'other-current-asset',
|
|
||||||
parent_account_id: null,
|
|
||||||
code: '100010',
|
|
||||||
active: true,
|
|
||||||
index: 1,
|
|
||||||
predefined: true,
|
|
||||||
};
|
|
||||||
|
|
||||||
export default [
|
export default [
|
||||||
{
|
{
|
||||||
name: 'Bank Account',
|
name: 'Bank Account',
|
||||||
@@ -345,6 +323,4 @@ export default [
|
|||||||
index: 1,
|
index: 1,
|
||||||
predefined: 0,
|
predefined: 0,
|
||||||
},
|
},
|
||||||
UnearnedRevenueAccount,
|
|
||||||
PrepardExpenses,
|
|
||||||
];
|
];
|
||||||
|
|||||||
@@ -15,7 +15,6 @@ export interface IAccountDTO {
|
|||||||
export interface IAccountCreateDTO extends IAccountDTO {
|
export interface IAccountCreateDTO extends IAccountDTO {
|
||||||
currencyCode?: string;
|
currencyCode?: string;
|
||||||
plaidAccountId?: string;
|
plaidAccountId?: string;
|
||||||
plaidItemId?: string;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IAccountEditDTO extends IAccountDTO {}
|
export interface IAccountEditDTO extends IAccountDTO {}
|
||||||
@@ -38,8 +37,6 @@ export interface IAccount {
|
|||||||
accountNormal: string;
|
accountNormal: string;
|
||||||
accountParentType: string;
|
accountParentType: string;
|
||||||
bankBalance: string;
|
bankBalance: string;
|
||||||
plaidItemId: number | null
|
|
||||||
lastFeedsUpdatedAt: Date;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export enum AccountNormal {
|
export enum AccountNormal {
|
||||||
@@ -69,9 +66,7 @@ export interface IAccountTransaction {
|
|||||||
referenceId: number;
|
referenceId: number;
|
||||||
|
|
||||||
referenceNumber?: string;
|
referenceNumber?: string;
|
||||||
|
|
||||||
transactionNumber?: string;
|
transactionNumber?: string;
|
||||||
transactionType?: string;
|
|
||||||
|
|
||||||
note?: string;
|
note?: string;
|
||||||
|
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ export interface IRegisterDTO {
|
|||||||
lastName: string;
|
lastName: string;
|
||||||
email: string;
|
email: string;
|
||||||
password: string;
|
password: string;
|
||||||
|
organizationName: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ILoginDTO {
|
export interface ILoginDTO {
|
||||||
@@ -76,10 +77,6 @@ export interface IAuthSendedResetPassword {
|
|||||||
|
|
||||||
export interface IAuthGetMetaPOJO {
|
export interface IAuthGetMetaPOJO {
|
||||||
signupDisabled: boolean;
|
signupDisabled: boolean;
|
||||||
oneClickDemo: {
|
|
||||||
enable: boolean;
|
|
||||||
demoUrl: string;
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IAuthSignUpVerifingEventPayload {
|
export interface IAuthSignUpVerifingEventPayload {
|
||||||
|
|||||||
@@ -99,7 +99,6 @@ export interface IBillsFilter extends IDynamicListFilterDTO {
|
|||||||
stringifiedFilterRoles?: string;
|
stringifiedFilterRoles?: string;
|
||||||
page: number;
|
page: number;
|
||||||
pageSize: number;
|
pageSize: number;
|
||||||
filterQuery?: (q: any) => void;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IBillsService {
|
export interface IBillsService {
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
import { Knex } from 'knex';
|
|
||||||
import {
|
import {
|
||||||
IFinancialSheetCommonMeta,
|
IFinancialSheetCommonMeta,
|
||||||
INumberFormatQuery,
|
INumberFormatQuery,
|
||||||
@@ -236,7 +235,6 @@ export interface ICashflowTransactionSchema {
|
|||||||
export interface ICashflowTransactionInput extends ICashflowTransactionSchema {}
|
export interface ICashflowTransactionInput extends ICashflowTransactionSchema {}
|
||||||
|
|
||||||
export interface ICategorizeCashflowTransactioDTO {
|
export interface ICategorizeCashflowTransactioDTO {
|
||||||
date: Date;
|
|
||||||
creditAccountId: number;
|
creditAccountId: number;
|
||||||
referenceNo: string;
|
referenceNo: string;
|
||||||
transactionNumber: string;
|
transactionNumber: string;
|
||||||
@@ -259,6 +257,7 @@ export interface IUncategorizedCashflowTransaction {
|
|||||||
categorized: boolean;
|
categorized: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
export interface CreateUncategorizedTransactionDTO {
|
export interface CreateUncategorizedTransactionDTO {
|
||||||
date: Date | string;
|
date: Date | string;
|
||||||
accountId: number;
|
accountId: number;
|
||||||
@@ -268,34 +267,4 @@ export interface CreateUncategorizedTransactionDTO {
|
|||||||
description?: string;
|
description?: string;
|
||||||
referenceNo?: string | null;
|
referenceNo?: string | null;
|
||||||
plaidTransactionId?: string | null;
|
plaidTransactionId?: string | null;
|
||||||
pending?: boolean;
|
|
||||||
pendingPlaidTransactionId?: string | null;
|
|
||||||
batch?: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface IUncategorizedTransactionCreatingEventPayload {
|
|
||||||
tenantId: number;
|
|
||||||
createUncategorizedTransactionDTO: CreateUncategorizedTransactionDTO;
|
|
||||||
trx: Knex.Transaction;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface IUncategorizedTransactionCreatedEventPayload {
|
|
||||||
tenantId: number;
|
|
||||||
uncategorizedTransaction: any;
|
|
||||||
createUncategorizedTransactionDTO: CreateUncategorizedTransactionDTO;
|
|
||||||
trx: Knex.Transaction;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface IPendingTransactionRemovingEventPayload {
|
|
||||||
tenantId: number;
|
|
||||||
uncategorizedTransactionId: number;
|
|
||||||
pendingTransaction: IUncategorizedCashflowTransaction;
|
|
||||||
trx?: Knex.Transaction;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface IPendingTransactionRemovedEventPayload {
|
|
||||||
tenantId: number;
|
|
||||||
uncategorizedTransactionId: number;
|
|
||||||
pendingTransaction: IUncategorizedCashflowTransaction;
|
|
||||||
trx?: Knex.Transaction;
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -130,23 +130,19 @@ export interface ICommandCashflowDeletedPayload {
|
|||||||
|
|
||||||
export interface ICashflowTransactionCategorizedPayload {
|
export interface ICashflowTransactionCategorizedPayload {
|
||||||
tenantId: number;
|
tenantId: number;
|
||||||
uncategorizedTransactions: Array<IUncategorizedCashflowTransaction>;
|
cashflowTransactionId: number;
|
||||||
cashflowTransaction: ICashflowTransaction;
|
cashflowTransaction: ICashflowTransaction;
|
||||||
oldUncategorizedTransactions: Array<IUncategorizedCashflowTransaction>;
|
|
||||||
categorizeDTO: any;
|
|
||||||
trx: Knex.Transaction;
|
trx: Knex.Transaction;
|
||||||
}
|
}
|
||||||
export interface ICashflowTransactionUncategorizingPayload {
|
export interface ICashflowTransactionUncategorizingPayload {
|
||||||
tenantId: number;
|
tenantId: number;
|
||||||
uncategorizedTransactionId: number;
|
uncategorizedTransaction: IUncategorizedCashflowTransaction;
|
||||||
oldUncategorizedTransactions: Array<IUncategorizedCashflowTransaction>;
|
|
||||||
trx: Knex.Transaction;
|
trx: Knex.Transaction;
|
||||||
}
|
}
|
||||||
export interface ICashflowTransactionUncategorizedPayload {
|
export interface ICashflowTransactionUncategorizedPayload {
|
||||||
tenantId: number;
|
tenantId: number;
|
||||||
uncategorizedTransactionId: number;
|
uncategorizedTransaction: IUncategorizedCashflowTransaction;
|
||||||
uncategorizedTransactions: Array<IUncategorizedCashflowTransaction>;
|
oldUncategorizedTransaction: IUncategorizedCashflowTransaction;
|
||||||
oldUncategorizedTransactions: Array<IUncategorizedCashflowTransaction>;
|
|
||||||
trx: Knex.Transaction;
|
trx: Knex.Transaction;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -167,18 +163,4 @@ export interface CategorizeTransactionAsExpenseDTO {
|
|||||||
export interface IGetUncategorizedTransactionsQuery {
|
export interface IGetUncategorizedTransactionsQuery {
|
||||||
page?: number;
|
page?: number;
|
||||||
pageSize?: number;
|
pageSize?: number;
|
||||||
minDate?: Date;
|
|
||||||
maxDate?: Date;
|
|
||||||
minAmount?: number;
|
|
||||||
maxAmount?: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface IGetRecognizedTransactionsQuery {
|
|
||||||
page?: number;
|
|
||||||
pageSize?: number;
|
|
||||||
accountId?: number;
|
|
||||||
minDate?: Date;
|
|
||||||
maxDate?: Date;
|
|
||||||
minAmount?: number;
|
|
||||||
maxAmount?: number;
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -241,7 +241,6 @@ export interface ICustomerEventCreatingPayload {
|
|||||||
trx: Knex.Transaction;
|
trx: Knex.Transaction;
|
||||||
}
|
}
|
||||||
export interface ICustomerEventEditedPayload {
|
export interface ICustomerEventEditedPayload {
|
||||||
tenantId: number
|
|
||||||
customerId: number;
|
customerId: number;
|
||||||
customer: ICustomer;
|
customer: ICustomer;
|
||||||
trx: Knex.Transaction;
|
trx: Knex.Transaction;
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
import { Knex } from 'knex';
|
import { Knex } from 'knex';
|
||||||
import { IDynamicListFilter, IItemEntry } from '@/interfaces';
|
import { IDynamicListFilter, IItemEntry, IVendorCredit } from '@/interfaces';
|
||||||
import { ILedgerEntry } from './Ledger';
|
import { ILedgerEntry } from './Ledger';
|
||||||
import { AttachmentLinkDTO } from './Attachments';
|
import { AttachmentLinkDTO } from './Attachments';
|
||||||
|
|
||||||
export interface ICreditNoteEntryNewDTO {
|
export interface ICreditNoteEntryNewDTO {
|
||||||
index?: number;
|
index: number;
|
||||||
itemId: number;
|
itemId: number;
|
||||||
rate: number;
|
rate: number;
|
||||||
quantity: number;
|
quantity: number;
|
||||||
@@ -22,7 +22,7 @@ export interface ICreditNoteNewDTO {
|
|||||||
entries: ICreditNoteEntryNewDTO[];
|
entries: ICreditNoteEntryNewDTO[];
|
||||||
branchId?: number;
|
branchId?: number;
|
||||||
warehouseId?: number;
|
warehouseId?: number;
|
||||||
attachments?: AttachmentLinkDTO[];
|
attachments?: AttachmentLinkDTO[]
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ICreditNoteEditDTO {
|
export interface ICreditNoteEditDTO {
|
||||||
@@ -35,7 +35,7 @@ export interface ICreditNoteEditDTO {
|
|||||||
entries: ICreditNoteEntryNewDTO[];
|
entries: ICreditNoteEntryNewDTO[];
|
||||||
branchId?: number;
|
branchId?: number;
|
||||||
warehouseId?: number;
|
warehouseId?: number;
|
||||||
attachments?: AttachmentLinkDTO[];
|
attachments?: AttachmentLinkDTO[]
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ICreditNoteEntry extends IItemEntry {}
|
export interface ICreditNoteEntry extends IItemEntry {}
|
||||||
@@ -61,7 +61,7 @@ export interface ICreditNote {
|
|||||||
localAmount?: number;
|
localAmount?: number;
|
||||||
branchId?: number;
|
branchId?: number;
|
||||||
warehouseId: number;
|
warehouseId: number;
|
||||||
createdAt?: Date;
|
createdAt?: Date,
|
||||||
}
|
}
|
||||||
|
|
||||||
export enum CreditNoteAction {
|
export enum CreditNoteAction {
|
||||||
@@ -130,9 +130,7 @@ export interface ICreditNoteOpenedPayload {
|
|||||||
trx: Knex.Transaction;
|
trx: Knex.Transaction;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ICreditNotesQueryDTO {
|
export interface ICreditNotesQueryDTO {}
|
||||||
filterQuery?: (query: any) => void;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface ICreditNotesQueryDTO extends IDynamicListFilter {
|
export interface ICreditNotesQueryDTO extends IDynamicListFilter {
|
||||||
page: number;
|
page: number;
|
||||||
|
|||||||
@@ -17,7 +17,6 @@ export interface IExpensesFilter {
|
|||||||
columnSortBy: string;
|
columnSortBy: string;
|
||||||
sortOrder: string;
|
sortOrder: string;
|
||||||
viewSlug?: string;
|
viewSlug?: string;
|
||||||
filterQuery?: (query: any) => void;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IExpense {
|
export interface IExpense {
|
||||||
|
|||||||
@@ -29,9 +29,4 @@ export interface ICashflowAccountTransaction {
|
|||||||
|
|
||||||
date: Date;
|
date: Date;
|
||||||
formattedDate: string;
|
formattedDate: string;
|
||||||
|
|
||||||
status: string;
|
|
||||||
formattedStatus: string;
|
|
||||||
|
|
||||||
uncategorizedTransactionId: number;
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ export interface IGeneralLedgerSheetAccountTransaction {
|
|||||||
currencyCode: string;
|
currencyCode: string;
|
||||||
note?: string;
|
note?: string;
|
||||||
|
|
||||||
transactionTypeFormatted: string;
|
transactionType?: string;
|
||||||
transactionNumber: string;
|
transactionNumber: string;
|
||||||
|
|
||||||
referenceId?: number;
|
referenceId?: number;
|
||||||
|
|||||||
@@ -1,8 +0,0 @@
|
|||||||
import { ImportFilePreviewPOJO } from "@/services/Import/interfaces";
|
|
||||||
|
|
||||||
|
|
||||||
export interface IImportFileCommitedEventPayload {
|
|
||||||
tenantId: number;
|
|
||||||
importId: string;
|
|
||||||
meta: ImportFilePreviewPOJO;
|
|
||||||
}
|
|
||||||
@@ -48,7 +48,6 @@ export interface IItemEntry {
|
|||||||
|
|
||||||
export interface IItemEntryDTO {
|
export interface IItemEntryDTO {
|
||||||
id?: number;
|
id?: number;
|
||||||
index?: number;
|
|
||||||
itemId: number;
|
itemId: number;
|
||||||
landedCost?: boolean;
|
landedCost?: boolean;
|
||||||
warehouseId?: number;
|
warehouseId?: number;
|
||||||
|
|||||||
@@ -40,8 +40,6 @@ export interface ILedgerEntry {
|
|||||||
date: Date | string;
|
date: Date | string;
|
||||||
|
|
||||||
transactionType: string;
|
transactionType: string;
|
||||||
transactionSubType?: string;
|
|
||||||
|
|
||||||
transactionId: number;
|
transactionId: number;
|
||||||
|
|
||||||
transactionNumber?: string;
|
transactionNumber?: string;
|
||||||
|
|||||||
@@ -151,7 +151,6 @@ export interface IModelMetaFieldCommon2 {
|
|||||||
importHint?: string;
|
importHint?: string;
|
||||||
order?: number;
|
order?: number;
|
||||||
unique?: number;
|
unique?: number;
|
||||||
features?: Array<any>
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IModelMetaRelationField2 {
|
export interface IModelMetaRelationField2 {
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import { ILedgerEntry } from './Ledger';
|
|||||||
import { ISaleInvoice } from './SaleInvoice';
|
import { ISaleInvoice } from './SaleInvoice';
|
||||||
import { AttachmentLinkDTO } from './Attachments';
|
import { AttachmentLinkDTO } from './Attachments';
|
||||||
|
|
||||||
export interface IPaymentReceived {
|
export interface IPaymentReceive {
|
||||||
id?: number;
|
id?: number;
|
||||||
customerId: number;
|
customerId: number;
|
||||||
paymentDate: Date;
|
paymentDate: Date;
|
||||||
@@ -19,14 +19,14 @@ export interface IPaymentReceived {
|
|||||||
depositAccountId: number;
|
depositAccountId: number;
|
||||||
paymentReceiveNo: string;
|
paymentReceiveNo: string;
|
||||||
statement: string;
|
statement: string;
|
||||||
entries: IPaymentReceivedEntry[];
|
entries: IPaymentReceiveEntry[];
|
||||||
userId: number;
|
userId: number;
|
||||||
createdAt: Date;
|
createdAt: Date;
|
||||||
updatedAt: Date;
|
updatedAt: Date;
|
||||||
localAmount?: number;
|
localAmount?: number;
|
||||||
branchId?: number;
|
branchId?: number;
|
||||||
}
|
}
|
||||||
export interface IPaymentReceivedCreateDTO {
|
export interface IPaymentReceiveCreateDTO {
|
||||||
customerId: number;
|
customerId: number;
|
||||||
paymentDate: Date;
|
paymentDate: Date;
|
||||||
amount: number;
|
amount: number;
|
||||||
@@ -35,13 +35,13 @@ export interface IPaymentReceivedCreateDTO {
|
|||||||
depositAccountId: number;
|
depositAccountId: number;
|
||||||
paymentReceiveNo?: string;
|
paymentReceiveNo?: string;
|
||||||
statement: string;
|
statement: string;
|
||||||
entries: IPaymentReceivedEntryDTO[];
|
entries: IPaymentReceiveEntryDTO[];
|
||||||
|
|
||||||
branchId?: number;
|
branchId?: number;
|
||||||
attachments?: AttachmentLinkDTO[];
|
attachments?: AttachmentLinkDTO[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IPaymentReceivedEditDTO {
|
export interface IPaymentReceiveEditDTO {
|
||||||
customerId: number;
|
customerId: number;
|
||||||
paymentDate: Date;
|
paymentDate: Date;
|
||||||
amount: number;
|
amount: number;
|
||||||
@@ -50,12 +50,12 @@ export interface IPaymentReceivedEditDTO {
|
|||||||
depositAccountId: number;
|
depositAccountId: number;
|
||||||
paymentReceiveNo?: string;
|
paymentReceiveNo?: string;
|
||||||
statement: string;
|
statement: string;
|
||||||
entries: IPaymentReceivedEntryDTO[];
|
entries: IPaymentReceiveEntryDTO[];
|
||||||
branchId?: number;
|
branchId?: number;
|
||||||
attachments?: AttachmentLinkDTO[];
|
attachments?: AttachmentLinkDTO[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IPaymentReceivedEntry {
|
export interface IPaymentReceiveEntry {
|
||||||
id?: number;
|
id?: number;
|
||||||
paymentReceiveId: number;
|
paymentReceiveId: number;
|
||||||
invoiceId: number;
|
invoiceId: number;
|
||||||
@@ -64,17 +64,16 @@ export interface IPaymentReceivedEntry {
|
|||||||
invoice?: ISaleInvoice;
|
invoice?: ISaleInvoice;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IPaymentReceivedEntryDTO {
|
export interface IPaymentReceiveEntryDTO {
|
||||||
id?: number;
|
id?: number;
|
||||||
index?: number;
|
index: number;
|
||||||
paymentReceiveId?: number;
|
paymentReceiveId: number;
|
||||||
invoiceId: number;
|
invoiceId: number;
|
||||||
paymentAmount: number;
|
paymentAmount: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IPaymentsReceivedFilter extends IDynamicListFilterDTO {
|
export interface IPaymentReceivesFilter extends IDynamicListFilterDTO {
|
||||||
stringifiedFilterRoles?: string;
|
stringifiedFilterRoles?: string;
|
||||||
filterQuery?: (trx: Knex.Transaction) => void;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IPaymentReceivePageEntry {
|
export interface IPaymentReceivePageEntry {
|
||||||
@@ -89,65 +88,65 @@ export interface IPaymentReceivePageEntry {
|
|||||||
date: Date | string;
|
date: Date | string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IPaymentReceivedEditPage {
|
export interface IPaymentReceiveEditPage {
|
||||||
paymentReceive: IPaymentReceived;
|
paymentReceive: IPaymentReceive;
|
||||||
entries: IPaymentReceivePageEntry[];
|
entries: IPaymentReceivePageEntry[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IPaymentsReceivedService {
|
export interface IPaymentsReceiveService {
|
||||||
validateCustomerHasNoPayments(
|
validateCustomerHasNoPayments(
|
||||||
tenantId: number,
|
tenantId: number,
|
||||||
customerId: number
|
customerId: number
|
||||||
): Promise<void>;
|
): Promise<void>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IPaymentReceivedSmsDetails {
|
export interface IPaymentReceiveSmsDetails {
|
||||||
customerName: string;
|
customerName: string;
|
||||||
customerPhoneNumber: string;
|
customerPhoneNumber: string;
|
||||||
smsMessage: string;
|
smsMessage: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IPaymentReceivedCreatingPayload {
|
export interface IPaymentReceiveCreatingPayload {
|
||||||
tenantId: number;
|
tenantId: number;
|
||||||
paymentReceiveDTO: IPaymentReceivedCreateDTO;
|
paymentReceiveDTO: IPaymentReceiveCreateDTO;
|
||||||
trx: Knex.Transaction;
|
trx: Knex.Transaction;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IPaymentReceivedCreatedPayload {
|
export interface IPaymentReceiveCreatedPayload {
|
||||||
tenantId: number;
|
tenantId: number;
|
||||||
paymentReceive: IPaymentReceived;
|
paymentReceive: IPaymentReceive;
|
||||||
paymentReceiveId: number;
|
paymentReceiveId: number;
|
||||||
authorizedUser: ISystemUser;
|
authorizedUser: ISystemUser;
|
||||||
paymentReceiveDTO: IPaymentReceivedCreateDTO;
|
paymentReceiveDTO: IPaymentReceiveCreateDTO;
|
||||||
trx: Knex.Transaction;
|
trx: Knex.Transaction;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IPaymentReceivedEditedPayload {
|
export interface IPaymentReceiveEditedPayload {
|
||||||
tenantId: number;
|
tenantId: number;
|
||||||
paymentReceiveId: number;
|
paymentReceiveId: number;
|
||||||
paymentReceive: IPaymentReceived;
|
paymentReceive: IPaymentReceive;
|
||||||
oldPaymentReceive: IPaymentReceived;
|
oldPaymentReceive: IPaymentReceive;
|
||||||
paymentReceiveDTO: IPaymentReceivedEditDTO;
|
paymentReceiveDTO: IPaymentReceiveEditDTO;
|
||||||
authorizedUser: ISystemUser;
|
authorizedUser: ISystemUser;
|
||||||
trx: Knex.Transaction;
|
trx: Knex.Transaction;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IPaymentReceivedEditingPayload {
|
export interface IPaymentReceiveEditingPayload {
|
||||||
tenantId: number;
|
tenantId: number;
|
||||||
oldPaymentReceive: IPaymentReceived;
|
oldPaymentReceive: IPaymentReceive;
|
||||||
paymentReceiveDTO: IPaymentReceivedEditDTO;
|
paymentReceiveDTO: IPaymentReceiveEditDTO;
|
||||||
trx: Knex.Transaction;
|
trx: Knex.Transaction;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IPaymentReceivedDeletingPayload {
|
export interface IPaymentReceiveDeletingPayload {
|
||||||
tenantId: number;
|
tenantId: number;
|
||||||
oldPaymentReceive: IPaymentReceived;
|
oldPaymentReceive: IPaymentReceive;
|
||||||
trx: Knex.Transaction;
|
trx: Knex.Transaction;
|
||||||
}
|
}
|
||||||
export interface IPaymentReceivedDeletedPayload {
|
export interface IPaymentReceiveDeletedPayload {
|
||||||
tenantId: number;
|
tenantId: number;
|
||||||
paymentReceiveId: number;
|
paymentReceiveId: number;
|
||||||
oldPaymentReceive: IPaymentReceived;
|
oldPaymentReceive: IPaymentReceive;
|
||||||
authorizedUser: ISystemUser;
|
authorizedUser: ISystemUser;
|
||||||
trx: Knex.Transaction;
|
trx: Knex.Transaction;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
import { Knex } from "knex";
|
|
||||||
|
|
||||||
export interface IPlaidItemCreatedEventPayload {
|
export interface IPlaidItemCreatedEventPayload {
|
||||||
tenantId: number;
|
tenantId: number;
|
||||||
plaidAccessToken: string;
|
plaidAccessToken: string;
|
||||||
@@ -56,10 +54,3 @@ export interface SyncAccountsTransactionsTask {
|
|||||||
plaidAccountId: number;
|
plaidAccountId: number;
|
||||||
plaidTransactions: PlaidTransaction[];
|
plaidTransactions: PlaidTransaction[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IPlaidTransactionsSyncedEventPayload {
|
|
||||||
tenantId: number;
|
|
||||||
plaidAccountId: number;
|
|
||||||
batch: string;
|
|
||||||
trx?: Knex.Transaction
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -44,7 +44,6 @@ export interface ISaleEstimateDTO {
|
|||||||
|
|
||||||
export interface ISalesEstimatesFilter extends IDynamicListFilterDTO {
|
export interface ISalesEstimatesFilter extends IDynamicListFilterDTO {
|
||||||
stringifiedFilterRoles?: string;
|
stringifiedFilterRoles?: string;
|
||||||
filterQuery?: (q: any) => void;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ISalesEstimatesService {
|
export interface ISalesEstimatesService {
|
||||||
|
|||||||
@@ -79,7 +79,6 @@ export interface ISalesInvoicesFilter extends IDynamicListFilter {
|
|||||||
page: number;
|
page: number;
|
||||||
pageSize: number;
|
pageSize: number;
|
||||||
searchKeyword?: string;
|
searchKeyword?: string;
|
||||||
filterQuery?: (q: Knex.QueryBuilder) => void;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ISalesInvoicesService {
|
export interface ISalesInvoicesService {
|
||||||
|
|||||||
@@ -29,9 +29,7 @@ export interface ISaleReceipt {
|
|||||||
entries?: IItemEntry[];
|
entries?: IItemEntry[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ISalesReceiptsFilter {
|
export interface ISalesReceiptsFilter {}
|
||||||
filterQuery?: (query: any) => void;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface ISaleReceiptDTO {
|
export interface ISaleReceiptDTO {
|
||||||
customerId: number;
|
customerId: number;
|
||||||
|
|||||||
@@ -33,7 +33,3 @@ export interface IOrganizationBuildEventPayload {
|
|||||||
buildDTO: IOrganizationBuildDTO;
|
buildDTO: IOrganizationBuildDTO;
|
||||||
systemUser: ISystemUser;
|
systemUser: ISystemUser;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IOrganizationBuiltEventPayload {
|
|
||||||
tenantId: number;
|
|
||||||
}
|
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
export interface SubscriptionPayload {
|
|
||||||
lemonSqueezyId?: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export enum SubscriptionPaymentStatus {
|
|
||||||
Succeed = 'succeed',
|
|
||||||
Failed = 'failed',
|
|
||||||
}
|
|
||||||
@@ -51,4 +51,5 @@ export interface ISystemService {
|
|||||||
cache();
|
cache();
|
||||||
repositories();
|
repositories();
|
||||||
knex();
|
knex();
|
||||||
|
dbManager();
|
||||||
}
|
}
|
||||||
@@ -106,7 +106,6 @@ export interface IVendorCreditsQueryDTO extends IDynamicListFilter {
|
|||||||
page: number;
|
page: number;
|
||||||
pageSize: number;
|
pageSize: number;
|
||||||
searchKeyword?: string;
|
searchKeyword?: string;
|
||||||
filterQuery?: (q: any) => void;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IVendorCreditEditingPayload {
|
export interface IVendorCreditEditingPayload {
|
||||||
|
|||||||
@@ -75,7 +75,6 @@ export * from './Times';
|
|||||||
export * from './ProjectProfitabilitySummary';
|
export * from './ProjectProfitabilitySummary';
|
||||||
export * from './TaxRate';
|
export * from './TaxRate';
|
||||||
export * from './Plaid';
|
export * from './Plaid';
|
||||||
export * from './Subscription';
|
|
||||||
|
|
||||||
export interface I18nService {
|
export interface I18nService {
|
||||||
__: (input: string) => string;
|
__: (input: string) => string;
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ export default class ComputeItemCostJob {
|
|||||||
|
|
||||||
agenda.define(
|
agenda.define(
|
||||||
'compute-item-cost',
|
'compute-item-cost',
|
||||||
{ priority: 'high', concurrency: 20 },
|
{ priority: 'high', concurrency: 1 },
|
||||||
this.handler.bind(this)
|
this.handler.bind(this)
|
||||||
);
|
);
|
||||||
this.agenda.on('start:compute-item-cost', this.onJobStart.bind(this));
|
this.agenda.on('start:compute-item-cost', this.onJobStart.bind(this));
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ export default class OrganizationSetupJob {
|
|||||||
constructor(agenda) {
|
constructor(agenda) {
|
||||||
agenda.define(
|
agenda.define(
|
||||||
'organization-setup',
|
'organization-setup',
|
||||||
{ priority: 'high', concurrency: 20 },
|
{ priority: 'high', concurrency: 1 },
|
||||||
this.handler
|
this.handler
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ export default class WriteInvoicesJournalEntries {
|
|||||||
|
|
||||||
agenda.define(
|
agenda.define(
|
||||||
eventName,
|
eventName,
|
||||||
{ priority: 'normal', concurrency: 20 },
|
{ priority: 'normal', concurrency: 1 },
|
||||||
this.handler.bind(this)
|
this.handler.bind(this)
|
||||||
);
|
);
|
||||||
agenda.on(`complete:${eventName}`, this.onJobCompleted.bind(this));
|
agenda.on(`complete:${eventName}`, this.onJobCompleted.bind(this));
|
||||||
|
|||||||
@@ -1,12 +1,69 @@
|
|||||||
|
import { forEach } from 'lodash';
|
||||||
import { Configuration, PlaidApi, PlaidEnvironments } from 'plaid';
|
import { Configuration, PlaidApi, PlaidEnvironments } from 'plaid';
|
||||||
|
import { createPlaidApiEvent } from './PlaidApiEventsDBSync';
|
||||||
import config from '@/config';
|
import config from '@/config';
|
||||||
|
|
||||||
|
const OPTIONS = { clientApp: 'Plaid-Pattern' };
|
||||||
|
|
||||||
|
// We want to log requests to / responses from the Plaid API (via the Plaid client), as this data
|
||||||
|
// can be useful for troubleshooting.
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Logging function for Plaid client methods that use an access_token as an argument. Associates
|
||||||
|
* the Plaid API event log entry with the item and user the request is for.
|
||||||
|
*
|
||||||
|
* @param {string} clientMethod the name of the Plaid client method called.
|
||||||
|
* @param {Array} clientMethodArgs the arguments passed to the Plaid client method.
|
||||||
|
* @param {Object} response the response from the Plaid client.
|
||||||
|
*/
|
||||||
|
const defaultLogger = async (clientMethod, clientMethodArgs, response) => {
|
||||||
|
const accessToken = clientMethodArgs[0].access_token;
|
||||||
|
// const { id: itemId, user_id: userId } = await retrieveItemByPlaidAccessToken(
|
||||||
|
// accessToken
|
||||||
|
// );
|
||||||
|
// await createPlaidApiEvent(1, 1, clientMethod, clientMethodArgs, response);
|
||||||
|
|
||||||
|
// console.log(response);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Logging function for Plaid client methods that do not use access_token as an argument. These
|
||||||
|
* Plaid API event log entries will not be associated with an item or user.
|
||||||
|
*
|
||||||
|
* @param {string} clientMethod the name of the Plaid client method called.
|
||||||
|
* @param {Array} clientMethodArgs the arguments passed to the Plaid client method.
|
||||||
|
* @param {Object} response the response from the Plaid client.
|
||||||
|
*/
|
||||||
|
const noAccessTokenLogger = async (
|
||||||
|
clientMethod,
|
||||||
|
clientMethodArgs,
|
||||||
|
response
|
||||||
|
) => {
|
||||||
|
// console.log(response);
|
||||||
|
|
||||||
|
// await createPlaidApiEvent(
|
||||||
|
// undefined,
|
||||||
|
// undefined,
|
||||||
|
// clientMethod,
|
||||||
|
// clientMethodArgs,
|
||||||
|
// response
|
||||||
|
// );
|
||||||
|
};
|
||||||
|
|
||||||
|
// Plaid client methods used in this app, mapped to their appropriate logging functions.
|
||||||
|
const clientMethodLoggingFns = {
|
||||||
|
accountsGet: defaultLogger,
|
||||||
|
institutionsGet: noAccessTokenLogger,
|
||||||
|
institutionsGetById: noAccessTokenLogger,
|
||||||
|
itemPublicTokenExchange: noAccessTokenLogger,
|
||||||
|
itemRemove: defaultLogger,
|
||||||
|
linkTokenCreate: noAccessTokenLogger,
|
||||||
|
transactionsSync: defaultLogger,
|
||||||
|
sandboxItemResetLogin: defaultLogger,
|
||||||
|
};
|
||||||
// Wrapper for the Plaid client. This allows us to easily log data for all Plaid client requests.
|
// Wrapper for the Plaid client. This allows us to easily log data for all Plaid client requests.
|
||||||
export class PlaidClientWrapper {
|
export class PlaidClientWrapper {
|
||||||
private static instance: PlaidClientWrapper;
|
constructor() {
|
||||||
private client: PlaidApi;
|
|
||||||
|
|
||||||
private constructor() {
|
|
||||||
// Initialize the Plaid client.
|
// Initialize the Plaid client.
|
||||||
const configuration = new Configuration({
|
const configuration = new Configuration({
|
||||||
basePath: PlaidEnvironments[config.plaid.env],
|
basePath: PlaidEnvironments[config.plaid.env],
|
||||||
@@ -18,13 +75,26 @@ export class PlaidClientWrapper {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
this.client = new PlaidApi(configuration);
|
this.client = new PlaidApi(configuration);
|
||||||
|
|
||||||
|
// Wrap the Plaid client methods to add a logging function.
|
||||||
|
forEach(clientMethodLoggingFns, (logFn, method) => {
|
||||||
|
this[method] = this.createWrappedClientMethod(method, logFn);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public static getClient(): PlaidApi {
|
// Allows us to log API request data for troubleshooting purposes.
|
||||||
if (!PlaidClientWrapper.instance) {
|
createWrappedClientMethod(clientMethod, log) {
|
||||||
PlaidClientWrapper.instance = new PlaidClientWrapper();
|
return async (...args) => {
|
||||||
}
|
try {
|
||||||
return PlaidClientWrapper.instance.client;
|
const res = await this.client[clientMethod](...args);
|
||||||
|
await log(clientMethod, args, res);
|
||||||
|
return res;
|
||||||
|
} catch (err) {
|
||||||
|
await log(clientMethod, args, err?.response?.data);
|
||||||
|
throw err;
|
||||||
|
}
|
||||||
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user