refactoring: balance sheet report.

refactoring: trial balance sheet report.
refactoring: general ledger report.
refactoring: journal report.
refactoring: P&L report.
This commit is contained in:
Ahmed Bouhuolia
2020-12-10 13:04:49 +02:00
parent e8f329e29e
commit d49992a6d7
71 changed files with 3203 additions and 1571 deletions

View File

@@ -1,25 +1,7 @@
import TenantRepository from 'repositories/TenantRepository';
import { IAccount } from 'interfaces';
import { Account } from 'models';
export default class AccountRepository extends TenantRepository {
models: any;
repositories: any;
cache: any;
/**
* Constructor method.
* @param {number} tenantId - The given tenant id.
*/
constructor(
tenantId: number,
) {
super(tenantId);
this.models = this.tenancy.models(tenantId);
this.cache = this.tenancy.cache(tenantId);
}
/**
* Retrieve accounts dependency graph.
* @returns {}
@@ -27,8 +9,9 @@ export default class AccountRepository extends TenantRepository {
async getDependencyGraph() {
const { Account } = this.models;
const accounts = await this.allAccounts();
const cacheKey = this.getCacheKey('accounts.depGraph');
return this.cache.get('accounts.depGraph', async () => {
return this.cache.get(cacheKey, async () => {
return Account.toDependencyGraph(accounts);
});
}
@@ -37,10 +20,13 @@ export default class AccountRepository extends TenantRepository {
* Retrieve all accounts on the storage.
* @return {IAccount[]}
*/
allAccounts(): IAccount[] {
allAccounts(withRelations?: string|string[]): IAccount[] {
const { Account } = this.models;
return this.cache.get('accounts', async () => {
return Account.query();
const cacheKey = this.getCacheKey('accounts.depGraph', withRelations);
return this.cache.get(cacheKey, async () => {
return Account.query()
.withGraphFetched(withRelations);
});
}
@@ -51,7 +37,9 @@ export default class AccountRepository extends TenantRepository {
*/
getBySlug(slug: string): IAccount {
const { Account } = this.models;
return this.cache.get(`accounts.slug.${slug}`, () => {
const cacheKey = this.getCacheKey('accounts.slug', slug);
return this.cache.get(cacheKey, () => {
return Account.query().findOne('slug', slug);
});
}
@@ -63,7 +51,9 @@ export default class AccountRepository extends TenantRepository {
*/
findById(id: number): IAccount {
const { Account } = this.models;
return this.cache.get(`accounts.id.${id}`, () => {
const cacheKey = this.getCacheKey('accounts.id', id);
return this.cache.get(cacheKey, () => {
return Account.query().findById(id);
});
}
@@ -75,7 +65,11 @@ export default class AccountRepository extends TenantRepository {
*/
findByIds(accountsIds: number[]) {
const { Account } = this.models;
return Account.query().whereIn('id', accountsIds);
const cacheKey = this.getCacheKey('accounts.id', accountsIds);
return this.cache.get(cacheKey, () => {
return Account.query().whereIn('id', accountsIds);
});
}
/**
@@ -143,6 +137,6 @@ export default class AccountRepository extends TenantRepository {
* Flush repository cache.
*/
flushCache(): void {
this.cache.delStartWith('accounts');
this.cache.delStartWith(this.repositoryName);
}
}

View File

@@ -0,0 +1,60 @@
import { QueryBuilder } from 'knex';
import { AccountTransaction } from 'models';
import hashObject from 'object-hash';
import TenantRepository from 'repositories/TenantRepository';
interface IJournalTransactionsFilter {
fromDate: string | Date,
toDate: string | Date,
accountsIds: number[],
sumationCreditDebit: boolean,
fromAmount: number,
toAmount: number,
contactsIds?: number[],
contactType?: string,
};
export default class AccountTransactionsRepository extends TenantRepository {
journal(filter: IJournalTransactionsFilter) {
const { AccountTransaction } = this.models;
const cacheKey = this.getCacheKey('transactions.journal', filter);
return this.cache.get(cacheKey, () => {
return AccountTransaction.query()
.modify('filterAccounts', filter.accountsIds)
.modify('filterDateRange', filter.fromDate, filter.toDate)
.withGraphFetched('account.type')
.onBuild((query) => {
if (filter.sumationCreditDebit) {
query.modify('sumationCreditDebit');
}
if (filter.fromAmount || filter.toAmount) {
query.modify('filterAmountRange', filter.fromAmount, filter.toAmount);
}
if (filter.contactsIds) {
query.modify('filterContactIds', filter.contactsIds);
}
if (filter.contactType) {
query.where('contact_type', filter.contactType);
}
});
});
}
openingBalance(fromDate) {
return this.cache.get('transaction.openingBalance', () => {
return AccountTransaction.query()
.modify('openingBalance', fromDate);
})
}
closingOpening(toDate) {
return this.cache.get('transaction.closingBalance', () => {
return AccountTransaction.query()
.modify('closingBalance', toDate);
});
}
}

View File

@@ -2,22 +2,6 @@ import TenantRepository from 'repositories/TenantRepository';
import { IAccountType } from 'interfaces';
export default class AccountTypeRepository extends TenantRepository {
cache: any;
models: any;
/**
* Constructor method.
* @param {number} tenantId - The given tenant id.
*/
constructor(
tenantId: number,
) {
super(tenantId);
this.models = this.tenancy.models(tenantId);
this.cache = this.tenancy.cache(tenantId);
}
/**
* Retrieve all accounts types.
* @return {IAccountType[]}

View File

@@ -0,0 +1,19 @@
import hashObject from 'object-hash';
export default class CachableRepository {
repositoryName: string;
/**
* Retrieve the cache key of the method name and arguments.
* @param {string} method
* @param {...any} args
* @return {string}
*/
getCacheKey(method, ...args) {
const hashArgs = hashObject({ ...args });
const repositoryName = this.repositoryName;
return `${repositoryName}-${method}-${hashArgs}`;
}
}

View File

@@ -2,22 +2,6 @@ import TenantRepository from 'repositories/TenantRepository';
import { IContact } from 'interfaces';
export default class ContactRepository extends TenantRepository {
cache: any;
models: any;
/**
* Constructor method.
* @param {number} tenantId - The given tenant id.
*/
constructor(
tenantId: number,
) {
super(tenantId);
this.models = this.tenancy.models(tenantId);
this.cache = this.tenancy.cache(tenantId);
}
/**
* Retrieve the given contact model.
* @param {number} contactId

View File

@@ -1,18 +1,12 @@
import TenantRepository from "./TenantRepository";
export default class CustomerRepository extends TenantRepository {
models: any;
cache: any;
all() {
const { Contact } = this.models;
/**
* Constructor method.
* @param {number} tenantId
*/
constructor(tenantId: number) {
super(tenantId);
this.models = this.tenancy.models(tenantId);
this.cache = this.tenancy.cache(tenantId);
return this.cache.get('customers', () => {
return Contact.query().modify('customer');
});
}
/**

View File

@@ -3,21 +3,6 @@ import { IExpense } from 'interfaces';
import moment from "moment";
export default class ExpenseRepository extends TenantRepository {
models: any;
repositories: any;
cache: any;
/**
* Constructor method.
* @param {number} tenantId
*/
constructor(tenantId: number) {
super(tenantId);
this.models = this.tenancy.models(tenantId);
this.cache = this.tenancy.cache(tenantId);
}
/**
* Retrieve the given expense by id.
* @param {number} expenseId

View File

@@ -0,0 +1,18 @@
import { IBalanceSheetQuery } from 'interfaces';
import TenantRepository from 'repositories/TenantRepository';
export default class JournalRepository extends TenantRepository {
balanceSheet(query: IBalanceSheetQuery) {
// Accounts dependency graph.
const accountsGraph = Account.toDependencyGraph(balanceSheetAccounts);
// Load all entries that associated to the given accounts.
const journalEntriesCollected = Account.collectJournalEntries(balanceSheetAccounts);
const journalEntries = new JournalPoster(accountsGraph);
journalEntries.loadEntries(journalEntriesCollected);
}
}

View File

@@ -1,16 +1,45 @@
import { Container } from 'typedi';
import TenancyService from 'services/Tenancy/TenancyService';
import CachableRepository from './CachableRepository';
export default class TenantRepository {
export default class TenantRepository extends CachableRepository {
repositoryName: string;
tenantId: number;
tenancy: TenancyService;
modelsInstance: any;
repositoriesInstance: any;
cacheInstance: any;
/**
* Constructor method.
* @param {number} tenantId
*/
constructor(tenantId: number) {
super();
this.tenantId = tenantId;
this.tenancy = Container.get(TenancyService);
this.repositoryName = this.constructor.name;
}
get models() {
if (!this.modelsInstance) {
this.modelsInstance = this.tenancy.models(this.tenantId);
}
return this.modelsInstance;
}
get repositories() {
if (!this.repositoriesInstance) {
this.repositoriesInstance = this.tenancy.repositories(this.tenantId);
}
return this.repositoriesInstance;
}
get cache() {
if (!this.cacheInstance) {
this.cacheInstance = this.tenancy.cache(this.tenantId);
}
return this.cacheInstance;
}
}

View File

@@ -3,19 +3,6 @@ import TenantRepository from "./TenantRepository";
export default class VendorRepository extends TenantRepository {
models: any;
cache: any;
/**
* Constructor method.
* @param {number} tenantId
*/
constructor(tenantId: number) {
super(tenantId);
this.models = this.tenancy.models(tenantId);
this.cache = this.tenancy.cache(tenantId);
}
/**
* Retrieve vendor details of the given id.
@@ -68,7 +55,6 @@ export default class VendorRepository extends TenantRepository {
[changeMethod]('balance', Math.abs(amount));
}
async changeDiffBalance(
vendorId: number,
amount: number,

View File

@@ -2,22 +2,6 @@ import { IView } from 'interfaces';
import TenantRepository from 'repositories/TenantRepository';
export default class ViewRepository extends TenantRepository {
models: any;
cache: any;
repositories: any;
/**
* Constructor method.
* @param {number} tenantId - The given tenant id.
*/
constructor(
tenantId: number,
) {
super(tenantId);
this.models = this.tenancy.models(tenantId);
this.cache = this.tenancy.cache(tenantId);
}
/**
* Retrieve view model by the given id.

View File

@@ -2,23 +2,6 @@ import { omit } from 'lodash';
import TenantRepository from 'repositories/TenantRepository';
export default class ViewRoleRepository extends TenantRepository {
models: any;
cache: any;
repositories: any;
/**
* Constructor method.
* @param {number} tenantId - The given tenant id.
*/
constructor(
tenantId: number,
) {
super(tenantId);
this.models = this.tenancy.models(tenantId);
this.cache = this.tenancy.cache(tenantId);
this.repositories = this.tenancy.cache(tenantId);
}
allByView(viewId: number) {
const { ViewRole } = this.models;