2
0
mirror of https://github.com/frappe/books.git synced 2024-09-19 19:19:02 +00:00

Merge pull request #780 from mildred/bug-fixes

Various bug fixes
This commit is contained in:
Mildred Ki'Lya 2023-12-21 21:03:21 +01:00 committed by GitHub
commit 5e4873cda8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 93 additions and 53 deletions

View File

@ -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) => {
@ -236,6 +239,17 @@ export abstract class AccountReport extends LedgerReport {
return null; return null;
} }
// Fix arythmetic on dates when adding or substracting months. If the
// reference date was the last day in month, ensure that the resulting date is
// also the last day.
_fixMonthsJump(refDate: DateTime, date: DateTime): DateTime {
if (refDate.day == refDate.daysInMonth && date.day != date.daysInMonth) {
return date.set({ day: date.daysInMonth });
} else {
return date;
}
}
async _getDateRanges(): Promise<DateRange[]> { async _getDateRanges(): Promise<DateRange[]> {
const endpoints = await this._getFromAndToDates(); const endpoints = await this._getFromAndToDates();
const fromDate = DateTime.fromISO(endpoints.fromDate); const fromDate = DateTime.fromISO(endpoints.fromDate);
@ -252,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: toDate.minus({ months }) }, {
toDate,
fromDate: this._fixMonthsJump(toDate, toDate.minus({ months })),
},
]; ];
let count = this.count ?? 1; let count = this.count ?? 1;
@ -264,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: lastRange.fromDate.minus({ months }), fromDate: this._fixMonthsJump(
toDate,
lastRange.fromDate.minus({ months })
),
}); });
} }
@ -445,14 +465,15 @@ export async function getFiscalEndpoints(
const fromDate = [ const fromDate = [
fromYear, fromYear,
fys.toISOString().split('T')[0].split('-').slice(1), (fys.getMonth() + 1).toString().padStart(2, '0'),
] fys.getDate().toString().padStart(2, '0'),
.flat() ].join('-');
.join('-');
const toDate = [toYear, fye.toISOString().split('T')[0].split('-').slice(1)] const toDate = [
.flat() toYear,
.join('-'); (fye.getMonth() + 1).toString().padStart(2, '0'),
fye.getDate().toString().padStart(2, '0'),
].join('-');
return { fromDate, toDate }; return { fromDate, toDate };
} }
@ -573,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;
} }

View File

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

View File

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

View File

@ -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;

View File

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