mirror of
https://github.com/frappe/books.git
synced 2024-12-22 10:58:59 +00:00
fix(reports): Allow multiple root account to have the same type
In French accounting, multiple root accounts can be of the same type, ensure that reports take all accounts and not only the first one.
This commit is contained in:
parent
d04b1561cd
commit
dd2830530b
@ -64,12 +64,12 @@ export abstract class AccountReport extends LedgerReport {
|
|||||||
this._dateRanges = await this._getDateRanges();
|
this._dateRanges = await this._getDateRanges();
|
||||||
}
|
}
|
||||||
|
|
||||||
getRootNode(
|
getRootNodes(
|
||||||
rootType: AccountRootType,
|
rootType: AccountRootType,
|
||||||
accountTree: AccountTree
|
accountTree: AccountTree
|
||||||
): AccountTreeNode | undefined {
|
): AccountTreeNode[] | undefined {
|
||||||
const rootNodeList = Object.values(accountTree);
|
const rootNodeList = Object.values(accountTree);
|
||||||
return rootNodeList.find((n) => n.rootType === rootType);
|
return rootNodeList.filter((n) => n.rootType === rootType);
|
||||||
}
|
}
|
||||||
|
|
||||||
getEmptyRow(): ReportRow {
|
getEmptyRow(): ReportRow {
|
||||||
@ -88,8 +88,11 @@ export abstract class AccountReport extends LedgerReport {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
getTotalNode(rootNode: AccountTreeNode, name: string): AccountListNode {
|
getTotalNode(rootNodes: AccountTreeNode[], name: string): AccountListNode {
|
||||||
const accountTree = { [rootNode.name]: rootNode };
|
const accountTree: Tree = {};
|
||||||
|
for (const rootNode of rootNodes) {
|
||||||
|
accountTree[rootNode.name] = rootNode;
|
||||||
|
}
|
||||||
const leafNodes = getListOfLeafNodes(accountTree) as AccountTreeNode[];
|
const leafNodes = getListOfLeafNodes(accountTree) as AccountTreeNode[];
|
||||||
|
|
||||||
const totalMap = leafNodes.reduce((acc, node) => {
|
const totalMap = leafNodes.reduce((acc, node) => {
|
||||||
@ -241,9 +244,9 @@ export abstract class AccountReport extends LedgerReport {
|
|||||||
// also the last day.
|
// also the last day.
|
||||||
_fixMonthsJump(refDate: DateTime, date: DateTime): DateTime {
|
_fixMonthsJump(refDate: DateTime, date: DateTime): DateTime {
|
||||||
if (refDate.day == refDate.daysInMonth && date.day != date.daysInMonth) {
|
if (refDate.day == refDate.daysInMonth && date.day != date.daysInMonth) {
|
||||||
return date.set({day: date.daysInMonth})
|
return date.set({ day: date.daysInMonth });
|
||||||
} else {
|
} else {
|
||||||
return date
|
return date;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -263,7 +266,10 @@ export abstract class AccountReport extends LedgerReport {
|
|||||||
|
|
||||||
const months: number = monthsMap[this.periodicity];
|
const months: number = monthsMap[this.periodicity];
|
||||||
const dateRanges: DateRange[] = [
|
const dateRanges: DateRange[] = [
|
||||||
{ toDate, fromDate: this._fixMonthsJump(toDate, toDate.minus({ months })) },
|
{
|
||||||
|
toDate,
|
||||||
|
fromDate: this._fixMonthsJump(toDate, toDate.minus({ months })),
|
||||||
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
let count = this.count ?? 1;
|
let count = this.count ?? 1;
|
||||||
@ -275,7 +281,10 @@ export abstract class AccountReport extends LedgerReport {
|
|||||||
const lastRange = dateRanges.at(-1)!;
|
const lastRange = dateRanges.at(-1)!;
|
||||||
dateRanges.push({
|
dateRanges.push({
|
||||||
toDate: lastRange.fromDate,
|
toDate: lastRange.fromDate,
|
||||||
fromDate: this._fixMonthsJump(toDate, lastRange.fromDate.minus({ months })),
|
fromDate: this._fixMonthsJump(
|
||||||
|
toDate,
|
||||||
|
lastRange.fromDate.minus({ months })
|
||||||
|
),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -457,13 +466,13 @@ export async function getFiscalEndpoints(
|
|||||||
const fromDate = [
|
const fromDate = [
|
||||||
fromYear,
|
fromYear,
|
||||||
(fys.getMonth() + 1).toString().padStart(2, '0'),
|
(fys.getMonth() + 1).toString().padStart(2, '0'),
|
||||||
fys.getDate().toString().padStart(2, '0')
|
fys.getDate().toString().padStart(2, '0'),
|
||||||
].join('-');
|
].join('-');
|
||||||
|
|
||||||
const toDate = [
|
const toDate = [
|
||||||
toYear,
|
toYear,
|
||||||
(fye.getMonth() + 1).toString().padStart(2, '0'),
|
(fye.getMonth() + 1).toString().padStart(2, '0'),
|
||||||
fye.getDate().toString().padStart(2, '0')
|
fye.getDate().toString().padStart(2, '0'),
|
||||||
].join('-');
|
].join('-');
|
||||||
|
|
||||||
return { fromDate, toDate };
|
return { fromDate, toDate };
|
||||||
@ -585,15 +594,17 @@ function getPrunedChildren(children: AccountTreeNode[]): AccountTreeNode[] {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export function convertAccountRootNodeToAccountList(
|
export function convertAccountRootNodesToAccountList(
|
||||||
rootNode: AccountTreeNode
|
rootNodes: AccountTreeNode[]
|
||||||
): AccountList {
|
): AccountList {
|
||||||
if (!rootNode) {
|
if (!rootNodes || rootNodes.length == 0) {
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
const accountList: AccountList = [];
|
const accountList: AccountList = [];
|
||||||
pushToAccountList(rootNode, accountList, 0);
|
for (const rootNode of rootNodes) {
|
||||||
|
pushToAccountList(rootNode, accountList, 0);
|
||||||
|
}
|
||||||
return accountList;
|
return accountList;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5,7 +5,7 @@ import {
|
|||||||
} from 'models/baseModels/Account/types';
|
} from 'models/baseModels/Account/types';
|
||||||
import {
|
import {
|
||||||
AccountReport,
|
AccountReport,
|
||||||
convertAccountRootNodeToAccountList,
|
convertAccountRootNodesToAccountList,
|
||||||
} from 'reports/AccountReport';
|
} from 'reports/AccountReport';
|
||||||
import { ReportData, RootTypeRow } from 'reports/types';
|
import { ReportData, RootTypeRow } from 'reports/types';
|
||||||
import { getMapFromList } from 'utils';
|
import { getMapFromList } from 'utils';
|
||||||
@ -44,15 +44,15 @@ export class BalanceSheet extends AccountReport {
|
|||||||
|
|
||||||
const rootTypeRows: RootTypeRow[] = this.rootTypes
|
const rootTypeRows: RootTypeRow[] = this.rootTypes
|
||||||
.map((rootType) => {
|
.map((rootType) => {
|
||||||
const rootNode = this.getRootNode(rootType, accountTree)!;
|
const rootNodes = this.getRootNodes(rootType, accountTree)!;
|
||||||
const rootList = convertAccountRootNodeToAccountList(rootNode);
|
const rootList = convertAccountRootNodesToAccountList(rootNodes);
|
||||||
return {
|
return {
|
||||||
rootType,
|
rootType,
|
||||||
rootNode,
|
rootNodes,
|
||||||
rows: this.getReportRowsFromAccountList(rootList),
|
rows: this.getReportRowsFromAccountList(rootList),
|
||||||
};
|
};
|
||||||
})
|
})
|
||||||
.filter((row) => !!row.rootNode);
|
.filter((row) => !!row.rootNodes.length);
|
||||||
|
|
||||||
this.reportData = this.getReportDataFromRows(
|
this.reportData = this.getReportDataFromRows(
|
||||||
getMapFromList(rootTypeRows, 'rootType')
|
getMapFromList(rootTypeRows, 'rootType')
|
||||||
@ -88,8 +88,8 @@ export class BalanceSheet extends AccountReport {
|
|||||||
|
|
||||||
reportData.push(...row.rows);
|
reportData.push(...row.rows);
|
||||||
|
|
||||||
if (row.rootNode) {
|
if (row.rootNodes.length) {
|
||||||
const totalNode = this.getTotalNode(row.rootNode, totalName);
|
const totalNode = this.getTotalNode(row.rootNodes, totalName);
|
||||||
const totalRow = this.getRowFromAccountListNode(totalNode);
|
const totalRow = this.getRowFromAccountListNode(totalNode);
|
||||||
reportData.push(totalRow);
|
reportData.push(totalRow);
|
||||||
}
|
}
|
||||||
|
@ -5,7 +5,7 @@ import {
|
|||||||
} from 'models/baseModels/Account/types';
|
} from 'models/baseModels/Account/types';
|
||||||
import {
|
import {
|
||||||
AccountReport,
|
AccountReport,
|
||||||
convertAccountRootNodeToAccountList,
|
convertAccountRootNodesToAccountList,
|
||||||
} from 'reports/AccountReport';
|
} from 'reports/AccountReport';
|
||||||
import {
|
import {
|
||||||
AccountListNode,
|
AccountListNode,
|
||||||
@ -45,28 +45,28 @@ export class ProfitAndLoss extends AccountReport {
|
|||||||
/**
|
/**
|
||||||
* Income Rows
|
* Income Rows
|
||||||
*/
|
*/
|
||||||
const incomeRoot = this.getRootNode(
|
const incomeRoots = this.getRootNodes(
|
||||||
AccountRootTypeEnum.Income,
|
AccountRootTypeEnum.Income,
|
||||||
accountTree
|
accountTree
|
||||||
)!;
|
)!;
|
||||||
const incomeList = convertAccountRootNodeToAccountList(incomeRoot);
|
const incomeList = convertAccountRootNodesToAccountList(incomeRoots);
|
||||||
const incomeRows = this.getReportRowsFromAccountList(incomeList);
|
const incomeRows = this.getReportRowsFromAccountList(incomeList);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Expense Rows
|
* Expense Rows
|
||||||
*/
|
*/
|
||||||
const expenseRoot = this.getRootNode(
|
const expenseRoots = this.getRootNodes(
|
||||||
AccountRootTypeEnum.Expense,
|
AccountRootTypeEnum.Expense,
|
||||||
accountTree
|
accountTree
|
||||||
)!;
|
)!;
|
||||||
const expenseList = convertAccountRootNodeToAccountList(expenseRoot);
|
const expenseList = convertAccountRootNodesToAccountList(expenseRoots);
|
||||||
const expenseRows = this.getReportRowsFromAccountList(expenseList);
|
const expenseRows = this.getReportRowsFromAccountList(expenseList);
|
||||||
|
|
||||||
this.reportData = this.getReportDataFromRows(
|
this.reportData = this.getReportDataFromRows(
|
||||||
incomeRows,
|
incomeRows,
|
||||||
expenseRows,
|
expenseRows,
|
||||||
incomeRoot,
|
incomeRoots,
|
||||||
expenseRoot
|
expenseRoots
|
||||||
);
|
);
|
||||||
this.loading = false;
|
this.loading = false;
|
||||||
}
|
}
|
||||||
@ -74,43 +74,57 @@ export class ProfitAndLoss extends AccountReport {
|
|||||||
getReportDataFromRows(
|
getReportDataFromRows(
|
||||||
incomeRows: ReportData,
|
incomeRows: ReportData,
|
||||||
expenseRows: ReportData,
|
expenseRows: ReportData,
|
||||||
incomeRoot: AccountTreeNode | undefined,
|
incomeRoots: AccountTreeNode[] | undefined,
|
||||||
expenseRoot: AccountTreeNode | undefined
|
expenseRoots: AccountTreeNode[] | undefined
|
||||||
): ReportData {
|
): ReportData {
|
||||||
if (incomeRoot && !expenseRoot) {
|
if (
|
||||||
|
incomeRoots &&
|
||||||
|
incomeRoots.length &&
|
||||||
|
!expenseRoots &&
|
||||||
|
!expenseRoots.length
|
||||||
|
) {
|
||||||
return this.getIncomeOrExpenseRows(
|
return this.getIncomeOrExpenseRows(
|
||||||
incomeRoot,
|
incomeRoots,
|
||||||
incomeRows,
|
incomeRows,
|
||||||
t`Total Income (Credit)`
|
t`Total Income (Credit)`
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (expenseRoot && !incomeRoot) {
|
if (
|
||||||
|
expenseRoots &&
|
||||||
|
expenseRoots.length &&
|
||||||
|
(!incomeRoots || !incomeRoots.length)
|
||||||
|
) {
|
||||||
return this.getIncomeOrExpenseRows(
|
return this.getIncomeOrExpenseRows(
|
||||||
expenseRoot,
|
expenseRoots,
|
||||||
expenseRows,
|
expenseRows,
|
||||||
t`Total Income (Credit)`
|
t`Total Income (Credit)`
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!incomeRoot || !expenseRoot) {
|
if (
|
||||||
|
!incomeRoots ||
|
||||||
|
!incomeRoots.length ||
|
||||||
|
!expenseRoots ||
|
||||||
|
!expenseRoots.length
|
||||||
|
) {
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
return this.getIncomeAndExpenseRows(
|
return this.getIncomeAndExpenseRows(
|
||||||
incomeRows,
|
incomeRows,
|
||||||
expenseRows,
|
expenseRows,
|
||||||
incomeRoot,
|
incomeRoots,
|
||||||
expenseRoot
|
expenseRoots
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
getIncomeOrExpenseRows(
|
getIncomeOrExpenseRows(
|
||||||
root: AccountTreeNode,
|
roots: AccountTreeNode[],
|
||||||
rows: ReportData,
|
rows: ReportData,
|
||||||
totalRowName: string
|
totalRowName: string
|
||||||
): ReportData {
|
): ReportData {
|
||||||
const total = this.getTotalNode(root, totalRowName);
|
const total = this.getTotalNode(roots, totalRowName);
|
||||||
const totalRow = this.getRowFromAccountListNode(total);
|
const totalRow = this.getRowFromAccountListNode(total);
|
||||||
|
|
||||||
return [rows, totalRow].flat();
|
return [rows, totalRow].flat();
|
||||||
@ -119,14 +133,17 @@ export class ProfitAndLoss extends AccountReport {
|
|||||||
getIncomeAndExpenseRows(
|
getIncomeAndExpenseRows(
|
||||||
incomeRows: ReportData,
|
incomeRows: ReportData,
|
||||||
expenseRows: ReportData,
|
expenseRows: ReportData,
|
||||||
incomeRoot: AccountTreeNode,
|
incomeRoots: AccountTreeNode[],
|
||||||
expenseRoot: AccountTreeNode
|
expenseRoots: AccountTreeNode[]
|
||||||
) {
|
) {
|
||||||
const totalIncome = this.getTotalNode(incomeRoot, t`Total Income (Credit)`);
|
const totalIncome = this.getTotalNode(
|
||||||
|
incomeRoots,
|
||||||
|
t`Total Income (Credit)`
|
||||||
|
);
|
||||||
const totalIncomeRow = this.getRowFromAccountListNode(totalIncome);
|
const totalIncomeRow = this.getRowFromAccountListNode(totalIncome);
|
||||||
|
|
||||||
const totalExpense = this.getTotalNode(
|
const totalExpense = this.getTotalNode(
|
||||||
expenseRoot,
|
expenseRoots,
|
||||||
t`Total Expense (Debit)`
|
t`Total Expense (Debit)`
|
||||||
);
|
);
|
||||||
const totalExpenseRow = this.getRowFromAccountListNode(totalExpense);
|
const totalExpenseRow = this.getRowFromAccountListNode(totalExpense);
|
||||||
|
@ -9,7 +9,7 @@ import {
|
|||||||
AccountReport,
|
AccountReport,
|
||||||
ACC_BAL_WIDTH,
|
ACC_BAL_WIDTH,
|
||||||
ACC_NAME_WIDTH,
|
ACC_NAME_WIDTH,
|
||||||
convertAccountRootNodeToAccountList,
|
convertAccountRootNodesToAccountList,
|
||||||
getFiscalEndpoints,
|
getFiscalEndpoints,
|
||||||
} from 'reports/AccountReport';
|
} from 'reports/AccountReport';
|
||||||
import {
|
import {
|
||||||
@ -65,15 +65,15 @@ export class TrialBalance extends AccountReport {
|
|||||||
|
|
||||||
const rootTypeRows: RootTypeRow[] = this.rootTypes
|
const rootTypeRows: RootTypeRow[] = this.rootTypes
|
||||||
.map((rootType) => {
|
.map((rootType) => {
|
||||||
const rootNode = this.getRootNode(rootType, accountTree)!;
|
const rootNodes = this.getRootNodes(rootType, accountTree)!;
|
||||||
const rootList = convertAccountRootNodeToAccountList(rootNode);
|
const rootList = convertAccountRootNodesToAccountList(rootNodes);
|
||||||
return {
|
return {
|
||||||
rootType,
|
rootType,
|
||||||
rootNode,
|
rootNodes,
|
||||||
rows: this.getReportRowsFromAccountList(rootList),
|
rows: this.getReportRowsFromAccountList(rootList),
|
||||||
};
|
};
|
||||||
})
|
})
|
||||||
.filter((row) => !!row.rootNode);
|
.filter((row) => !!(row.rootNodes && row.rootNodes.length));
|
||||||
|
|
||||||
this.reportData = await this.getReportDataFromRows(rootTypeRows);
|
this.reportData = await this.getReportDataFromRows(rootTypeRows);
|
||||||
this.loading = false;
|
this.loading = false;
|
||||||
|
@ -107,6 +107,6 @@ export type Tree = Record<string, TreeNode>;
|
|||||||
|
|
||||||
export type RootTypeRow = {
|
export type RootTypeRow = {
|
||||||
rootType: AccountRootType;
|
rootType: AccountRootType;
|
||||||
rootNode: AccountTreeNode;
|
rootNodes: AccountTreeNode[];
|
||||||
rows: ReportData;
|
rows: ReportData;
|
||||||
};
|
};
|
Loading…
Reference in New Issue
Block a user