feat: journal and general ledger report.

This commit is contained in:
a.bouhuolia
2021-01-21 14:32:31 +02:00
parent da69c333d7
commit 1a89730855
43 changed files with 797 additions and 372 deletions

View File

@@ -16,7 +16,8 @@ export default class JournalSheetController extends BaseFinancialReportControlle
router() {
const router = Router();
router.get('/',
router.get(
'/',
this.journalValidationSchema,
this.validationResult,
this.asyncMiddleware(this.journal.bind(this))
@@ -31,18 +32,20 @@ export default class JournalSheetController extends BaseFinancialReportControlle
return [
query('from_date').optional().isISO8601(),
query('to_date').optional().isISO8601(),
oneOf([
query('transaction_types').optional().isArray({ min: 1 }),
query('transaction_types.*').optional().isNumeric().toInt(),
], [
query('transaction_types').optional().trim().escape(),
]),
oneOf([
query('account_ids').optional().isArray({ min: 1 }),
query('account_ids.*').optional().isNumeric().toInt(),
], [
query('account_ids').optional().isNumeric().toInt(),
]),
oneOf(
[
query('transaction_types').optional().isArray({ min: 1 }),
query('transaction_types.*').optional().isNumeric().toInt(),
],
[query('transaction_types').optional().trim().escape()]
),
oneOf(
[
query('account_ids').optional().isArray({ min: 1 }),
query('account_ids.*').optional().isNumeric().toInt(),
],
[query('account_ids').optional().isNumeric().toInt()]
),
query('from_range').optional().isNumeric().toInt(),
query('to_range').optional().isNumeric().toInt(),
query('number_format.no_cents').optional().isBoolean().toBoolean(),
@@ -52,7 +55,7 @@ export default class JournalSheetController extends BaseFinancialReportControlle
/**
* Retrieve the ledger report of the given account.
* @param {Request} req -
* @param {Request} req -
* @param {Response} res -
*/
async journal(req: Request, res: Response, next: NextFunction) {
@@ -63,11 +66,20 @@ export default class JournalSheetController extends BaseFinancialReportControlle
...filter,
accountsIds: castArray(filter.accountsIds),
};
const organizationName = settings.get({ group: 'organization', key: 'name' });
const baseCurrency = settings.get({ group: 'organization', key: 'base_currency' });
const organizationName = settings.get({
group: 'organization',
key: 'name',
});
const baseCurrency = settings.get({
group: 'organization',
key: 'base_currency',
});
try {
const { data, query } = await this.journalService.journalSheet(tenantId, filter);
const { data, query } = await this.journalService.journalSheet(
tenantId,
filter
);
return res.status(200).send({
organization_name: organizationName,
@@ -79,4 +91,4 @@ export default class JournalSheetController extends BaseFinancialReportControlle
next(error);
}
}
}
}

View File

@@ -8,19 +8,42 @@ const balanceSheetStructure: IBalanceSheetStructureSection[] = [
children: [
{
name: 'Current Asset',
type: 'accounts_section',
accountsTypesRelated: ['current_asset'],
sectionType: 'assets',
type: 'section',
children: [
{
name: 'Cash and cash equivalents',
type: 'accounts_section',
accountsTypes: ['cash', 'bank'],
},
{
name: 'Accounts Receivable',
type: 'accounts_section',
accountsTypes: ['accounts_receivable'],
},
{
name: 'Inventories',
type: 'accounts_section',
accountsTypes: ['inventory'],
},
{
name: 'Other current assets',
type: 'accounts_section',
accountsTypes: ['other_current_asset'],
},
],
alwaysShow: true,
},
{
name: 'Fixed Asset',
type: 'accounts_section',
accountsTypesRelated: ['fixed_asset'],
accountsTypes: ['fixed_asset'],
},
{
name: 'Other Asset',
name: 'Non-Current Assets',
type: 'accounts_section',
accountsTypesRelated: ['other_asset'],
},
accountsTypes: ['non_current_asset'],
}
],
alwaysShow: true,
},
@@ -35,27 +58,32 @@ const balanceSheetStructure: IBalanceSheetStructureSection[] = [
type: 'section',
children: [
{
name: 'Current Liability',
name: 'Current Liabilties',
type: 'accounts_section',
accountsTypesRelated: ['current_liability'],
accountsTypes: [
'accounts_payable',
'tax_payable',
'credit_card',
'other_current_liability'
],
},
{
name: 'Long Term Liability',
name: 'Long-Term Liabilities',
type: 'accounts_section',
accountsTypesRelated: ['long_term_liability'],
accountsTypes: ['long_term_liability'],
},
{
name: 'Other Liability',
name: 'Non-Current Liabilities',
type: 'accounts_section',
accountsTypesRelated: ['other_liability'],
},
accountsTypes: ['non_current_liability'],
}
],
},
{
name: 'Equity',
sectionType: 'equity',
type: 'accounts_section',
accountsTypesRelated: ['equity'],
accountsTypes: ['equity'],
},
],
alwaysShow: true,

