Files
bigcapital/temp/CashFlow/CashFlowDatePeriods.ts
2025-01-18 22:32:45 +02:00

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);
};
};