mirror of
https://github.com/bigcapitalhq/bigcapital.git
synced 2026-02-14 03:40:31 +00:00
413 lines
12 KiB
TypeScript
413 lines
12 KiB
TypeScript
import * as R from 'ramda';
|
|
import { sumBy, mapValues, get } from 'lodash';
|
|
import { ACCOUNT_ROOT_TYPE } from '@/constants/accounts';
|
|
import {
|
|
ICashFlowDatePeriod,
|
|
ICashFlowStatementNetIncomeSection,
|
|
ICashFlowStatementAccountSection,
|
|
ICashFlowStatementSection,
|
|
ICashFlowSchemaTotalSection,
|
|
ICashFlowStatementTotalSection,
|
|
ICashFlowStatementQuery,
|
|
IDateRange,
|
|
} from './Cashflow.types';
|
|
import { IFormatNumberSettings } from '../../types/Report.types';
|
|
import { dateRangeFromToCollection } from '@/utils/date-range-collection';
|
|
import { accumSum } from '@/utils/accum-sum';
|
|
|
|
export const CashFlowStatementDatePeriods = (Base) =>
|
|
class extends Base {
|
|
dateRangeSet: IDateRange[];
|
|
query: ICashFlowStatementQuery;
|
|
|
|
/**
|
|
* Initialize date range set.
|
|
*/
|
|
public initDateRangeCollection() {
|
|
this.dateRangeSet = dateRangeFromToCollection(
|
|
this.query.fromDate,
|
|
this.query.toDate,
|
|
this.comparatorDateType
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Retrieve the date period meta.
|
|
* @param {number} total - Total amount.
|
|
* @param {Date} fromDate - From date.
|
|
* @param {Date} toDate - To date.
|
|
* @return {ICashFlowDatePeriod}
|
|
*/
|
|
public getDatePeriodTotalMeta = (
|
|
total: number,
|
|
fromDate: Date,
|
|
toDate: Date,
|
|
overrideSettings: IFormatNumberSettings = {}
|
|
): ICashFlowDatePeriod => {
|
|
return this.getDatePeriodMeta(total, fromDate, toDate, {
|
|
money: true,
|
|
...overrideSettings,
|
|
});
|
|
};
|
|
|
|
/**
|
|
* Retrieve the date period meta.
|
|
* @param {number} total - Total amount.
|
|
* @param {Date} fromDate - From date.
|
|
* @param {Date} toDate - To date.
|
|
* @return {ICashFlowDatePeriod}
|
|
*/
|
|
public getDatePeriodMeta = (
|
|
total: number,
|
|
fromDate: Date,
|
|
toDate: Date,
|
|
overrideSettings?: IFormatNumberSettings
|
|
): ICashFlowDatePeriod => {
|
|
return {
|
|
fromDate: this.getDateMeta(fromDate),
|
|
toDate: this.getDateMeta(toDate),
|
|
total: this.getAmountMeta(total, overrideSettings),
|
|
};
|
|
};
|
|
|
|
// Net income --------------------
|
|
/**
|
|
* Retrieve the net income between the given date range.
|
|
* @param {Date} fromDate
|
|
* @param {Date} toDate
|
|
* @returns {number}
|
|
*/
|
|
public getNetIncomeDateRange = (fromDate: Date, toDate: Date) => {
|
|
// Mapping income/expense accounts ids.
|
|
const incomeAccountsIds = this.getAccountsIdsByType(
|
|
ACCOUNT_ROOT_TYPE.INCOME
|
|
);
|
|
const expenseAccountsIds = this.getAccountsIdsByType(
|
|
ACCOUNT_ROOT_TYPE.EXPENSE
|
|
);
|
|
// Income closing balance.
|
|
const incomeClosingBalance = accumSum(incomeAccountsIds, (id) =>
|
|
this.netIncomeLedger
|
|
.whereFromDate(fromDate)
|
|
.whereToDate(toDate)
|
|
.whereAccountId(id)
|
|
.getClosingBalance()
|
|
);
|
|
// Expense closing balance.
|
|
const expenseClosingBalance = accumSum(expenseAccountsIds, (id) =>
|
|
this.netIncomeLedger
|
|
.whereToDate(toDate)
|
|
.whereFromDate(fromDate)
|
|
.whereAccountId(id)
|
|
.getClosingBalance()
|
|
);
|
|
// Net income = income - expenses.
|
|
const netIncome = incomeClosingBalance - expenseClosingBalance;
|
|
|
|
return netIncome;
|
|
};
|
|
|
|
/**
|
|
* Retrieve the net income of date period.
|
|
* @param {IDateRange} dateRange -
|
|
* @retrun {ICashFlowDatePeriod}
|
|
*/
|
|
public getNetIncomeDatePeriod = (dateRange): ICashFlowDatePeriod => {
|
|
const total = this.getNetIncomeDateRange(
|
|
dateRange.fromDate,
|
|
dateRange.toDate
|
|
);
|
|
return this.getDatePeriodMeta(
|
|
total,
|
|
dateRange.fromDate,
|
|
dateRange.toDate
|
|
);
|
|
};
|
|
|
|
/**
|
|
* Retrieve the net income node between the given date ranges.
|
|
* @param {Date} fromDate
|
|
* @param {Date} toDate
|
|
* @returns {ICashFlowDatePeriod[]}
|
|
*/
|
|
public getNetIncomeDatePeriods = (
|
|
section: ICashFlowStatementNetIncomeSection
|
|
): ICashFlowDatePeriod[] => {
|
|
return this.dateRangeSet.map(this.getNetIncomeDatePeriod.bind(this));
|
|
};
|
|
|
|
/**
|
|
* Writes periods property to net income section.
|
|
* @param {ICashFlowStatementNetIncomeSection} section
|
|
* @returns {ICashFlowStatementNetIncomeSection}
|
|
*/
|
|
public assocPeriodsToNetIncomeNode = (
|
|
section: ICashFlowStatementNetIncomeSection
|
|
): ICashFlowStatementNetIncomeSection => {
|
|
const incomeDatePeriods = this.getNetIncomeDatePeriods(section);
|
|
return R.assoc('periods', incomeDatePeriods, section);
|
|
};
|
|
|
|
// Account nodes --------------------
|
|
/**
|
|
* Retrieve the account total between date range.
|
|
* @param {Date} fromDate - From date.
|
|
* @param {Date} toDate - To date.
|
|
* @return {number}
|
|
*/
|
|
public getAccountTotalDateRange = (
|
|
node: ICashFlowStatementAccountSection,
|
|
fromDate: Date,
|
|
toDate: Date
|
|
): number => {
|
|
const closingBalance = this.ledger
|
|
.whereFromDate(fromDate)
|
|
.whereToDate(toDate)
|
|
.whereAccountId(node.id)
|
|
.getClosingBalance();
|
|
|
|
return this.amountAdjustment(node.adjustmentType, closingBalance);
|
|
};
|
|
|
|
/**
|
|
* Retrieve the given account node total date period.
|
|
* @param {ICashFlowStatementAccountSection} node -
|
|
* @param {Date} fromDate - From date.
|
|
* @param {Date} toDate - To date.
|
|
* @return {ICashFlowDatePeriod}
|
|
*/
|
|
public getAccountTotalDatePeriod = (
|
|
node: ICashFlowStatementAccountSection,
|
|
fromDate: Date,
|
|
toDate: Date
|
|
): ICashFlowDatePeriod => {
|
|
const total = this.getAccountTotalDateRange(node, fromDate, toDate);
|
|
return this.getDatePeriodMeta(total, fromDate, toDate);
|
|
};
|
|
|
|
/**
|
|
* Retrieve the accounts date periods nodes of the give account node.
|
|
* @param {ICashFlowStatementAccountSection} node -
|
|
* @return {ICashFlowDatePeriod[]}
|
|
*/
|
|
public getAccountDatePeriods = (
|
|
node: ICashFlowStatementAccountSection
|
|
): ICashFlowDatePeriod[] => {
|
|
return this.getNodeDatePeriods(
|
|
node,
|
|
this.getAccountTotalDatePeriod.bind(this)
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Writes `periods` property to account node.
|
|
* @param {ICashFlowStatementAccountSection} node -
|
|
* @return {ICashFlowStatementAccountSection}
|
|
*/
|
|
public assocPeriodsToAccountNode = (
|
|
node: ICashFlowStatementAccountSection
|
|
): ICashFlowStatementAccountSection => {
|
|
const datePeriods = this.getAccountDatePeriods(node);
|
|
return R.assoc('periods', datePeriods, node);
|
|
}
|
|
|
|
// Aggregate node -------------------------
|
|
/**
|
|
* Retrieve total of the given period index for node that has children nodes.
|
|
* @return {number}
|
|
*/
|
|
public getChildrenTotalPeriodByIndex = (
|
|
node: ICashFlowStatementSection,
|
|
index: number
|
|
): number => {
|
|
return sumBy(node.children, `periods[${index}].total.amount`);
|
|
}
|
|
|
|
/**
|
|
* Retrieve date period meta of the given node index.
|
|
* @param {ICashFlowStatementSection} node -
|
|
* @param {number} index - Loop index.
|
|
* @param {Date} fromDate - From date.
|
|
* @param {Date} toDate - To date.
|
|
*/
|
|
public getChildrenTotalPeriodMetaByIndex(
|
|
node: ICashFlowStatementSection,
|
|
index: number,
|
|
fromDate: Date,
|
|
toDate: Date
|
|
) {
|
|
const total = this.getChildrenTotalPeriodByIndex(node, index);
|
|
return this.getDatePeriodTotalMeta(total, fromDate, toDate);
|
|
}
|
|
|
|
/**
|
|
* Retrieve the date periods of aggregate node.
|
|
* @param {ICashFlowStatementSection} node
|
|
*/
|
|
public getAggregateNodeDatePeriods(node: ICashFlowStatementSection) {
|
|
const getChildrenTotalPeriodMetaByIndex = R.curry(
|
|
this.getChildrenTotalPeriodMetaByIndex.bind(this)
|
|
)(node);
|
|
|
|
return this.dateRangeSet.map((dateRange, index) =>
|
|
getChildrenTotalPeriodMetaByIndex(
|
|
index,
|
|
dateRange.fromDate,
|
|
dateRange.toDate
|
|
)
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Writes `periods` property to aggregate section node.
|
|
* @param {ICashFlowStatementSection} node -
|
|
* @return {ICashFlowStatementSection}
|
|
*/
|
|
public assocPeriodsToAggregateNode = (
|
|
node: ICashFlowStatementSection
|
|
): ICashFlowStatementSection => {
|
|
const datePeriods = this.getAggregateNodeDatePeriods(node);
|
|
return R.assoc('periods', datePeriods, node);
|
|
};
|
|
|
|
// Total equation node --------------------
|
|
|
|
public sectionsMapToTotalPeriod = (
|
|
mappedSections: { [key: number]: any },
|
|
index
|
|
) => {
|
|
return mapValues(
|
|
mappedSections,
|
|
(node) => get(node, `periods[${index}].total.amount`) || 0
|
|
);
|
|
};
|
|
|
|
/**
|
|
* Retrieve the date periods of the given total equation.
|
|
* @param {ICashFlowSchemaTotalSection}
|
|
* @param {string} equation -
|
|
* @return {ICashFlowDatePeriod[]}
|
|
*/
|
|
public getTotalEquationDatePeriods = (
|
|
node: ICashFlowSchemaTotalSection,
|
|
equation: string,
|
|
nodesTable
|
|
): ICashFlowDatePeriod[] => {
|
|
return this.getNodeDatePeriods(node, (node, fromDate, toDate, index) => {
|
|
const periodScope = this.sectionsMapToTotalPeriod(nodesTable, index);
|
|
const total = this.evaluateEquation(equation, periodScope);
|
|
|
|
return this.getDatePeriodTotalMeta(total, fromDate, toDate);
|
|
});
|
|
};
|
|
|
|
/**
|
|
* Associates the total periods of total equation to the ginve total node..
|
|
* @param {ICashFlowSchemaTotalSection} totalSection -
|
|
* @return {ICashFlowStatementTotalSection}
|
|
*/
|
|
public assocTotalEquationDatePeriods = (
|
|
nodesTable: any,
|
|
equation: string,
|
|
node: ICashFlowSchemaTotalSection
|
|
): ICashFlowStatementTotalSection => {
|
|
const datePeriods = this.getTotalEquationDatePeriods(
|
|
node,
|
|
equation,
|
|
nodesTable
|
|
);
|
|
|
|
return R.assoc('periods', datePeriods, node);
|
|
};
|
|
|
|
// Cash at beginning ----------------------
|
|
|
|
/**
|
|
* Retrieve the date preioods of the given node and accumulated function.
|
|
* @param {} node
|
|
* @param {}
|
|
* @return {}
|
|
*/
|
|
public getNodeDatePeriods = (node, callback) => {
|
|
const curriedCallback = R.curry(callback)(node);
|
|
|
|
return this.dateRangeSet.map((dateRange, index) => {
|
|
return curriedCallback(dateRange.fromDate, dateRange.toDate, index);
|
|
});
|
|
};
|
|
|
|
/**
|
|
* Retrieve the account total between date range.
|
|
* @param {Date} fromDate - From date.
|
|
* @param {Date} toDate - To date.
|
|
* @return {number}
|
|
*/
|
|
public getBeginningCashAccountDateRange = (
|
|
node: ICashFlowStatementSection,
|
|
fromDate: Date,
|
|
toDate: Date
|
|
) => {
|
|
const cashToDate = this.beginningCashFrom(fromDate);
|
|
|
|
return this.cashLedger
|
|
.whereToDate(cashToDate)
|
|
.whereAccountId(node.id)
|
|
.getClosingBalance();
|
|
};
|
|
|
|
/**
|
|
* Retrieve the beginning cash date period.
|
|
* @param {ICashFlowStatementSection} node -
|
|
* @param {Date} fromDate - From date.
|
|
* @param {Date} toDate - To date.
|
|
* @return {ICashFlowDatePeriod}
|
|
*/
|
|
public getBeginningCashDatePeriod = (
|
|
node: ICashFlowStatementSection,
|
|
fromDate: Date,
|
|
toDate: Date
|
|
) => {
|
|
const total = this.getBeginningCashAccountDateRange(
|
|
node,
|
|
fromDate,
|
|
toDate
|
|
);
|
|
return this.getDatePeriodTotalMeta(total, fromDate, toDate);
|
|
};
|
|
|
|
/**
|
|
* Retrieve the beginning cash account periods.
|
|
* @param {ICashFlowStatementSection} node
|
|
* @return {ICashFlowDatePeriod}
|
|
*/
|
|
public getBeginningCashAccountPeriods = (
|
|
node: ICashFlowStatementSection
|
|
): ICashFlowDatePeriod => {
|
|
return this.getNodeDatePeriods(node, this.getBeginningCashDatePeriod);
|
|
};
|
|
|
|
/**
|
|
* Writes `periods` property to cash at beginning date periods.
|
|
* @param {ICashFlowStatementSection} section -
|
|
* @return {ICashFlowStatementSection}
|
|
*/
|
|
public assocCashAtBeginningDatePeriods = (
|
|
node: ICashFlowStatementSection
|
|
): ICashFlowStatementSection => {
|
|
const datePeriods = this.getAggregateNodeDatePeriods(node);
|
|
return R.assoc('periods', datePeriods, node);
|
|
};
|
|
|
|
/**
|
|
* Associates `periods` propery to cash at beginning account node.
|
|
* @param {ICashFlowStatementSection} node -
|
|
* @return {ICashFlowStatementSection}
|
|
*/
|
|
public assocCashAtBeginningAccountDatePeriods = (
|
|
node: ICashFlowStatementSection
|
|
): ICashFlowStatementSection => {
|
|
const datePeriods = this.getBeginningCashAccountPeriods(node);
|
|
return R.assoc('periods', datePeriods, node);
|
|
};
|
|
};
|