diff --git a/packages/desktop-client/src/components/banksync/AccountsList.tsx b/packages/desktop-client/src/components/banksync/AccountsList.tsx index 4bff9360ac4..49469a38e13 100644 --- a/packages/desktop-client/src/components/banksync/AccountsList.tsx +++ b/packages/desktop-client/src/components/banksync/AccountsList.tsx @@ -24,7 +24,11 @@ export function AccountsList({ } return ( - + {accounts.map(account => { const hovered = hoveredAccount === account.id; diff --git a/packages/desktop-client/src/components/banksync/index.tsx b/packages/desktop-client/src/components/banksync/index.tsx index 021bca870a4..6eb1b8f3d27 100644 --- a/packages/desktop-client/src/components/banksync/index.tsx +++ b/packages/desktop-client/src/components/banksync/index.tsx @@ -116,7 +116,7 @@ export function BankSync() { )} {Object.entries(groupedAccounts).map(([syncProvider, accounts]) => { return ( - + {Object.keys(groupedAccounts).length > 1 && ( Link a European bank account {' '} - to automatically download transactions. - - - GoCardless provides reliable, up-to-date information - from hundreds of banks. + to automatically download transactions. GoCardless + provides reliable, up-to-date information from + hundreds of banks. Link a North American bank account {' '} - to automatically download transactions. - - - SimpleFIN provides reliable, up-to-date information - from hundreds of banks. + to automatically download transactions. SimpleFIN + provides reliable, up-to-date information from + hundreds of banks. {isPluggyAiEnabled && ( diff --git a/packages/desktop-client/src/components/transactions/TransactionList.jsx b/packages/desktop-client/src/components/transactions/TransactionList.jsx index 3bbf25cc328..c404ffbfdc1 100644 --- a/packages/desktop-client/src/components/transactions/TransactionList.jsx +++ b/packages/desktop-client/src/components/transactions/TransactionList.jsx @@ -220,7 +220,7 @@ export function TransactionList({ const onManagePayees = useCallback( id => { - navigate('/payees', { state: { selectedPayee: id } }); + navigate('/payees', id && { state: { selectedPayee: id } }); }, [navigate], ); diff --git a/packages/desktop-client/src/components/transactions/TransactionsTable.jsx b/packages/desktop-client/src/components/transactions/TransactionsTable.jsx index 79dc8a70e66..8312f63b682 100644 --- a/packages/desktop-client/src/components/transactions/TransactionsTable.jsx +++ b/packages/desktop-client/src/components/transactions/TransactionsTable.jsx @@ -1861,6 +1861,7 @@ function TransactionTableInner({ : trans.error; const hasSplitError = + (trans.is_parent || trans.is_child) && (!expanded || isLastChild(transactions, index)) && error && error.type === 'SplitTransactionError'; diff --git a/packages/loot-core/src/client/data-hooks/transactions.ts b/packages/loot-core/src/client/data-hooks/transactions.ts index 8fc9abf6888..9099f9bae30 100644 --- a/packages/loot-core/src/client/data-hooks/transactions.ts +++ b/packages/loot-core/src/client/data-hooks/transactions.ts @@ -317,6 +317,7 @@ export function useTransactionsSearch({ resetQuery(); setIsSearching(false); } else if (searchText) { + resetQuery(); updateQuery(previousQuery => queries.transactionsSearch(previousQuery, searchText, dateFormat), ); diff --git a/packages/loot-core/src/server/accounts/app.ts b/packages/loot-core/src/server/accounts/app.ts index a4513d19d8a..1150b5a2694 100644 --- a/packages/loot-core/src/server/accounts/app.ts +++ b/packages/loot-core/src/server/accounts/app.ts @@ -744,13 +744,13 @@ type SyncResponse = { updatedAccounts: Array; }; -function handleSyncResponse( +async function handleSyncResponse( res: { added: Array; updated: Array; }, acct: db.DbAccount, -): SyncResponse { +): Promise { const { added, updated } = res; const newTransactions: Array = []; const matchedTransactions: Array = []; @@ -763,6 +763,9 @@ function handleSyncResponse( updatedAccounts.push(acct.id); } + const ts = new Date().getTime().toString(); + await db.update('accounts', { id: acct.id, last_sync: ts }); + return { newTransactions, matchedTransactions, @@ -861,7 +864,7 @@ async function accountsBankSync({ acct.bankId, ); - const syncResponseData = handleSyncResponse(syncResponse, acct); + const syncResponseData = await handleSyncResponse(syncResponse, acct); newTransactions.push(...syncResponseData.newTransactions); matchedTransactions.push(...syncResponseData.matchedTransactions); @@ -964,7 +967,10 @@ async function simpleFinBatchSync({ ), ); } else { - const syncResponseData = handleSyncResponse(syncResponse.res, account); + const syncResponseData = await handleSyncResponse( + syncResponse.res, + account, + ); newTransactions.push(...syncResponseData.newTransactions); matchedTransactions.push(...syncResponseData.matchedTransactions); diff --git a/packages/loot-core/src/server/budget/cleanup-template.ts b/packages/loot-core/src/server/budget/cleanup-template.ts index 8c1b109212c..7b0dd8536e9 100644 --- a/packages/loot-core/src/server/budget/cleanup-template.ts +++ b/packages/loot-core/src/server/budget/cleanup-template.ts @@ -284,7 +284,7 @@ async function processCleanup(month: string): Promise { } const budgetAvailable = await getSheetValue(sheetName, `to-budget`); - if (budgetAvailable <= 0) { + if (budgetAvailable < 0) { warnings.push('Global: No funds are available to reallocate.'); } @@ -351,6 +351,11 @@ async function processCleanup(month: string): Promise { message: 'Global: Funds not available:', pre: warnings.join('\n\n'), }; + } else if (budgetAvailable === 0) { + return { + type: 'message', + message: 'All categories were up to date.', + }; } else { return { type: 'message', diff --git a/packages/loot-core/src/shared/transactions.test.ts b/packages/loot-core/src/shared/transactions.test.ts index 7b0c6969723..e083bcb126f 100644 --- a/packages/loot-core/src/shared/transactions.test.ts +++ b/packages/loot-core/src/shared/transactions.test.ts @@ -206,4 +206,23 @@ describe('Transactions', () => { expect.objectContaining({ amount: 3002 }), ]); }); + + test('deleting all child split transactions works', () => { + const transactions = [ + makeTransaction({ amount: 2001 }), + ...makeSplitTransaction( + { id: 't1', amount: 2500, error: splitError(500) }, + [{ id: 't2', amount: 2000 }], + ), + makeTransaction({ amount: 3002 }), + ]; + const { data } = deleteTransaction(transactions, 't2'); + + expect(data).toEqual([ + expect.objectContaining({ amount: 2001 }), + // Must delete error if no children + expect.objectContaining({ amount: 2500, error: null }), + expect.objectContaining({ amount: 3002 }), + ]); + }); }); diff --git a/packages/loot-core/src/shared/transactions.ts b/packages/loot-core/src/shared/transactions.ts index 6142640bce7..afd3b7229c7 100644 --- a/packages/loot-core/src/shared/transactions.ts +++ b/packages/loot-core/src/shared/transactions.ts @@ -282,10 +282,11 @@ export function deleteTransaction( if (trans.id === id) { return null; } else if (trans.subtransactions?.length === 1) { - const { error, subtransactions, ...rest } = trans; + const { subtransactions, ...rest } = trans; return { ...rest, is_parent: false, + error: null, } satisfies TransactionEntity; } else { const sub = trans.subtransactions?.filter(t => t.id !== id); diff --git a/upcoming-release-notes/4458.md b/upcoming-release-notes/4458.md new file mode 100644 index 00000000000..bc9c01dd22e --- /dev/null +++ b/upcoming-release-notes/4458.md @@ -0,0 +1,6 @@ +--- +category: Bugfix +authors: [matt-fidd] +--- + +Fix row spacing on bank sync page diff --git a/upcoming-release-notes/4461.md b/upcoming-release-notes/4461.md new file mode 100644 index 00000000000..3585daf99ee --- /dev/null +++ b/upcoming-release-notes/4461.md @@ -0,0 +1,6 @@ +--- +category: Bugfix +authors: [alecbakholdin] +--- + +Fixed bug where partially erasing search string would not reset search and result in incorrect search results. diff --git a/upcoming-release-notes/4462.md b/upcoming-release-notes/4462.md new file mode 100644 index 00000000000..754d56e9d2b --- /dev/null +++ b/upcoming-release-notes/4462.md @@ -0,0 +1,6 @@ +--- +category: Bugfix +authors: [alecbakholdin] +--- + +Fixed bug where navigating to payees page by clicking "manage payees" with an empty payee from a transaction would result in a crash. diff --git a/upcoming-release-notes/4463.md b/upcoming-release-notes/4463.md new file mode 100644 index 00000000000..269cb823909 --- /dev/null +++ b/upcoming-release-notes/4463.md @@ -0,0 +1,6 @@ +--- +category: Bugfix +authors: [jfdoming] +--- + +Add missing space in translation for bank sync diff --git a/upcoming-release-notes/4465.md b/upcoming-release-notes/4465.md new file mode 100644 index 00000000000..869cc6b2e38 --- /dev/null +++ b/upcoming-release-notes/4465.md @@ -0,0 +1,6 @@ +--- +category: Bugfix +authors: [jfdoming] +--- + +Fix crash when deleting child transactions from an errored split diff --git a/upcoming-release-notes/4468.md b/upcoming-release-notes/4468.md new file mode 100644 index 00000000000..4687a359388 --- /dev/null +++ b/upcoming-release-notes/4468.md @@ -0,0 +1,6 @@ +--- +category: Bugfix +authors: [youngcw] +--- + +Remove warning on cleanup templates if budget is already "clean" diff --git a/upcoming-release-notes/4469.md b/upcoming-release-notes/4469.md new file mode 100644 index 00000000000..c2e4143ec51 --- /dev/null +++ b/upcoming-release-notes/4469.md @@ -0,0 +1,6 @@ +--- +category: Bugfix +authors: [matt-fidd] +--- + +Fix category group deletion on mobile diff --git a/upcoming-release-notes/4472.md b/upcoming-release-notes/4472.md new file mode 100644 index 00000000000..210b6ae75c0 --- /dev/null +++ b/upcoming-release-notes/4472.md @@ -0,0 +1,6 @@ +--- +category: Bugfix +authors: [matt-fidd] +--- + +Add last bank sync tracking back in