From fc6eb4be33b759b16b414ae24de33124d57e20e6 Mon Sep 17 00:00:00 2001 From: Neil <55785687+carkom@users.noreply.github.com> Date: Tue, 11 Jul 2023 20:19:50 +0100 Subject: [PATCH] Add transfers to CashFlow Report (#1311) --- .../src/components/reports/CashFlow.js | 14 ++++- .../reports/graphs/cash-flow-spreadsheet.tsx | 57 +++++++++++-------- .../src/components/reports/util.js | 18 ++++-- upcoming-release-notes/1311.md | 6 ++ 4 files changed, 66 insertions(+), 29 deletions(-) create mode 100644 upcoming-release-notes/1311.md diff --git a/packages/desktop-client/src/components/reports/CashFlow.js b/packages/desktop-client/src/components/reports/CashFlow.js index 5c5f652c5..07d4a21c6 100644 --- a/packages/desktop-client/src/components/reports/CashFlow.js +++ b/packages/desktop-client/src/components/reports/CashFlow.js @@ -87,7 +87,7 @@ function CashFlow() { return null; } - const { graphData, totalExpenses, totalIncome } = data; + const { graphData, totalExpenses, totalIncome, totalTransfers } = data; return ( <View style={[styles.page, { minWidth: 650, overflow: 'hidden' }]}> @@ -142,8 +142,18 @@ function CashFlow() { </Text> } /> + + <AlignedText + style={{ marginBottom: 5, minWidth: 160 }} + left={<Block>Transfers:</Block>} + right={ + <Text style={{ fontWeight: 600 }}> + {integerToCurrency(totalTransfers)} + </Text> + } + /> <Text style={{ fontWeight: 600 }}> - <Change amount={totalIncome + totalExpenses} /> + <Change amount={totalIncome + totalExpenses + totalTransfers} /> </Text> </View> diff --git a/packages/desktop-client/src/components/reports/graphs/cash-flow-spreadsheet.tsx b/packages/desktop-client/src/components/reports/graphs/cash-flow-spreadsheet.tsx index b3623f6f2..c42734ed7 100644 --- a/packages/desktop-client/src/components/reports/graphs/cash-flow-spreadsheet.tsx +++ b/packages/desktop-client/src/components/reports/graphs/cash-flow-spreadsheet.tsx @@ -8,7 +8,7 @@ import * as monthUtils from 'loot-core/src/shared/months'; import { integerToCurrency, integerToAmount } from 'loot-core/src/shared/util'; import { AlignedText } from '../../common'; -import { fromDateRepr, fromDateReprToDay, runAll, index } from '../util'; +import { runAll, indexCashFlow } from '../util'; export function simpleCashFlow(start, end) { return async (spreadsheet, setData) => { @@ -68,26 +68,25 @@ export function cashFlowByDate( { date: { $transform: '$month', $lte: end } }, ], 'account.offbudget': false, - $or: [ - { - 'payee.transfer_acct.offbudget': true, - 'payee.transfer_acct': null, - }, - ], }); if (isConcise) { return query - .groupBy({ $month: '$date' }) + .groupBy([{ $month: '$date' }, 'payee.transfer_acct']) .select([ { date: { $month: '$date' } }, + { isTransfer: 'payee.transfer_acct' }, { amount: { $sum: '$amount' } }, ]); } return query - .groupBy('date') - .select(['date', { amount: { $sum: '$amount' } }]); + .groupBy(['date', 'payee.transfer_acct']) + .select([ + 'date', + { isTransfer: 'payee.transfer_acct' }, + { amount: { $sum: '$amount' } }, + ]); } return runAll( @@ -111,41 +110,46 @@ export function cashFlowByDate( function recalculate(data, start, end, isConcise) { let [startingBalance, income, expense] = data; + let convIncome = income.map(t => { + return { ...t, isTransfer: t.isTransfer !== null }; + }); + let convExpense = expense.map(t => { + return { ...t, isTransfer: t.isTransfer !== null }; + }); const dates = isConcise ? monthUtils.rangeInclusive( monthUtils.getMonth(start), monthUtils.getMonth(end), ) : monthUtils.dayRangeInclusive(start, end); - const incomes = index( - income, - 'date', - isConcise ? fromDateRepr : fromDateReprToDay, - ); - const expenses = index( - expense, - 'date', - isConcise ? fromDateRepr : fromDateReprToDay, - ); + const incomes = indexCashFlow(convIncome, 'date', 'isTransfer'); + const expenses = indexCashFlow(convExpense, 'date', 'isTransfer'); let balance = startingBalance; let totalExpenses = 0; let totalIncome = 0; + let totalTransfers = 0; + const graphData = dates.reduce( (res, date) => { let income = 0; let expense = 0; + let creditTransfers = 0; + let debitTransfers = 0; if (incomes[date]) { - income = incomes[date].amount; + income = !incomes[date].false ? 0 : incomes[date].false; + creditTransfers = !incomes[date].true ? 0 : incomes[date].true; } if (expenses[date]) { - expense = expenses[date].amount; + expense = !expenses[date].false ? 0 : expenses[date].false; + debitTransfers = !expenses[date].true ? 0 : expenses[date].true; } totalExpenses += expense; totalIncome += income; - balance += income + expense; + balance += income + expense + creditTransfers + debitTransfers; + totalTransfers += creditTransfers + debitTransfers; const x = d.parseISO(date); const label = ( @@ -162,6 +166,12 @@ function recalculate(data, start, end, isConcise) { left="Change:" right={<strong>{integerToCurrency(income + expense)}</strong>} /> + {creditTransfers + debitTransfers !== 0 && ( + <AlignedText + left="Transfers:" + right={integerToCurrency(creditTransfers + debitTransfers)} + /> + )} <AlignedText left="Balance:" right={integerToCurrency(balance)} /> </div> </div> @@ -187,6 +197,7 @@ function recalculate(data, start, end, isConcise) { balance: balances[balances.length - 1].amount, totalExpenses, totalIncome, + totalTransfers, totalChange: balances[balances.length - 1].amount - balances[0].amount, }; } diff --git a/packages/desktop-client/src/components/reports/util.js b/packages/desktop-client/src/components/reports/util.js index 9cd905366..ac7bc5e84 100644 --- a/packages/desktop-client/src/components/reports/util.js +++ b/packages/desktop-client/src/components/reports/util.js @@ -4,10 +4,6 @@ export function fromDateRepr(date) { return date.slice(0, 7); } -export function fromDateReprToDay(date) { - return date; -} - export async function runAll(queries, cb) { let data = await Promise.all( queries.map(q => { @@ -24,3 +20,17 @@ export function index(data, field, mapper) { }); return result; } + +export function indexCashFlow(data, date, isTransfer) { + const results = {}; + data.forEach(item => { + let findExisting = results[item.date] + ? results[item.date][item.xfer] + ? results[item.date][item.xfer] + : 0 + : 0; + let result = { [item[isTransfer]]: item.amount + findExisting }; + results[item[date]] = { ...results[item[date]], ...result }; + }); + return results; +} diff --git a/upcoming-release-notes/1311.md b/upcoming-release-notes/1311.md new file mode 100644 index 000000000..0a55f7beb --- /dev/null +++ b/upcoming-release-notes/1311.md @@ -0,0 +1,6 @@ +--- +category: Bugfix +authors: [carkom] +--- + +The cashflow report filters out transfers which makes the ending balance inaccurate (and variable depending on when the tranfers land). I've added transfers into the report and split them out from the totals. \ No newline at end of file -- GitLab