fix: Balance sheet and P/L nested accounts

This commit is contained in:
Ahmed Bouhuolia
2024-06-12 13:05:02 +02:00
parent 858f347fd4
commit cfd37f8894
4 changed files with 89 additions and 16 deletions

View File

@@ -20,6 +20,8 @@ import { BalanceSheetPercentage } from './BalanceSheetPercentage';
import { BalanceSheetSchema } from './BalanceSheetSchema'; import { BalanceSheetSchema } from './BalanceSheetSchema';
import { BalanceSheetBase } from './BalanceSheetBase'; import { BalanceSheetBase } from './BalanceSheetBase';
import { BalanceSheetQuery } from './BalanceSheetQuery'; import { BalanceSheetQuery } from './BalanceSheetQuery';
import { flatToNestedArray } from '@/utils';
import BalanceSheetRepository from './BalanceSheetRepository';
export const BalanceSheetAccounts = (Base: any) => export const BalanceSheetAccounts = (Base: any) =>
class extends R.compose( class extends R.compose(
@@ -56,6 +58,11 @@ export const BalanceSheetAccounts = (Base: any) =>
*/ */
readonly i18n: any; readonly i18n: any;
/**
* Balance sheet repository.
*/
readonly repository: BalanceSheetRepository;
/** /**
* Retrieve the accounts node of accounts types. * Retrieve the accounts node of accounts types.
* @param {string} accountsTypes * @param {string} accountsTypes
@@ -78,8 +85,12 @@ export const BalanceSheetAccounts = (Base: any) =>
private reportSchemaAccountNodeMapper = ( private reportSchemaAccountNodeMapper = (
account: IAccount account: IAccount
): IBalanceSheetAccountNode => { ): IBalanceSheetAccountNode => {
const childrenAccountsIds = this.repository.accountsGraph.dependenciesOf(
account.id
);
const accountIds = R.uniq(R.append(account.id, childrenAccountsIds));
const total = this.repository.totalAccountsLedger const total = this.repository.totalAccountsLedger
.whereAccountId(account.id) .whereAccountsIds(accountIds)
.getClosingBalance(); .getClosingBalance();
return { return {
@@ -128,8 +139,19 @@ export const BalanceSheetAccounts = (Base: any) =>
private getAccountsNodesByAccountTypes = ( private getAccountsNodesByAccountTypes = (
accountsTypes: string[] accountsTypes: string[]
): IBalanceSheetAccountNode[] => { ): IBalanceSheetAccountNode[] => {
// Retrieves accounts from the given defined node account types.
const accounts = this.getAccountsByAccountTypes(accountsTypes); 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
);
}; };
/** /**

View File

@@ -3,7 +3,6 @@ import * as R from 'ramda';
import { Knex } from 'knex'; import { Knex } from 'knex';
import { isEmpty } from 'lodash'; import { isEmpty } from 'lodash';
import { import {
IAccount,
IAccountTransactionsGroupBy, IAccountTransactionsGroupBy,
IBalanceSheetQuery, IBalanceSheetQuery,
ILedger, ILedger,
@@ -12,7 +11,6 @@ import { transformToMapBy } from 'utils';
import Ledger from '@/services/Accounting/Ledger'; import Ledger from '@/services/Accounting/Ledger';
import { BalanceSheetQuery } from './BalanceSheetQuery'; import { BalanceSheetQuery } from './BalanceSheetQuery';
import { FinancialDatePeriods } from '../FinancialDatePeriods'; import { FinancialDatePeriods } from '../FinancialDatePeriods';
import { ACCOUNT_PARENT_TYPE, ACCOUNT_TYPE } from '@/data/AccountTypes';
import { BalanceSheetRepositoryNetIncome } from './BalanceSheetRepositoryNetIncome'; import { BalanceSheetRepositoryNetIncome } from './BalanceSheetRepositoryNetIncome';
@Service() @Service()
@@ -40,6 +38,11 @@ export default class BalanceSheetRepository extends R.compose(
*/ */
public accounts: any; public accounts: any;
/**
* @param {}
*/
public accountsGraph: any;
/** /**
* *
*/ */
@@ -163,6 +166,8 @@ export default class BalanceSheetRepository extends R.compose(
*/ */
public asyncInitialize = async () => { public asyncInitialize = async () => {
await this.initAccounts(); await this.initAccounts();
await this.initAccountsGraph();
await this.initAccountsTotalLedger(); await this.initAccountsTotalLedger();
// Date periods. // Date periods.
@@ -204,6 +209,15 @@ export default class BalanceSheetRepository extends R.compose(
this.accountsByParentType = transformToMapBy(accounts, 'accountParentType'); this.accountsByParentType = transformToMapBy(accounts, 'accountParentType');
}; };
/**
* Initialize accounts graph.
*/
public initAccountsGraph = async () => {
const { Account } = this.models;
this.accountsGraph = Account.toDependencyGraph(this.accounts);
};
// ---------------------------- // ----------------------------
// # Closing Total // # Closing Total
// ---------------------------- // ----------------------------

View File

@@ -24,6 +24,7 @@ import { ProfitLossSheetPreviousYear } from './ProfitLossSheetPreviousYear';
import { ProfitLossSheetPreviousPeriod } from './ProfitLossSheetPreviousPeriod'; import { ProfitLossSheetPreviousPeriod } from './ProfitLossSheetPreviousPeriod';
import { FinancialDateRanges } from '../FinancialDateRanges'; import { FinancialDateRanges } from '../FinancialDateRanges';
import { ProfitLossSheetFilter } from './ProfitLossSheetFilter'; import { ProfitLossSheetFilter } from './ProfitLossSheetFilter';
import { flatToNestedArray } from '@/utils';
export default class ProfitLossSheet extends R.compose( export default class ProfitLossSheet extends R.compose(
ProfitLossSheetPreviousYear, ProfitLossSheetPreviousYear,
@@ -82,14 +83,22 @@ export default class ProfitLossSheet extends R.compose(
/** /**
* Retrieve the sheet account node from the given account. * Retrieve the sheet account node from the given account.
* @param {IAccount} account * @param {IAccount} account
* @returns {IProfitLossSheetAccountNode} * @returns {IProfitLossSheetAccountNode}
*/ */
private accountNodeMapper = ( private accountNodeMapper = (
account: IAccount account: IAccount
): IProfitLossSheetAccountNode => { ): 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 const total = this.repository.totalAccountsLedger
.whereAccountId(account.id) .whereAccountsIds(accountIds)
.getClosingBalance(); .getClosingBalance();
return { return {
@@ -126,18 +135,19 @@ export default class ProfitLossSheet extends R.compose(
}; };
/** /**
* Retrieve report accounts nodes by the given accounts types. * Retrieves report accounts nodes by the given accounts types.
* @param {string[]} types * @param {string[]} types
* @returns {IBalanceSheetAccountNode} * @returns {IBalanceSheetAccountNode}
*/ */
private getAccountsNodesByTypes = ( private getAccountsNodesByTypes = (
types: string[] types: string[]
): IProfitLossSheetAccountNode[] => { ): IProfitLossSheetAccountNode[] => {
return R.compose( const accounts = this.repository.getAccountsByType(types);
R.map(this.accountNodeCompose), const accountsTree = flatToNestedArray(accounts, {
R.flatten, id: 'id',
R.map(this.repository.getAccountsByType) parentId: 'parentAccountId',
)(types); });
return this.mapNodesDeep(accountsTree, this.accountNodeCompose);
}; };
/** /**

View File

@@ -1,4 +1,4 @@
import { defaultTo } from 'lodash'; import { castArray, defaultTo } from 'lodash';
import * as R from 'ramda'; import * as R from 'ramda';
import { Knex } from 'knex'; import { Knex } from 'knex';
import { isEmpty } from 'lodash'; import { isEmpty } from 'lodash';
@@ -31,6 +31,11 @@ export class ProfitLossSheetRepository extends R.compose(FinancialDatePeriods)(
*/ */
public accounts: IAccount[]; public accounts: IAccount[];
/**
*
*/
public accountsGraph: any;
/** /**
* Transactions group type. * Transactions group type.
* @param {IAccountTransactionsGroupBy} * @param {IAccountTransactionsGroupBy}
@@ -135,6 +140,8 @@ export class ProfitLossSheetRepository extends R.compose(FinancialDatePeriods)(
*/ */
public asyncInitialize = async () => { public asyncInitialize = async () => {
await this.initAccounts(); await this.initAccounts();
await this.initAccountsGraph();
await this.initAccountsTotalLedger(); await this.initAccountsTotalLedger();
// Date Periods. // Date Periods.
@@ -177,6 +184,15 @@ export class ProfitLossSheetRepository extends R.compose(FinancialDatePeriods)(
this.accountsByType = transformToMapBy(accounts, 'accountType'); this.accountsByType = transformToMapBy(accounts, 'accountType');
}; };
/**
* Initialize accounts graph.
*/
private initAccountsGraph = async () => {
const { Account } = this.models;
this.accountsGraph = Account.toDependencyGraph(this.accounts);
};
// ---------------------------- // ----------------------------
// # Closing Total. // # Closing Total.
// ---------------------------- // ----------------------------
@@ -337,7 +353,18 @@ export class ProfitLossSheetRepository extends R.compose(FinancialDatePeriods)(
return Account.query(); 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);
}; };
} }