2
0
mirror of https://github.com/frappe/books.git synced 2024-09-20 11:29:00 +00:00
books/reports/ProfitAndLoss/ProfitAndLoss.ts
2022-05-23 16:18:23 +05:30

132 lines
3.3 KiB
TypeScript

import { t } from 'fyo';
import {
AccountRootType,
AccountRootTypeEnum,
} from 'models/baseModels/Account/types';
import {
AccountReport,
convertAccountRootNodeToAccountList,
} from 'reports/AccountReport';
import {
AccountListNode,
AccountTreeNode,
ReportData,
ValueMap,
} from 'reports/types';
export class ProfitAndLoss extends AccountReport {
static title = t`Profit And Loss`;
static reportName = 'profit-and-loss';
loading: boolean = false;
get rootTypes(): AccountRootType[] {
return [AccountRootTypeEnum.Income, AccountRootTypeEnum.Expense];
}
async setReportData(filter?: string) {
this.loading = true;
if (filter !== 'hideGroupAmounts') {
await this._setRawData();
}
const map = this._getGroupedMap(true, 'account');
const rangeGroupedMap = await this._getGroupedByDateRanges(map);
const accountTree = await this._getAccountTree(rangeGroupedMap);
for (const name of Object.keys(accountTree)) {
const { rootType } = accountTree[name];
if (this.rootTypes.includes(rootType)) {
continue;
}
delete accountTree[name];
}
/**
* Income Rows
*/
const incomeRoot = this.getRootNode(
AccountRootTypeEnum.Income,
accountTree
)!;
const incomeList = convertAccountRootNodeToAccountList(incomeRoot);
const incomeRows = this.getReportRowsFromAccountList(incomeList);
/**
* Expense Rows
*/
const expenseRoot = this.getRootNode(
AccountRootTypeEnum.Expense,
accountTree
)!;
const expenseList = convertAccountRootNodeToAccountList(expenseRoot);
const expenseRows = this.getReportRowsFromAccountList(expenseList);
this.reportData = await this.getReportDataFromRows(
incomeRows,
expenseRows,
incomeRoot,
expenseRoot
);
this.loading = false;
}
async getReportDataFromRows(
incomeRows: ReportData,
expenseRows: ReportData,
incomeRoot: AccountTreeNode,
expenseRoot: AccountTreeNode
): Promise<ReportData> {
const totalIncome = await this.getTotalNode(
incomeRoot,
t`Total Income (Credit)`
);
const totalExpense = await this.getTotalNode(
expenseRoot,
t`Total Expense (Debit)`
);
const totalValueMap: ValueMap = new Map();
for (const key of totalIncome.valueMap!.keys()) {
const income = totalIncome.valueMap!.get(key)?.balance ?? 0;
const expense = totalExpense.valueMap!.get(key)?.balance ?? 0;
totalValueMap.set(key, { balance: income - expense });
}
const totalProfit = {
name: t`Total Profit`,
valueMap: totalValueMap,
level: 0,
} as AccountListNode;
const totalIncomeRow = this.getRowFromAccountListNode(totalIncome);
const totalExpenseRow = this.getRowFromAccountListNode(totalExpense);
const totalProfitRow = this.getRowFromAccountListNode(totalProfit);
totalProfitRow.cells.forEach((c) => {
c.bold = true;
if (typeof c.rawValue !== 'number') {
return;
}
if (c.rawValue > 0) {
c.color = 'green';
} else if (c.rawValue < 0) {
c.color = 'red';
}
});
const emptyRow = this.getEmptyRow();
return [
incomeRows,
totalIncomeRow,
emptyRow,
expenseRows,
totalExpenseRow,
emptyRow,
totalProfitRow,
].flat() as ReportData;
}
}