mirror of
https://github.com/bigcapitalhq/bigcapital.git
synced 2026-02-17 13:20:31 +00:00
264 lines
7.2 KiB
TypeScript
264 lines
7.2 KiB
TypeScript
import { sumBy } from 'lodash';
|
|
import * as R from 'ramda';
|
|
import {
|
|
ITrialBalanceSheetQuery,
|
|
ITrialBalanceAccount,
|
|
IAccount,
|
|
ITrialBalanceTotal,
|
|
ITrialBalanceSheetData,
|
|
IAccountType,
|
|
} from '@/interfaces';
|
|
import FinancialSheet from '../FinancialSheet';
|
|
import { allPassedConditionsPass, flatToNestedArray } from 'utils';
|
|
import { TrialBalanceSheetRepository } from './TrialBalanceSheetRepository';
|
|
|
|
export default class TrialBalanceSheet extends FinancialSheet {
|
|
/**
|
|
* Trial balance sheet query.
|
|
* @param {ITrialBalanceSheetQuery} query
|
|
*/
|
|
private query: ITrialBalanceSheetQuery;
|
|
|
|
/**
|
|
* Trial balance sheet repository.
|
|
* @param {TrialBalanceSheetRepository}
|
|
*/
|
|
private repository: TrialBalanceSheetRepository;
|
|
|
|
/**
|
|
* Organization base currency.
|
|
* @param {string}
|
|
*/
|
|
private baseCurrency: string;
|
|
|
|
/**
|
|
* Constructor method.
|
|
* @param {number} tenantId
|
|
* @param {ITrialBalanceSheetQuery} query
|
|
* @param {IAccount[]} accounts
|
|
* @param journalFinancial
|
|
*/
|
|
constructor(
|
|
tenantId: number,
|
|
query: ITrialBalanceSheetQuery,
|
|
repository: TrialBalanceSheetRepository,
|
|
baseCurrency: string
|
|
) {
|
|
super();
|
|
|
|
this.tenantId = tenantId;
|
|
this.query = query;
|
|
this.repository = repository;
|
|
this.numberFormat = this.query.numberFormat;
|
|
this.baseCurrency = baseCurrency;
|
|
}
|
|
|
|
/**
|
|
* Retrieves the closing credit of the given account.
|
|
* @param {number} accountId
|
|
* @returns {number}
|
|
*/
|
|
public getClosingAccountCredit(accountId: number) {
|
|
const depsAccountsIds =
|
|
this.repository.accountsDepGraph.dependenciesOf(accountId);
|
|
|
|
return this.repository.totalAccountsLedger
|
|
.whereAccountsIds([accountId, ...depsAccountsIds])
|
|
.getClosingCredit();
|
|
}
|
|
|
|
/**
|
|
* Retrieves the closing debit of the given account.
|
|
* @param {number} accountId
|
|
* @returns {number}
|
|
*/
|
|
public getClosingAccountDebit(accountId: number) {
|
|
const depsAccountsIds =
|
|
this.repository.accountsDepGraph.dependenciesOf(accountId);
|
|
|
|
return this.repository.totalAccountsLedger
|
|
.whereAccountsIds([accountId, ...depsAccountsIds])
|
|
.getClosingDebit();
|
|
}
|
|
|
|
/**
|
|
* Retrieves the closing total of the given account.
|
|
* @param {number} accountId
|
|
* @returns {number}
|
|
*/
|
|
public getClosingAccountTotal(accountId: number) {
|
|
const credit = this.getClosingAccountCredit(accountId);
|
|
const debit = this.getClosingAccountDebit(accountId);
|
|
|
|
return debit - credit;
|
|
}
|
|
|
|
/**
|
|
* Account mapper.
|
|
* @param {IAccount} account
|
|
* @return {ITrialBalanceAccount}
|
|
*/
|
|
private accountTransformer = (
|
|
account: IAccount & { type: IAccountType }
|
|
): ITrialBalanceAccount => {
|
|
const debit = this.getClosingAccountDebit(account.id);
|
|
const credit = this.getClosingAccountCredit(account.id);
|
|
const balance = this.getClosingAccountTotal(account.id);
|
|
|
|
return {
|
|
id: account.id,
|
|
parentAccountId: account.parentAccountId,
|
|
name: account.name,
|
|
formattedName: account.code
|
|
? `${account.name} - ${account.code}`
|
|
: `${account.name}`,
|
|
code: account.code,
|
|
accountNormal: account.accountNormal,
|
|
|
|
credit,
|
|
debit,
|
|
balance,
|
|
currencyCode: this.baseCurrency,
|
|
|
|
formattedCredit: this.formatNumber(credit),
|
|
formattedDebit: this.formatNumber(debit),
|
|
formattedBalance: this.formatNumber(balance),
|
|
};
|
|
};
|
|
|
|
/**
|
|
* Filters trial balance sheet accounts nodes based on the given report query.
|
|
* @param {ITrialBalanceAccount} accountNode
|
|
* @returns {boolean}
|
|
*/
|
|
private accountFilter = (accountNode: ITrialBalanceAccount): boolean => {
|
|
const { noneTransactions, noneZero, onlyActive } = this.query;
|
|
|
|
// Conditions pair filter detarminer.
|
|
const condsPairFilters = [
|
|
[noneTransactions, this.filterNoneTransactions],
|
|
[noneZero, this.filterNoneZero],
|
|
[onlyActive, this.filterActiveOnly],
|
|
];
|
|
return allPassedConditionsPass(condsPairFilters)(accountNode);
|
|
};
|
|
|
|
/**
|
|
* Fitlers the accounts nodes.
|
|
* @param {ITrialBalanceAccount[]} accountsNodes
|
|
* @returns {ITrialBalanceAccount[]}
|
|
*/
|
|
private accountsFilter = (
|
|
accountsNodes: ITrialBalanceAccount[]
|
|
): ITrialBalanceAccount[] => {
|
|
return accountsNodes.filter(this.accountFilter);
|
|
};
|
|
|
|
/**
|
|
* Mappes the given account object to trial balance account node.
|
|
* @param {IAccount[]} accountsNodes
|
|
* @returns {ITrialBalanceAccount[]}
|
|
*/
|
|
private accountsMapper = (
|
|
accountsNodes: IAccount[]
|
|
): ITrialBalanceAccount[] => {
|
|
return accountsNodes.map(this.accountTransformer);
|
|
};
|
|
|
|
/**
|
|
* Detarmines whether the given account node is not none transactions.
|
|
* @param {ITrialBalanceAccount} accountNode
|
|
* @returns {boolean}
|
|
*/
|
|
private filterNoneTransactions = (
|
|
accountNode: ITrialBalanceAccount
|
|
): boolean => {
|
|
return false === this.repository.totalAccountsLedger.isEmpty();
|
|
};
|
|
|
|
/**
|
|
* Detarmines whether the given account none zero.
|
|
* @param {ITrialBalanceAccount} accountNode
|
|
* @returns {boolean}
|
|
*/
|
|
private filterNoneZero = (accountNode: ITrialBalanceAccount): boolean => {
|
|
return accountNode.balance !== 0;
|
|
};
|
|
|
|
/**
|
|
* Detarmines whether the given account is active.
|
|
* @param {ITrialBalanceAccount} accountNode
|
|
* @returns {boolean}
|
|
*/
|
|
private filterActiveOnly = (accountNode: ITrialBalanceAccount): boolean => {
|
|
return accountNode.credit !== 0 || accountNode.debit !== 0;
|
|
};
|
|
|
|
/**
|
|
* Transformes the flatten nodes to nested nodes.
|
|
* @param {ITrialBalanceAccount[]} flattenAccounts
|
|
* @returns {ITrialBalanceAccount[]}
|
|
*/
|
|
private nestedAccountsNode = (
|
|
flattenAccounts: ITrialBalanceAccount[]
|
|
): ITrialBalanceAccount[] => {
|
|
return flatToNestedArray(flattenAccounts, {
|
|
id: 'id',
|
|
parentId: 'parentAccountId',
|
|
});
|
|
};
|
|
|
|
/**
|
|
* Retrieve trial balance total section.
|
|
* @param {ITrialBalanceAccount[]} accountsBalances
|
|
* @return {ITrialBalanceTotal}
|
|
*/
|
|
private tatalSection(
|
|
accountsBalances: ITrialBalanceAccount[]
|
|
): ITrialBalanceTotal {
|
|
const credit = sumBy(accountsBalances, 'credit');
|
|
const debit = sumBy(accountsBalances, 'debit');
|
|
const balance = sumBy(accountsBalances, 'balance');
|
|
const currencyCode = this.baseCurrency;
|
|
|
|
return {
|
|
credit,
|
|
debit,
|
|
balance,
|
|
currencyCode,
|
|
formattedCredit: this.formatTotalNumber(credit),
|
|
formattedDebit: this.formatTotalNumber(debit),
|
|
formattedBalance: this.formatTotalNumber(balance),
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Retrieve accounts section of trial balance report.
|
|
* @param {IAccount[]} accounts
|
|
* @returns {ITrialBalanceAccount[]}
|
|
*/
|
|
private accountsSection(accounts: IAccount & { type: IAccountType }[]) {
|
|
return R.compose(
|
|
this.nestedAccountsNode,
|
|
this.accountsFilter,
|
|
this.accountsMapper
|
|
)(accounts);
|
|
}
|
|
|
|
/**
|
|
* Retrieve trial balance sheet statement data.
|
|
* Note: Retruns null in case there is no transactions between the given date periods.
|
|
*
|
|
* @return {ITrialBalanceSheetData}
|
|
*/
|
|
public reportData(): ITrialBalanceSheetData {
|
|
// Retrieve accounts nodes.
|
|
const accounts = this.accountsSection(this.repository.accounts);
|
|
|
|
// Retrieve account node.
|
|
const total = this.tatalSection(accounts);
|
|
|
|
return { accounts, total };
|
|
}
|
|
}
|