View File

@@ -53,7 +53,7 @@ export default [
key: 'non_current_asset',
normal: 'debit',
root_type: 'asset',
child_type: 'non_current_asset',
child_type: 'fixed_asset',
balance_sheet: true,
income_sheet: false,
},
@@ -81,14 +81,6 @@ export default [
balance_sheet: true,
income_sheet: false,
},
{
key: 'long_term_liability',
normal: 'credit',
root_type: 'liability',
child_type: 'long_term_liability',
balance_sheet: false,
income_sheet: true,
},
{
key: 'other_current_liability',
normal: 'credit',
@@ -97,6 +89,22 @@ export default [
balance_sheet: false,
income_sheet: true,
},
{
key: 'non_current_liability',
normal: 'credit',
root_type: 'liability',
child_type: 'current_liability',
balance_sheet: false,
income_sheet: true,
},
{
key: 'long_term_liability',
normal: 'credit',
root_type: 'liability',
child_type: 'long_term_liability',
balance_sheet: false,
income_sheet: true,
},
{
key: 'equity',
normal: 'credit',

View File

@@ -42,7 +42,7 @@ export interface IBalanceSheetStructureSection {
sectionType?: string;
type: 'section' | 'accounts_section';
children?: IBalanceSheetStructureSection[];
accountsTypesRelated?: string[];
accountsTypes?: string[];
alwaysShow?: boolean;
}
@@ -74,6 +74,6 @@ export interface IBalanceSheetSection {
total: IBalanceSheetAccountTotal;
totalPeriods?: IBalanceSheetAccountTotal[];
accountsTypesRelated?: string[];
accountsTypes?: string[];
_forceShow?: boolean;
}

View File

@@ -14,13 +14,26 @@ export interface IGeneralLedgerSheetQuery {
export interface IGeneralLedgerSheetAccountTransaction {
id: number,
amount: number,
runningBalance: number,
credit: number,
debit: number,
formattedAmount: string,
formattedCredit: string,
formattedDebit: string,
formattedRunningBalance: string,
currencyCode: string,
note?: string,
transactionType?: string,
transactionNumber: string,
referenceId?: number,
referenceType?: string,
date: Date|string,
};
@@ -38,8 +51,8 @@ export interface IGeneralLedgerSheetAccount {
index: number,
parentAccountId: number,
transactions: IGeneralLedgerSheetAccountTransaction[],
opening: IGeneralLedgerSheetAccountBalance,
closing: IGeneralLedgerSheetAccountBalance,
openingBalance: IGeneralLedgerSheetAccountBalance,
closingBalance: IGeneralLedgerSheetAccountBalance,
}
export interface IAccountTransaction {

View File

@@ -50,7 +50,7 @@ export interface IProfitLossSheetStatement {
costOfSales: IProfitLossSheetAccountsSection,
expenses: IProfitLossSheetAccountsSection,
otherExpenses: IProfitLossSheetAccountsSection,
otherIncome: IProfitLossSheetAccountsSection,
netIncome: IProfitLossSheetTotalSection;
operatingProfit: IProfitLossSheetTotalSection;
grossProfit: IProfitLossSheetTotalSection;

View File

@@ -58,23 +58,23 @@ export default class AccountType extends TenantModel {
static get labels() {
return {
inventory: 'Inventory',
other_current_asset: 'Other current asset',
bank: 'Bank account',
other_current_asset: 'Other Current Asset',
bank: 'Bank Account',
cash: 'Cash',
fixed_asset: 'Fixed asset',
non_current_asset: 'Non-current asset',
accounts_payable: 'Accounts payable (A/P)',
accounts_receivable: 'Accounts receivable (A/R)',
credit_card: 'Credit card',
long_term_liability: 'Long term liability',
other_current_liability: 'Other current liability',
other_liability: 'Other liability',
fixed_asset: 'Fixed Asset',
non_current_asset: 'Non-Current Asset',
accounts_payable: 'Accounts Payable (A/P)',
accounts_receivable: 'Accounts Receivable (A/R)',
credit_card: 'Credit Card',
long_term_liability: 'Long Term Liability',
other_current_liability: 'Other Current Liability',
other_liability: 'Other Liability',
equity: "Equity",
expense: "Expense",
income: "Income",
other_income: "Other income",
other_expense: "Other expense",
cost_of_goods_sold: "Cost of goods sold (COGS)",
other_income: "Other Income",
other_expense: "Other Expense",
cost_of_goods_sold: "Cost of Goods Sold (COGS)",
};
}
}

View File

@@ -71,6 +71,13 @@ export default class JournalPoster implements IJournalPoster {
}
}
/**
*
*/
public isEmpty() {
return this.entries.length === 0;
}
/**
* Writes the credit entry for the given account.
* @param {IJournalEntry} entry -

View File

@@ -184,7 +184,7 @@ export default class BalanceSheetStatement extends FinancialSheet {
const filteredAccounts = accounts
// Filter accounts that associated to the section accounts types.
.filter(
(account) => sectionAccountsTypes.indexOf(account.type.childType) !== -1
(account) => sectionAccountsTypes.indexOf(account.type.key) !== -1
)
.map((account) => this.balanceSheetAccountMapper(account))
// Filter accounts that have no transaction when `noneTransactions` is on.
@@ -258,7 +258,7 @@ export default class BalanceSheetStatement extends FinancialSheet {
type: structure.type,
...(structure.type === 'accounts_section'
? this.structureRelatedAccountsMapper(
structure.accountsTypesRelated,
structure.accountsTypes,
accounts
)
: this.structureSectionMapper(structure, accounts)),

View File

@@ -1,4 +1,4 @@
import { pick } from 'lodash';
import { pick, get, last } from 'lodash';
import {
IGeneralLedgerSheetQuery,
IGeneralLedgerSheetAccount,
@@ -8,9 +8,13 @@ import {
IJournalPoster,
IAccountType,
IJournalEntry,
IContact,
} from 'interfaces';
import FinancialSheet from '../FinancialSheet';
/**
* General ledger sheet.
*/
export default class GeneralLedgerSheet extends FinancialSheet {
tenantId: number;
accounts: IAccount[];
@@ -18,6 +22,7 @@ export default class GeneralLedgerSheet extends FinancialSheet {
openingBalancesJournal: IJournalPoster;
closingBalancesJournal: IJournalPoster;
transactions: IJournalPoster;
contactsMap: Map<number, IContact>;
baseCurrency: string;
/**
@@ -32,6 +37,7 @@ export default class GeneralLedgerSheet extends FinancialSheet {
tenantId: number,
query: IGeneralLedgerSheetQuery,
accounts: IAccount[],
contactsByIdMap: Map<number, IContact>,
transactions: IJournalPoster,
openingBalancesJournal: IJournalPoster,
closingBalancesJournal: IJournalPoster,
@@ -43,48 +49,100 @@ export default class GeneralLedgerSheet extends FinancialSheet {
this.query = query;
this.numberFormat = this.query.numberFormat;
this.accounts = accounts;
this.contactsMap = contactsByIdMap;
this.transactions = transactions;
this.openingBalancesJournal = openingBalancesJournal;
this.closingBalancesJournal = closingBalancesJournal;
this.baseCurrency = baseCurrency;
}
/**
* Retrieve the transaction amount.
* @param {number} credit - Credit amount.
* @param {number} debit - Debit amount.
* @param {string} normal - Credit or debit.
*/
getAmount(credit: number, debit: number, normal: string) {
return normal === 'credit' ? credit - debit : debit - credit;
}
/**
* Entry mapper.
* @param {IJournalEntry} entry -
* @return {IGeneralLedgerSheetAccountTransaction}
*/
entryReducer(
entries: IGeneralLedgerSheetAccountTransaction[],
entry: IJournalEntry,
index: number
): IGeneralLedgerSheetAccountTransaction[] {
const lastEntry = last(entries);
const openingBalance = 0;
const contact = this.contactsMap.get(entry.contactId);
const amount = this.getAmount(
entry.credit,
entry.debit,
entry.accountNormal
);
const runningBalance =
(entries.length === 0
? openingBalance
: lastEntry
? lastEntry.runningBalance
: 0) + amount;
const newEntry = {
date: entry.date,
entryId: entry.id,
referenceType: entry.referenceType,
referenceId: entry.referenceId,
referenceTypeFormatted: entry.referenceTypeFormatted,
contactName: get(contact, 'displayName'),
contactType: get(contact, 'contactService'),
transactionType: entry.transactionType,
index: entry.index,
note: entry.note,
credit: entry.credit,
debit: entry.debit,
amount,
runningBalance,
formattedAmount: this.formatNumber(amount),
formattedCredit: this.formatNumber(entry.credit),
formattedDebit: this.formatNumber(entry.debit),
formattedRunningBalance: this.formatNumber(runningBalance),
currencyCode: this.baseCurrency,
};
entries.push(newEntry);
return entries;
}
/**
* Mapping the account transactions to general ledger transactions of the given account.
* @param {IAccount} account
* @return {IGeneralLedgerSheetAccountTransaction[]}
*/
private accountTransactionsMapper(
account: IAccount & { type: IAccountType }
account: IAccount & { type: IAccountType },
openingBalance: number
): IGeneralLedgerSheetAccountTransaction[] {
const entries = this.transactions.getAccountEntries(account.id);
return entries.map(
(transaction: IJournalEntry): IGeneralLedgerSheetAccountTransaction => {
let amount = 0;
if (account.type.normal === 'credit') {
amount += transaction.credit - transaction.debit;
} else if (account.type.normal === 'debit') {
amount += transaction.debit - transaction.credit;
}
const formattedAmount = this.formatNumber(amount);
return {
...pick(transaction, [
'id',
'note',
'transactionType',
'referenceType',
'referenceId',
'referenceTypeFormatted',
'date',
]),
amount,
formattedAmount,
currencyCode: this.baseCurrency,
};
}
return entries.reduce(
(
entries: IGeneralLedgerSheetAccountTransaction[],
entry: IJournalEntry
) => {
return this.entryReducer(entries, entry, openingBalance);
},
[]
);
}
@@ -128,11 +186,21 @@ export default class GeneralLedgerSheet extends FinancialSheet {
private accountMapper(
account: IAccount & { type: IAccountType }
): IGeneralLedgerSheetAccount {
const openingBalance = this.accountOpeningBalance(account);
const closingBalance = this.accountClosingBalance(account);
return {
...pick(account, ['id', 'name', 'code', 'index', 'parentAccountId']),
opening: this.accountOpeningBalance(account),
transactions: this.accountTransactionsMapper(account),
closing: this.accountClosingBalance(account),
id: account.id,
name: account.name,
code: account.code,
index: account.index,
parentAccountId: account.parentAccountId,
openingBalance,
transactions: this.accountTransactionsMapper(
account,
openingBalance.amount
),
closingBalance,
};
}
@@ -149,7 +217,8 @@ export default class GeneralLedgerSheet extends FinancialSheet {
.map((account: IAccount & { type: IAccountType }) =>
this.accountMapper(account)
)
// Filter general ledger accounts that have no transactions when `noneTransactions` is on.
// Filter general ledger accounts that have no transactions
// when`noneTransactions` is on.
.filter(
(generalLedgerAccount: IGeneralLedgerSheetAccount) =>
!(

View File

@@ -7,6 +7,8 @@ import TenancyService from 'services/Tenancy/TenancyService';
import Journal from 'services/Accounting/JournalPoster';
import GeneralLedgerSheet from 'services/FinancialStatements/GeneralLedger/GeneralLedger';
import { transformToMap } from 'utils';
const ERRORS = {
ACCOUNTS_NOT_FOUND: 'ACCOUNTS_NOT_FOUND',
};
@@ -70,6 +72,7 @@ export default class GeneralLedgerService {
const {
accountRepository,
transactionsRepository,
contactRepository
} = this.tenancy.repositories(tenantId);
const settings = this.tenancy.settings(tenantId);
@@ -89,6 +92,10 @@ export default class GeneralLedgerService {
const accounts = await accountRepository.all('type');
const accountsGraph = await accountRepository.getDependencyGraph();
// Retrieve all contacts on the storage.
const contacts = await contactRepository.all();
const contactsByIdMap = transformToMap(contacts, 'id');
// Retreive journal transactions from/to the given date.
const transactions = await transactionsRepository.journal({
fromDate: filter.fromDate,
@@ -127,6 +134,7 @@ export default class GeneralLedgerService {
tenantId,
filter,
accounts,
contactsByIdMap,
transactionsJournal,
openingTransJournal,
closingTransJournal,

View File

@@ -1,19 +1,20 @@
import { sumBy, chain, omit } from 'lodash';
import { sumBy, chain, get, head } from 'lodash';
import {
IJournalEntry,
IJournalPoster,
IJournalReportEntriesGroup,
IJournalReportQuery,
IJournalReport,
IContact,
} from 'interfaces';
import FinancialSheet from '../FinancialSheet';
import { AccountTransaction } from 'models';
export default class JournalSheet extends FinancialSheet {
tenantId: number;
journal: IJournalPoster;
query: IJournalReportQuery;
baseCurrency: string;
readonly contactsById: Map<number | string, IContact>;
/**
* Constructor method.
@@ -24,6 +25,8 @@ export default class JournalSheet extends FinancialSheet {
tenantId: number,
query: IJournalReportQuery,
journal: IJournalPoster,
accountsGraph: any,
contactsById: Map<number | string, IContact>,
baseCurrency: string
) {
super();
@@ -32,22 +35,48 @@ export default class JournalSheet extends FinancialSheet {
this.journal = journal;
this.query = query;
this.numberFormat = this.query.numberFormat;
this.accountsGraph = accountsGraph;
this.contactsById = contactsById;
this.baseCurrency = baseCurrency;
}
/**
* Mappes the journal entries.
* @param {IJournalEntry[]} entries -
* Entry mapper.
* @param {IJournalEntry} entry
*/
entriesMapper(
entries: IJournalEntry[],
) {
return entries.map((entry: IJournalEntry) => {
return {
...omit(entry, 'account'),
currencyCode: this.baseCurrency,
};
})
entryMapper(entry: IJournalEntry) {
const account = this.accountsGraph.getNodeData(entry.accountId);
const contact = this.contactsById.get(entry.contactId);
return {
entryId: entry.id,
index: entry.index,
note: entry.note,
contactName: get(contact, 'displayName'),
contactType: get(contact, 'contactService'),
accountName: account.name,
accountCode: account.code,
transactionNumber: entry.transactionNumber,
currencyCode: this.baseCurrency,
formattedCredit: this.formatNumber(entry.credit),
formattedDebit: this.formatNumber(entry.debit),
credit: entry.credit,
debit: entry.debit,
createdAt: entry.createdAt,
};
}
/**
* Mappes the journal entries.
* @param {IJournalEntry[]} entries -
*/
entriesMapper(entries: IJournalEntry[]) {
return entries.map(this.entryMapper.bind(this));
}
/**
@@ -58,13 +87,17 @@ export default class JournalSheet extends FinancialSheet {
*/
entriesGroupsMapper(
entriesGroup: IJournalEntry[],
key: string
groupEntry: IJournalEntry
): IJournalReportEntriesGroup {
const totalCredit = sumBy(entriesGroup, 'credit');
const totalDebit = sumBy(entriesGroup, 'debit');
return {
id: key,
date: groupEntry.date,
referenceType: groupEntry.referenceType,
referenceId: groupEntry.referenceId,
referenceTypeFormatted: groupEntry.referenceTypeFormatted,
entries: this.entriesMapper(entriesGroup),
currencyCode: this.baseCurrency,
@@ -72,8 +105,8 @@ export default class JournalSheet extends FinancialSheet {
credit: totalCredit,
debit: totalDebit,
formattedCredit: this.formatNumber(totalCredit),
formattedDebit: this.formatNumber(totalDebit),
formattedCredit: this.formatTotalNumber(totalCredit),
formattedDebit: this.formatTotalNumber(totalDebit),
};
}
@@ -85,9 +118,10 @@ export default class JournalSheet extends FinancialSheet {
entriesWalker(entries: IJournalEntry[]): IJournalReportEntriesGroup[] {
return chain(entries)
.groupBy((entry) => `${entry.referenceId}-${entry.referenceType}`)
.map((entriesGroup: IJournalEntry[], key: string) =>
this.entriesGroupsMapper(entriesGroup, key)
)
.map((entriesGroup: IJournalEntry[], key: string) => {
const headEntry = head(entriesGroup);
return this.entriesGroupsMapper(entriesGroup, headEntry);
})
.value();
}

View File

@@ -1,10 +1,13 @@
import { Service, Inject } from 'typedi';
import { IJournalReportQuery } from 'interfaces';
import moment from 'moment';
import JournalSheet from './JournalSheet';
import TenancyService from 'services/Tenancy/TenancyService';
import Journal from 'services/Accounting/JournalPoster';
import { transformToMap } from 'utils';
@Service()
export default class JournalSheetService {
@Inject()
@@ -40,6 +43,7 @@ export default class JournalSheetService {
const {
accountRepository,
transactionsRepository,
contactRepository,
} = this.tenancy.repositories(tenantId);
const filter = {
@@ -50,7 +54,6 @@ export default class JournalSheetService {
tenantId,
filter,
});
// Settings service.
const settings = this.tenancy.settings(tenantId);
const baseCurrency = settings.get({
@@ -60,6 +63,10 @@ export default class JournalSheetService {
// Retrieve all accounts on the storage.
const accountsGraph = await accountRepository.getDependencyGraph();
// Retrieve all contacts on the storage.
const contacts = await contactRepository.all();
const contactsByIdMap = transformToMap(contacts, 'id');
// Retrieve all journal transactions based on the given query.
const transactions = await transactionsRepository.journal({
fromDate: filter.fromDate,
@@ -79,6 +86,8 @@ export default class JournalSheetService {
tenantId,
filter,
transactionsJournal,
accountsGraph,
contactsByIdMap,
baseCurrency
);
// Retrieve journal report columns.

View File

@@ -50,6 +50,10 @@ export default class ProfitLossSheet extends FinancialSheet {
this.initDateRangeCollection();
}
get otherIncomeAccounts() {
return this.accounts.filter((a) => a.type.key === 'other_income');
}
/**
* Filtering income accounts.
* @return {IAccount & { type: IAccountType }[]}
@@ -235,6 +239,14 @@ export default class ProfitLossSheet extends FinancialSheet {
};
}
private get otherIncomeSection(): any {
return {
name: 'Other Income',
entryNormal: 'credit',
...this.sectionMapper(this.otherIncomeAccounts)
}
}
/**
* Retreive expenses section.
* @return {IProfitLossSheetLossSection}
@@ -343,10 +355,14 @@ export default class ProfitLossSheet extends FinancialSheet {
* @return {IProfitLossSheetStatement}
*/
public reportData(): IProfitLossSheetStatement {
if (this.journal.isEmpty()) {
return null;
}
const income = this.incomeSection;
const costOfSales = this.costOfSalesSection;
const expenses = this.expensesSection;
const otherExpenses = this.otherExpensesSection;
const otherIncome = this.otherIncomeSection;
// - Gross profit = Total income - COGS.
const grossProfit = this.getSummarySection(income, costOfSales);
@@ -356,7 +372,6 @@ export default class ProfitLossSheet extends FinancialSheet {
expenses,
costOfSales,
]);
// - Net income = Operating profit - Other expenses.
const netIncome = this.getSummarySection(operatingProfit, otherExpenses);
@@ -365,6 +380,7 @@ export default class ProfitLossSheet extends FinancialSheet {
costOfSales,
grossProfit,
expenses,
otherIncome,
otherExpenses,
netIncome,
operatingProfit,

View File

@@ -4,6 +4,7 @@ import {
ITrialBalanceAccount,
IAccount,
ITrialBalanceTotal,
ITrialBalanceSheetData,
IAccountType,
} from 'interfaces';
import FinancialSheet from '../FinancialSheet';
@@ -49,6 +50,7 @@ export default class TrialBalanceSheet extends FinancialSheet {
/**
* Account mapper.
* @param {IAccount} account
* @return {ITrialBalanceAccount}
*/
private accountMapper(
account: IAccount & { type: IAccountType }
@@ -80,6 +82,7 @@ export default class TrialBalanceSheet extends FinancialSheet {
/**
* Accounts walker.
* @param {IAccount[]} accounts
* @return {ITrialBalanceAccount[]}
*/
private accountsWalker(
accounts: IAccount & { type: IAccountType }[]
@@ -136,8 +139,15 @@ export default class TrialBalanceSheet extends FinancialSheet {
/**
* Retrieve trial balance sheet statement data.
* Note: Retruns null in case there is no transactions between the given date periods.
*
* @return {ITrialBalanceSheetData}
*/
public reportData() {
public reportData(): ITrialBalanceSheetData {
// Don't return noting if the journal has no transactions.
if (this.journalFinancial.isEmpty()) {
return null;
}
const accounts = this.accountsWalker(this.accounts);
const total = this.tatalSection(accounts);

View File

@@ -278,6 +278,15 @@ function defaultToTransform(value, defaultOrTransformedValue, defaultValue) {
: _transfromedValue;
}
const transformToMap = (objects, key) => {
const map = new Map();
objects.forEach(object => {
map.set(object[key], object);
});
return map;
}
export {
hashPassword,
origin,
@@ -299,4 +308,5 @@ export {
formatNumber,
isBlank,
defaultToTransform,
transformToMap
};