diff --git a/packages/server/src/services/FinancialStatements/BalanceSheet/BalanceSheetAccounts.ts b/packages/server/src/services/FinancialStatements/BalanceSheet/BalanceSheetAccounts.ts index 1e077f2e00..c4e85c76ac 100644 --- a/packages/server/src/services/FinancialStatements/BalanceSheet/BalanceSheetAccounts.ts +++ b/packages/server/src/services/FinancialStatements/BalanceSheet/BalanceSheetAccounts.ts @@ -20,6 +20,8 @@ import { BalanceSheetPercentage } from './BalanceSheetPercentage'; import { BalanceSheetSchema } from './BalanceSheetSchema'; import { BalanceSheetBase } from './BalanceSheetBase'; import { BalanceSheetQuery } from './BalanceSheetQuery'; +import { flatToNestedArray } from '@/utils'; +import BalanceSheetRepository from './BalanceSheetRepository'; export const BalanceSheetAccounts = (Base: any) => class extends R.compose( @@ -56,6 +58,11 @@ export const BalanceSheetAccounts = (Base: any) => */ readonly i18n: any; + /** + * Balance sheet repository. + */ + readonly repository: BalanceSheetRepository; + /** * Retrieve the accounts node of accounts types. * @param {string} accountsTypes @@ -78,8 +85,12 @@ export const BalanceSheetAccounts = (Base: any) => private reportSchemaAccountNodeMapper = ( account: IAccount ): IBalanceSheetAccountNode => { + const childrenAccountsIds = this.repository.accountsGraph.dependenciesOf( + account.id + ); + const accountIds = R.uniq(R.append(account.id, childrenAccountsIds)); const total = this.repository.totalAccountsLedger - .whereAccountId(account.id) + .whereAccountsIds(accountIds) .getClosingBalance(); return { @@ -128,8 +139,19 @@ export const BalanceSheetAccounts = (Base: any) => private getAccountsNodesByAccountTypes = ( accountsTypes: string[] ): IBalanceSheetAccountNode[] => { + // Retrieves accounts from the given defined node account types. const accounts = this.getAccountsByAccountTypes(accountsTypes); - return R.map(this.reportSchemaAccountNodeComposer, accounts); + + // Converts the flatten accounts to tree. + const accountsTree = flatToNestedArray(accounts, { + id: 'id', + parentId: 'parentAccountId', + }); + // Maps over the accounts tree. + return this.mapNodesDeep( + accountsTree, + this.reportSchemaAccountNodeComposer + ); }; /** diff --git a/packages/server/src/services/FinancialStatements/BalanceSheet/BalanceSheetRepository.ts b/packages/server/src/services/FinancialStatements/BalanceSheet/BalanceSheetRepository.ts index 001f266beb..75a2571911 100644 --- a/packages/server/src/services/FinancialStatements/BalanceSheet/BalanceSheetRepository.ts +++ b/packages/server/src/services/FinancialStatements/BalanceSheet/BalanceSheetRepository.ts @@ -3,7 +3,6 @@ import * as R from 'ramda'; import { Knex } from 'knex'; import { isEmpty } from 'lodash'; import { - IAccount, IAccountTransactionsGroupBy, IBalanceSheetQuery, ILedger, @@ -12,7 +11,6 @@ import { transformToMapBy } from 'utils'; import Ledger from '@/services/Accounting/Ledger'; import { BalanceSheetQuery } from './BalanceSheetQuery'; import { FinancialDatePeriods } from '../FinancialDatePeriods'; -import { ACCOUNT_PARENT_TYPE, ACCOUNT_TYPE } from '@/data/AccountTypes'; import { BalanceSheetRepositoryNetIncome } from './BalanceSheetRepositoryNetIncome'; @Service() @@ -40,6 +38,11 @@ export default class BalanceSheetRepository extends R.compose( */ public accounts: any; + /** + * @param {} + */ + public accountsGraph: any; + /** * */ @@ -163,6 +166,8 @@ export default class BalanceSheetRepository extends R.compose( */ public asyncInitialize = async () => { await this.initAccounts(); + await this.initAccountsGraph(); + await this.initAccountsTotalLedger(); // Date periods. @@ -204,6 +209,15 @@ export default class BalanceSheetRepository extends R.compose( this.accountsByParentType = transformToMapBy(accounts, 'accountParentType'); }; + /** + * Initialize accounts graph. + */ + public initAccountsGraph = async () => { + const { Account } = this.models; + + this.accountsGraph = Account.toDependencyGraph(this.accounts); + }; + // ---------------------------- // # Closing Total // ---------------------------- diff --git a/packages/server/src/services/FinancialStatements/ProfitLossSheet/ProfitLossSheet.ts b/packages/server/src/services/FinancialStatements/ProfitLossSheet/ProfitLossSheet.ts index 1392c7c38e..ba8d325421 100644 --- a/packages/server/src/services/FinancialStatements/ProfitLossSheet/ProfitLossSheet.ts +++ b/packages/server/src/services/FinancialStatements/ProfitLossSheet/ProfitLossSheet.ts @@ -24,6 +24,7 @@ import { ProfitLossSheetPreviousYear } from './ProfitLossSheetPreviousYear'; import { ProfitLossSheetPreviousPeriod } from './ProfitLossSheetPreviousPeriod'; import { FinancialDateRanges } from '../FinancialDateRanges'; import { ProfitLossSheetFilter } from './ProfitLossSheetFilter'; +import { flatToNestedArray } from '@/utils'; export default class ProfitLossSheet extends R.compose( ProfitLossSheetPreviousYear, @@ -82,14 +83,22 @@ export default class ProfitLossSheet extends R.compose( /** * Retrieve the sheet account node from the given account. - * @param {IAccount} account + * @param {IAccount} account * @returns {IProfitLossSheetAccountNode} */ private accountNodeMapper = ( account: IAccount ): IProfitLossSheetAccountNode => { + // Retrieves the children account ids of the given account id. + const childrenAccountIds = this.repository.accountsGraph.dependenciesOf( + account.id + ); + // Concat the children and the given account id. + const accountIds = R.uniq(R.append(account.id, childrenAccountIds)); + + // Retrieves the closing balance of the account included children accounts. const total = this.repository.totalAccountsLedger - .whereAccountId(account.id) + .whereAccountsIds(accountIds) .getClosingBalance(); return { @@ -126,18 +135,19 @@ export default class ProfitLossSheet extends R.compose( }; /** - * Retrieve report accounts nodes by the given accounts types. - * @param {string[]} types + * Retrieves report accounts nodes by the given accounts types. + * @param {string[]} types * @returns {IBalanceSheetAccountNode} */ private getAccountsNodesByTypes = ( types: string[] ): IProfitLossSheetAccountNode[] => { - return R.compose( - R.map(this.accountNodeCompose), - R.flatten, - R.map(this.repository.getAccountsByType) - )(types); + const accounts = this.repository.getAccountsByType(types); + const accountsTree = flatToNestedArray(accounts, { + id: 'id', + parentId: 'parentAccountId', + }); + return this.mapNodesDeep(accountsTree, this.accountNodeCompose); }; /** diff --git a/packages/server/src/services/FinancialStatements/ProfitLossSheet/ProfitLossSheetRepository.ts b/packages/server/src/services/FinancialStatements/ProfitLossSheet/ProfitLossSheetRepository.ts index def66c041e..f1bccba01f 100644 --- a/packages/server/src/services/FinancialStatements/ProfitLossSheet/ProfitLossSheetRepository.ts +++ b/packages/server/src/services/FinancialStatements/ProfitLossSheet/ProfitLossSheetRepository.ts @@ -1,4 +1,4 @@ -import { defaultTo } from 'lodash'; +import { castArray, defaultTo } from 'lodash'; import * as R from 'ramda'; import { Knex } from 'knex'; import { isEmpty } from 'lodash'; @@ -31,6 +31,11 @@ export class ProfitLossSheetRepository extends R.compose(FinancialDatePeriods)( */ public accounts: IAccount[]; + /** + * + */ + public accountsGraph: any; + /** * Transactions group type. * @param {IAccountTransactionsGroupBy} @@ -135,6 +140,8 @@ export class ProfitLossSheetRepository extends R.compose(FinancialDatePeriods)( */ public asyncInitialize = async () => { await this.initAccounts(); + await this.initAccountsGraph(); + await this.initAccountsTotalLedger(); // Date Periods. @@ -177,6 +184,15 @@ export class ProfitLossSheetRepository extends R.compose(FinancialDatePeriods)( this.accountsByType = transformToMapBy(accounts, 'accountType'); }; + /** + * Initialize accounts graph. + */ + private initAccountsGraph = async () => { + const { Account } = this.models; + + this.accountsGraph = Account.toDependencyGraph(this.accounts); + }; + // ---------------------------- // # Closing Total. // ---------------------------- @@ -337,7 +353,18 @@ export class ProfitLossSheetRepository extends R.compose(FinancialDatePeriods)( return Account.query(); }; - public getAccountsByType = (type: string) => { - return defaultTo(this.accountsByType.get(type), []); + /** + * + * @param type + * @returns + */ + public getAccountsByType = (type: string[] | string) => { + return R.compose( + R.flatten, + R.map((accountType) => + R.defaultTo([], this.accountsByType.get(accountType)) + ), + castArray + )(type); }; }