diff --git a/packages/desktop-client/src/components/settings/FixSplits.tsx b/packages/desktop-client/src/components/settings/FixSplits.tsx index 2897ee431a0..fa87cecfee8 100644 --- a/packages/desktop-client/src/components/settings/FixSplits.tsx +++ b/packages/desktop-client/src/components/settings/FixSplits.tsx @@ -1,5 +1,5 @@ import React, { useState } from 'react'; -import { useTranslation } from 'react-i18next'; +import { useTranslation, Trans } from 'react-i18next'; import { send } from 'loot-core/src/platform/client/fetch'; import { type Handlers } from 'loot-core/src/types/handlers'; @@ -14,53 +14,85 @@ import { Setting } from './UI'; type Results = Awaited>; -function renderResults(results: Results) { - const { numBlankPayees, numCleared, numDeleted } = results; - let result = ''; +function useRenderResults() { + const { t } = useTranslation(); - if (numBlankPayees === 0 && numCleared === 0 && numDeleted === 0) { - result = 'No split transactions found needing repair.'; - } else { - if (numBlankPayees > 0) { - result += `Fixed ${numBlankPayees} splits with a blank payee.`; - } - if (numCleared > 0) { - if (result !== '') { - result += '\n'; + function renderResults(results: Results) { + const { numBlankPayees, numCleared, numDeleted, mismatchedSplits } = + results; + const result: string[] = []; + + if ( + numBlankPayees === 0 && + numCleared === 0 && + numDeleted === 0 && + mismatchedSplits.length === 0 + ) { + result.push(t('No split transactions found needing repair.')); + } else { + if (numBlankPayees > 0) { + result.push( + t('Fixed {{count}} splits with a blank payee.', { + count: numBlankPayees, + }), + ); } - result += `Fixed ${numCleared} splits with the wrong cleared flag.`; - } - if (numDeleted > 0) { - if (result !== '') { - result += '\n'; + if (numCleared > 0) { + result.push( + t('Fixed {{count}} splits with the wrong cleared flag.', { + count: numCleared, + }), + ); + } + if (numDeleted > 0) { + result.push( + t('Fixed {{count}} splits that weren’t properly deleted.', { + count: numDeleted, + }), + ); + } + if (mismatchedSplits.length > 0) { + const mismatchedSplitInfo = mismatchedSplits + .map(t => `- ${t.date}`) + .join('\n'); + + result.push( + t( + 'Found {{count}} split transactions with mismatched amounts on the below dates. Please review them manually:', + { count: mismatchedSplits.length }, + ) + `\n${mismatchedSplitInfo}`, + ); } - result += `Fixed ${numDeleted} splits that weren’t properly deleted.`; } + + return ( + + {result.join('\n')} + + ); } - return ( - - {result} - - ); + return { renderResults }; } export function FixSplits() { - const { t } = useTranslation(); const [loading, setLoading] = useState(false); const [results, setResults] = useState(null); + const { renderResults } = useRenderResults(); + async function onFix() { setLoading(true); const res = await send('tools/fix-split-transactions'); + setResults(res); setLoading(false); } @@ -70,38 +102,46 @@ export function FixSplits() { primaryAction={ - {t('Repair split transactions')} + Repair split transactions {results && renderResults(results)} } > - - {t('Repair split transactions')} - {t( - ' if you are experiencing bugs relating to split transactions and the “Reset budget cache” button above does not help, this tool may fix them. Some examples of bugs include seeing blank payees on splits or incorrect account balances. This tool does two things:', - )} - - + + + Repair split transactions if you are experiencing + bugs relating to split transactions and the “Reset budget cache” + button above does not help, this tool may fix them. Some examples of + bugs include seeing blank payees on splits or incorrect account + balances. This tool does three things: + +
    +
  • + Ensures that deleted split transactions are fully deleted. In + previous versions of the app, certain split transactions may appear + deleted but not all of them are actually deleted. This causes the + transactions list to look correct, but certain balances may be + incorrect when filtering. +
  • +
  • + Sync the payee and cleared flag of a split transaction to the main + or “parent” transaction, if appropriate. The payee will only be set + if it currently doesn’t have one. +
  • +
  • + Checks that the sum of all child transactions adds up to the total + amount. If not, these will be flagged below to allow you to easily + locate and fix the amounts. +
  • +
+
); } diff --git a/packages/loot-core/src/server/tools/app.ts b/packages/loot-core/src/server/tools/app.ts index 31b48447a83..95cb254f9f3 100644 --- a/packages/loot-core/src/server/tools/app.ts +++ b/packages/loot-core/src/server/tools/app.ts @@ -1,6 +1,8 @@ // @ts-strict-ignore +import { q } from '../../shared/query'; import { batchUpdateTransactions } from '../accounts/transactions'; import { createApp } from '../app'; +import { runQuery } from '../aql'; import * as db from '../db'; import { runMutator } from '../mutators'; @@ -54,9 +56,27 @@ app.method('tools/fix-split-transactions', async () => { await batchUpdateTransactions({ updated }); }); + const splitTransactions = ( + await runQuery( + q('transactions') + .options({ splits: 'grouped' }) + .filter({ + is_parent: true, + }) + .select('*'), + ) + ).data; + + const mismatchedSplits = splitTransactions.filter(t => { + const subValue = t.subtransactions.reduce((acc, st) => acc + st.amount, 0); + + return subValue !== t.amount; + }); + return { numBlankPayees: blankPayeeRows.length, numCleared: clearedRows.length, numDeleted: deletedRows.length, + mismatchedSplits, }; }); diff --git a/packages/loot-core/src/server/tools/types/handlers.d.ts b/packages/loot-core/src/server/tools/types/handlers.d.ts index 841db08c084..8a31465a369 100644 --- a/packages/loot-core/src/server/tools/types/handlers.d.ts +++ b/packages/loot-core/src/server/tools/types/handlers.d.ts @@ -1,7 +1,10 @@ +import { TransactionEntity } from './models'; + export interface ToolsHandlers { 'tools/fix-split-transactions': () => Promise<{ numBlankPayees: number; numCleared: number; numDeleted: number; + mismatchedSplits: TransactionEntity[]; }>; } diff --git a/upcoming-release-notes/3970.md b/upcoming-release-notes/3970.md new file mode 100644 index 00000000000..ec541471f6b --- /dev/null +++ b/upcoming-release-notes/3970.md @@ -0,0 +1,6 @@ +--- +category: Enhancements +authors: [matt-fidd] +--- + +Extend fix splits tool to report splits with mismatched amounts