mirror of
https://github.com/bigcapitalhq/bigcapital.git
synced 2026-02-18 05:40:31 +00:00
Compare commits
119 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
74b6e41cd4 | ||
|
|
d239003047 | ||
|
|
9f21f649f0 | ||
|
|
d3d2112b8a | ||
|
|
3795322a65 | ||
|
|
fe5cd5a8ea | ||
|
|
c032a5db16 | ||
|
|
3fcb6fefde | ||
|
|
16f5cb713d | ||
|
|
f7a7925028 | ||
|
|
66fb0c9fa3 | ||
|
|
85acc85f17 | ||
|
|
c76ce09191 | ||
|
|
e3532098b2 | ||
|
|
b6783eb22e | ||
|
|
4ef00ab122 | ||
|
|
3dd827417a | ||
|
|
cbacd02aa2 | ||
|
|
3b7e0fb78a | ||
|
|
9add716395 | ||
|
|
083ea28a1f | ||
|
|
1b51742c36 | ||
|
|
0c6f23e770 | ||
|
|
37a8ca4e97 | ||
|
|
795303c3a8 | ||
|
|
63ba3f0898 | ||
|
|
62594efa00 | ||
|
|
9ac0dcbdc3 | ||
|
|
df588dc4ce | ||
|
|
d54f14a87a | ||
|
|
a4d4be54c1 | ||
|
|
ddd17e74b5 | ||
|
|
81c0761fbe | ||
|
|
0812e3087e | ||
|
|
0dd05493b2 | ||
|
|
bfb3909d26 | ||
|
|
266902026e | ||
|
|
791c4a4e9e | ||
|
|
2cfa9123b8 | ||
|
|
bb9614aafb | ||
|
|
302564a56e | ||
|
|
dcfc231d4d | ||
|
|
64080ed678 | ||
|
|
263935d91e | ||
|
|
7f5ffb8da1 | ||
|
|
f07d25edbe | ||
|
|
7c07d6b5ff | ||
|
|
e433f4ad68 | ||
|
|
a79b9caff6 | ||
|
|
2227cead66 | ||
|
|
410c4ea3e2 | ||
|
|
f92acbcbe0 | ||
|
|
c986585cd9 | ||
|
|
250f0a30ef | ||
|
|
84b5e1adc1 | ||
|
|
2ab28370db | ||
|
|
a88a525326 | ||
|
|
fce8e2c5a4 | ||
|
|
095608266c | ||
|
|
0ec8aaa330 | ||
|
|
9fcb3ef77d | ||
|
|
dc61c57daf | ||
|
|
af284f3f6d | ||
|
|
c43123db76 | ||
|
|
ebbcab3926 | ||
|
|
a235f573c0 | ||
|
|
84a0b8f495 | ||
|
|
b87321c897 | ||
|
|
fc6ebfea5c | ||
|
|
c9fe6d9b37 | ||
|
|
161d60393a | ||
|
|
79413fa85e | ||
|
|
58552c6c94 | ||
|
|
2072e35cfa | ||
|
|
1eaac9d691 | ||
|
|
a916e8a0cb | ||
|
|
a56f560036 | ||
|
|
0fb886936c | ||
|
|
670136916f | ||
|
|
768297f137 | ||
|
|
ef505a0a62 | ||
|
|
42d40620ec | ||
|
|
ee2d8d3065 | ||
|
|
959ef7a691 | ||
|
|
60f03f534b | ||
|
|
e44ebb700a | ||
|
|
8e94c7a755 | ||
|
|
3a2ca36c07 | ||
|
|
88ece74c8a | ||
|
|
67a8610328 | ||
|
|
278d61ce61 | ||
|
|
e72d6ad6b8 | ||
|
|
bf66b31679 | ||
|
|
b4d426d2e8 | ||
|
|
7f7dd270e7 | ||
|
|
f6bad8fe30 | ||
|
|
820b363f79 | ||
|
|
07740a51ef | ||
|
|
d15fb6fe19 | ||
|
|
5749ccec81 | ||
|
|
4a99f6c0cf | ||
|
|
59f480f9d5 | ||
|
|
6cb9c919b5 | ||
|
|
1062b65b5b | ||
|
|
bf3a70cabd | ||
|
|
f46cd28f87 | ||
|
|
dffcfe50aa | ||
|
|
fac55efbc7 | ||
|
|
8b90ce5f6c | ||
|
|
705b8da053 | ||
|
|
4a05ccc692 | ||
|
|
3200d65d90 | ||
|
|
3f23038227 | ||
|
|
408c807fc2 | ||
|
|
d29079a8c5 | ||
|
|
cca596b4a9 | ||
|
|
fed620505d | ||
|
|
a008aea3f3 | ||
|
|
df8b68fda6 |
@@ -89,3 +89,7 @@ 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=
|
||||||
@@ -37,6 +37,7 @@
|
|||||||
"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",
|
||||||
@@ -98,6 +99,7 @@
|
|||||||
"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",
|
||||||
@@ -107,6 +109,7 @@
|
|||||||
"rtl-detect": "^1.0.4",
|
"rtl-detect": "^1.0.4",
|
||||||
"socket.io": "^4.7.4",
|
"socket.io": "^4.7.4",
|
||||||
"source-map-loader": "^4.0.1",
|
"source-map-loader": "^4.0.1",
|
||||||
|
"swagger-ui-express": "^5.0.1",
|
||||||
"tmp-promise": "^3.0.3",
|
"tmp-promise": "^3.0.3",
|
||||||
"ts-transformer-keys": "^0.4.2",
|
"ts-transformer-keys": "^0.4.2",
|
||||||
"tsyringe": "^4.3.0",
|
"tsyringe": "^4.3.0",
|
||||||
|
|||||||
@@ -5,7 +5,14 @@ import { body, param } from 'express-validator';
|
|||||||
import BaseController from '@/api/controllers/BaseController';
|
import BaseController from '@/api/controllers/BaseController';
|
||||||
import { AttachmentsApplication } from '@/services/Attachments/AttachmentsApplication';
|
import { AttachmentsApplication } from '@/services/Attachments/AttachmentsApplication';
|
||||||
import { AttachmentUploadPipeline } from '@/services/Attachments/S3UploadPipeline';
|
import { AttachmentUploadPipeline } from '@/services/Attachments/S3UploadPipeline';
|
||||||
|
import {
|
||||||
|
ApiOperation,
|
||||||
|
ApiResponse,
|
||||||
|
ApiTags,
|
||||||
|
Route,
|
||||||
|
} from '@/decorators/swagger-decorators';
|
||||||
|
|
||||||
|
@ApiTags('Attachments')
|
||||||
@Service()
|
@Service()
|
||||||
export class AttachmentsController extends BaseController {
|
export class AttachmentsController extends BaseController {
|
||||||
@Inject()
|
@Inject()
|
||||||
@@ -121,6 +128,26 @@ export class AttachmentsController extends BaseController {
|
|||||||
* @param {NextFunction} next
|
* @param {NextFunction} next
|
||||||
* @returns {Promise<Response|void>}
|
* @returns {Promise<Response|void>}
|
||||||
*/
|
*/
|
||||||
|
@ApiResponse({
|
||||||
|
status: 200,
|
||||||
|
description: 'Details of the given attachement',
|
||||||
|
schema: {
|
||||||
|
type: 'array',
|
||||||
|
items: {
|
||||||
|
type: 'object',
|
||||||
|
properties: {
|
||||||
|
id: { type: 'string' },
|
||||||
|
name: { type: 'string' },
|
||||||
|
email: { type: 'string' },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
@ApiOperation({
|
||||||
|
summary: 'Retrieve a specific details of attachment',
|
||||||
|
description: 'Get all registered users',
|
||||||
|
})
|
||||||
|
@Route('/attachments/:id')
|
||||||
private async getAttachment(
|
private async getAttachment(
|
||||||
req: Request,
|
req: Request,
|
||||||
res: Response,
|
res: Response,
|
||||||
|
|||||||
@@ -46,6 +46,10 @@ export class ExcludeBankTransactionsController extends BaseController {
|
|||||||
query('account_id').optional().isNumeric().toInt(),
|
query('account_id').optional().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(),
|
||||||
],
|
],
|
||||||
this.validationResult,
|
this.validationResult,
|
||||||
this.getExcludedBankTransactions.bind(this)
|
this.getExcludedBankTransactions.bind(this)
|
||||||
|
|||||||
@@ -21,6 +21,10 @@ export class RecognizedTransactionsController extends BaseController {
|
|||||||
query('page').optional().isNumeric().toInt(),
|
query('page').optional().isNumeric().toInt(),
|
||||||
query('page_size').optional().isNumeric().toInt(),
|
query('page_size').optional().isNumeric().toInt(),
|
||||||
query('account_id').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.validationResult,
|
||||||
this.getRecognizedTransactions.bind(this)
|
this.getRecognizedTransactions.bind(this)
|
||||||
|
|||||||
@@ -84,6 +84,10 @@ 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(),
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -8,6 +8,11 @@ import { IItemDTO, ItemAction, AbilitySubject } from '@/interfaces';
|
|||||||
import { DATATYPES_LENGTH } from '@/data/DataTypes';
|
import { DATATYPES_LENGTH } from '@/data/DataTypes';
|
||||||
import CheckAbilities from '@/api/middleware/CheckPolicies';
|
import CheckAbilities from '@/api/middleware/CheckPolicies';
|
||||||
import { ItemsApplication } from '@/services/Items/ItemsApplication';
|
import { ItemsApplication } from '@/services/Items/ItemsApplication';
|
||||||
|
import {
|
||||||
|
ApiOperation,
|
||||||
|
ApiResponse,
|
||||||
|
Route,
|
||||||
|
} from '@/decorators/swagger-decorators';
|
||||||
|
|
||||||
@Service()
|
@Service()
|
||||||
export default class ItemsController extends BaseController {
|
export default class ItemsController extends BaseController {
|
||||||
@@ -198,6 +203,22 @@ export default class ItemsController extends BaseController {
|
|||||||
* @param {Request} req
|
* @param {Request} req
|
||||||
* @param {Response} res
|
* @param {Response} res
|
||||||
*/
|
*/
|
||||||
|
@ApiResponse({
|
||||||
|
status: 200,
|
||||||
|
description: 'Details of the given attachement',
|
||||||
|
schema: {
|
||||||
|
type: 'object',
|
||||||
|
properties: {
|
||||||
|
id: { type: 'string' },
|
||||||
|
name: { type: 'string' },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
@ApiOperation({
|
||||||
|
summary: 'Creates a new item (inventory or service)',
|
||||||
|
description: 'Get all registered users',
|
||||||
|
})
|
||||||
|
@Route('/items')
|
||||||
private async newItem(req: Request, res: Response, next: NextFunction) {
|
private async newItem(req: Request, res: Response, next: NextFunction) {
|
||||||
const { tenantId } = req;
|
const { tenantId } = req;
|
||||||
const itemDTO: IItemDTO = this.matchedBodyData(req);
|
const itemDTO: IItemDTO = this.matchedBodyData(req);
|
||||||
|
|||||||
@@ -0,0 +1,87 @@
|
|||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -113,7 +113,7 @@ export class SubscriptionController extends BaseController {
|
|||||||
const { tenantId } = req;
|
const { tenantId } = req;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await this.subscriptionApp.cancelSubscription(tenantId, '455610');
|
await this.subscriptionApp.cancelSubscription(tenantId);
|
||||||
|
|
||||||
return res.status(200).send({
|
return res.status(200).send({
|
||||||
status: 200,
|
status: 200,
|
||||||
|
|||||||
@@ -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'] ?? '';
|
const signature = req.headers['x-signature'] as string ?? '';
|
||||||
const rawBody = req.rawBody;
|
const rawBody = req.rawBody;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|||||||
@@ -63,6 +63,7 @@ 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();
|
||||||
@@ -80,6 +81,7 @@ 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,11 +1,21 @@
|
|||||||
import { Request, Response, NextFunction } from 'express';
|
|
||||||
import { Container } from 'typedi';
|
import { Container } from 'typedi';
|
||||||
|
import { Request, Response, NextFunction } from 'express';
|
||||||
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 Logger = Container.get('logger');
|
const settings = await initializeTenantSettings(tenantId);
|
||||||
|
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')) {
|
||||||
@@ -18,10 +28,5 @@ export default async (req: Request, res: Response, next: NextFunction) => {
|
|||||||
|
|
||||||
await settings.load();
|
await settings.load();
|
||||||
|
|
||||||
req.settings = settings;
|
return settings;
|
||||||
|
|
||||||
res.on('finish', async () => {
|
|
||||||
await settings.save();
|
|
||||||
});
|
|
||||||
next();
|
|
||||||
}
|
}
|
||||||
@@ -1,6 +1,8 @@
|
|||||||
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;
|
||||||
@@ -19,8 +21,10 @@ export default (subscriptionSlug = 'main') =>
|
|||||||
errors: [{ type: 'TENANT.HAS.NO.SUBSCRIPTION' }],
|
errors: [{ type: 'TENANT.HAS.NO.SUBSCRIPTION' }],
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
// Validate in case the subscription is inactive.
|
const isMethodSupported = SupportedMethods.includes(req.method);
|
||||||
else if (subscription.inactive()) {
|
const isSubscriptionInactive = 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,6 +4,7 @@ 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;
|
||||||
@@ -16,7 +17,7 @@ export default (req: Request, tenant: ITenant) => {
|
|||||||
|
|
||||||
const tenantContainer = tenantServices.tenantContainer(tenantId);
|
const tenantContainer = tenantServices.tenantContainer(tenantId);
|
||||||
|
|
||||||
tenantContainer.set('i18n', injectI18nUtils(req));
|
tenantContainer.set('i18n', injectI18nUtils());
|
||||||
|
|
||||||
const knexInstance = tenantServices.knex(tenantId);
|
const knexInstance = tenantServices.knex(tenantId);
|
||||||
const models = tenantServices.models(tenantId);
|
const models = tenantServices.models(tenantId);
|
||||||
@@ -33,14 +34,35 @@ export default (req: Request, tenant: ITenant) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const injectI18nUtils = (req) => {
|
export const injectI18nUtils = (req) => {
|
||||||
const locale = req.getLocale();
|
const globalI18n = Container.get('i18n');
|
||||||
|
const locale = globalI18n.getLocale();
|
||||||
const direction = rtlDetect.getLangDir(locale);
|
const direction = rtlDetect.getLangDir(locale);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
locale,
|
locale,
|
||||||
__: req.__,
|
__: globalI18n.__,
|
||||||
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);
|
||||||
|
};
|
||||||
|
|||||||
@@ -245,4 +245,20 @@ module.exports = {
|
|||||||
loops: {
|
loops: {
|
||||||
apiKey: process.env.LOOPS_API_KEY,
|
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
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
79
packages/server/src/constants/event-tracker.ts
Normal file
79
packages/server/src/constants/event-tracker.ts
Normal file
@@ -0,0 +1,79 @@
|
|||||||
|
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 SUBSCRIPTION_CANCELLED = 'Subscription cancelled';
|
||||||
|
export const SUBSCRIPTION_RESUMED = 'Subscription resumed';
|
||||||
|
export const SUBSCRIPTION_PLAN_CHANGED = 'Subscription plan changed';
|
||||||
|
|
||||||
|
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 TRANSACTIONS_LOCKING_LOCKED = 'Transactions locking locked';
|
||||||
|
export const TRANSACTIONS_LOCKING_LOCKING_CANCELLED =
|
||||||
|
'Transactions locking cancelled';
|
||||||
|
export const TRANSACTIONS_LOCKING_PARTIALLY_UNLOCKED =
|
||||||
|
'Transactions locking partially unlocked';
|
||||||
|
export const TRANSACTIONS_LOCKING_PARTIALLY_UNLOCK_CANCELLED =
|
||||||
|
'Transactions locking partially unlock cancelled';
|
||||||
|
|
||||||
|
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 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 BANK_RULE_CREATED = 'Bank rule created';
|
||||||
|
export const BANK_RULE_EDITED = 'Bank rule edited';
|
||||||
|
export const BANK_RULE_DELETED = 'Bank rule deleted';
|
||||||
|
|
||||||
|
// # Event Groups
|
||||||
|
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';
|
||||||
@@ -15,6 +15,7 @@ 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.
|
||||||
|
|||||||
63
packages/server/src/decorators/swagger-decorators.ts
Normal file
63
packages/server/src/decorators/swagger-decorators.ts
Normal file
@@ -0,0 +1,63 @@
|
|||||||
|
export const swaggerDocs = {
|
||||||
|
tags: {},
|
||||||
|
paths: {},
|
||||||
|
};
|
||||||
|
|
||||||
|
// Decorator to set a tag for a route
|
||||||
|
export function ApiTags(tag) {
|
||||||
|
return function (target) {
|
||||||
|
if (!swaggerDocs.tags[tag]) {
|
||||||
|
swaggerDocs.tags[tag] = { name: tag };
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Decorator to add an operation for a specific route
|
||||||
|
export function ApiOperation(options) {
|
||||||
|
return function (target, propertyKey, descriptor) {
|
||||||
|
const routePath = Reflect.getMetadata('path', target, propertyKey);
|
||||||
|
|
||||||
|
swaggerDocs.paths[routePath] = swaggerDocs.paths[routePath] || {};
|
||||||
|
swaggerDocs.paths[routePath].get = {
|
||||||
|
summary: options.summary,
|
||||||
|
description: options.description || '',
|
||||||
|
responses: options.responses || {
|
||||||
|
200: {
|
||||||
|
description: 'Successful Response',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Decorator to define the route path
|
||||||
|
export function Route(path) {
|
||||||
|
return function (target, propertyKey, descriptor) {
|
||||||
|
Reflect.defineMetadata('path', path, target, propertyKey);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Decorator to add a response schema for a specific route
|
||||||
|
export function ApiResponse(options) {
|
||||||
|
return function (target, propertyKey, descriptor) {
|
||||||
|
const routePath = Reflect.getMetadata('path', target, propertyKey);
|
||||||
|
|
||||||
|
if (!swaggerDocs.paths[routePath]) {
|
||||||
|
swaggerDocs.paths[routePath] = { get: {} };
|
||||||
|
}
|
||||||
|
|
||||||
|
swaggerDocs.paths[routePath].get.responses =
|
||||||
|
swaggerDocs.paths[routePath].get.responses || {};
|
||||||
|
|
||||||
|
swaggerDocs.paths[routePath].get.responses[options.status] = {
|
||||||
|
description: options.description || 'No description provided',
|
||||||
|
content: {
|
||||||
|
'application/json': {
|
||||||
|
schema: options.schema || {},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -7,7 +7,6 @@ export interface IRegisterDTO {
|
|||||||
lastName: string;
|
lastName: string;
|
||||||
email: string;
|
email: string;
|
||||||
password: string;
|
password: string;
|
||||||
organizationName: string;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ILoginDTO {
|
export interface ILoginDTO {
|
||||||
@@ -77,6 +76,10 @@ 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,6 +99,7 @@ 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 {
|
||||||
|
|||||||
@@ -167,11 +167,18 @@ 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 {
|
export interface IGetRecognizedTransactionsQuery {
|
||||||
page?: number;
|
page?: number;
|
||||||
pageSize?: number;
|
pageSize?: number;
|
||||||
accountId?: number;
|
accountId?: number;
|
||||||
}
|
minDate?: Date;
|
||||||
|
maxDate?: Date;
|
||||||
|
minAmount?: number;
|
||||||
|
maxAmount?: number;
|
||||||
|
}
|
||||||
|
|||||||
@@ -241,6 +241,7 @@ 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, IVendorCredit } from '@/interfaces';
|
import { IDynamicListFilter, IItemEntry } 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,7 +130,9 @@ 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,6 +17,7 @@ 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 {
|
||||||
|
|||||||
@@ -3,6 +3,6 @@ import { ImportFilePreviewPOJO } from "@/services/Import/interfaces";
|
|||||||
|
|
||||||
export interface IImportFileCommitedEventPayload {
|
export interface IImportFileCommitedEventPayload {
|
||||||
tenantId: number;
|
tenantId: number;
|
||||||
importId: number;
|
importId: string;
|
||||||
meta: ImportFilePreviewPOJO;
|
meta: ImportFilePreviewPOJO;
|
||||||
}
|
}
|
||||||
@@ -48,6 +48,7 @@ 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;
|
||||||
|
|||||||
@@ -151,6 +151,7 @@ export interface IModelMetaFieldCommon2 {
|
|||||||
importHint?: string;
|
importHint?: string;
|
||||||
order?: number;
|
order?: number;
|
||||||
unique?: number;
|
unique?: number;
|
||||||
|
features?: Array<any>
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IModelMetaRelationField2 {
|
export interface IModelMetaRelationField2 {
|
||||||
|
|||||||
@@ -66,7 +66,7 @@ export interface IPaymentReceivedEntry {
|
|||||||
|
|
||||||
export interface IPaymentReceivedEntryDTO {
|
export interface IPaymentReceivedEntryDTO {
|
||||||
id?: number;
|
id?: number;
|
||||||
index: number;
|
index?: number;
|
||||||
paymentReceiveId?: number;
|
paymentReceiveId?: number;
|
||||||
invoiceId: number;
|
invoiceId: number;
|
||||||
paymentAmount: number;
|
paymentAmount: number;
|
||||||
@@ -74,6 +74,7 @@ export interface IPaymentReceivedEntryDTO {
|
|||||||
|
|
||||||
export interface IPaymentsReceivedFilter extends IDynamicListFilterDTO {
|
export interface IPaymentsReceivedFilter extends IDynamicListFilterDTO {
|
||||||
stringifiedFilterRoles?: string;
|
stringifiedFilterRoles?: string;
|
||||||
|
filterQuery?: (trx: Knex.Transaction) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IPaymentReceivePageEntry {
|
export interface IPaymentReceivePageEntry {
|
||||||
|
|||||||
@@ -44,6 +44,7 @@ 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,6 +79,7 @@ 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,7 +29,9 @@ 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,3 +33,7 @@ export interface IOrganizationBuildEventPayload {
|
|||||||
buildDTO: IOrganizationBuildDTO;
|
buildDTO: IOrganizationBuildDTO;
|
||||||
systemUser: ISystemUser;
|
systemUser: ISystemUser;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface IOrganizationBuiltEventPayload {
|
||||||
|
tenantId: number;
|
||||||
|
}
|
||||||
8
packages/server/src/interfaces/Subscription.ts
Normal file
8
packages/server/src/interfaces/Subscription.ts
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
export interface SubscriptionPayload {
|
||||||
|
lemonSqueezyId?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export enum SubscriptionPaymentStatus {
|
||||||
|
Succeed = 'succeed',
|
||||||
|
Failed = 'failed',
|
||||||
|
}
|
||||||
@@ -106,6 +106,7 @@ 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,6 +75,7 @@ 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;
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import moment from 'moment';
|
|||||||
import * as R from 'ramda';
|
import * as R from 'ramda';
|
||||||
import { includes, isFunction, isObject, isUndefined, omit } from 'lodash';
|
import { includes, isFunction, isObject, isUndefined, omit } from 'lodash';
|
||||||
import { formatNumber, sortObjectKeysAlphabetically } from 'utils';
|
import { formatNumber, sortObjectKeysAlphabetically } from 'utils';
|
||||||
|
import { EXPORT_DTE_FORMAT } from '@/services/Export/constants';
|
||||||
|
|
||||||
export class Transformer {
|
export class Transformer {
|
||||||
public context: any;
|
public context: any;
|
||||||
@@ -155,19 +156,35 @@ export class Transformer {
|
|||||||
this.dateFormat = format;
|
this.dateFormat = format;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Format date.
|
||||||
|
* @param {} date
|
||||||
|
* @param {string} format -
|
||||||
|
* @returns {}
|
||||||
|
*/
|
||||||
|
protected formatDate(date, format?: string) {
|
||||||
|
// Use the export date format if the async operation is in exporting,
|
||||||
|
// otherwise use the given or default format.
|
||||||
|
const _format = this.context.exportAls.isExport
|
||||||
|
? EXPORT_DTE_FORMAT
|
||||||
|
: format || this.dateFormat;
|
||||||
|
|
||||||
|
return date ? moment(date).format(_format) : '';
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @param date
|
* @param date
|
||||||
* @returns
|
* @returns {}
|
||||||
*/
|
*/
|
||||||
protected formatDate(date) {
|
protected formatDateFromNow(date) {
|
||||||
return date ? moment(date).format(this.dateFormat) : '';
|
return date ? moment(date).fromNow(true) : '';
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @param number
|
* @param number
|
||||||
* @returns
|
* @returns {}
|
||||||
*/
|
*/
|
||||||
protected formatNumber(number, props?) {
|
protected formatNumber(number, props?) {
|
||||||
return formatNumber(number, { money: false, ...props });
|
return formatNumber(number, { money: false, ...props });
|
||||||
@@ -177,7 +194,7 @@ export class Transformer {
|
|||||||
*
|
*
|
||||||
* @param money
|
* @param money
|
||||||
* @param options
|
* @param options
|
||||||
* @returns
|
* @returns {}
|
||||||
*/
|
*/
|
||||||
protected formatMoney(money, options?) {
|
protected formatMoney(money, options?) {
|
||||||
return formatNumber(money, {
|
return formatNumber(money, {
|
||||||
|
|||||||
@@ -3,12 +3,17 @@ import { isNull } from 'lodash';
|
|||||||
import HasTenancyService from '@/services/Tenancy/TenancyService';
|
import HasTenancyService from '@/services/Tenancy/TenancyService';
|
||||||
import { TenantMetadata } from '@/system/models';
|
import { TenantMetadata } from '@/system/models';
|
||||||
import { Transformer } from './Transformer';
|
import { Transformer } from './Transformer';
|
||||||
|
import { ImportAls } from '@/services/Import/ImportALS';
|
||||||
|
import { ExportAls } from '@/services/Export/ExportAls';
|
||||||
|
|
||||||
@Service()
|
@Service()
|
||||||
export class TransformerInjectable {
|
export class TransformerInjectable {
|
||||||
@Inject()
|
@Inject()
|
||||||
private tenancy: HasTenancyService;
|
private tenancy: HasTenancyService;
|
||||||
|
|
||||||
|
@Inject()
|
||||||
|
private exportAls: ExportAls;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieves the application context of all tenant transformers.
|
* Retrieves the application context of all tenant transformers.
|
||||||
* @param {number} tenantId
|
* @param {number} tenantId
|
||||||
@@ -17,10 +22,12 @@ export class TransformerInjectable {
|
|||||||
async getApplicationContext(tenantId: number) {
|
async getApplicationContext(tenantId: number) {
|
||||||
const i18n = this.tenancy.i18n(tenantId);
|
const i18n = this.tenancy.i18n(tenantId);
|
||||||
const organization = await TenantMetadata.query().findOne({ tenantId });
|
const organization = await TenantMetadata.query().findOne({ tenantId });
|
||||||
|
const exportAls = this.exportAls;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
organization,
|
organization,
|
||||||
i18n,
|
i18n,
|
||||||
|
exportAls,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -116,6 +116,9 @@ import { DecrementUncategorizedTransactionOnCategorize } from '@/services/Cashfl
|
|||||||
import { DisconnectPlaidItemOnAccountDeleted } from '@/services/Banking/BankAccounts/events/DisconnectPlaidItemOnAccountDeleted';
|
import { DisconnectPlaidItemOnAccountDeleted } from '@/services/Banking/BankAccounts/events/DisconnectPlaidItemOnAccountDeleted';
|
||||||
import { LoopsEventsSubscriber } from '@/services/Loops/LoopsEventsSubscriber';
|
import { LoopsEventsSubscriber } from '@/services/Loops/LoopsEventsSubscriber';
|
||||||
import { DeleteUncategorizedTransactionsOnAccountDeleting } from '@/services/Banking/BankAccounts/events/DeleteUncategorizedTransactionsOnAccountDeleting';
|
import { DeleteUncategorizedTransactionsOnAccountDeleting } from '@/services/Banking/BankAccounts/events/DeleteUncategorizedTransactionsOnAccountDeleting';
|
||||||
|
import { SeedInitialDemoAccountDataOnOrgBuild } from '@/services/OneClickDemo/events/SeedInitialDemoAccountData';
|
||||||
|
import { TriggerInvalidateCacheOnSubscriptionChange } from '@/services/Subscription/events/TriggerInvalidateCacheOnSubscriptionChange';
|
||||||
|
import { EventsTrackerListeners } from '@/services/EventsTracker/events/events';
|
||||||
|
|
||||||
export default () => {
|
export default () => {
|
||||||
return new EventPublisher();
|
return new EventPublisher();
|
||||||
@@ -246,8 +249,10 @@ export const susbcribers = () => {
|
|||||||
DeleteCashflowTransactionOnUncategorize,
|
DeleteCashflowTransactionOnUncategorize,
|
||||||
PreventDeleteTransactionOnDelete,
|
PreventDeleteTransactionOnDelete,
|
||||||
|
|
||||||
|
// Subscription
|
||||||
SubscribeFreeOnSignupCommunity,
|
SubscribeFreeOnSignupCommunity,
|
||||||
SendVerfiyMailOnSignUp,
|
SendVerfiyMailOnSignUp,
|
||||||
|
TriggerInvalidateCacheOnSubscriptionChange,
|
||||||
|
|
||||||
// Attachments
|
// Attachments
|
||||||
AttachmentsOnSaleInvoiceCreated,
|
AttachmentsOnSaleInvoiceCreated,
|
||||||
@@ -281,6 +286,11 @@ export const susbcribers = () => {
|
|||||||
DeleteUncategorizedTransactionsOnAccountDeleting,
|
DeleteUncategorizedTransactionsOnAccountDeleting,
|
||||||
|
|
||||||
// Loops
|
// Loops
|
||||||
LoopsEventsSubscriber
|
LoopsEventsSubscriber,
|
||||||
|
|
||||||
|
// Demo Account
|
||||||
|
SeedInitialDemoAccountDataOnOrgBuild,
|
||||||
|
|
||||||
|
...EventsTrackerListeners
|
||||||
];
|
];
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import { I18n } from 'i18n';
|
|||||||
|
|
||||||
export default () => new I18n({
|
export default () => new I18n({
|
||||||
locales: ['en', 'ar'],
|
locales: ['en', 'ar'],
|
||||||
|
defaultLocale: 'en',
|
||||||
register: global,
|
register: global,
|
||||||
directory: global.__locales_dir,
|
directory: global.__locales_dir,
|
||||||
updateFiles: false,
|
updateFiles: false,
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
import { Features } from '@/interfaces';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
defaultFilterField: 'vendor',
|
defaultFilterField: 'vendor',
|
||||||
defaultSort: {
|
defaultSort: {
|
||||||
@@ -167,6 +169,18 @@ export default {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
branch: {
|
||||||
|
name: 'Branch',
|
||||||
|
type: 'text',
|
||||||
|
accessor: 'branch.name',
|
||||||
|
features: [Features.BRANCHES],
|
||||||
|
},
|
||||||
|
warehouse: {
|
||||||
|
name: 'Warehouse',
|
||||||
|
type: 'text',
|
||||||
|
accessor: 'warehouse.name',
|
||||||
|
features: [Features.BRANCHES],
|
||||||
|
},
|
||||||
},
|
},
|
||||||
fields2: {
|
fields2: {
|
||||||
billNumber: {
|
billNumber: {
|
||||||
@@ -238,6 +252,22 @@ export default {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
branchId: {
|
||||||
|
name: 'Branch',
|
||||||
|
fieldType: 'relation',
|
||||||
|
relationModel: 'Branch',
|
||||||
|
relationImportMatch: ['name', 'code'],
|
||||||
|
features: [Features.BRANCHES],
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
warehouseId: {
|
||||||
|
name: 'Warehouse',
|
||||||
|
fieldType: 'relation',
|
||||||
|
relationModel: 'Warehouse',
|
||||||
|
relationImportMatch: ['name', 'code'],
|
||||||
|
features: [Features.WAREHOUSES],
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -402,6 +402,7 @@ export default class Bill extends mixin(TenantModel, [
|
|||||||
const ItemEntry = require('models/ItemEntry');
|
const ItemEntry = require('models/ItemEntry');
|
||||||
const BillLandedCost = require('models/BillLandedCost');
|
const BillLandedCost = require('models/BillLandedCost');
|
||||||
const Branch = require('models/Branch');
|
const Branch = require('models/Branch');
|
||||||
|
const Warehouse = require('models/Warehouse');
|
||||||
const TaxRateTransaction = require('models/TaxRateTransaction');
|
const TaxRateTransaction = require('models/TaxRateTransaction');
|
||||||
const Document = require('models/Document');
|
const Document = require('models/Document');
|
||||||
const { MatchedBankTransaction } = require('models/MatchedBankTransaction');
|
const { MatchedBankTransaction } = require('models/MatchedBankTransaction');
|
||||||
@@ -453,6 +454,18 @@ export default class Bill extends mixin(TenantModel, [
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Bill may has associated warehouse.
|
||||||
|
*/
|
||||||
|
warehouse: {
|
||||||
|
relation: Model.BelongsToOneRelation,
|
||||||
|
modelClass: Warehouse.default,
|
||||||
|
join: {
|
||||||
|
from: 'bills.warehouseId',
|
||||||
|
to: 'warehouses.id',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Bill may has associated tax rate transactions.
|
* Bill may has associated tax rate transactions.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
import { Features } from '@/interfaces';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
defaultFilterField: 'vendor',
|
defaultFilterField: 'vendor',
|
||||||
defaultSort: {
|
defaultSort: {
|
||||||
@@ -5,6 +7,8 @@ export default {
|
|||||||
sortField: 'bill_date',
|
sortField: 'bill_date',
|
||||||
},
|
},
|
||||||
exportable: true,
|
exportable: true,
|
||||||
|
exportFlattenOn: 'entries',
|
||||||
|
|
||||||
importable: true,
|
importable: true,
|
||||||
importAggregator: 'group',
|
importAggregator: 'group',
|
||||||
importAggregateOn: 'entries',
|
importAggregateOn: 'entries',
|
||||||
@@ -77,7 +81,7 @@ export default {
|
|||||||
paymentDate: {
|
paymentDate: {
|
||||||
name: 'bill_payment.field.payment_date',
|
name: 'bill_payment.field.payment_date',
|
||||||
type: 'date',
|
type: 'date',
|
||||||
accessor: 'formattedPaymentDate'
|
accessor: 'formattedPaymentDate',
|
||||||
},
|
},
|
||||||
paymentNumber: {
|
paymentNumber: {
|
||||||
name: 'bill_payment.field.payment_number',
|
name: 'bill_payment.field.payment_number',
|
||||||
@@ -111,6 +115,40 @@ export default {
|
|||||||
name: 'bill_payment.field.reference',
|
name: 'bill_payment.field.reference',
|
||||||
type: 'text',
|
type: 'text',
|
||||||
},
|
},
|
||||||
|
entries: {
|
||||||
|
name: 'Entries',
|
||||||
|
accessor: 'entries',
|
||||||
|
type: 'collection',
|
||||||
|
collectionOf: 'object',
|
||||||
|
columns: {
|
||||||
|
date: {
|
||||||
|
name: 'Bill date',
|
||||||
|
accessor: 'bill.formattedBillDate',
|
||||||
|
},
|
||||||
|
billNo: {
|
||||||
|
name: 'Bill No.',
|
||||||
|
accessor: 'bill.billNo',
|
||||||
|
},
|
||||||
|
billRefNo: {
|
||||||
|
name: 'Bill Reference No.',
|
||||||
|
accessor: 'bill.referenceNo',
|
||||||
|
},
|
||||||
|
billAmount: {
|
||||||
|
name: 'Bill Amount',
|
||||||
|
accessor: 'bill.totalFormatted',
|
||||||
|
},
|
||||||
|
paidAmount: {
|
||||||
|
name: 'Paid Amount',
|
||||||
|
accessor: 'paymentAmountFormatted',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
branch: {
|
||||||
|
name: 'Branch',
|
||||||
|
type: 'text',
|
||||||
|
accessor: 'branch.name',
|
||||||
|
features: [Features.BRANCHES],
|
||||||
|
},
|
||||||
},
|
},
|
||||||
fields2: {
|
fields2: {
|
||||||
vendorId: {
|
vendorId: {
|
||||||
@@ -174,5 +212,13 @@ export default {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
branchId: {
|
||||||
|
name: 'Branch',
|
||||||
|
fieldType: 'relation',
|
||||||
|
relationModel: 'Branch',
|
||||||
|
relationImportMatch: ['name', 'code'],
|
||||||
|
features: [Features.BRANCHES],
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|||||||
11
packages/server/src/models/Branch.settings.ts
Normal file
11
packages/server/src/models/Branch.settings.ts
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
export default {
|
||||||
|
fields2: {
|
||||||
|
name: {
|
||||||
|
name: 'Name',
|
||||||
|
fieldType: 'text',
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
columns: {},
|
||||||
|
fields: {}
|
||||||
|
};
|
||||||
@@ -1,7 +1,9 @@
|
|||||||
import { Model } from 'objection';
|
import { Model, mixin } from 'objection';
|
||||||
import TenantModel from 'models/TenantModel';
|
import TenantModel from 'models/TenantModel';
|
||||||
|
import BranchMetadata from './Branch.settings';
|
||||||
|
import ModelSetting from './ModelSetting';
|
||||||
|
|
||||||
export default class Branch extends TenantModel {
|
export default class Branch extends mixin(TenantModel, [ModelSetting]) {
|
||||||
/**
|
/**
|
||||||
* Table name.
|
* Table name.
|
||||||
*/
|
*/
|
||||||
@@ -169,4 +171,11 @@ export default class Branch extends TenantModel {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Model settings.
|
||||||
|
*/
|
||||||
|
static get meta() {
|
||||||
|
return BranchMetadata;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
import { Features } from '@/interfaces';
|
||||||
|
|
||||||
function StatusFieldFilterQuery(query, role) {
|
function StatusFieldFilterQuery(query, role) {
|
||||||
query.modify('filterByStatus', role.value);
|
query.modify('filterByStatus', role.value);
|
||||||
}
|
}
|
||||||
@@ -100,7 +102,7 @@ export default {
|
|||||||
},
|
},
|
||||||
creditNoteDate: {
|
creditNoteDate: {
|
||||||
name: 'Credit Note Date',
|
name: 'Credit Note Date',
|
||||||
accessor: 'formattedCreditNoteDate'
|
accessor: 'formattedCreditNoteDate',
|
||||||
},
|
},
|
||||||
referenceNo: {
|
referenceNo: {
|
||||||
name: 'Reference No.',
|
name: 'Reference No.',
|
||||||
@@ -147,6 +149,18 @@ export default {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
branch: {
|
||||||
|
name: 'Branch',
|
||||||
|
type: 'text',
|
||||||
|
accessor: 'branch.name',
|
||||||
|
features: [Features.BRANCHES],
|
||||||
|
},
|
||||||
|
warehouse: {
|
||||||
|
name: 'Warehouse',
|
||||||
|
type: 'text',
|
||||||
|
accessor: 'warehouse.name',
|
||||||
|
features: [Features.BRANCHES],
|
||||||
|
},
|
||||||
},
|
},
|
||||||
fields2: {
|
fields2: {
|
||||||
customerId: {
|
customerId: {
|
||||||
@@ -215,5 +229,21 @@ export default {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
branchId: {
|
||||||
|
name: 'Branch',
|
||||||
|
fieldType: 'relation',
|
||||||
|
relationModel: 'Branch',
|
||||||
|
relationImportMatch: ['name', 'code'],
|
||||||
|
features: [Features.BRANCHES],
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
warehouseId: {
|
||||||
|
name: 'Warehouse',
|
||||||
|
fieldType: 'relation',
|
||||||
|
relationModel: 'Warehouse',
|
||||||
|
relationImportMatch: ['name', 'code'],
|
||||||
|
features: [Features.WAREHOUSES],
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -175,6 +175,7 @@ export default class CreditNote extends mixin(TenantModel, [
|
|||||||
const Customer = require('models/Customer');
|
const Customer = require('models/Customer');
|
||||||
const Branch = require('models/Branch');
|
const Branch = require('models/Branch');
|
||||||
const Document = require('models/Document');
|
const Document = require('models/Document');
|
||||||
|
const Warehouse = require('models/Warehouse');
|
||||||
|
|
||||||
return {
|
return {
|
||||||
/**
|
/**
|
||||||
@@ -235,6 +236,18 @@ export default class CreditNote extends mixin(TenantModel, [
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Credit note may has associated warehouse.
|
||||||
|
*/
|
||||||
|
warehouse: {
|
||||||
|
relation: Model.BelongsToOneRelation,
|
||||||
|
modelClass: Warehouse.default,
|
||||||
|
join: {
|
||||||
|
from: 'credit_notes.warehouseId',
|
||||||
|
to: 'warehouses.id',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Credit note may has many attached attachments.
|
* Credit note may has many attached attachments.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -95,6 +95,11 @@ export default {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
columns: {
|
columns: {
|
||||||
|
customerType: {
|
||||||
|
name: 'Customer Type',
|
||||||
|
type: 'text',
|
||||||
|
accessor: 'formattedCustomerType',
|
||||||
|
},
|
||||||
firstName: {
|
firstName: {
|
||||||
name: 'vendor.field.first_name',
|
name: 'vendor.field.first_name',
|
||||||
type: 'text',
|
type: 'text',
|
||||||
@@ -135,116 +140,117 @@ export default {
|
|||||||
openingBalance: {
|
openingBalance: {
|
||||||
name: 'vendor.field.opening_balance',
|
name: 'vendor.field.opening_balance',
|
||||||
type: 'number',
|
type: 'number',
|
||||||
printable: false
|
printable: false,
|
||||||
},
|
},
|
||||||
openingBalanceAt: {
|
openingBalanceAt: {
|
||||||
name: 'vendor.field.opening_balance_at',
|
name: 'vendor.field.opening_balance_at',
|
||||||
type: 'date',
|
type: 'date',
|
||||||
printable: false
|
printable: false,
|
||||||
|
accessor: 'formattedOpeningBalanceAt'
|
||||||
},
|
},
|
||||||
currencyCode: {
|
currencyCode: {
|
||||||
name: 'vendor.field.currency',
|
name: 'vendor.field.currency',
|
||||||
type: 'text',
|
type: 'text',
|
||||||
printable: false
|
printable: false,
|
||||||
},
|
},
|
||||||
status: {
|
status: {
|
||||||
name: 'vendor.field.status',
|
name: 'vendor.field.status',
|
||||||
printable: false
|
printable: false,
|
||||||
},
|
},
|
||||||
note: {
|
note: {
|
||||||
name: 'vendor.field.note',
|
name: 'vendor.field.note',
|
||||||
printable: false
|
printable: false,
|
||||||
},
|
},
|
||||||
// Billing Address
|
// Billing Address
|
||||||
billingAddress1: {
|
billingAddress1: {
|
||||||
name: 'Billing Address 1',
|
name: 'Billing Address 1',
|
||||||
column: 'billing_address1',
|
column: 'billing_address1',
|
||||||
type: 'text',
|
type: 'text',
|
||||||
printable: false
|
printable: false,
|
||||||
},
|
},
|
||||||
billingAddress2: {
|
billingAddress2: {
|
||||||
name: 'Billing Address 2',
|
name: 'Billing Address 2',
|
||||||
column: 'billing_address2',
|
column: 'billing_address2',
|
||||||
type: 'text',
|
type: 'text',
|
||||||
printable: false
|
printable: false,
|
||||||
},
|
},
|
||||||
billingAddressCity: {
|
billingAddressCity: {
|
||||||
name: 'Billing Address City',
|
name: 'Billing Address City',
|
||||||
column: 'billing_address_city',
|
column: 'billing_address_city',
|
||||||
type: 'text',
|
type: 'text',
|
||||||
printable: false
|
printable: false,
|
||||||
},
|
},
|
||||||
billingAddressCountry: {
|
billingAddressCountry: {
|
||||||
name: 'Billing Address Country',
|
name: 'Billing Address Country',
|
||||||
column: 'billing_address_country',
|
column: 'billing_address_country',
|
||||||
type: 'text',
|
type: 'text',
|
||||||
printable: false
|
printable: false,
|
||||||
},
|
},
|
||||||
billingAddressPostcode: {
|
billingAddressPostcode: {
|
||||||
name: 'Billing Address Postcode',
|
name: 'Billing Address Postcode',
|
||||||
column: 'billing_address_postcode',
|
column: 'billing_address_postcode',
|
||||||
type: 'text',
|
type: 'text',
|
||||||
printable: false
|
printable: false,
|
||||||
},
|
},
|
||||||
billingAddressState: {
|
billingAddressState: {
|
||||||
name: 'Billing Address State',
|
name: 'Billing Address State',
|
||||||
column: 'billing_address_state',
|
column: 'billing_address_state',
|
||||||
type: 'text',
|
type: 'text',
|
||||||
printable: false
|
printable: false,
|
||||||
},
|
},
|
||||||
billingAddressPhone: {
|
billingAddressPhone: {
|
||||||
name: 'Billing Address Phone',
|
name: 'Billing Address Phone',
|
||||||
column: 'billing_address_phone',
|
column: 'billing_address_phone',
|
||||||
type: 'text',
|
type: 'text',
|
||||||
printable: false
|
printable: false,
|
||||||
},
|
},
|
||||||
// Shipping Address
|
// Shipping Address
|
||||||
shippingAddress1: {
|
shippingAddress1: {
|
||||||
name: 'Shipping Address 1',
|
name: 'Shipping Address 1',
|
||||||
column: 'shipping_address1',
|
column: 'shipping_address1',
|
||||||
type: 'text',
|
type: 'text',
|
||||||
printable: false
|
printable: false,
|
||||||
},
|
},
|
||||||
shippingAddress2: {
|
shippingAddress2: {
|
||||||
name: 'Shipping Address 2',
|
name: 'Shipping Address 2',
|
||||||
column: 'shipping_address2',
|
column: 'shipping_address2',
|
||||||
type: 'text',
|
type: 'text',
|
||||||
printable: false
|
printable: false,
|
||||||
},
|
},
|
||||||
shippingAddressCity: {
|
shippingAddressCity: {
|
||||||
name: 'Shipping Address City',
|
name: 'Shipping Address City',
|
||||||
column: 'shipping_address_city',
|
column: 'shipping_address_city',
|
||||||
type: 'text',
|
type: 'text',
|
||||||
printable: false
|
printable: false,
|
||||||
},
|
},
|
||||||
shippingAddressCountry: {
|
shippingAddressCountry: {
|
||||||
name: 'Shipping Address Country',
|
name: 'Shipping Address Country',
|
||||||
column: 'shipping_address_country',
|
column: 'shipping_address_country',
|
||||||
type: 'text',
|
type: 'text',
|
||||||
printable: false
|
printable: false,
|
||||||
},
|
},
|
||||||
shippingAddressPostcode: {
|
shippingAddressPostcode: {
|
||||||
name: 'Shipping Address Postcode',
|
name: 'Shipping Address Postcode',
|
||||||
column: 'shipping_address_postcode',
|
column: 'shipping_address_postcode',
|
||||||
type: 'text',
|
type: 'text',
|
||||||
printable: false
|
printable: false,
|
||||||
},
|
},
|
||||||
shippingAddressPhone: {
|
shippingAddressPhone: {
|
||||||
name: 'Shipping Address Phone',
|
name: 'Shipping Address Phone',
|
||||||
column: 'shipping_address_phone',
|
column: 'shipping_address_phone',
|
||||||
type: 'text',
|
type: 'text',
|
||||||
printable: false
|
printable: false,
|
||||||
},
|
},
|
||||||
shippingAddressState: {
|
shippingAddressState: {
|
||||||
name: 'Shipping Address State',
|
name: 'Shipping Address State',
|
||||||
column: 'shipping_address_state',
|
column: 'shipping_address_state',
|
||||||
type: 'text',
|
type: 'text',
|
||||||
printable: false
|
printable: false,
|
||||||
},
|
},
|
||||||
createdAt: {
|
createdAt: {
|
||||||
name: 'vendor.field.created_at',
|
name: 'vendor.field.created_at',
|
||||||
type: 'date',
|
type: 'date',
|
||||||
printable: false
|
printable: false,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
fields2: {
|
fields2: {
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
import { Features } from '@/interfaces';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Expense - Settings.
|
* Expense - Settings.
|
||||||
*/
|
*/
|
||||||
@@ -119,6 +121,12 @@ export default {
|
|||||||
type: 'boolean',
|
type: 'boolean',
|
||||||
printable: false,
|
printable: false,
|
||||||
},
|
},
|
||||||
|
branch: {
|
||||||
|
name: 'Branch',
|
||||||
|
type: 'text',
|
||||||
|
accessor: 'branch.name',
|
||||||
|
features: [Features.BRANCHES],
|
||||||
|
},
|
||||||
},
|
},
|
||||||
fields2: {
|
fields2: {
|
||||||
paymentAccountId: {
|
paymentAccountId: {
|
||||||
@@ -178,6 +186,14 @@ export default {
|
|||||||
name: 'expense.field.publish',
|
name: 'expense.field.publish',
|
||||||
fieldType: 'boolean',
|
fieldType: 'boolean',
|
||||||
},
|
},
|
||||||
|
branchId: {
|
||||||
|
name: 'Branch',
|
||||||
|
fieldType: 'relation',
|
||||||
|
relationModel: 'Branch',
|
||||||
|
relationImportMatch: ['name', 'code'],
|
||||||
|
features: [Features.BRANCHES],
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -41,17 +41,17 @@ export default {
|
|||||||
fieldType: 'boolean',
|
fieldType: 'boolean',
|
||||||
},
|
},
|
||||||
sell_price: {
|
sell_price: {
|
||||||
name: 'item.field.cost_price',
|
name: 'item.field.sell_price',
|
||||||
column: 'sell_price',
|
column: 'sell_price',
|
||||||
fieldType: 'number',
|
fieldType: 'number',
|
||||||
},
|
},
|
||||||
cost_price: {
|
cost_price: {
|
||||||
name: 'item.field.cost_account',
|
name: 'item.field.cost_price',
|
||||||
column: 'cost_price',
|
column: 'cost_price',
|
||||||
fieldType: 'number',
|
fieldType: 'number',
|
||||||
},
|
},
|
||||||
cost_account: {
|
cost_account: {
|
||||||
name: 'item.field.sell_account',
|
name: 'item.field.cost_account',
|
||||||
column: 'cost_account_id',
|
column: 'cost_account_id',
|
||||||
fieldType: 'relation',
|
fieldType: 'relation',
|
||||||
|
|
||||||
@@ -62,7 +62,7 @@ export default {
|
|||||||
relationEntityKey: 'slug',
|
relationEntityKey: 'slug',
|
||||||
},
|
},
|
||||||
sell_account: {
|
sell_account: {
|
||||||
name: 'item.field.sell_description',
|
name: 'item.field.sell_account',
|
||||||
column: 'sell_account_id',
|
column: 'sell_account_id',
|
||||||
fieldType: 'relation',
|
fieldType: 'relation',
|
||||||
|
|
||||||
@@ -155,24 +155,24 @@ export default {
|
|||||||
printable: false,
|
printable: false,
|
||||||
},
|
},
|
||||||
sellPrice: {
|
sellPrice: {
|
||||||
name: 'item.field.cost_price',
|
name: 'item.field.sell_price',
|
||||||
type: 'number',
|
type: 'number',
|
||||||
exportable: true,
|
exportable: true,
|
||||||
},
|
},
|
||||||
costPrice: {
|
costPrice: {
|
||||||
name: 'item.field.cost_account',
|
name: 'item.field.cost_price',
|
||||||
type: 'number',
|
type: 'number',
|
||||||
exportable: true,
|
exportable: true,
|
||||||
},
|
},
|
||||||
costAccount: {
|
costAccount: {
|
||||||
name: 'item.field.sell_account',
|
name: 'item.field.cost_account',
|
||||||
type: 'text',
|
type: 'text',
|
||||||
accessor: 'costAccount.name',
|
accessor: 'costAccount.name',
|
||||||
exportable: true,
|
exportable: true,
|
||||||
printable: false,
|
printable: false,
|
||||||
},
|
},
|
||||||
sellAccount: {
|
sellAccount: {
|
||||||
name: 'item.field.sell_description',
|
name: 'item.field.sell_account',
|
||||||
type: 'text',
|
type: 'text',
|
||||||
accessor: 'sellAccount.name',
|
accessor: 'sellAccount.name',
|
||||||
exportable: true,
|
exportable: true,
|
||||||
@@ -257,25 +257,25 @@ export default {
|
|||||||
name: 'item.field.sell_price',
|
name: 'item.field.sell_price',
|
||||||
fieldType: 'number',
|
fieldType: 'number',
|
||||||
},
|
},
|
||||||
cost_price: {
|
costPrice: {
|
||||||
name: 'item.field.cost_price',
|
name: 'item.field.cost_price',
|
||||||
fieldType: 'number',
|
fieldType: 'number',
|
||||||
},
|
},
|
||||||
costAccount: {
|
costAccountId: {
|
||||||
name: 'item.field.cost_account',
|
name: 'item.field.cost_account',
|
||||||
fieldType: 'relation',
|
fieldType: 'relation',
|
||||||
relationModel: 'Account',
|
relationModel: 'Account',
|
||||||
relationImportMatch: ['name', 'code'],
|
relationImportMatch: ['name', 'code'],
|
||||||
importHint: 'Matches the account name or code.',
|
importHint: 'Matches the account name or code.',
|
||||||
},
|
},
|
||||||
sellAccount: {
|
sellAccountId: {
|
||||||
name: 'item.field.sell_account',
|
name: 'item.field.sell_account',
|
||||||
fieldType: 'relation',
|
fieldType: 'relation',
|
||||||
relationModel: 'Account',
|
relationModel: 'Account',
|
||||||
relationImportMatch: ['name', 'code'],
|
relationImportMatch: ['name', 'code'],
|
||||||
importHint: 'Matches the account name or code.',
|
importHint: 'Matches the account name or code.',
|
||||||
},
|
},
|
||||||
inventoryAccount: {
|
inventoryAccountId: {
|
||||||
name: 'item.field.inventory_account',
|
name: 'item.field.inventory_account',
|
||||||
fieldType: 'relation',
|
fieldType: 'relation',
|
||||||
relationModel: 'Account',
|
relationModel: 'Account',
|
||||||
|
|||||||
@@ -1,6 +1,11 @@
|
|||||||
|
import { Features } from '@/interfaces';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
importable: true,
|
importable: true,
|
||||||
|
|
||||||
exportable: true,
|
exportable: true,
|
||||||
|
exportFlattenOn: 'entries',
|
||||||
|
|
||||||
importAggregator: 'group',
|
importAggregator: 'group',
|
||||||
importAggregateOn: 'entries',
|
importAggregateOn: 'entries',
|
||||||
importAggregateBy: 'paymentReceiveNo',
|
importAggregateBy: 'paymentReceiveNo',
|
||||||
@@ -72,7 +77,7 @@ export default {
|
|||||||
amount: {
|
amount: {
|
||||||
name: 'payment_receive.field.amount',
|
name: 'payment_receive.field.amount',
|
||||||
type: 'number',
|
type: 'number',
|
||||||
accessor: 'formattedAmount'
|
accessor: 'formattedAmount',
|
||||||
},
|
},
|
||||||
referenceNo: {
|
referenceNo: {
|
||||||
name: 'payment_receive.field.reference_no',
|
name: 'payment_receive.field.reference_no',
|
||||||
@@ -92,11 +97,45 @@ export default {
|
|||||||
type: 'text',
|
type: 'text',
|
||||||
printable: false,
|
printable: false,
|
||||||
},
|
},
|
||||||
|
entries: {
|
||||||
|
name: 'Entries',
|
||||||
|
accessor: 'entries',
|
||||||
|
type: 'collection',
|
||||||
|
collectionOf: 'object',
|
||||||
|
columns: {
|
||||||
|
date: {
|
||||||
|
name: 'Invoice date',
|
||||||
|
accessor: 'invoice.invoiceDateFormatted',
|
||||||
|
},
|
||||||
|
invoiceNo: {
|
||||||
|
name: 'Invoice No.',
|
||||||
|
accessor: 'invoice.invoiceNo',
|
||||||
|
},
|
||||||
|
invoiceRefNo: {
|
||||||
|
name: 'Invoice Reference No.',
|
||||||
|
accessor: 'invoice.referenceNo',
|
||||||
|
},
|
||||||
|
invoiceAmount: {
|
||||||
|
name: 'Invoice Amount',
|
||||||
|
accessor: 'invoice.totalFormatted',
|
||||||
|
},
|
||||||
|
paidAmount: {
|
||||||
|
name: 'Paid Amount',
|
||||||
|
accessor: 'paymentAmountFormatted',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
created_at: {
|
created_at: {
|
||||||
name: 'payment_receive.field.created_at',
|
name: 'payment_receive.field.created_at',
|
||||||
type: 'date',
|
type: 'date',
|
||||||
printable: false,
|
printable: false,
|
||||||
},
|
},
|
||||||
|
branch: {
|
||||||
|
name: 'Branch',
|
||||||
|
type: 'text',
|
||||||
|
accessor: 'branch.name',
|
||||||
|
features: [Features.BRANCHES],
|
||||||
|
},
|
||||||
},
|
},
|
||||||
fields2: {
|
fields2: {
|
||||||
customerId: {
|
customerId: {
|
||||||
@@ -158,5 +197,13 @@ export default {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
branchId: {
|
||||||
|
name: 'Branch',
|
||||||
|
fieldType: 'relation',
|
||||||
|
relationModel: 'Branch',
|
||||||
|
relationImportMatch: ['name', 'code'],
|
||||||
|
features: [Features.BRANCHES],
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
import { Features } from '@/interfaces';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
defaultFilterField: 'estimate_date',
|
defaultFilterField: 'estimate_date',
|
||||||
defaultSort: {
|
defaultSort: {
|
||||||
@@ -13,7 +15,7 @@ export default {
|
|||||||
importAggregateBy: 'estimateNumber',
|
importAggregateBy: 'estimateNumber',
|
||||||
|
|
||||||
print: {
|
print: {
|
||||||
pageTitle: 'Sale Estimates'
|
pageTitle: 'Sale Estimates',
|
||||||
},
|
},
|
||||||
|
|
||||||
fields: {
|
fields: {
|
||||||
@@ -142,6 +144,7 @@ export default {
|
|||||||
delivered: {
|
delivered: {
|
||||||
name: 'Delivered',
|
name: 'Delivered',
|
||||||
type: 'boolean',
|
type: 'boolean',
|
||||||
|
accessor: 'isDelivered',
|
||||||
exportable: true,
|
exportable: true,
|
||||||
printable: false,
|
printable: false,
|
||||||
},
|
},
|
||||||
@@ -173,6 +176,18 @@ export default {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
branch: {
|
||||||
|
name: 'Branch',
|
||||||
|
type: 'text',
|
||||||
|
accessor: 'branch.name',
|
||||||
|
features: [Features.BRANCHES],
|
||||||
|
},
|
||||||
|
warehouse: {
|
||||||
|
name: 'Warehouse',
|
||||||
|
type: 'text',
|
||||||
|
accessor: 'warehouse.name',
|
||||||
|
features: [Features.BRANCHES],
|
||||||
|
},
|
||||||
},
|
},
|
||||||
fields2: {
|
fields2: {
|
||||||
customerId: {
|
customerId: {
|
||||||
@@ -251,6 +266,22 @@ export default {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
branchId: {
|
||||||
|
name: 'Branch',
|
||||||
|
fieldType: 'relation',
|
||||||
|
relationModel: 'Branch',
|
||||||
|
relationImportMatch: ['name', 'code'],
|
||||||
|
features: [Features.BRANCHES],
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
warehouseId: {
|
||||||
|
name: 'Warehouse',
|
||||||
|
fieldType: 'relation',
|
||||||
|
relationModel: 'Warehouse',
|
||||||
|
relationImportMatch: ['name', 'code'],
|
||||||
|
features: [Features.WAREHOUSES],
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -182,6 +182,7 @@ export default class SaleEstimate extends mixin(TenantModel, [
|
|||||||
const ItemEntry = require('models/ItemEntry');
|
const ItemEntry = require('models/ItemEntry');
|
||||||
const Customer = require('models/Customer');
|
const Customer = require('models/Customer');
|
||||||
const Branch = require('models/Branch');
|
const Branch = require('models/Branch');
|
||||||
|
const Warehouse = require('models/Warehouse');
|
||||||
const Document = require('models/Document');
|
const Document = require('models/Document');
|
||||||
|
|
||||||
return {
|
return {
|
||||||
@@ -221,6 +222,18 @@ export default class SaleEstimate extends mixin(TenantModel, [
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sale estimate may has associated warehouse.
|
||||||
|
*/
|
||||||
|
warehouse: {
|
||||||
|
relation: Model.BelongsToOneRelation,
|
||||||
|
modelClass: Warehouse.default,
|
||||||
|
join: {
|
||||||
|
from: 'sales_estimates.warehouseId',
|
||||||
|
to: 'warehouses.id',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sale estimate transaction may has many attached attachments.
|
* Sale estimate transaction may has many attached attachments.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
import { Features } from '@/interfaces';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
defaultFilterField: 'customer',
|
defaultFilterField: 'customer',
|
||||||
defaultSort: {
|
defaultSort: {
|
||||||
@@ -155,6 +157,7 @@ export default {
|
|||||||
name: 'invoice.field.delivered',
|
name: 'invoice.field.delivered',
|
||||||
type: 'boolean',
|
type: 'boolean',
|
||||||
printable: false,
|
printable: false,
|
||||||
|
accessor: 'isDelivered',
|
||||||
},
|
},
|
||||||
entries: {
|
entries: {
|
||||||
name: 'Entries',
|
name: 'Entries',
|
||||||
@@ -184,6 +187,18 @@ export default {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
branch: {
|
||||||
|
name: 'Branch',
|
||||||
|
type: 'text',
|
||||||
|
accessor: 'branch.name',
|
||||||
|
features: [Features.BRANCHES],
|
||||||
|
},
|
||||||
|
warehouse: {
|
||||||
|
name: 'Warehouse',
|
||||||
|
type: 'text',
|
||||||
|
accessor: 'warehouse.name',
|
||||||
|
features: [Features.BRANCHES],
|
||||||
|
},
|
||||||
},
|
},
|
||||||
fields2: {
|
fields2: {
|
||||||
invoiceDate: {
|
invoiceDate: {
|
||||||
@@ -267,6 +282,22 @@ export default {
|
|||||||
fieldType: 'boolean',
|
fieldType: 'boolean',
|
||||||
printable: false,
|
printable: false,
|
||||||
},
|
},
|
||||||
|
branchId: {
|
||||||
|
name: 'Branch',
|
||||||
|
fieldType: 'relation',
|
||||||
|
relationModel: 'Branch',
|
||||||
|
relationImportMatch: ['name', 'code'],
|
||||||
|
features: [Features.BRANCHES],
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
warehouseId: {
|
||||||
|
name: 'Warehouse',
|
||||||
|
fieldType: 'relation',
|
||||||
|
relationModel: 'Warehouse',
|
||||||
|
relationImportMatch: ['name', 'code'],
|
||||||
|
features: [Features.WAREHOUSES],
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -408,6 +408,7 @@ export default class SaleInvoice extends mixin(TenantModel, [
|
|||||||
const InventoryCostLotTracker = require('models/InventoryCostLotTracker');
|
const InventoryCostLotTracker = require('models/InventoryCostLotTracker');
|
||||||
const PaymentReceiveEntry = require('models/PaymentReceiveEntry');
|
const PaymentReceiveEntry = require('models/PaymentReceiveEntry');
|
||||||
const Branch = require('models/Branch');
|
const Branch = require('models/Branch');
|
||||||
|
const Warehouse = require('models/Warehouse');
|
||||||
const Account = require('models/Account');
|
const Account = require('models/Account');
|
||||||
const TaxRateTransaction = require('models/TaxRateTransaction');
|
const TaxRateTransaction = require('models/TaxRateTransaction');
|
||||||
const Document = require('models/Document');
|
const Document = require('models/Document');
|
||||||
@@ -499,6 +500,18 @@ export default class SaleInvoice extends mixin(TenantModel, [
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Invoice may has associated warehouse.
|
||||||
|
*/
|
||||||
|
warehouse: {
|
||||||
|
relation: Model.BelongsToOneRelation,
|
||||||
|
modelClass: Warehouse.default,
|
||||||
|
join: {
|
||||||
|
from: 'sales_invoices.warehouseId',
|
||||||
|
to: 'warehouses.id',
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Invoice may has associated written-off expense account.
|
* Invoice may has associated written-off expense account.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
import { Features } from '@/interfaces';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
defaultFilterField: 'receipt_date',
|
defaultFilterField: 'receipt_date',
|
||||||
defaultSort: {
|
defaultSort: {
|
||||||
@@ -169,6 +171,18 @@ export default {
|
|||||||
type: 'date',
|
type: 'date',
|
||||||
printable: false,
|
printable: false,
|
||||||
},
|
},
|
||||||
|
branch: {
|
||||||
|
name: 'Branch',
|
||||||
|
type: 'text',
|
||||||
|
accessor: 'branch.name',
|
||||||
|
features: [Features.BRANCHES],
|
||||||
|
},
|
||||||
|
warehouse: {
|
||||||
|
name: 'Warehouse',
|
||||||
|
type: 'text',
|
||||||
|
accessor: 'warehouse.name',
|
||||||
|
features: [Features.BRANCHES],
|
||||||
|
},
|
||||||
},
|
},
|
||||||
fields2: {
|
fields2: {
|
||||||
receiptDate: {
|
receiptDate: {
|
||||||
@@ -245,6 +259,22 @@ export default {
|
|||||||
name: 'Receipt Message',
|
name: 'Receipt Message',
|
||||||
fieldType: 'text',
|
fieldType: 'text',
|
||||||
},
|
},
|
||||||
|
branchId: {
|
||||||
|
name: 'Branch',
|
||||||
|
fieldType: 'relation',
|
||||||
|
relationModel: 'Branch',
|
||||||
|
relationImportMatch: ['name', 'code'],
|
||||||
|
features: [Features.BRANCHES],
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
warehouseId: {
|
||||||
|
name: 'Warehouse',
|
||||||
|
fieldType: 'relation',
|
||||||
|
relationModel: 'Warehouse',
|
||||||
|
relationImportMatch: ['name', 'code'],
|
||||||
|
features: [Features.WAREHOUSES],
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -109,6 +109,7 @@ export default class SaleReceipt extends mixin(TenantModel, [
|
|||||||
const ItemEntry = require('models/ItemEntry');
|
const ItemEntry = require('models/ItemEntry');
|
||||||
const Branch = require('models/Branch');
|
const Branch = require('models/Branch');
|
||||||
const Document = require('models/Document');
|
const Document = require('models/Document');
|
||||||
|
const Warehouse = require('models/Warehouse');
|
||||||
|
|
||||||
return {
|
return {
|
||||||
customer: {
|
customer: {
|
||||||
@@ -169,6 +170,18 @@ export default class SaleReceipt extends mixin(TenantModel, [
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sale receipt may has associated warehouse.
|
||||||
|
*/
|
||||||
|
warehouse: {
|
||||||
|
relation: Model.BelongsToOneRelation,
|
||||||
|
modelClass: Warehouse.default,
|
||||||
|
join: {
|
||||||
|
from: 'sales_receipts.warehouseId',
|
||||||
|
to: 'warehouses.id',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sale receipt transaction may has many attached attachments.
|
* Sale receipt transaction may has many attached attachments.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
/* eslint-disable global-require */
|
/* eslint-disable global-require */
|
||||||
|
import moment from 'moment';
|
||||||
import { Model, mixin } from 'objection';
|
import { Model, mixin } from 'objection';
|
||||||
import TenantModel from 'models/TenantModel';
|
import TenantModel from 'models/TenantModel';
|
||||||
import ModelSettings from './ModelSetting';
|
import ModelSettings from './ModelSetting';
|
||||||
import Account from './Account';
|
|
||||||
import UncategorizedCashflowTransactionMeta from './UncategorizedCashflowTransaction.meta';
|
import UncategorizedCashflowTransactionMeta from './UncategorizedCashflowTransaction.meta';
|
||||||
|
|
||||||
export default class UncategorizedCashflowTransaction extends mixin(
|
export default class UncategorizedCashflowTransaction extends mixin(
|
||||||
@@ -166,6 +166,28 @@ export default class UncategorizedCashflowTransaction extends mixin(
|
|||||||
pending(query) {
|
pending(query) {
|
||||||
query.where('pending', true);
|
query.where('pending', true);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
minAmount(query, minAmount) {
|
||||||
|
query.where('amount', '>=', minAmount);
|
||||||
|
},
|
||||||
|
|
||||||
|
maxAmount(query, maxAmount) {
|
||||||
|
query.where('amount', '<=', maxAmount);
|
||||||
|
},
|
||||||
|
|
||||||
|
toDate(query, toDate) {
|
||||||
|
const dateFormat = 'YYYY-MM-DD';
|
||||||
|
const _toDate = moment(toDate).endOf('day').format(dateFormat);
|
||||||
|
|
||||||
|
query.where('date', '<=', _toDate);
|
||||||
|
},
|
||||||
|
|
||||||
|
fromDate(query, fromDate) {
|
||||||
|
const dateFormat = 'YYYY-MM-DD';
|
||||||
|
const _fromDate = moment(fromDate).startOf('day').format(dateFormat);
|
||||||
|
|
||||||
|
query.where('date', '>=', _fromDate);
|
||||||
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
import { Features } from '@/interfaces';
|
||||||
|
|
||||||
function StatusFieldFilterQuery(query, role) {
|
function StatusFieldFilterQuery(query, role) {
|
||||||
query.modify('filterByStatus', role.value);
|
query.modify('filterByStatus', role.value);
|
||||||
}
|
}
|
||||||
@@ -160,6 +162,18 @@ export default {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
branch: {
|
||||||
|
name: 'Branch',
|
||||||
|
type: 'text',
|
||||||
|
accessor: 'branch.name',
|
||||||
|
features: [Features.BRANCHES],
|
||||||
|
},
|
||||||
|
warehouse: {
|
||||||
|
name: 'Warehouse',
|
||||||
|
type: 'text',
|
||||||
|
accessor: 'warehouse.name',
|
||||||
|
features: [Features.BRANCHES],
|
||||||
|
},
|
||||||
},
|
},
|
||||||
fields2: {
|
fields2: {
|
||||||
vendorId: {
|
vendorId: {
|
||||||
@@ -225,5 +239,21 @@ export default {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
branchId: {
|
||||||
|
name: 'Branch',
|
||||||
|
fieldType: 'relation',
|
||||||
|
relationModel: 'Branch',
|
||||||
|
relationImportMatch: ['name', 'code'],
|
||||||
|
features: [Features.BRANCHES],
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
warehouseId: {
|
||||||
|
name: 'Warehouse',
|
||||||
|
fieldType: 'relation',
|
||||||
|
relationModel: 'Warehouse',
|
||||||
|
relationImportMatch: ['name', 'code'],
|
||||||
|
features: [Features.WAREHOUSES],
|
||||||
|
required: true
|
||||||
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -178,6 +178,7 @@ export default class VendorCredit extends mixin(TenantModel, [
|
|||||||
const ItemEntry = require('models/ItemEntry');
|
const ItemEntry = require('models/ItemEntry');
|
||||||
const Branch = require('models/Branch');
|
const Branch = require('models/Branch');
|
||||||
const Document = require('models/Document');
|
const Document = require('models/Document');
|
||||||
|
const Warehouse = require('models/Warehouse');
|
||||||
|
|
||||||
return {
|
return {
|
||||||
vendor: {
|
vendor: {
|
||||||
@@ -217,6 +218,18 @@ export default class VendorCredit extends mixin(TenantModel, [
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Vendor credit may has associated warehouse.
|
||||||
|
*/
|
||||||
|
warehouse: {
|
||||||
|
relation: Model.BelongsToOneRelation,
|
||||||
|
modelClass: Warehouse.default,
|
||||||
|
join: {
|
||||||
|
from: 'vendor_credits.warehouseId',
|
||||||
|
to: 'warehouses.id',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Vendor credit may has many attached attachments.
|
* Vendor credit may has many attached attachments.
|
||||||
*/
|
*/
|
||||||
|
|||||||
11
packages/server/src/models/Warehouse.settings.ts
Normal file
11
packages/server/src/models/Warehouse.settings.ts
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
export default {
|
||||||
|
fields2: {
|
||||||
|
name: {
|
||||||
|
name: 'Name',
|
||||||
|
fieldType: 'text',
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
columns: {},
|
||||||
|
fields: {}
|
||||||
|
};
|
||||||
@@ -2,6 +2,7 @@ import { Inject, Service } from 'typedi';
|
|||||||
import { AccountsApplication } from './AccountsApplication';
|
import { AccountsApplication } from './AccountsApplication';
|
||||||
import { Exportable } from '../Export/Exportable';
|
import { Exportable } from '../Export/Exportable';
|
||||||
import { IAccountsFilter, IAccountsStructureType } from '@/interfaces';
|
import { IAccountsFilter, IAccountsStructureType } from '@/interfaces';
|
||||||
|
import { EXPORT_SIZE_LIMIT } from '../Export/constants';
|
||||||
|
|
||||||
@Service()
|
@Service()
|
||||||
export class AccountsExportable extends Exportable {
|
export class AccountsExportable extends Exportable {
|
||||||
@@ -20,7 +21,7 @@ export class AccountsExportable extends Exportable {
|
|||||||
inactiveMode: false,
|
inactiveMode: false,
|
||||||
...query,
|
...query,
|
||||||
structure: IAccountsStructureType.Flat,
|
structure: IAccountsStructureType.Flat,
|
||||||
pageSize: 12000,
|
pageSize: EXPORT_SIZE_LIMIT,
|
||||||
page: 1,
|
page: 1,
|
||||||
} as IAccountsFilter;
|
} as IAccountsFilter;
|
||||||
|
|
||||||
|
|||||||
@@ -11,6 +11,10 @@ export class GetAuthMeta {
|
|||||||
public async getAuthMeta(): Promise<IAuthGetMetaPOJO> {
|
public async getAuthMeta(): Promise<IAuthGetMetaPOJO> {
|
||||||
return {
|
return {
|
||||||
signupDisabled: config.signupRestrictions.disabled,
|
signupDisabled: config.signupRestrictions.disabled,
|
||||||
|
oneClickDemo: {
|
||||||
|
enable: config.oneClickDemoAccounts.enable,
|
||||||
|
demoUrl: config.oneClickDemoAccounts.demoUrl,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import HasTenancyService from '@/services/Tenancy/TenancyService';
|
|
||||||
import { Inject, Service } from 'typedi';
|
import { Inject, Service } from 'typedi';
|
||||||
|
import moment from 'moment';
|
||||||
|
import HasTenancyService from '@/services/Tenancy/TenancyService';
|
||||||
import { ExcludedBankTransactionsQuery } from './_types';
|
import { ExcludedBankTransactionsQuery } from './_types';
|
||||||
import { UncategorizedTransactionTransformer } from '@/services/Cashflow/UncategorizedTransactionTransformer';
|
import { UncategorizedTransactionTransformer } from '@/services/Cashflow/UncategorizedTransactionTransformer';
|
||||||
import { TransformerInjectable } from '@/lib/Transformer/TransformerInjectable';
|
import { TransformerInjectable } from '@/lib/Transformer/TransformerInjectable';
|
||||||
@@ -39,6 +40,18 @@ export class GetExcludedBankTransactionsService {
|
|||||||
if (_query.accountId) {
|
if (_query.accountId) {
|
||||||
q.where('account_id', _query.accountId);
|
q.where('account_id', _query.accountId);
|
||||||
}
|
}
|
||||||
|
if (_query.minDate) {
|
||||||
|
q.modify('fromDate', _query.minDate);
|
||||||
|
}
|
||||||
|
if (_query.maxDate) {
|
||||||
|
q.modify('toDate', _query.maxDate);
|
||||||
|
}
|
||||||
|
if (_query.minAmount) {
|
||||||
|
q.modify('minAmount', _query.minAmount);
|
||||||
|
}
|
||||||
|
if (_query.maxAmount) {
|
||||||
|
q.modify('maxAmount', _query.maxAmount);
|
||||||
|
}
|
||||||
})
|
})
|
||||||
.pagination(_query.page - 1, _query.pageSize);
|
.pagination(_query.page - 1, _query.pageSize);
|
||||||
|
|
||||||
|
|||||||
@@ -4,6 +4,10 @@ export interface ExcludedBankTransactionsQuery {
|
|||||||
page?: number;
|
page?: number;
|
||||||
pageSize?: number;
|
pageSize?: number;
|
||||||
accountId?: number;
|
accountId?: number;
|
||||||
|
minDate?: Date;
|
||||||
|
maxDate?: Date;
|
||||||
|
minAmount?: number;
|
||||||
|
maxAmount?: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IBankTransactionUnexcludingEventPayload {
|
export interface IBankTransactionUnexcludingEventPayload {
|
||||||
|
|||||||
@@ -78,9 +78,9 @@ export class RecognizeTranasctionsService {
|
|||||||
});
|
});
|
||||||
|
|
||||||
const bankRules = await BankRule.query(trx).onBuild((q) => {
|
const bankRules = await BankRule.query(trx).onBuild((q) => {
|
||||||
const rulesIds = castArray(ruleId);
|
const rulesIds = !isEmpty(ruleId) ? castArray(ruleId) : [];
|
||||||
|
|
||||||
if (!isEmpty(rulesIds)) {
|
if (rulesIds?.length > 0) {
|
||||||
q.whereIn('id', rulesIds);
|
q.whereIn('id', rulesIds);
|
||||||
}
|
}
|
||||||
q.withGraphFetched('conditions');
|
q.withGraphFetched('conditions');
|
||||||
|
|||||||
@@ -100,12 +100,14 @@ export class TriggerRecognizedTransactions {
|
|||||||
private async triggerRecognizeTransactionsOnImportCommitted({
|
private async triggerRecognizeTransactionsOnImportCommitted({
|
||||||
tenantId,
|
tenantId,
|
||||||
importId,
|
importId,
|
||||||
meta,
|
|
||||||
}: IImportFileCommitedEventPayload) {
|
}: IImportFileCommitedEventPayload) {
|
||||||
const importFile = await Import.query().findOne({ importId });
|
const importFile = await Import.query().findOne({ importId });
|
||||||
const batch = importFile.paramsParsed.batch;
|
const batch = importFile.paramsParsed.batch;
|
||||||
const payload = { tenantId, transactionsCriteria: { batch } };
|
const payload = { tenantId, transactionsCriteria: { batch } };
|
||||||
|
|
||||||
|
// Cannot continue if the imported resource is not bank account transactions.
|
||||||
|
if (importFile.resource !== 'UncategorizedCashflowTransaction') return;
|
||||||
|
|
||||||
await this.agenda.now('recognize-uncategorized-transactions-job', payload);
|
await this.agenda.now('recognize-uncategorized-transactions-job', payload);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,7 +8,12 @@ export class CashflowAccountTransformer extends Transformer {
|
|||||||
* @returns {string[]}
|
* @returns {string[]}
|
||||||
*/
|
*/
|
||||||
public includeAttributes = (): string[] => {
|
public includeAttributes = (): string[] => {
|
||||||
return ['formattedAmount'];
|
return [
|
||||||
|
'formattedAmount',
|
||||||
|
'lastFeedsUpdatedAt',
|
||||||
|
'lastFeedsUpdatedAtFormatted',
|
||||||
|
'lastFeedsUpdatedFromNow',
|
||||||
|
];
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -29,7 +34,7 @@ export class CashflowAccountTransformer extends Transformer {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieve formatted account amount.
|
* Retrieve formatted account amount.
|
||||||
* @param {IAccount} invoice
|
* @param {IAccount} invoice
|
||||||
* @returns {string}
|
* @returns {string}
|
||||||
*/
|
*/
|
||||||
protected formattedAmount = (account: IAccount): string => {
|
protected formattedAmount = (account: IAccount): string => {
|
||||||
@@ -37,4 +42,22 @@ export class CashflowAccountTransformer extends Transformer {
|
|||||||
currencyCode: account.currencyCode,
|
currencyCode: account.currencyCode,
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves the last feeds update at formatted date.
|
||||||
|
* @param {IAccount} account
|
||||||
|
* @returns {string}
|
||||||
|
*/
|
||||||
|
protected lastFeedsUpdatedAtFormatted(account: IAccount): string {
|
||||||
|
return this.formatDate(account.lastFeedsUpdatedAt);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves the last feeds updated from now.
|
||||||
|
* @param {IAccount} account
|
||||||
|
* @returns {string}
|
||||||
|
*/
|
||||||
|
protected lastFeedsUpdatedFromNow(account: IAccount): string {
|
||||||
|
return this.formatDateFromNow(account.lastFeedsUpdatedAt);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ export class GetRecognizedTransactionsService {
|
|||||||
) {
|
) {
|
||||||
const { UncategorizedCashflowTransaction } = this.tenancy.models(tenantId);
|
const { UncategorizedCashflowTransaction } = this.tenancy.models(tenantId);
|
||||||
|
|
||||||
const _filter = {
|
const _query = {
|
||||||
page: 1,
|
page: 1,
|
||||||
pageSize: 20,
|
pageSize: 20,
|
||||||
...filter,
|
...filter,
|
||||||
@@ -41,11 +41,26 @@ export class GetRecognizedTransactionsService {
|
|||||||
// Exclude the pending transactions.
|
// Exclude the pending transactions.
|
||||||
q.modify('notPending');
|
q.modify('notPending');
|
||||||
|
|
||||||
if (_filter.accountId) {
|
if (_query.accountId) {
|
||||||
q.where('accountId', _filter.accountId);
|
q.where('accountId', _query.accountId);
|
||||||
|
}
|
||||||
|
if (_query.minDate) {
|
||||||
|
q.modify('fromDate', _query.minDate);
|
||||||
|
}
|
||||||
|
if (_query.maxDate) {
|
||||||
|
q.modify('toDate', _query.maxDate);
|
||||||
|
}
|
||||||
|
if (_query.minAmount) {
|
||||||
|
q.modify('minAmount', _query.minAmount);
|
||||||
|
}
|
||||||
|
if (_query.maxAmount) {
|
||||||
|
q.modify('maxAmount', _query.maxAmount);
|
||||||
|
}
|
||||||
|
if (_query.accountId) {
|
||||||
|
q.where('accountId', _query.accountId);
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.pagination(_filter.page - 1, _filter.pageSize);
|
.pagination(_query.page - 1, _query.pageSize);
|
||||||
|
|
||||||
const data = await this.transformer.transform(
|
const data = await this.transformer.transform(
|
||||||
tenantId,
|
tenantId,
|
||||||
|
|||||||
@@ -62,6 +62,19 @@ export class GetUncategorizedTransactions {
|
|||||||
|
|
||||||
q.whereNull('matchedBankTransactions.id');
|
q.whereNull('matchedBankTransactions.id');
|
||||||
q.orderBy('date', 'DESC');
|
q.orderBy('date', 'DESC');
|
||||||
|
|
||||||
|
if (_query.minDate) {
|
||||||
|
q.modify('fromDate', _query.minDate);
|
||||||
|
}
|
||||||
|
if (_query.maxDate) {
|
||||||
|
q.modify('toDate', _query.maxDate);
|
||||||
|
}
|
||||||
|
if (_query.minAmount) {
|
||||||
|
q.modify('minAmount', _query.minAmount);
|
||||||
|
}
|
||||||
|
if (_query.maxAmount) {
|
||||||
|
q.modify('maxAmount', _query.maxAmount);
|
||||||
|
}
|
||||||
})
|
})
|
||||||
.pagination(_query.page - 1, _query.pageSize);
|
.pagination(_query.page - 1, _query.pageSize);
|
||||||
|
|
||||||
|
|||||||
@@ -87,7 +87,7 @@ export class UncategorizedTransactionsImportable extends Importable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Transformes the import params before storing them.
|
* Transforms the import params before storing them.
|
||||||
* @param {Record<string, any>} parmas
|
* @param {Record<string, any>} parmas
|
||||||
*/
|
*/
|
||||||
public transformParams(parmas: Record<string, any>) {
|
public transformParams(parmas: Record<string, any>) {
|
||||||
|
|||||||
@@ -65,6 +65,7 @@ export class EditCustomer {
|
|||||||
});
|
});
|
||||||
// Triggers `onCustomerEdited` event.
|
// Triggers `onCustomerEdited` event.
|
||||||
await this.eventPublisher.emitAsync(events.customers.onEdited, {
|
await this.eventPublisher.emitAsync(events.customers.onEdited, {
|
||||||
|
tenantId,
|
||||||
customerId,
|
customerId,
|
||||||
customer,
|
customer,
|
||||||
trx,
|
trx,
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import { Inject, Service } from 'typedi';
|
|||||||
import { IItemsFilter } from '@/interfaces';
|
import { IItemsFilter } from '@/interfaces';
|
||||||
import { CustomersApplication } from './CustomersApplication';
|
import { CustomersApplication } from './CustomersApplication';
|
||||||
import { Exportable } from '@/services/Export/Exportable';
|
import { Exportable } from '@/services/Export/Exportable';
|
||||||
|
import { EXPORT_SIZE_LIMIT } from '@/services/Export/constants';
|
||||||
|
|
||||||
@Service()
|
@Service()
|
||||||
export class CustomersExportable extends Exportable {
|
export class CustomersExportable extends Exportable {
|
||||||
@@ -17,9 +18,9 @@ export class CustomersExportable extends Exportable {
|
|||||||
const parsedQuery = {
|
const parsedQuery = {
|
||||||
sortOrder: 'DESC',
|
sortOrder: 'DESC',
|
||||||
columnSortBy: 'created_at',
|
columnSortBy: 'created_at',
|
||||||
page: 1,
|
|
||||||
...query,
|
...query,
|
||||||
pageSize: 12,
|
page: 1,
|
||||||
|
pageSize: EXPORT_SIZE_LIMIT,
|
||||||
} as IItemsFilter;
|
} as IItemsFilter;
|
||||||
|
|
||||||
return this.customersApplication
|
return this.customersApplication
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import { Inject, Service } from 'typedi';
|
|||||||
import { IItemsFilter } from '@/interfaces';
|
import { IItemsFilter } from '@/interfaces';
|
||||||
import { Exportable } from '@/services/Export/Exportable';
|
import { Exportable } from '@/services/Export/Exportable';
|
||||||
import { VendorsApplication } from './VendorsApplication';
|
import { VendorsApplication } from './VendorsApplication';
|
||||||
|
import { EXPORT_SIZE_LIMIT } from '@/services/Export/constants';
|
||||||
|
|
||||||
@Service()
|
@Service()
|
||||||
export class VendorsExportable extends Exportable {
|
export class VendorsExportable extends Exportable {
|
||||||
@@ -17,9 +18,9 @@ export class VendorsExportable extends Exportable {
|
|||||||
const parsedQuery = {
|
const parsedQuery = {
|
||||||
sortOrder: 'DESC',
|
sortOrder: 'DESC',
|
||||||
columnSortBy: 'created_at',
|
columnSortBy: 'created_at',
|
||||||
page: 1,
|
|
||||||
...query,
|
...query,
|
||||||
pageSize: 12,
|
page: 1,
|
||||||
|
pageSize: EXPORT_SIZE_LIMIT,
|
||||||
} as IItemsFilter;
|
} as IItemsFilter;
|
||||||
|
|
||||||
return this.vendorsApplication
|
return this.vendorsApplication
|
||||||
|
|||||||
@@ -5,11 +5,17 @@ import * as R from 'ramda';
|
|||||||
import { ServiceError } from '@/exceptions';
|
import { ServiceError } from '@/exceptions';
|
||||||
import HasTenancyService from '@/services/Tenancy/TenancyService';
|
import HasTenancyService from '@/services/Tenancy/TenancyService';
|
||||||
import { ERRORS } from './constants';
|
import { ERRORS } from './constants';
|
||||||
import { ICreditNote, ICreditNoteEditDTO, ICreditNoteNewDTO } from '@/interfaces';
|
import {
|
||||||
|
ICreditNote,
|
||||||
|
ICreditNoteEditDTO,
|
||||||
|
ICreditNoteEntryNewDTO,
|
||||||
|
ICreditNoteNewDTO,
|
||||||
|
} from '@/interfaces';
|
||||||
import ItemsEntriesService from '@/services/Items/ItemsEntriesService';
|
import ItemsEntriesService from '@/services/Items/ItemsEntriesService';
|
||||||
import AutoIncrementOrdersService from '@/services/Sales/AutoIncrementOrdersService';
|
import AutoIncrementOrdersService from '@/services/Sales/AutoIncrementOrdersService';
|
||||||
import { WarehouseTransactionDTOTransform } from '@/services/Warehouses/Integrations/WarehouseTransactionDTOTransform';
|
import { WarehouseTransactionDTOTransform } from '@/services/Warehouses/Integrations/WarehouseTransactionDTOTransform';
|
||||||
import { BranchTransactionDTOTransform } from '@/services/Branches/Integrations/BranchTransactionDTOTransform';
|
import { BranchTransactionDTOTransform } from '@/services/Branches/Integrations/BranchTransactionDTOTransform';
|
||||||
|
import { assocItemEntriesDefaultIndex } from '../Items/utils';
|
||||||
|
|
||||||
@Service()
|
@Service()
|
||||||
export default class BaseCreditNotes {
|
export default class BaseCreditNotes {
|
||||||
@@ -43,10 +49,17 @@ export default class BaseCreditNotes {
|
|||||||
const amount = this.itemsEntriesService.getTotalItemsEntries(
|
const amount = this.itemsEntriesService.getTotalItemsEntries(
|
||||||
creditNoteDTO.entries
|
creditNoteDTO.entries
|
||||||
);
|
);
|
||||||
const entries = creditNoteDTO.entries.map((entry) => ({
|
const entries = R.compose(
|
||||||
...entry,
|
// Associate the default index to each item entry.
|
||||||
referenceType: 'CreditNote',
|
assocItemEntriesDefaultIndex,
|
||||||
}));
|
|
||||||
|
// Associate the reference type to credit note entries.
|
||||||
|
R.map((entry: ICreditNoteEntryNewDTO) => ({
|
||||||
|
...entry,
|
||||||
|
referenceType: 'CreditNote',
|
||||||
|
}))
|
||||||
|
)(creditNoteDTO.entries);
|
||||||
|
|
||||||
// Retreive the next credit note number.
|
// Retreive the next credit note number.
|
||||||
const autoNextNumber = this.getNextCreditNumber(tenantId);
|
const autoNextNumber = this.getNextCreditNumber(tenantId);
|
||||||
|
|
||||||
|
|||||||
@@ -15,12 +15,17 @@ export class CreditNotesExportable extends Exportable {
|
|||||||
* @returns {}
|
* @returns {}
|
||||||
*/
|
*/
|
||||||
public exportable(tenantId: number, query: ICreditNotesQueryDTO) {
|
public exportable(tenantId: number, query: ICreditNotesQueryDTO) {
|
||||||
|
const filterQuery = (query) => {
|
||||||
|
query.withGraphFetched('branch');
|
||||||
|
query.withGraphFetched('warehouse');
|
||||||
|
};
|
||||||
const parsedQuery = {
|
const parsedQuery = {
|
||||||
sortOrder: 'desc',
|
sortOrder: 'desc',
|
||||||
columnSortBy: 'created_at',
|
columnSortBy: 'created_at',
|
||||||
...query,
|
...query,
|
||||||
page: 1,
|
page: 1,
|
||||||
pageSize: 12000,
|
pageSize: 12000,
|
||||||
|
filterQuery,
|
||||||
} as ICreditNotesQueryDTO;
|
} as ICreditNotesQueryDTO;
|
||||||
|
|
||||||
return this.getCreditNotes
|
return this.getCreditNotes
|
||||||
|
|||||||
@@ -48,6 +48,7 @@ export default class ListCreditNotes extends BaseCreditNotes {
|
|||||||
builder.withGraphFetched('entries.item');
|
builder.withGraphFetched('entries.item');
|
||||||
builder.withGraphFetched('customer');
|
builder.withGraphFetched('customer');
|
||||||
dynamicFilter.buildQuery()(builder);
|
dynamicFilter.buildQuery()(builder);
|
||||||
|
creditNotesQuery?.filterQuery && creditNotesQuery?.filterQuery(builder);
|
||||||
})
|
})
|
||||||
.pagination(filter.page - 1, filter.pageSize);
|
.pagination(filter.page - 1, filter.pageSize);
|
||||||
|
|
||||||
|
|||||||
24
packages/server/src/services/EventsTracker/PostHog.ts
Normal file
24
packages/server/src/services/EventsTracker/PostHog.ts
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
import { PostHog } from 'posthog-node';
|
||||||
|
import { Service } from 'typedi';
|
||||||
|
import { EventMessage } from 'posthog-node/src/types';
|
||||||
|
import config from '@/config';
|
||||||
|
|
||||||
|
@Service()
|
||||||
|
export class PosthogService {
|
||||||
|
public posthog: PostHog;
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
if (config.posthog.apiKey && config.posthog.host) {
|
||||||
|
this.posthog = new PostHog(config.posthog.apiKey, {
|
||||||
|
host: config.posthog.host,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public trackEvent(event: EventMessage) {
|
||||||
|
// Cannot continue if the Posthog not configured.
|
||||||
|
if (!this.posthog) return;
|
||||||
|
|
||||||
|
this.posthog.capture(event);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,65 @@
|
|||||||
|
import { Inject, Service } from 'typedi';
|
||||||
|
import { EventSubscriber } from '@/lib/EventPublisher/EventPublisher';
|
||||||
|
import {
|
||||||
|
IAccountEventCreatedPayload,
|
||||||
|
IAccountEventEditedPayload,
|
||||||
|
IAccountEventDeletedPayload,
|
||||||
|
} from '@/interfaces';
|
||||||
|
import { PosthogService } from '../PostHog';
|
||||||
|
import events from '@/subscribers/events';
|
||||||
|
import {
|
||||||
|
ACCOUNT_CREATED,
|
||||||
|
ACCOUNT_EDITED,
|
||||||
|
ACCOUNT_DELETED,
|
||||||
|
} from '@/constants/event-tracker';
|
||||||
|
|
||||||
|
@Service()
|
||||||
|
export class AccountEventsTracker extends EventSubscriber {
|
||||||
|
@Inject()
|
||||||
|
private posthog: PosthogService;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor method.
|
||||||
|
*/
|
||||||
|
public attach(bus) {
|
||||||
|
bus.subscribe(
|
||||||
|
events.accounts.onCreated,
|
||||||
|
this.handleTrackAccountCreatedEvent
|
||||||
|
);
|
||||||
|
bus.subscribe(events.accounts.onEdited, this.handleTrackEditedAccountEvent);
|
||||||
|
bus.subscribe(
|
||||||
|
events.accounts.onDeleted,
|
||||||
|
this.handleTrackDeletedAccountEvent
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private handleTrackAccountCreatedEvent = ({
|
||||||
|
tenantId,
|
||||||
|
}: IAccountEventCreatedPayload) => {
|
||||||
|
this.posthog.trackEvent({
|
||||||
|
distinctId: `tenant-${tenantId}`,
|
||||||
|
event: ACCOUNT_CREATED,
|
||||||
|
properties: {},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
private handleTrackEditedAccountEvent = ({
|
||||||
|
tenantId,
|
||||||
|
}: IAccountEventEditedPayload) => {
|
||||||
|
this.posthog.trackEvent({
|
||||||
|
distinctId: `tenant-${tenantId}`,
|
||||||
|
event: ACCOUNT_EDITED,
|
||||||
|
properties: {},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
private handleTrackDeletedAccountEvent = ({
|
||||||
|
tenantId,
|
||||||
|
}: IAccountEventDeletedPayload) => {
|
||||||
|
this.posthog.trackEvent({
|
||||||
|
distinctId: `tenant-${tenantId}`,
|
||||||
|
event: ACCOUNT_DELETED,
|
||||||
|
properties: {},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
import { Inject, Service } from 'typedi';
|
||||||
|
import { EventSubscriber } from '@/lib/EventPublisher/EventPublisher';
|
||||||
|
import { IAuthSignedUpEventPayload } from '@/interfaces';
|
||||||
|
import { PosthogService } from '../PostHog';
|
||||||
|
import { AUTH_SIGNED_UP } from '@/constants/event-tracker';
|
||||||
|
import events from '@/subscribers/events';
|
||||||
|
|
||||||
|
@Service()
|
||||||
|
export class AuthenticationEventsTracker extends EventSubscriber {
|
||||||
|
@Inject()
|
||||||
|
private posthog: PosthogService;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor method.
|
||||||
|
*/
|
||||||
|
public attach(bus) {
|
||||||
|
bus.subscribe(events.auth.signUp, this.handleTrackSignUpEvent);
|
||||||
|
}
|
||||||
|
|
||||||
|
private handleTrackSignUpEvent = ({
|
||||||
|
signupDTO,
|
||||||
|
user,
|
||||||
|
tenant,
|
||||||
|
}: IAuthSignedUpEventPayload) => {
|
||||||
|
this.posthog.trackEvent({
|
||||||
|
distinctId: user.email,
|
||||||
|
event: AUTH_SIGNED_UP,
|
||||||
|
properties: {
|
||||||
|
firstName: user.firstName,
|
||||||
|
lastName: user.lastName,
|
||||||
|
email: user.email,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -0,0 +1,68 @@
|
|||||||
|
import { Inject, Service } from 'typedi';
|
||||||
|
import { EventSubscriber } from '@/lib/EventPublisher/EventPublisher';
|
||||||
|
import {
|
||||||
|
IBankRuleEventCreatedPayload,
|
||||||
|
IBankRuleEventEditedPayload,
|
||||||
|
IBankRuleEventDeletedPayload,
|
||||||
|
} from '@/services/Banking/Rules/types'; // Updated import path for interfaces
|
||||||
|
import { PosthogService } from '../PostHog';
|
||||||
|
import events from '@/subscribers/events';
|
||||||
|
import {
|
||||||
|
BANK_RULE_CREATED,
|
||||||
|
BANK_RULE_EDITED,
|
||||||
|
BANK_RULE_DELETED,
|
||||||
|
} from '@/constants/event-tracker';
|
||||||
|
|
||||||
|
@Service()
|
||||||
|
export class BankRuleEventsTracker extends EventSubscriber {
|
||||||
|
@Inject()
|
||||||
|
private posthog: PosthogService;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor method.
|
||||||
|
*/
|
||||||
|
public attach(bus) {
|
||||||
|
bus.subscribe(
|
||||||
|
events.bankRules.onCreated,
|
||||||
|
this.handleTrackBankRuleCreatedEvent
|
||||||
|
);
|
||||||
|
bus.subscribe(
|
||||||
|
events.bankRules.onEdited,
|
||||||
|
this.handleTrackEditedBankRuleEvent
|
||||||
|
);
|
||||||
|
bus.subscribe(
|
||||||
|
events.bankRules.onDeleted,
|
||||||
|
this.handleTrackDeletedBankRuleEvent
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private handleTrackBankRuleCreatedEvent = ({
|
||||||
|
tenantId,
|
||||||
|
}: IBankRuleEventCreatedPayload) => {
|
||||||
|
this.posthog.trackEvent({
|
||||||
|
distinctId: `tenant-${tenantId}`,
|
||||||
|
event: BANK_RULE_CREATED,
|
||||||
|
properties: {},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
private handleTrackEditedBankRuleEvent = ({
|
||||||
|
tenantId,
|
||||||
|
}: IBankRuleEventEditedPayload) => {
|
||||||
|
this.posthog.trackEvent({
|
||||||
|
distinctId: `tenant-${tenantId}`,
|
||||||
|
event: BANK_RULE_EDITED,
|
||||||
|
properties: {},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
private handleTrackDeletedBankRuleEvent = ({
|
||||||
|
tenantId,
|
||||||
|
}: IBankRuleEventDeletedPayload) => {
|
||||||
|
this.posthog.trackEvent({
|
||||||
|
distinctId: `tenant-${tenantId}`,
|
||||||
|
event: BANK_RULE_DELETED,
|
||||||
|
properties: {},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -0,0 +1,97 @@
|
|||||||
|
import { Inject, Service } from 'typedi';
|
||||||
|
import { EventSubscriber } from '@/lib/EventPublisher/EventPublisher';
|
||||||
|
import { PosthogService } from '../PostHog';
|
||||||
|
import events from '@/subscribers/events';
|
||||||
|
import {
|
||||||
|
BANK_TRANSACTION_MATCHED,
|
||||||
|
BANK_TRANSACTION_EXCLUDED,
|
||||||
|
BANK_TRANSACTION_CATEGORIZED,
|
||||||
|
BANK_TRANSACTION_UNCATEGORIZED,
|
||||||
|
BANK_ACCOUNT_DISCONNECTED,
|
||||||
|
} from '@/constants/event-tracker';
|
||||||
|
import { IBankTransactionMatchedEventPayload } from '@/services/Banking/Matching/types';
|
||||||
|
import { IBankAccountDisconnectedEventPayload } from '@/services/Banking/BankAccounts/types';
|
||||||
|
import {
|
||||||
|
ICashflowTransactionCategorizedPayload,
|
||||||
|
ICashflowTransactionUncategorizedPayload,
|
||||||
|
} from '@/interfaces';
|
||||||
|
import { IBankTransactionExcludedEventPayload } from '@/services/Banking/Exclude/_types';
|
||||||
|
|
||||||
|
@Service()
|
||||||
|
export class BankTransactionEventsTracker extends EventSubscriber {
|
||||||
|
@Inject()
|
||||||
|
private posthog: PosthogService;
|
||||||
|
|
||||||
|
public attach(bus) {
|
||||||
|
bus.subscribe(
|
||||||
|
events.bankMatch.onMatched,
|
||||||
|
this.handleTrackBankTransactionMatchedEvent
|
||||||
|
);
|
||||||
|
bus.subscribe(
|
||||||
|
events.bankTransactions.onExcluded,
|
||||||
|
this.handleTrackBankTransactionExcludedEvent
|
||||||
|
);
|
||||||
|
bus.subscribe(
|
||||||
|
events.cashflow.onTransactionCategorized,
|
||||||
|
this.handleTrackBankTransactionCategorizedEvent
|
||||||
|
);
|
||||||
|
bus.subscribe(
|
||||||
|
events.cashflow.onTransactionUncategorized,
|
||||||
|
this.handleTrackBankTransactionUncategorizedEvent
|
||||||
|
);
|
||||||
|
bus.subscribe(
|
||||||
|
events.bankAccount.onDisconnected,
|
||||||
|
this.handleTrackBankAccountDisconnectedEvent
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private handleTrackBankTransactionMatchedEvent = ({
|
||||||
|
tenantId,
|
||||||
|
}: IBankTransactionMatchedEventPayload) => {
|
||||||
|
this.posthog.trackEvent({
|
||||||
|
distinctId: `tenant-${tenantId}`,
|
||||||
|
event: BANK_TRANSACTION_MATCHED,
|
||||||
|
properties: {},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
private handleTrackBankTransactionExcludedEvent = ({
|
||||||
|
tenantId,
|
||||||
|
}: IBankTransactionExcludedEventPayload) => {
|
||||||
|
this.posthog.trackEvent({
|
||||||
|
distinctId: `tenant-${tenantId}`,
|
||||||
|
event: BANK_TRANSACTION_EXCLUDED,
|
||||||
|
properties: {},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
private handleTrackBankTransactionCategorizedEvent = ({
|
||||||
|
tenantId,
|
||||||
|
}: ICashflowTransactionCategorizedPayload) => {
|
||||||
|
this.posthog.trackEvent({
|
||||||
|
distinctId: `tenant-${tenantId}`,
|
||||||
|
event: BANK_TRANSACTION_CATEGORIZED,
|
||||||
|
properties: {},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
private handleTrackBankTransactionUncategorizedEvent = ({
|
||||||
|
tenantId,
|
||||||
|
}: ICashflowTransactionUncategorizedPayload) => {
|
||||||
|
this.posthog.trackEvent({
|
||||||
|
distinctId: `tenant-${tenantId}`,
|
||||||
|
event: BANK_TRANSACTION_UNCATEGORIZED,
|
||||||
|
properties: {},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
private handleTrackBankAccountDisconnectedEvent = ({
|
||||||
|
tenantId,
|
||||||
|
}: IBankAccountDisconnectedEventPayload) => {
|
||||||
|
this.posthog.trackEvent({
|
||||||
|
distinctId: `tenant-${tenantId}`,
|
||||||
|
event: BANK_ACCOUNT_DISCONNECTED,
|
||||||
|
properties: {},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -0,0 +1,59 @@
|
|||||||
|
import { Inject, Service } from 'typedi';
|
||||||
|
import { EventSubscriber } from '@/lib/EventPublisher/EventPublisher';
|
||||||
|
import {
|
||||||
|
IBillPaymentEventCreatedPayload,
|
||||||
|
IBillPaymentEventEditedPayload,
|
||||||
|
IBillPaymentEventDeletedPayload,
|
||||||
|
} from '@/interfaces';
|
||||||
|
import { PosthogService } from '../PostHog';
|
||||||
|
import events from '@/subscribers/events';
|
||||||
|
import {
|
||||||
|
BILL_CREATED,
|
||||||
|
BILL_EDITED,
|
||||||
|
BILL_DELETED,
|
||||||
|
} from '@/constants/event-tracker';
|
||||||
|
|
||||||
|
@Service()
|
||||||
|
export class BillEventsTracker extends EventSubscriber {
|
||||||
|
@Inject()
|
||||||
|
private posthog: PosthogService;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor method.
|
||||||
|
*/
|
||||||
|
public attach(bus) {
|
||||||
|
bus.subscribe(events.bill.onCreated, this.handleTrackBillCreatedEvent);
|
||||||
|
bus.subscribe(events.bill.onEdited, this.handleTrackEditedBillEvent);
|
||||||
|
bus.subscribe(events.bill.onDeleted, this.handleTrackDeletedBillEvent);
|
||||||
|
}
|
||||||
|
|
||||||
|
private handleTrackBillCreatedEvent = ({
|
||||||
|
tenantId,
|
||||||
|
}: IBillPaymentEventCreatedPayload) => {
|
||||||
|
this.posthog.trackEvent({
|
||||||
|
distinctId: `tenant-${tenantId}`,
|
||||||
|
event: BILL_CREATED,
|
||||||
|
properties: {},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
private handleTrackEditedBillEvent = ({
|
||||||
|
tenantId,
|
||||||
|
}: IBillPaymentEventEditedPayload) => {
|
||||||
|
this.posthog.trackEvent({
|
||||||
|
distinctId: `tenant-${tenantId}`,
|
||||||
|
event: BILL_EDITED,
|
||||||
|
properties: {},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
private handleTrackDeletedBillEvent = ({
|
||||||
|
tenantId,
|
||||||
|
}: IBillPaymentEventDeletedPayload) => {
|
||||||
|
this.posthog.trackEvent({
|
||||||
|
distinctId: `tenant-${tenantId}`,
|
||||||
|
event: BILL_DELETED,
|
||||||
|
properties: {},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -0,0 +1,65 @@
|
|||||||
|
import { Inject, Service } from 'typedi';
|
||||||
|
import { EventSubscriber } from '@/lib/EventPublisher/EventPublisher';
|
||||||
|
import {
|
||||||
|
ICustomerEventCreatedPayload,
|
||||||
|
ICustomerEventEditedPayload,
|
||||||
|
ICustomerEventDeletedPayload,
|
||||||
|
} from '@/interfaces';
|
||||||
|
import { PosthogService } from '../PostHog';
|
||||||
|
import events from '@/subscribers/events';
|
||||||
|
import {
|
||||||
|
CUSTOMER_CREATED,
|
||||||
|
CUSTOMER_EDITED,
|
||||||
|
CUSTOMER_DELETED,
|
||||||
|
} from '@/constants/event-tracker';
|
||||||
|
|
||||||
|
@Service()
|
||||||
|
export class CustomerEventsTracker extends EventSubscriber {
|
||||||
|
@Inject()
|
||||||
|
private posthog: PosthogService;
|
||||||
|
|
||||||
|
public attach(bus) {
|
||||||
|
bus.subscribe(
|
||||||
|
events.customers.onCreated,
|
||||||
|
this.handleTrackCustomerCreatedEvent
|
||||||
|
);
|
||||||
|
bus.subscribe(
|
||||||
|
events.customers.onEdited,
|
||||||
|
this.handleTrackEditedCustomerEvent
|
||||||
|
);
|
||||||
|
bus.subscribe(
|
||||||
|
events.customers.onDeleted,
|
||||||
|
this.handleTrackDeletedCustomerEvent
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private handleTrackCustomerCreatedEvent = ({
|
||||||
|
tenantId,
|
||||||
|
}: ICustomerEventCreatedPayload) => {
|
||||||
|
this.posthog.trackEvent({
|
||||||
|
distinctId: `tenant-${tenantId}`,
|
||||||
|
event: CUSTOMER_CREATED,
|
||||||
|
properties: {},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
private handleTrackEditedCustomerEvent = ({
|
||||||
|
tenantId,
|
||||||
|
}: ICustomerEventEditedPayload) => {
|
||||||
|
this.posthog.trackEvent({
|
||||||
|
distinctId: `tenant-${tenantId}`,
|
||||||
|
event: CUSTOMER_EDITED,
|
||||||
|
properties: {},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
private handleTrackDeletedCustomerEvent = ({
|
||||||
|
tenantId,
|
||||||
|
}: ICustomerEventDeletedPayload) => {
|
||||||
|
this.posthog.trackEvent({
|
||||||
|
distinctId: `tenant-${tenantId}`,
|
||||||
|
event: CUSTOMER_DELETED,
|
||||||
|
properties: {},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -0,0 +1,65 @@
|
|||||||
|
import { Inject, Service } from 'typedi';
|
||||||
|
import { EventSubscriber } from '@/lib/EventPublisher/EventPublisher';
|
||||||
|
import {
|
||||||
|
IExpenseCreatedPayload,
|
||||||
|
IExpenseEventEditPayload,
|
||||||
|
IExpenseEventDeletePayload,
|
||||||
|
} from '@/interfaces';
|
||||||
|
import { PosthogService } from '../PostHog';
|
||||||
|
import events from '@/subscribers/events';
|
||||||
|
import {
|
||||||
|
EXPENSE_CREATED,
|
||||||
|
EXPENSE_EDITED,
|
||||||
|
EXPENSE_DELETED,
|
||||||
|
} from '@/constants/event-tracker';
|
||||||
|
|
||||||
|
@Service()
|
||||||
|
export class ExpenseEventsTracker extends EventSubscriber {
|
||||||
|
@Inject()
|
||||||
|
private posthog: PosthogService;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor method.
|
||||||
|
*/
|
||||||
|
public attach(bus) {
|
||||||
|
bus.subscribe(
|
||||||
|
events.expenses.onCreated,
|
||||||
|
this.handleTrackExpenseCreatedEvent
|
||||||
|
);
|
||||||
|
bus.subscribe(events.expenses.onEdited, this.handleTrackEditedExpenseEvent);
|
||||||
|
bus.subscribe(
|
||||||
|
events.expenses.onDeleted,
|
||||||
|
this.handleTrackDeletedExpenseEvent
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private handleTrackExpenseCreatedEvent = ({
|
||||||
|
tenantId,
|
||||||
|
}: IExpenseCreatedPayload) => {
|
||||||
|
this.posthog.trackEvent({
|
||||||
|
distinctId: `tenant-${tenantId}`,
|
||||||
|
event: EXPENSE_CREATED,
|
||||||
|
properties: {},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
private handleTrackEditedExpenseEvent = ({
|
||||||
|
tenantId,
|
||||||
|
}: IExpenseEventEditPayload) => {
|
||||||
|
this.posthog.trackEvent({
|
||||||
|
distinctId: `tenant-${tenantId}`,
|
||||||
|
event: EXPENSE_EDITED,
|
||||||
|
properties: {},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
private handleTrackDeletedExpenseEvent = ({
|
||||||
|
tenantId,
|
||||||
|
}: IExpenseEventDeletePayload) => {
|
||||||
|
this.posthog.trackEvent({
|
||||||
|
distinctId: `tenant-${tenantId}`,
|
||||||
|
event: EXPENSE_DELETED,
|
||||||
|
properties: {},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -0,0 +1,59 @@
|
|||||||
|
import { Inject, Service } from 'typedi';
|
||||||
|
import { EventSubscriber } from '@/lib/EventPublisher/EventPublisher';
|
||||||
|
import {
|
||||||
|
IItemEventCreatedPayload,
|
||||||
|
IItemEventEditedPayload,
|
||||||
|
IItemEventDeletedPayload,
|
||||||
|
} from '@/interfaces';
|
||||||
|
import { PosthogService } from '../PostHog';
|
||||||
|
import events from '@/subscribers/events';
|
||||||
|
import {
|
||||||
|
ITEM_EVENT_CREATED,
|
||||||
|
ITEM_EVENT_EDITED,
|
||||||
|
ITEM_EVENT_DELETED,
|
||||||
|
} from '@/constants/event-tracker';
|
||||||
|
|
||||||
|
@Service()
|
||||||
|
export class ItemEventsTracker extends EventSubscriber {
|
||||||
|
@Inject()
|
||||||
|
private posthog: PosthogService;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor method.
|
||||||
|
*/
|
||||||
|
public attach(bus) {
|
||||||
|
bus.subscribe(events.item.onCreated, this.handleTrackItemCreatedEvent);
|
||||||
|
bus.subscribe(events.item.onEdited, this.handleTrackEditedItemEvent);
|
||||||
|
bus.subscribe(events.item.onDeleted, this.handleTrackDeletedItemEvent);
|
||||||
|
}
|
||||||
|
|
||||||
|
private handleTrackItemCreatedEvent = ({
|
||||||
|
tenantId,
|
||||||
|
}: IItemEventCreatedPayload) => {
|
||||||
|
this.posthog.trackEvent({
|
||||||
|
distinctId: `tenant-${tenantId}`,
|
||||||
|
event: ITEM_EVENT_CREATED,
|
||||||
|
properties: {},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
private handleTrackEditedItemEvent = ({
|
||||||
|
tenantId,
|
||||||
|
}: IItemEventEditedPayload) => {
|
||||||
|
this.posthog.trackEvent({
|
||||||
|
distinctId: `tenant-${tenantId}`,
|
||||||
|
event: ITEM_EVENT_EDITED,
|
||||||
|
properties: {},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
private handleTrackDeletedItemEvent = ({
|
||||||
|
tenantId,
|
||||||
|
}: IItemEventDeletedPayload) => {
|
||||||
|
this.posthog.trackEvent({
|
||||||
|
distinctId: `tenant-${tenantId}`,
|
||||||
|
event: ITEM_EVENT_DELETED,
|
||||||
|
properties: {},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -0,0 +1,68 @@
|
|||||||
|
import { Inject, Service } from 'typedi';
|
||||||
|
import { EventSubscriber } from '@/lib/EventPublisher/EventPublisher';
|
||||||
|
import {
|
||||||
|
IManualJournalEventCreatedPayload,
|
||||||
|
IManualJournalEventEditedPayload,
|
||||||
|
IManualJournalEventDeletedPayload,
|
||||||
|
} from '@/interfaces';
|
||||||
|
import { PosthogService } from '../PostHog';
|
||||||
|
import events from '@/subscribers/events';
|
||||||
|
import {
|
||||||
|
MANUAL_JOURNAL_CREATED,
|
||||||
|
MANUAL_JOURNAL_EDITED,
|
||||||
|
MANUAL_JOURNAL_DELETED,
|
||||||
|
} from '@/constants/event-tracker';
|
||||||
|
|
||||||
|
@Service()
|
||||||
|
export class ManualJournalEventsTracker extends EventSubscriber {
|
||||||
|
@Inject()
|
||||||
|
private posthog: PosthogService;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor method.
|
||||||
|
*/
|
||||||
|
public attach(bus) {
|
||||||
|
bus.subscribe(
|
||||||
|
events.manualJournals.onCreated,
|
||||||
|
this.handleTrackManualJournalCreatedEvent
|
||||||
|
);
|
||||||
|
bus.subscribe(
|
||||||
|
events.manualJournals.onEdited,
|
||||||
|
this.handleTrackEditedManualJournalEvent
|
||||||
|
);
|
||||||
|
bus.subscribe(
|
||||||
|
events.manualJournals.onDeleted,
|
||||||
|
this.handleTrackDeletedManualJournalEvent
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private handleTrackManualJournalCreatedEvent = ({
|
||||||
|
tenantId,
|
||||||
|
}: IManualJournalEventCreatedPayload) => {
|
||||||
|
this.posthog.trackEvent({
|
||||||
|
distinctId: `tenant-${tenantId}`,
|
||||||
|
event: MANUAL_JOURNAL_CREATED,
|
||||||
|
properties: {},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
private handleTrackEditedManualJournalEvent = ({
|
||||||
|
tenantId,
|
||||||
|
}: IManualJournalEventEditedPayload) => {
|
||||||
|
this.posthog.trackEvent({
|
||||||
|
distinctId: `tenant-${tenantId}`,
|
||||||
|
event: MANUAL_JOURNAL_EDITED,
|
||||||
|
properties: {},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
private handleTrackDeletedManualJournalEvent = ({
|
||||||
|
tenantId,
|
||||||
|
}: IManualJournalEventDeletedPayload) => {
|
||||||
|
this.posthog.trackEvent({
|
||||||
|
distinctId: `tenant-${tenantId}`,
|
||||||
|
event: MANUAL_JOURNAL_DELETED,
|
||||||
|
properties: {},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -0,0 +1,68 @@
|
|||||||
|
import { Inject, Service } from 'typedi';
|
||||||
|
import { EventSubscriber } from '@/lib/EventPublisher/EventPublisher';
|
||||||
|
import {
|
||||||
|
IBillPaymentEventCreatedPayload,
|
||||||
|
IBillPaymentEditingPayload,
|
||||||
|
IBillPaymentEventDeletedPayload,
|
||||||
|
} from '@/interfaces';
|
||||||
|
import { PosthogService } from '../PostHog';
|
||||||
|
import events from '@/subscribers/events';
|
||||||
|
import {
|
||||||
|
PAYMENT_MADE_CREATED,
|
||||||
|
PAYMENT_MADE_EDITED,
|
||||||
|
PAYMENT_MADE_DELETED,
|
||||||
|
} from '@/constants/event-tracker';
|
||||||
|
|
||||||
|
@Service()
|
||||||
|
export class PaymentMadeEventsTracker extends EventSubscriber {
|
||||||
|
@Inject()
|
||||||
|
private posthog: PosthogService;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor method.
|
||||||
|
*/
|
||||||
|
public attach(bus) {
|
||||||
|
bus.subscribe(
|
||||||
|
events.billPayment.onCreated,
|
||||||
|
this.handleTrackPaymentMadeCreatedEvent
|
||||||
|
);
|
||||||
|
bus.subscribe(
|
||||||
|
events.billPayment.onEdited,
|
||||||
|
this.handleTrackEditedPaymentMadeEvent
|
||||||
|
);
|
||||||
|
bus.subscribe(
|
||||||
|
events.billPayment.onDeleted,
|
||||||
|
this.handleTrackDeletedPaymentMadeEvent
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private handleTrackPaymentMadeCreatedEvent = ({
|
||||||
|
tenantId,
|
||||||
|
}: IBillPaymentEventCreatedPayload) => {
|
||||||
|
this.posthog.trackEvent({
|
||||||
|
distinctId: `tenant-${tenantId}`,
|
||||||
|
event: PAYMENT_MADE_CREATED,
|
||||||
|
properties: {},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
private handleTrackEditedPaymentMadeEvent = ({
|
||||||
|
tenantId,
|
||||||
|
}: IBillPaymentEditingPayload) => {
|
||||||
|
this.posthog.trackEvent({
|
||||||
|
distinctId: `tenant-${tenantId}`,
|
||||||
|
event: PAYMENT_MADE_EDITED,
|
||||||
|
properties: {},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
private handleTrackDeletedPaymentMadeEvent = ({
|
||||||
|
tenantId,
|
||||||
|
}: IBillPaymentEventDeletedPayload) => {
|
||||||
|
this.posthog.trackEvent({
|
||||||
|
distinctId: `tenant-${tenantId}`,
|
||||||
|
event: PAYMENT_MADE_DELETED,
|
||||||
|
properties: {},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -0,0 +1,68 @@
|
|||||||
|
import { Inject, Service } from 'typedi';
|
||||||
|
import { EventSubscriber } from '@/lib/EventPublisher/EventPublisher';
|
||||||
|
import {
|
||||||
|
IPaymentReceivedCreatedPayload,
|
||||||
|
IPaymentReceivedEditedPayload,
|
||||||
|
IPaymentReceivedDeletedPayload,
|
||||||
|
} from '@/interfaces';
|
||||||
|
import { PosthogService } from '../PostHog';
|
||||||
|
import events from '@/subscribers/events';
|
||||||
|
import {
|
||||||
|
PAYMENT_RECEIVED_CREATED,
|
||||||
|
PAYMENT_RECEIVED_EDITED,
|
||||||
|
PAYMENT_RECEIVED_DELETED,
|
||||||
|
} from '@/constants/event-tracker';
|
||||||
|
|
||||||
|
@Service()
|
||||||
|
export class PaymentReceivedEventsTracker extends EventSubscriber {
|
||||||
|
@Inject()
|
||||||
|
private posthog: PosthogService;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor method.
|
||||||
|
*/
|
||||||
|
public attach(bus) {
|
||||||
|
bus.subscribe(
|
||||||
|
events.paymentReceive.onCreated,
|
||||||
|
this.handleTrackPaymentReceivedCreatedEvent
|
||||||
|
);
|
||||||
|
bus.subscribe(
|
||||||
|
events.paymentReceive.onEdited,
|
||||||
|
this.handleTrackEditedPaymentReceivedEvent
|
||||||
|
);
|
||||||
|
bus.subscribe(
|
||||||
|
events.paymentReceive.onDeleted,
|
||||||
|
this.handleTrackDeletedPaymentReceivedEvent
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private handleTrackPaymentReceivedCreatedEvent = ({
|
||||||
|
tenantId,
|
||||||
|
}: IPaymentReceivedCreatedPayload) => {
|
||||||
|
this.posthog.trackEvent({
|
||||||
|
distinctId: `tenant-${tenantId}`,
|
||||||
|
event: PAYMENT_RECEIVED_CREATED,
|
||||||
|
properties: {},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
private handleTrackEditedPaymentReceivedEvent = ({
|
||||||
|
tenantId,
|
||||||
|
}: IPaymentReceivedEditedPayload) => {
|
||||||
|
this.posthog.trackEvent({
|
||||||
|
distinctId: `tenant-${tenantId}`,
|
||||||
|
event: PAYMENT_RECEIVED_EDITED,
|
||||||
|
properties: {},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
private handleTrackDeletedPaymentReceivedEvent = ({
|
||||||
|
tenantId,
|
||||||
|
}: IPaymentReceivedDeletedPayload) => {
|
||||||
|
this.posthog.trackEvent({
|
||||||
|
distinctId: `tenant-${tenantId}`,
|
||||||
|
event: PAYMENT_RECEIVED_DELETED,
|
||||||
|
properties: {},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -0,0 +1,68 @@
|
|||||||
|
import { Inject, Service } from 'typedi';
|
||||||
|
import { EventSubscriber } from '@/lib/EventPublisher/EventPublisher';
|
||||||
|
import {
|
||||||
|
ISaleEstimateCreatedPayload,
|
||||||
|
ISaleEstimateEditedPayload,
|
||||||
|
ISaleEstimateDeletedPayload,
|
||||||
|
} from '@/interfaces';
|
||||||
|
import { PosthogService } from '../PostHog';
|
||||||
|
import events from '@/subscribers/events';
|
||||||
|
import {
|
||||||
|
SALE_ESTIMATE_CREATED,
|
||||||
|
SALE_ESTIMATE_EDITED,
|
||||||
|
SALE_ESTIMATE_DELETED,
|
||||||
|
} from '@/constants/event-tracker';
|
||||||
|
|
||||||
|
@Service()
|
||||||
|
export class SaleEstimateEventsTracker extends EventSubscriber {
|
||||||
|
@Inject()
|
||||||
|
private posthog: PosthogService;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor method.
|
||||||
|
*/
|
||||||
|
public attach(bus) {
|
||||||
|
bus.subscribe(
|
||||||
|
events.saleEstimate.onCreated,
|
||||||
|
this.handleTrackEstimateCreatedEvent
|
||||||
|
);
|
||||||
|
bus.subscribe(
|
||||||
|
events.saleEstimate.onEdited,
|
||||||
|
this.handleTrackEditedEstimateEvent
|
||||||
|
);
|
||||||
|
bus.subscribe(
|
||||||
|
events.saleEstimate.onDeleted,
|
||||||
|
this.handleTrackDeletedEstimateEvent
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private handleTrackEstimateCreatedEvent = ({
|
||||||
|
tenantId,
|
||||||
|
}: ISaleEstimateCreatedPayload) => {
|
||||||
|
this.posthog.trackEvent({
|
||||||
|
distinctId: `tenant-${tenantId}`,
|
||||||
|
event: SALE_ESTIMATE_CREATED,
|
||||||
|
properties: {},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
private handleTrackEditedEstimateEvent = ({
|
||||||
|
tenantId,
|
||||||
|
}: ISaleEstimateEditedPayload) => {
|
||||||
|
this.posthog.trackEvent({
|
||||||
|
distinctId: `tenant-${tenantId}`,
|
||||||
|
event: SALE_ESTIMATE_EDITED,
|
||||||
|
properties: {},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
private handleTrackDeletedEstimateEvent = ({
|
||||||
|
tenantId,
|
||||||
|
}: ISaleEstimateDeletedPayload) => {
|
||||||
|
this.posthog.trackEvent({
|
||||||
|
distinctId: `tenant-${tenantId}`,
|
||||||
|
event: SALE_ESTIMATE_DELETED,
|
||||||
|
properties: {},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -0,0 +1,67 @@
|
|||||||
|
import { Inject, Service } from 'typedi';
|
||||||
|
import { EventSubscriber } from '@/lib/EventPublisher/EventPublisher';
|
||||||
|
import {
|
||||||
|
ISaleInvoiceCreatedPayload,
|
||||||
|
ISaleInvoiceEditedPayload,
|
||||||
|
} from '@/interfaces';
|
||||||
|
import { PosthogService } from '../PostHog';
|
||||||
|
import events from '@/subscribers/events';
|
||||||
|
import {
|
||||||
|
SALE_INVOICE_CREATED,
|
||||||
|
SALE_INVOICE_DELETED,
|
||||||
|
SALE_INVOICE_EDITED,
|
||||||
|
} from '@/constants/event-tracker';
|
||||||
|
|
||||||
|
@Service()
|
||||||
|
export class SaleInvoiceEventsTracker extends EventSubscriber {
|
||||||
|
@Inject()
|
||||||
|
private posthog: PosthogService;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor method.
|
||||||
|
*/
|
||||||
|
public attach(bus) {
|
||||||
|
bus.subscribe(
|
||||||
|
events.saleInvoice.onCreated,
|
||||||
|
this.handleTrackInvoiceCreatedEvent
|
||||||
|
);
|
||||||
|
bus.subscribe(
|
||||||
|
events.saleInvoice.onEdited,
|
||||||
|
this.handleTrackEditedInvoiceEvent
|
||||||
|
);
|
||||||
|
bus.subscribe(
|
||||||
|
events.saleInvoice.onDeleted,
|
||||||
|
this.handleTrackDeletedInvoiceEvent
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private handleTrackInvoiceCreatedEvent = ({
|
||||||
|
tenantId,
|
||||||
|
}: ISaleInvoiceCreatedPayload) => {
|
||||||
|
this.posthog.trackEvent({
|
||||||
|
distinctId: `tenant-${tenantId}`,
|
||||||
|
event: SALE_INVOICE_CREATED,
|
||||||
|
properties: {},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
private handleTrackEditedInvoiceEvent = ({
|
||||||
|
tenantId,
|
||||||
|
}: ISaleInvoiceEditedPayload) => {
|
||||||
|
this.posthog.trackEvent({
|
||||||
|
distinctId: `tenant-${tenantId}`,
|
||||||
|
event: SALE_INVOICE_EDITED,
|
||||||
|
properties: {},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
private handleTrackDeletedInvoiceEvent = ({
|
||||||
|
tenantId,
|
||||||
|
}: ISaleInvoiceEditedPayload) => {
|
||||||
|
this.posthog.trackEvent({
|
||||||
|
distinctId: `tenant-${tenantId}`,
|
||||||
|
event: SALE_INVOICE_DELETED,
|
||||||
|
properties: {},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -0,0 +1,76 @@
|
|||||||
|
import { Inject, Service } from 'typedi';
|
||||||
|
import { EventSubscriber } from '@/lib/EventPublisher/EventPublisher';
|
||||||
|
import { ITransactionsLockingPartialUnlocked } from '@/interfaces';
|
||||||
|
import { PosthogService } from '../PostHog';
|
||||||
|
import {
|
||||||
|
TRANSACTIONS_LOCKING_LOCKED,
|
||||||
|
TRANSACTIONS_LOCKING_LOCKING_CANCELLED,
|
||||||
|
TRANSACTIONS_LOCKING_PARTIALLY_UNLOCK_CANCELLED,
|
||||||
|
TRANSACTIONS_LOCKING_PARTIALLY_UNLOCKED,
|
||||||
|
} from '@/constants/event-tracker';
|
||||||
|
import events from '@/subscribers/events';
|
||||||
|
|
||||||
|
@Service()
|
||||||
|
export class TransactionsLockingEventsTracker extends EventSubscriber {
|
||||||
|
@Inject()
|
||||||
|
private posthog: PosthogService;
|
||||||
|
|
||||||
|
public attach(bus) {
|
||||||
|
bus.subscribe(
|
||||||
|
events.transactionsLocking.locked,
|
||||||
|
this.handleTransactionsLockingLockedEvent
|
||||||
|
);
|
||||||
|
bus.subscribe(
|
||||||
|
events.transactionsLocking.lockCanceled,
|
||||||
|
this.handleTransactionsLockingCancelledEvent
|
||||||
|
);
|
||||||
|
bus.subscribe(
|
||||||
|
events.transactionsLocking.partialUnlocked,
|
||||||
|
this.handleTransactionsLockingPartiallyUnlockedEvent
|
||||||
|
);
|
||||||
|
bus.subscribe(
|
||||||
|
events.transactionsLocking.partialUnlockCanceled,
|
||||||
|
this.handleTransactionsLockingPartiallyUnlockCancelledEvent
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private handleTransactionsLockingLockedEvent = ({
|
||||||
|
tenantId,
|
||||||
|
}: ITransactionsLockingPartialUnlocked) => {
|
||||||
|
this.posthog.trackEvent({
|
||||||
|
distinctId: `tenant-${tenantId}`,
|
||||||
|
event: TRANSACTIONS_LOCKING_LOCKED,
|
||||||
|
properties: {},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
private handleTransactionsLockingCancelledEvent = ({
|
||||||
|
tenantId,
|
||||||
|
}: ITransactionsLockingPartialUnlocked) => {
|
||||||
|
this.posthog.trackEvent({
|
||||||
|
distinctId: `tenant-${tenantId}`,
|
||||||
|
event: TRANSACTIONS_LOCKING_LOCKING_CANCELLED,
|
||||||
|
properties: {},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
private handleTransactionsLockingPartiallyUnlockedEvent = ({
|
||||||
|
tenantId,
|
||||||
|
}: ITransactionsLockingPartialUnlocked) => {
|
||||||
|
this.posthog.trackEvent({
|
||||||
|
distinctId: `tenant-${tenantId}`,
|
||||||
|
event: TRANSACTIONS_LOCKING_PARTIALLY_UNLOCKED,
|
||||||
|
properties: {},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
private handleTransactionsLockingPartiallyUnlockCancelledEvent = ({
|
||||||
|
tenantId,
|
||||||
|
}: ITransactionsLockingPartialUnlocked) => {
|
||||||
|
this.posthog.trackEvent({
|
||||||
|
distinctId: `tenant-${tenantId}`,
|
||||||
|
event: TRANSACTIONS_LOCKING_PARTIALLY_UNLOCK_CANCELLED,
|
||||||
|
properties: {},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -0,0 +1,55 @@
|
|||||||
|
import { Inject, Service } from 'typedi';
|
||||||
|
import { EventSubscriber } from '@/lib/EventPublisher/EventPublisher';
|
||||||
|
import { ITransactionsLockingPartialUnlocked } from '@/interfaces';
|
||||||
|
import { PosthogService } from '../PostHog';
|
||||||
|
import {
|
||||||
|
SUBSCRIPTION_CANCELLED,
|
||||||
|
SUBSCRIPTION_PLAN_CHANGED,
|
||||||
|
SUBSCRIPTION_RESUMED,
|
||||||
|
} from '@/constants/event-tracker';
|
||||||
|
import events from '@/subscribers/events';
|
||||||
|
|
||||||
|
@Service()
|
||||||
|
export class TransactionsLockingEventsTracker extends EventSubscriber {
|
||||||
|
@Inject()
|
||||||
|
private posthog: PosthogService;
|
||||||
|
|
||||||
|
public attach(bus) {
|
||||||
|
bus.subscribe(
|
||||||
|
events.subscription.onSubscriptionResumed,
|
||||||
|
this.handleSubscriptionResumedEvent
|
||||||
|
);
|
||||||
|
bus.subscribe(
|
||||||
|
events.subscription.onSubscriptionCancelled,
|
||||||
|
this.handleSubscriptionCancelledEvent
|
||||||
|
);
|
||||||
|
bus.subscribe(
|
||||||
|
events.subscription.onSubscriptionPlanChanged,
|
||||||
|
this.handleSubscriptionPlanChangedEvent
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private handleSubscriptionResumedEvent = ({ tenantId }) => {
|
||||||
|
this.posthog.trackEvent({
|
||||||
|
distinctId: `tenant-${tenantId}`,
|
||||||
|
event: SUBSCRIPTION_RESUMED,
|
||||||
|
properties: {},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
private handleSubscriptionCancelledEvent = ({ tenantId }) => {
|
||||||
|
this.posthog.trackEvent({
|
||||||
|
distinctId: `tenant-${tenantId}`,
|
||||||
|
event: SUBSCRIPTION_CANCELLED,
|
||||||
|
properties: {},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
private handleSubscriptionPlanChangedEvent = ({ tenantId }) => {
|
||||||
|
this.posthog.trackEvent({
|
||||||
|
distinctId: `tenant-${tenantId}`,
|
||||||
|
event: SUBSCRIPTION_PLAN_CHANGED,
|
||||||
|
properties: {},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -0,0 +1,56 @@
|
|||||||
|
import { Inject, Service } from 'typedi';
|
||||||
|
import { EventSubscriber } from '@/lib/EventPublisher/EventPublisher';
|
||||||
|
import {
|
||||||
|
IVendorEventCreatedPayload,
|
||||||
|
IVendorEventEditedPayload,
|
||||||
|
IVendorEventDeletedPayload,
|
||||||
|
} from '@/interfaces';
|
||||||
|
import { PosthogService } from '../PostHog';
|
||||||
|
import events from '@/subscribers/events';
|
||||||
|
import {
|
||||||
|
VENDOR_CREATED,
|
||||||
|
VENDOR_EDITED,
|
||||||
|
VENDOR_DELETED,
|
||||||
|
} from '@/constants/event-tracker';
|
||||||
|
|
||||||
|
@Service()
|
||||||
|
export class VendorEventsTracker extends EventSubscriber {
|
||||||
|
@Inject()
|
||||||
|
private posthog: PosthogService;
|
||||||
|
|
||||||
|
public attach(bus) {
|
||||||
|
bus.subscribe(events.vendors.onCreated, this.handleTrackVendorCreatedEvent);
|
||||||
|
bus.subscribe(events.vendors.onEdited, this.handleTrackEditedVendorEvent);
|
||||||
|
bus.subscribe(events.vendors.onDeleted, this.handleTrackDeletedVendorEvent);
|
||||||
|
}
|
||||||
|
|
||||||
|
private handleTrackVendorCreatedEvent = ({
|
||||||
|
tenantId,
|
||||||
|
}: IVendorEventCreatedPayload) => {
|
||||||
|
this.posthog.trackEvent({
|
||||||
|
distinctId: `tenant-${tenantId}`,
|
||||||
|
event: VENDOR_CREATED,
|
||||||
|
properties: {},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
private handleTrackEditedVendorEvent = ({
|
||||||
|
tenantId,
|
||||||
|
}: IVendorEventEditedPayload) => {
|
||||||
|
this.posthog.trackEvent({
|
||||||
|
distinctId: `tenant-${tenantId}`,
|
||||||
|
event: VENDOR_EDITED,
|
||||||
|
properties: {},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
private handleTrackDeletedVendorEvent = ({
|
||||||
|
tenantId,
|
||||||
|
}: IVendorEventDeletedPayload) => {
|
||||||
|
this.posthog.trackEvent({
|
||||||
|
distinctId: `tenant-${tenantId}`,
|
||||||
|
event: VENDOR_DELETED,
|
||||||
|
properties: {},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
}
|
||||||
31
packages/server/src/services/EventsTracker/events/events.ts
Normal file
31
packages/server/src/services/EventsTracker/events/events.ts
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
import { SaleInvoiceEventsTracker } from './SaleInvoicesEventsTracker';
|
||||||
|
import { SaleEstimateEventsTracker } from './SaleEstimateEventsTracker';
|
||||||
|
import { PaymentMadeEventsTracker } from './PaymentMadeEventsTracker';
|
||||||
|
import { PaymentReceivedEventsTracker } from './PaymentReceivedEventsTracker';
|
||||||
|
import { BillEventsTracker } from './BillEventsTracker';
|
||||||
|
import { ExpenseEventsTracker } from './ExpenseEventsTracker';
|
||||||
|
import { AccountEventsTracker } from './AccountEventsTracker';
|
||||||
|
import { AuthenticationEventsTracker } from './AuthenticationEventsTracker';
|
||||||
|
import { ItemEventsTracker } from './ItemEventsTracker';
|
||||||
|
import { BankTransactionEventsTracker } from './BankTransactionEventsTracker';
|
||||||
|
import { CustomerEventsTracker } from './CustomerEventsTracker';
|
||||||
|
import { VendorEventsTracker } from './VendorEventsTracker';
|
||||||
|
import { ManualJournalEventsTracker } from './ManualJournalEventsTracker';
|
||||||
|
import { BankRuleEventsTracker } from './BankRuleEventsTracker';
|
||||||
|
|
||||||
|
export const EventsTrackerListeners = [
|
||||||
|
SaleInvoiceEventsTracker,
|
||||||
|
SaleEstimateEventsTracker,
|
||||||
|
PaymentMadeEventsTracker,
|
||||||
|
PaymentReceivedEventsTracker,
|
||||||
|
BillEventsTracker,
|
||||||
|
AccountEventsTracker,
|
||||||
|
ExpenseEventsTracker,
|
||||||
|
AuthenticationEventsTracker,
|
||||||
|
ItemEventsTracker,
|
||||||
|
BankTransactionEventsTracker,
|
||||||
|
CustomerEventsTracker,
|
||||||
|
VendorEventsTracker,
|
||||||
|
ManualJournalEventsTracker,
|
||||||
|
BankRuleEventsTracker,
|
||||||
|
];
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
import { Service, Inject } from 'typedi';
|
import { Service, Inject } from 'typedi';
|
||||||
import { sumBy, difference } from 'lodash';
|
import { sumBy, difference } from 'lodash';
|
||||||
import { ServiceError } from '@/exceptions';
|
import { ServiceError } from '@/exceptions';
|
||||||
import { ERRORS } from '../constants';
|
import { ERRORS, SUPPORTED_EXPENSE_PAYMENT_ACCOUNT_TYPES } from '../constants';
|
||||||
import {
|
import {
|
||||||
IAccount,
|
IAccount,
|
||||||
IExpense,
|
IExpense,
|
||||||
@@ -79,7 +79,9 @@ export class CommandExpenseValidator {
|
|||||||
* @throws {ServiceError}
|
* @throws {ServiceError}
|
||||||
*/
|
*/
|
||||||
public validatePaymentAccountType = (paymentAccount: number[]) => {
|
public validatePaymentAccountType = (paymentAccount: number[]) => {
|
||||||
if (!paymentAccount.isParentType(ACCOUNT_PARENT_TYPE.CURRENT_ASSET)) {
|
if (
|
||||||
|
!paymentAccount.isAccountType(SUPPORTED_EXPENSE_PAYMENT_ACCOUNT_TYPES)
|
||||||
|
) {
|
||||||
throw new ServiceError(ERRORS.PAYMENT_ACCOUNT_HAS_INVALID_TYPE);
|
throw new ServiceError(ERRORS.PAYMENT_ACCOUNT_HAS_INVALID_TYPE);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ import {
|
|||||||
} from '@/interfaces';
|
} from '@/interfaces';
|
||||||
import { BranchTransactionDTOTransform } from '@/services/Branches/Integrations/BranchTransactionDTOTransform';
|
import { BranchTransactionDTOTransform } from '@/services/Branches/Integrations/BranchTransactionDTOTransform';
|
||||||
import { TenantMetadata } from '@/system/models';
|
import { TenantMetadata } from '@/system/models';
|
||||||
|
import { assocItemEntriesDefaultIndex } from '@/services/Items/utils';
|
||||||
|
|
||||||
@Service()
|
@Service()
|
||||||
export class ExpenseDTOTransformer {
|
export class ExpenseDTOTransformer {
|
||||||
@@ -40,8 +41,8 @@ export class ExpenseDTOTransformer {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Mapping expense DTO to model.
|
* Mapping expense DTO to model.
|
||||||
* @param {IExpenseDTO} expenseDTO
|
* @param {IExpenseDTO} expenseDTO
|
||||||
* @param {ISystemUser} authorizedUser
|
* @param {ISystemUser} authorizedUser
|
||||||
* @return {IExpense}
|
* @return {IExpense}
|
||||||
*/
|
*/
|
||||||
private expenseDTOToModel(
|
private expenseDTOToModel(
|
||||||
@@ -52,9 +53,14 @@ export class ExpenseDTOTransformer {
|
|||||||
const landedCostAmount = this.getExpenseLandedCostAmount(expenseDTO);
|
const landedCostAmount = this.getExpenseLandedCostAmount(expenseDTO);
|
||||||
const totalAmount = this.getExpenseCategoriesTotal(expenseDTO.categories);
|
const totalAmount = this.getExpenseCategoriesTotal(expenseDTO.categories);
|
||||||
|
|
||||||
|
const categories = R.compose(
|
||||||
|
// Associate the default index to categories lines.
|
||||||
|
assocItemEntriesDefaultIndex
|
||||||
|
)(expenseDTO.categories || []);
|
||||||
|
|
||||||
const initialDTO = {
|
const initialDTO = {
|
||||||
categories: [],
|
|
||||||
...omit(expenseDTO, ['publish', 'attachments']),
|
...omit(expenseDTO, ['publish', 'attachments']),
|
||||||
|
categories,
|
||||||
totalAmount,
|
totalAmount,
|
||||||
landedCostAmount,
|
landedCostAmount,
|
||||||
paymentDate: moment(expenseDTO.paymentDate).toMySqlDateTime(),
|
paymentDate: moment(expenseDTO.paymentDate).toMySqlDateTime(),
|
||||||
|
|||||||
@@ -54,6 +54,7 @@ export class GetExpenses {
|
|||||||
builder.withGraphFetched('categories.expenseAccount');
|
builder.withGraphFetched('categories.expenseAccount');
|
||||||
|
|
||||||
dynamicList.buildQuery()(builder);
|
dynamicList.buildQuery()(builder);
|
||||||
|
filterDTO?.filterQuery && filterDTO?.filterQuery(builder);
|
||||||
})
|
})
|
||||||
.pagination(filter.page - 1, filter.pageSize);
|
.pagination(filter.page - 1, filter.pageSize);
|
||||||
|
|
||||||
|
|||||||
113
packages/server/src/services/Expenses/ExpenseGL.ts
Normal file
113
packages/server/src/services/Expenses/ExpenseGL.ts
Normal file
@@ -0,0 +1,113 @@
|
|||||||
|
import * as R from 'ramda';
|
||||||
|
import {
|
||||||
|
AccountNormal,
|
||||||
|
IExpenseCategory,
|
||||||
|
ILedger,
|
||||||
|
ILedgerEntry,
|
||||||
|
} from '@/interfaces';
|
||||||
|
import Ledger from '../Accounting/Ledger';
|
||||||
|
|
||||||
|
export class ExpenseGL {
|
||||||
|
private expense: any;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor method.
|
||||||
|
*/
|
||||||
|
constructor(expense: any) {
|
||||||
|
this.expense = expense;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves the expense GL common entry.
|
||||||
|
* @param {IExpense} expense
|
||||||
|
* @returns {Partial<ILedgerEntry>}
|
||||||
|
*/
|
||||||
|
private getExpenseGLCommonEntry = (): Partial<ILedgerEntry> => {
|
||||||
|
return {
|
||||||
|
currencyCode: this.expense.currencyCode,
|
||||||
|
exchangeRate: this.expense.exchangeRate,
|
||||||
|
|
||||||
|
transactionType: 'Expense',
|
||||||
|
transactionId: this.expense.id,
|
||||||
|
|
||||||
|
date: this.expense.paymentDate,
|
||||||
|
userId: this.expense.userId,
|
||||||
|
|
||||||
|
debit: 0,
|
||||||
|
credit: 0,
|
||||||
|
|
||||||
|
branchId: this.expense.branchId,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves the expense GL payment entry.
|
||||||
|
* @param {IExpense} expense
|
||||||
|
* @returns {ILedgerEntry}
|
||||||
|
*/
|
||||||
|
private getExpenseGLPaymentEntry = (): ILedgerEntry => {
|
||||||
|
const commonEntry = this.getExpenseGLCommonEntry();
|
||||||
|
|
||||||
|
return {
|
||||||
|
...commonEntry,
|
||||||
|
credit: this.expense.localAmount,
|
||||||
|
accountId: this.expense.paymentAccountId,
|
||||||
|
accountNormal:
|
||||||
|
this.expense?.paymentAccount?.accountNormal === 'debit'
|
||||||
|
? AccountNormal.DEBIT
|
||||||
|
: AccountNormal.CREDIT,
|
||||||
|
index: 1,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves the expense GL category entry.
|
||||||
|
* @param {IExpense} expense -
|
||||||
|
* @param {IExpenseCategory} expenseCategory -
|
||||||
|
* @param {number} index
|
||||||
|
* @returns {ILedgerEntry}
|
||||||
|
*/
|
||||||
|
private getExpenseGLCategoryEntry = R.curry(
|
||||||
|
(category: IExpenseCategory, index: number): ILedgerEntry => {
|
||||||
|
const commonEntry = this.getExpenseGLCommonEntry();
|
||||||
|
const localAmount = category.amount * this.expense.exchangeRate;
|
||||||
|
|
||||||
|
return {
|
||||||
|
...commonEntry,
|
||||||
|
accountId: category.expenseAccountId,
|
||||||
|
accountNormal: AccountNormal.DEBIT,
|
||||||
|
debit: localAmount,
|
||||||
|
note: category.description,
|
||||||
|
index: index + 2,
|
||||||
|
projectId: category.projectId,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves the expense GL entries.
|
||||||
|
* @param {IExpense} expense
|
||||||
|
* @returns {ILedgerEntry[]}
|
||||||
|
*/
|
||||||
|
public getExpenseGLEntries = (): ILedgerEntry[] => {
|
||||||
|
const getCategoryEntry = this.getExpenseGLCategoryEntry();
|
||||||
|
|
||||||
|
const paymentEntry = this.getExpenseGLPaymentEntry();
|
||||||
|
const categoryEntries = this.expense.categories.map(getCategoryEntry);
|
||||||
|
|
||||||
|
return [paymentEntry, ...categoryEntries];
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves the given expense ledger.
|
||||||
|
* @param {IExpense} expense
|
||||||
|
* @returns {ILedger}
|
||||||
|
*/
|
||||||
|
public getExpenseLedger = (): ILedger => {
|
||||||
|
const entries = this.getExpenseGLEntries();
|
||||||
|
|
||||||
|
console.log(entries, 'entries');
|
||||||
|
|
||||||
|
return new Ledger(entries);
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -1,106 +0,0 @@
|
|||||||
import * as R from 'ramda';
|
|
||||||
import { Service } from 'typedi';
|
|
||||||
import {
|
|
||||||
AccountNormal,
|
|
||||||
IExpense,
|
|
||||||
IExpenseCategory,
|
|
||||||
ILedger,
|
|
||||||
ILedgerEntry,
|
|
||||||
} from '@/interfaces';
|
|
||||||
import Ledger from '@/services/Accounting/Ledger';
|
|
||||||
|
|
||||||
@Service()
|
|
||||||
export class ExpenseGLEntries {
|
|
||||||
/**
|
|
||||||
* Retrieves the expense GL common entry.
|
|
||||||
* @param {IExpense} expense
|
|
||||||
* @returns
|
|
||||||
*/
|
|
||||||
private getExpenseGLCommonEntry = (expense: IExpense) => {
|
|
||||||
return {
|
|
||||||
currencyCode: expense.currencyCode,
|
|
||||||
exchangeRate: expense.exchangeRate,
|
|
||||||
|
|
||||||
transactionType: 'Expense',
|
|
||||||
transactionId: expense.id,
|
|
||||||
|
|
||||||
date: expense.paymentDate,
|
|
||||||
userId: expense.userId,
|
|
||||||
|
|
||||||
debit: 0,
|
|
||||||
credit: 0,
|
|
||||||
|
|
||||||
branchId: expense.branchId,
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Retrieves the expense GL payment entry.
|
|
||||||
* @param {IExpense} expense
|
|
||||||
* @returns {ILedgerEntry}
|
|
||||||
*/
|
|
||||||
private getExpenseGLPaymentEntry = (expense: IExpense): ILedgerEntry => {
|
|
||||||
const commonEntry = this.getExpenseGLCommonEntry(expense);
|
|
||||||
|
|
||||||
return {
|
|
||||||
...commonEntry,
|
|
||||||
credit: expense.localAmount,
|
|
||||||
accountId: expense.paymentAccountId,
|
|
||||||
accountNormal: AccountNormal.DEBIT,
|
|
||||||
index: 1,
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Retrieves the expense GL category entry.
|
|
||||||
* @param {IExpense} expense -
|
|
||||||
* @param {IExpenseCategory} expenseCategory -
|
|
||||||
* @param {number} index
|
|
||||||
* @returns {ILedgerEntry}
|
|
||||||
*/
|
|
||||||
private getExpenseGLCategoryEntry = R.curry(
|
|
||||||
(
|
|
||||||
expense: IExpense,
|
|
||||||
category: IExpenseCategory,
|
|
||||||
index: number
|
|
||||||
): ILedgerEntry => {
|
|
||||||
const commonEntry = this.getExpenseGLCommonEntry(expense);
|
|
||||||
const localAmount = category.amount * expense.exchangeRate;
|
|
||||||
|
|
||||||
return {
|
|
||||||
...commonEntry,
|
|
||||||
accountId: category.expenseAccountId,
|
|
||||||
accountNormal: AccountNormal.DEBIT,
|
|
||||||
debit: localAmount,
|
|
||||||
note: category.description,
|
|
||||||
index: index + 2,
|
|
||||||
projectId: category.projectId,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Retrieves the expense GL entries.
|
|
||||||
* @param {IExpense} expense
|
|
||||||
* @returns {ILedgerEntry[]}
|
|
||||||
*/
|
|
||||||
public getExpenseGLEntries = (expense: IExpense): ILedgerEntry[] => {
|
|
||||||
const getCategoryEntry = this.getExpenseGLCategoryEntry(expense);
|
|
||||||
|
|
||||||
const paymentEntry = this.getExpenseGLPaymentEntry(expense);
|
|
||||||
const categoryEntries = expense.categories.map(getCategoryEntry);
|
|
||||||
|
|
||||||
return [paymentEntry, ...categoryEntries];
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Retrieves the given expense ledger.
|
|
||||||
* @param {IExpense} expense
|
|
||||||
* @returns {ILedger}
|
|
||||||
*/
|
|
||||||
public getExpenseLedger = (expense: IExpense): ILedger => {
|
|
||||||
const entries = this.getExpenseGLEntries(expense);
|
|
||||||
|
|
||||||
return new Ledger(entries);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,45 @@
|
|||||||
|
import { Knex } from 'knex';
|
||||||
|
import { Inject, Service } from 'typedi';
|
||||||
|
import { IExpense, ILedger } from '@/interfaces';
|
||||||
|
import { ExpenseGL } from './ExpenseGL';
|
||||||
|
import HasTenancyService from '../Tenancy/TenancyService';
|
||||||
|
|
||||||
|
@Service()
|
||||||
|
export class ExpenseGLEntries {
|
||||||
|
@Inject()
|
||||||
|
private tenancy: HasTenancyService;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves the expense G/L of the given id.
|
||||||
|
* @param {number} tenantId
|
||||||
|
* @param {number} expenseId
|
||||||
|
* @param {Knex.Transaction} trx
|
||||||
|
* @returns {Promise<ILedger>}
|
||||||
|
*/
|
||||||
|
public getExpenseLedgerById = async (
|
||||||
|
tenantId: number,
|
||||||
|
expenseId: number,
|
||||||
|
trx?: Knex.Transaction
|
||||||
|
): Promise<ILedger> => {
|
||||||
|
const { Expense } = await this.tenancy.models(tenantId);
|
||||||
|
|
||||||
|
const expense = await Expense.query(trx)
|
||||||
|
.findById(expenseId)
|
||||||
|
.withGraphFetched('categories')
|
||||||
|
.withGraphFetched('paymentAccount')
|
||||||
|
.throwIfNotFound();
|
||||||
|
|
||||||
|
return this.getExpenseLedger(expense);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves the given expense ledger.
|
||||||
|
* @param {IExpense} expense
|
||||||
|
* @returns {ILedger}
|
||||||
|
*/
|
||||||
|
public getExpenseLedger = (expense: IExpense): ILedger => {
|
||||||
|
const expenseGL = new ExpenseGL(expense);
|
||||||
|
|
||||||
|
return expenseGL.getExpenseLedger();
|
||||||
|
};
|
||||||
|
}
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user