fix: Trial balance sheet adjusted balance (#273)

This commit is contained in:
Ahmed Bouhuolia
2023-10-25 13:18:13 +02:00
committed by GitHub
parent 017908600e
commit 2c5537efad
16 changed files with 509 additions and 163 deletions

View File

@@ -16,7 +16,7 @@ export default class TrialBalanceSheetController extends BaseFinancialReportCont
/** /**
* Router constructor. * Router constructor.
*/ */
router() { public router() {
const router = Router(); const router = Router();
router.get( router.get(
@@ -36,7 +36,7 @@ export default class TrialBalanceSheetController extends BaseFinancialReportCont
* Validation schema. * Validation schema.
* @return {ValidationChain[]} * @return {ValidationChain[]}
*/ */
get trialBalanceSheetValidationSchema(): ValidationChain[] { private get trialBalanceSheetValidationSchema(): ValidationChain[] {
return [ return [
...this.sheetNumberFormatValidationSchema, ...this.sheetNumberFormatValidationSchema,
query('basis').optional(), query('basis').optional(),
@@ -59,28 +59,37 @@ export default class TrialBalanceSheetController extends BaseFinancialReportCont
/** /**
* Retrieve the trial balance sheet. * Retrieve the trial balance sheet.
*/ */
public async trialBalanceSheet( private async trialBalanceSheet(
req: Request, req: Request,
res: Response, res: Response,
next: NextFunction next: NextFunction
) { ) {
const { tenantId, settings } = req; const { tenantId } = req;
let filter = this.matchedQueryData(req); let filter = this.matchedQueryData(req);
filter = { filter = {
...filter, ...filter,
accountsIds: castArray(filter.accountsIds), accountsIds: castArray(filter.accountsIds),
}; };
try { try {
const { data, query, meta } = const accept = this.accepts(req);
await this.trialBalanceSheetService.trialBalanceSheet(tenantId, filter); const acceptType = accept.types(['json', 'application/json+table']);
return res.status(200).send({ if (acceptType === 'application/json+table') {
data: this.transfromToResponse(data), const { table, meta, query } =
query: this.transfromToResponse(query), await this.trialBalanceSheetService.trialBalanceSheetTable(
meta: this.transfromToResponse(meta), tenantId,
}); filter
);
return res.status(200).send({ table, meta, query });
} else {
const { data, query, meta } =
await this.trialBalanceSheetService.trialBalanceSheet(
tenantId,
filter
);
return res.status(200).send({ data, query, meta });
}
} catch (error) { } catch (error) {
next(error); next(error);
} }

View File

@@ -16,6 +16,8 @@ export interface ILedger {
getClosingBalance(): number; getClosingBalance(): number;
getForeignClosingBalance(): number; getForeignClosingBalance(): number;
getClosingDebit(): number;
getClosingCredit(): number;
getContactsIds(): number[]; getContactsIds(): number[];
getAccountsIds(): number[]; getAccountsIds(): number[];

View File

@@ -33,6 +33,7 @@ export interface ITrialBalanceAccount extends ITrialBalanceTotal {
id: number; id: number;
parentAccountId: number; parentAccountId: number;
name: string; name: string;
formattedName: string;
code: string; code: string;
accountNormal: string; accountNormal: string;
} }

View File

@@ -1,5 +1,5 @@
import moment from 'moment'; import moment from 'moment';
import { defaultTo, uniqBy } from 'lodash'; import { defaultTo, sumBy, uniqBy } from 'lodash';
import { IAccountTransaction, ILedger, ILedgerEntry } from '@/interfaces'; import { IAccountTransaction, ILedger, ILedgerEntry } from '@/interfaces';
export default class Ledger implements ILedger { export default class Ledger implements ILedger {
@@ -49,6 +49,15 @@ export default class Ledger implements ILedger {
return this.filter((entry) => entry.accountId === accountId); return this.filter((entry) => entry.accountId === accountId);
} }
/**
* Filters entries by the given accounts ids then returns a new ledger.
* @param {number[]} accountsIds - Accounts ids.
* @returns {ILedger}
*/
public whereAccountsIds(accountsIds: number[]): ILedger {
return this.filter((entry) => accountsIds.indexOf(entry.accountId) !== -1);
}
/** /**
* Filters entries that before or same the given date and returns a new ledger. * Filters entries that before or same the given date and returns a new ledger.
* @param {Date|string} fromDate * @param {Date|string} fromDate
@@ -130,6 +139,22 @@ export default class Ledger implements ILedger {
return closingBalance; return closingBalance;
} }
/**
* Retrieves the closing credit of the entries.
* @returns {number}
*/
public getClosingCredit(): number {
return sumBy(this.entries, 'credit');
}
/**
* Retrieves the closing debit of the entries.
* @returns {number}
*/
public getClosingDebit(): number {
return sumBy(this.entries, 'debit');
}
/** /**
* Retrieve the closing balance of the entries. * Retrieve the closing balance of the entries.
* @returns {number} * @returns {number}

View File

@@ -10,13 +10,26 @@ import {
} from '@/interfaces'; } from '@/interfaces';
import FinancialSheet from '../FinancialSheet'; import FinancialSheet from '../FinancialSheet';
import { allPassedConditionsPass, flatToNestedArray } from 'utils'; import { allPassedConditionsPass, flatToNestedArray } from 'utils';
import { TrialBalanceSheetRepository } from './TrialBalanceSheetRepository';
export default class TrialBalanceSheet extends FinancialSheet { export default class TrialBalanceSheet extends FinancialSheet {
tenantId: number; /**
query: ITrialBalanceSheetQuery; * Trial balance sheet query.
accounts: IAccount & { type: IAccountType }[]; * @param {ITrialBalanceSheetQuery} query
journalFinancial: any; */
baseCurrency: string; private query: ITrialBalanceSheetQuery;
/**
* Trial balance sheet repository.
* @param {TrialBalanceSheetRepository}
*/
private repository: TrialBalanceSheetRepository;
/**
* Organization base currency.
* @param {string}
*/
private baseCurrency: string;
/** /**
* Constructor method. * Constructor method.
@@ -28,20 +41,58 @@ export default class TrialBalanceSheet extends FinancialSheet {
constructor( constructor(
tenantId: number, tenantId: number,
query: ITrialBalanceSheetQuery, query: ITrialBalanceSheetQuery,
accounts: IAccount & { type: IAccountType }[], repository: TrialBalanceSheetRepository,
journalFinancial: any,
baseCurrency: string baseCurrency: string
) { ) {
super(); super();
this.tenantId = tenantId; this.tenantId = tenantId;
this.query = query; this.query = query;
this.accounts = accounts; this.repository = repository;
this.journalFinancial = journalFinancial;
this.numberFormat = this.query.numberFormat; this.numberFormat = this.query.numberFormat;
this.baseCurrency = baseCurrency; 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. * Account mapper.
* @param {IAccount} account * @param {IAccount} account
@@ -50,23 +101,28 @@ export default class TrialBalanceSheet extends FinancialSheet {
private accountTransformer = ( private accountTransformer = (
account: IAccount & { type: IAccountType } account: IAccount & { type: IAccountType }
): ITrialBalanceAccount => { ): ITrialBalanceAccount => {
const trial = this.journalFinancial.getTrialBalanceWithDepands(account.id); const debit = this.getClosingAccountDebit(account.id);
const credit = this.getClosingAccountCredit(account.id);
const balance = this.getClosingAccountTotal(account.id);
return { return {
id: account.id, id: account.id,
parentAccountId: account.parentAccountId, parentAccountId: account.parentAccountId,
name: account.name, name: account.name,
formattedName: account.code
? `${account.name} - ${account.code}`
: `${account.name}`,
code: account.code, code: account.code,
accountNormal: account.accountNormal, accountNormal: account.accountNormal,
credit: trial.credit, credit,
debit: trial.debit, debit,
balance: trial.balance, balance,
currencyCode: this.baseCurrency, currencyCode: this.baseCurrency,
formattedCredit: this.formatNumber(trial.credit), formattedCredit: this.formatNumber(credit),
formattedDebit: this.formatNumber(trial.debit), formattedDebit: this.formatNumber(debit),
formattedBalance: this.formatNumber(trial.balance), formattedBalance: this.formatNumber(balance),
}; };
}; };
@@ -117,10 +173,7 @@ export default class TrialBalanceSheet extends FinancialSheet {
private filterNoneTransactions = ( private filterNoneTransactions = (
accountNode: ITrialBalanceAccount accountNode: ITrialBalanceAccount
): boolean => { ): boolean => {
const entries = this.journalFinancial.getAccountEntriesWithDepents( return false === this.repository.totalAccountsLedger.isEmpty();
accountNode.id
);
return entries.length > 0;
}; };
/** /**
@@ -200,11 +253,11 @@ export default class TrialBalanceSheet extends FinancialSheet {
*/ */
public reportData(): ITrialBalanceSheetData { public reportData(): ITrialBalanceSheetData {
// Don't return noting if the journal has no transactions. // Don't return noting if the journal has no transactions.
if (this.journalFinancial.isEmpty()) { if (this.repository.totalAccountsLedger.isEmpty()) {
return null; return null;
} }
// Retrieve accounts nodes. // Retrieve accounts nodes.
const accounts = this.accountsSection(this.accounts); const accounts = this.accountsSection(this.repository.accounts);
// Retrieve account node. // Retrieve account node.
const total = this.tatalSection(accounts); const total = this.tatalSection(accounts);

View File

@@ -0,0 +1,105 @@
import { ITrialBalanceSheetQuery } from '@/interfaces';
import Ledger from '@/services/Accounting/Ledger';
import { Knex } from 'knex';
import { isEmpty } from 'lodash';
import { Service } from 'typedi';
@Service()
export class TrialBalanceSheetRepository {
private query: ITrialBalanceSheetQuery;
private models: any;
public accounts: any;
public accountsDepGraph;
/**
* Total closing accounts ledger.
* @param {Ledger}
*/
public totalAccountsLedger: Ledger;
/**
* Constructor method.
* @param {number} tenantId
* @param {IBalanceSheetQuery} query
*/
constructor(models: any, repos: any, query: ITrialBalanceSheetQuery) {
this.query = query;
this.repos = repos;
this.models = models;
}
/**
* Async initialize.
* @returns {Promise<void>}
*/
public asyncInitialize = async () => {
await this.initAccounts();
await this.initAccountsClosingTotalLedger();
};
// ----------------------------
// # Accounts
// ----------------------------
/**
* Initialize accounts.
* @returns {Promise<void>}
*/
public initAccounts = async () => {
const accounts = await this.getAccounts();
const accountsDepGraph =
await this.repos.accountRepository.getDependencyGraph();
this.accountsDepGraph = accountsDepGraph;
this.accounts = accounts;
};
/**
* Initialize all accounts closing total ledger.
* @return {Promise<void>}
*/
public initAccountsClosingTotalLedger = async (): Promise<void> => {
const totalByAccounts = await this.closingAccountsTotal(this.query.toDate);
this.totalAccountsLedger = Ledger.fromTransactions(totalByAccounts);
};
/**
* Retrieve accounts of the report.
* @return {Promise<IAccount[]>}
*/
private getAccounts = () => {
const { Account } = this.models;
return Account.query();
};
/**
* Retrieve the opening balance transactions of the report.
* @param {Date|string} openingDate -
*/
public closingAccountsTotal = async (openingDate: Date | string) => {
const { AccountTransaction } = this.models;
return AccountTransaction.query().onBuild((query) => {
query.sum('credit as credit');
query.sum('debit as debit');
query.groupBy('accountId');
query.select(['accountId']);
query.modify('filterDateRange', null, openingDate);
query.withGraphFetched('account');
this.commonFilterBranchesQuery(query);
});
};
/**
* Common branches filter query.
* @param {Knex.QueryBuilder} query
*/
private commonFilterBranchesQuery = (query: Knex.QueryBuilder) => {
if (!isEmpty(this.query.branchesIds)) {
query.modify('filterByBranches', this.query.branchesIds);
}
};
}

View File

@@ -2,12 +2,18 @@ import { Service, Inject } from 'typedi';
import moment from 'moment'; import moment from 'moment';
import TenancyService from '@/services/Tenancy/TenancyService'; import TenancyService from '@/services/Tenancy/TenancyService';
import Journal from '@/services/Accounting/JournalPoster'; import Journal from '@/services/Accounting/JournalPoster';
import { ITrialBalanceSheetMeta, ITrialBalanceSheetQuery, ITrialBalanceStatement } from '@/interfaces'; import {
ITrialBalanceSheetMeta,
ITrialBalanceSheetQuery,
ITrialBalanceStatement,
} from '@/interfaces';
import TrialBalanceSheet from './TrialBalanceSheet'; import TrialBalanceSheet from './TrialBalanceSheet';
import FinancialSheet from '../FinancialSheet'; import FinancialSheet from '../FinancialSheet';
import InventoryService from '@/services/Inventory/Inventory'; import InventoryService from '@/services/Inventory/Inventory';
import { parseBoolean } from 'utils'; import { parseBoolean } from 'utils';
import { Tenant } from '@/system/models'; import { Tenant } from '@/system/models';
import { TrialBalanceSheetRepository } from './TrialBalanceSheetRepository';
import { TrialBalanceSheetTable } from './TrialBalanceSheetTable';
@Service() @Service()
export default class TrialBalanceSheetService extends FinancialSheet { export default class TrialBalanceSheetService extends FinancialSheet {
@@ -51,9 +57,8 @@ export default class TrialBalanceSheetService extends FinancialSheet {
reportMetadata(tenantId: number): ITrialBalanceSheetMeta { reportMetadata(tenantId: number): ITrialBalanceSheetMeta {
const settings = this.tenancy.settings(tenantId); const settings = this.tenancy.settings(tenantId);
const isCostComputeRunning = this.inventoryService.isItemsCostComputeRunning( const isCostComputeRunning =
tenantId this.inventoryService.isItemsCostComputeRunning(tenantId);
);
const organizationName = settings.get({ const organizationName = settings.get({
group: 'organization', group: 'organization',
key: 'name', key: 'name',
@@ -72,10 +77,8 @@ export default class TrialBalanceSheetService extends FinancialSheet {
/** /**
* Retrieve trial balance sheet statement. * Retrieve trial balance sheet statement.
* -------------
* @param {number} tenantId * @param {number} tenantId
* @param {IBalanceSheetQuery} query * @param {IBalanceSheetQuery} query
*
* @return {IBalanceSheetStatement} * @return {IBalanceSheetStatement}
*/ */
public async trialBalanceSheet( public async trialBalanceSheet(
@@ -86,43 +89,27 @@ export default class TrialBalanceSheetService extends FinancialSheet {
...this.defaultQuery, ...this.defaultQuery,
...query, ...query,
}; };
const {
accountRepository,
transactionsRepository,
} = this.tenancy.repositories(tenantId);
const tenant = await Tenant.query() const tenant = await Tenant.query()
.findById(tenantId) .findById(tenantId)
.withGraphFetched('metadata'); .withGraphFetched('metadata');
this.logger.info('[trial_balance_sheet] trying to calcualte the report.', { const models = this.tenancy.models(tenantId);
tenantId, const repos = this.tenancy.repositories(tenantId);
filter,
});
// Retrieve all accounts on the storage.
const accounts = await accountRepository.all();
const accountsGraph = await accountRepository.getDependencyGraph();
// Retrieve all journal transactions based on the given query. const trialBalanceSheetRepos = new TrialBalanceSheetRepository(
const transactions = await transactionsRepository.journal({ models,
fromDate: query.fromDate, repos,
toDate: query.toDate, filter
sumationCreditDebit: true,
branchesIds: query.branchesIds
});
// Transform transactions array to journal collection.
const transactionsJournal = Journal.fromTransactions(
transactions,
tenantId,
accountsGraph
); );
await trialBalanceSheetRepos.asyncInitialize();
// Trial balance report instance. // Trial balance report instance.
const trialBalanceInstance = new TrialBalanceSheet( const trialBalanceInstance = new TrialBalanceSheet(
tenantId, tenantId,
filter, filter,
accounts, trialBalanceSheetRepos,
transactionsJournal, tenant.metadata.baseCurrency
tenant.metadata.baseCurrency,
); );
// Trial balance sheet data. // Trial balance sheet data.
const trialBalanceSheetData = trialBalanceInstance.reportData(); const trialBalanceSheetData = trialBalanceInstance.reportData();
@@ -133,4 +120,27 @@ export default class TrialBalanceSheetService extends FinancialSheet {
meta: this.reportMetadata(tenantId), meta: this.reportMetadata(tenantId),
}; };
} }
/**
* Retrieves the trial balance sheet table.
* @param {number} tenantId
* @param {ITrialBalanceSheetQuery} query
* @returns {Promise<any>}
*/
public async trialBalanceSheetTable(
tenantId: number,
query: ITrialBalanceSheetQuery
) {
const trialBalance = await this.trialBalanceSheet(tenantId, query);
const table = new TrialBalanceSheetTable(trialBalance.data, query, {});
return {
table: {
columns: table.tableColumns(),
rows: table.tableRows(),
},
meta: trialBalance.meta,
query: trialBalance.query,
};
}
} }

View File

@@ -0,0 +1,146 @@
import * as R from 'ramda';
import FinancialSheet from '../FinancialSheet';
import { FinancialTable } from '../FinancialTable';
import {
IBalanceSheetStatementData,
ITableColumn,
ITableColumnAccessor,
ITableRow,
ITrialBalanceAccount,
ITrialBalanceSheetData,
ITrialBalanceSheetQuery,
ITrialBalanceTotal,
} from '@/interfaces';
import { tableRowMapper } from '@/utils';
import { IROW_TYPE } from '../BalanceSheet/constants';
import { FinancialSheetStructure } from '../FinancialSheetStructure';
export class TrialBalanceSheetTable extends R.compose(
FinancialTable,
FinancialSheetStructure
)(FinancialSheet) {
/**
* @param {ITrialBalanceSheetData}
*/
public data: ITrialBalanceSheetData;
/**
* Balance sheet query.
* @param {ITrialBalanceSheetQuery}
*/
public query: ITrialBalanceSheetQuery;
/**
* Constructor method.
* @param {IBalanceSheetStatementData} reportData -
* @param {ITrialBalanceSheetQuery} query -
*/
constructor(
data: ITrialBalanceSheetData,
query: ITrialBalanceSheetQuery,
i18n: any
) {
super();
this.data = data;
this.query = query;
this.i18n = i18n;
}
/**
* Retrieve the common columns for all report nodes.
* @param {ITableColumnAccessor[]}
*/
private commonColumnsAccessors = (): ITableColumnAccessor[] => {
return [
{ key: 'account', accessor: 'formattedName' },
{ key: 'debit', accessor: 'formattedDebit' },
{ key: 'credit', accessor: 'formattedCredit' },
{ key: 'total', accessor: 'formattedBalance' },
];
};
/**
* Maps the account node to table row.
* @param {ITrialBalanceAccount} node -
* @returns {ITableRow}
*/
private accountNodeTableRowsMapper = (
node: ITrialBalanceAccount
): ITableRow => {
const columns = this.commonColumnsAccessors();
const meta = {
rowTypes: [IROW_TYPE.ACCOUNT],
id: node.id,
};
return tableRowMapper(node, columns, meta);
};
/**
* Maps the total node to table row.
* @param {ITrialBalanceTotal} node -
* @returns {ITableRow}
*/
private totalNodeTableRowsMapper = (node: ITrialBalanceTotal): ITableRow => {
const columns = this.commonColumnsAccessors();
const meta = {
rowTypes: [IROW_TYPE.TOTAL],
id: node.id,
};
return tableRowMapper(node, columns, meta);
};
/**
* Mappes the given report sections to table rows.
* @param {IBalanceSheetDataNode[]} nodes -
* @return {ITableRow}
*/
private accountsToTableRowsMap = (
nodes: ITrialBalanceAccount[]
): ITableRow[] => {
return this.mapNodesDeep(nodes, this.accountNodeTableRowsMapper);
};
/**
* Retrieves the accounts table rows of the given report data.
* @returns {ITableRow[]}
*/
private accountsTableRows = (): ITableRow[] => {
return this.accountsToTableRowsMap(this.data.accounts);
};
/**
* Maps the given total node to table row.
* @returns {ITableRow}
*/
private totalTableRow = (): ITableRow => {
return this.totalNodeTableRowsMapper(this.data.total);
};
/**
* Retrieves the table rows.
* @returns {ITableRow[]}
*/
public tableRows = (): ITableRow[] => {
return R.compose(
R.append(this.totalTableRow()),
R.concat(this.accountsTableRows())
)([]);
};
/**
* Retrrieves the table columns.
* @returns {ITableColumn[]}
*/
public tableColumns = (): ITableColumn[] => {
return R.compose(
this.tableColumnsCellIndexing,
R.concat([
{ key: 'account_name', label: 'Account' },
{ key: 'debit', label: 'Debit' },
{ key: 'credit', label: 'Credit' },
{ key: 'total', label: 'Total' },
])
)([]);
};
}

View File

@@ -0,0 +1,5 @@
export enum IROW_TYPE {
ACCOUNT = 'ACCOUNT',
TOTAL = 'TOTAL',
}

View File

@@ -15,7 +15,6 @@ import {
} from './components'; } from './components';
import withTrialBalanceActions from './withTrialBalanceActions'; import withTrialBalanceActions from './withTrialBalanceActions';
import { compose } from '@/utils'; import { compose } from '@/utils';
/** /**

View File

@@ -8,8 +8,7 @@ import { tableRowTypesToClassnames } from '@/utils';
import { ReportDataTable, FinancialSheet } from '@/components'; import { ReportDataTable, FinancialSheet } from '@/components';
import { useTrialBalanceSheetContext } from './TrialBalanceProvider'; import { useTrialBalanceSheetContext } from './TrialBalanceProvider';
import { useTrialBalanceTableColumns } from './components'; import { useTrialBalanceSheetTableColumns } from './hooks';
/** /**
* Trial Balance sheet data table. * Trial Balance sheet data table.
@@ -17,12 +16,12 @@ import { useTrialBalanceTableColumns } from './components';
export default function TrialBalanceSheetTable({ companyName }) { export default function TrialBalanceSheetTable({ companyName }) {
// Trial balance sheet context. // Trial balance sheet context.
const { const {
trialBalanceSheet: { tableRows, query }, trialBalanceSheet: { table, query },
isLoading, isLoading,
} = useTrialBalanceSheetContext(); } = useTrialBalanceSheetContext();
// Trial balance sheet table columns. // Trial balance sheet table columns.
const columns = useTrialBalanceTableColumns(); const columns = useTrialBalanceSheetTableColumns();
return ( return (
<FinancialSheet <FinancialSheet
@@ -36,7 +35,7 @@ export default function TrialBalanceSheetTable({ companyName }) {
> >
<TrialBalanceDataTable <TrialBalanceDataTable
columns={columns} columns={columns}
data={tableRows} data={table.rows}
expandable={true} expandable={true}
expandToggleColumn={1} expandToggleColumn={1}
expandColumnSpace={1} expandColumnSpace={1}
@@ -59,7 +58,7 @@ const TrialBalanceDataTable = styled(ReportDataTable)`
.balance.td { .balance.td {
border-top-color: #000; border-top-color: #000;
} }
.tr.row_type--total .td { .tr.row_type--TOTAL .td {
border-top: 1px solid #bbb; border-top: 1px solid #bbb;
font-weight: 500; font-weight: 500;
border-bottom: 3px double #000; border-bottom: 3px double #000;

View File

@@ -1,88 +1,10 @@
// @ts-nocheck // @ts-nocheck
import React from 'react';
import intl from 'react-intl-universal';
import { Button } from '@blueprintjs/core'; import { Button } from '@blueprintjs/core';
import { Align } from '@/constants';
import { getColumnWidth } from '@/utils';
import { CellTextSpan } from '@/components/Datatable/Cells';
import { If, Icon, FormattedMessage as T } from '@/components'; import { If, Icon, FormattedMessage as T } from '@/components';
import { useTrialBalanceSheetContext } from './TrialBalanceProvider'; import { useTrialBalanceSheetContext } from './TrialBalanceProvider';
import { FinancialComputeAlert } from '../FinancialReportPage'; import { FinancialComputeAlert } from '../FinancialReportPage';
import FinancialLoadingBar from '../FinancialLoadingBar'; import FinancialLoadingBar from '../FinancialLoadingBar';
/**
* Retrieves the credit column.
*/
const getCreditColumn = (data) => {
const width = getColumnWidth(data, `credit`, { minWidth: 140 });
return {
Header: intl.get('credit'),
Cell: CellTextSpan,
accessor: 'formatted_credit',
className: 'credit',
width,
textOverview: true,
align: Align.Right,
};
};
/**
* Retrieves the debit column.
*/
const getDebitColumn = (data) => {
return {
Header: intl.get('debit'),
Cell: CellTextSpan,
accessor: 'formatted_debit',
width: getColumnWidth(data, `debit`, { minWidth: 140 }),
textOverview: true,
align: Align.Right,
};
};
/**
* Retrieves the balance column.
*/
const getBalanceColumn = (data) => {
return {
Header: intl.get('balance'),
Cell: CellTextSpan,
accessor: 'formatted_balance',
className: 'balance',
width: getColumnWidth(data, `balance`, { minWidth: 140 }),
textOverview: true,
align: Align.Right,
};
};
/**
* Retrieve trial balance sheet table columns.
*/
export const useTrialBalanceTableColumns = () => {
// Trial balance sheet context.
const {
trialBalanceSheet: { tableRows },
} = useTrialBalanceSheetContext();
return React.useMemo(
() => [
{
Header: intl.get('account_name'),
accessor: (row) => (row.code ? `${row.name} - ${row.code}` : row.name),
className: 'name',
width: 350,
textOverview: true,
},
getCreditColumn(tableRows),
getDebitColumn(tableRows),
getBalanceColumn(tableRows),
],
[tableRows],
);
};
/** /**
* Trial balance sheet progress loading bar. * Trial balance sheet progress loading bar.
*/ */
@@ -101,7 +23,7 @@ export function TrialBalanceSheetLoadingBar() {
*/ */
export function TrialBalanceSheetAlerts() { export function TrialBalanceSheetAlerts() {
const { const {
trialBalanceSheet: { meta }, trialBalanceSheet,
isLoading, isLoading,
refetchSheet, refetchSheet,
} = useTrialBalanceSheetContext(); } = useTrialBalanceSheetContext();
@@ -115,7 +37,7 @@ export function TrialBalanceSheetAlerts() {
return null; return null;
} }
// Can't continue if the cost compute job is not running. // Can't continue if the cost compute job is not running.
if (!meta.is_cost_compute_running) { if (!trialBalanceSheet?.meta.is_cost_compute_running) {
return null; return null;
} }

View File

@@ -0,0 +1,56 @@
// @ts-nocheck
import * as R from 'ramda';
import { Align } from '@/constants';
import { getColumnWidth } from '@/utils';
const ACCOUNT_NAME_COLUMN_WIDTH = 320;
const AMOUNT_COLUMNS_MIN_WIDTH = 120;
const AMOUNT_COLUMNS_MAGIC_SPACING = 10;
const getTableCellValueAccessor = (index: number) => `cells[${index}].value`;
const accountNameAccessor = R.curry((data, column) => {
const accessor = getTableCellValueAccessor(column.cell_index);
return {
Header: column.label,
id: column.key,
accessor,
className: column.key,
width: ACCOUNT_NAME_COLUMN_WIDTH,
};
});
const amountAccessor = R.curry((data, column) => {
const accessor = getTableCellValueAccessor(column.cell_index);
return {
Header: column.label,
id: column.key,
accessor,
className: column.key,
width: getColumnWidth(data, accessor, {
magicSpacing: AMOUNT_COLUMNS_MAGIC_SPACING,
minWidth: AMOUNT_COLUMNS_MIN_WIDTH,
}),
align: Align.Right,
};
});
const dynamicColumnMapper = R.curry((data, column) => {
const accountNameColumn = accountNameAccessor(data);
const creditColumn = amountAccessor(data);
const debitColumn = amountAccessor(data);
const totalColumn = amountAccessor(data);
return R.compose(
R.when(R.pathEq(['key'], 'account_name'), accountNameColumn),
R.when(R.pathEq(['key'], 'credit'), creditColumn),
R.when(R.pathEq(['key'], 'debit'), debitColumn),
R.when(R.pathEq(['key'], 'total'), totalColumn),
)(column);
});
export const trialBalancesheetDynamicColumns = (columns, data) => {
return R.map(dynamicColumnMapper(data), columns);
};

View File

@@ -0,0 +1,18 @@
// @ts-nocheck
import React from 'react';
import { useTrialBalanceSheetContext } from './TrialBalanceProvider';
import { trialBalancesheetDynamicColumns } from './dynamicColumns';
/**
* Retrieves the trial balance sheet columns.
*/
export const useTrialBalanceSheetTableColumns = () => {
const {
trialBalanceSheet: { table },
} = useTrialBalanceSheetContext();
return React.useMemo(
() => trialBalancesheetDynamicColumns(table.columns, table.rows),
[table],
);
};

View File

@@ -43,17 +43,12 @@ export function useTrialBalanceSheet(query, props) {
method: 'get', method: 'get',
url: '/financial_statements/trial_balance_sheet', url: '/financial_statements/trial_balance_sheet',
params: query, params: query,
headers: {
Accept: 'application/json+table',
},
}, },
{ {
select: (res) => ({ select: (res) => res.data,
tableRows: trialBalanceSheetReducer(res.data.data),
...res.data,
}),
defaultData: {
tableRows: [],
data: [],
query: {},
},
...props, ...props,
}, },
); );

View File

@@ -1804,6 +1804,7 @@
"balance_sheet.total_change": "Total Change", "balance_sheet.total_change": "Total Change",
"balance_sheet.change": "% Change", "balance_sheet.change": "% Change",
"balance_sheet.previous_period": "Previous Period (PP)", "balance_sheet.previous_period": "Previous Period (PP)",
"balance_sheet.net_income": "Net Income",
"profit_loss_sheet.comparisons": "Comparisons", "profit_loss_sheet.comparisons": "Comparisons",
"profit_loss_sheet.dimensions": "Dimensions", "profit_loss_sheet.dimensions": "Dimensions",
"profit_loss_sheet.previous_year": "Previous Year", "profit_loss_sheet.previous_year": "Previous Year",