diff --git a/packages/desktop-client/src/components/accounts/Account.jsx b/packages/desktop-client/src/components/accounts/Account.jsx index ef660cbefce460cf966c83b54ef505a0e681241a..3f62365ade3f2c61ccf6b30108645d2fdb1d5966 100644 --- a/packages/desktop-client/src/components/accounts/Account.jsx +++ b/packages/desktop-client/src/components/accounts/Account.jsx @@ -7,7 +7,10 @@ import { v4 as uuidv4 } from 'uuid'; import { validForTransfer } from 'loot-core/client/transfer'; import { useFilters } from 'loot-core/src/client/data-hooks/filters'; -import { SchedulesProvider } from 'loot-core/src/client/data-hooks/schedules'; +import { + SchedulesProvider, + useDefaultSchedulesQueryTransform, +} from 'loot-core/src/client/data-hooks/schedules'; import * as queries from 'loot-core/src/client/queries'; import { runQuery, pagedQuery } from 'loot-core/src/client/query-helpers'; import { send, listen } from 'loot-core/src/platform/client/fetch'; @@ -1837,29 +1840,7 @@ export function Account() { const savedFiters = useFilters(); const actionCreators = useActions(); - const transform = useMemo(() => { - const filterByAccount = queries.getAccountFilter(params.id, '_account'); - const filterByPayee = queries.getAccountFilter( - params.id, - '_payee.transfer_acct', - ); - - return q => { - q = q.filter({ - $and: [{ '_account.closed': false }], - }); - if (params.id) { - if (params.id === 'uncategorized') { - q = q.filter({ next_date: null }); - } else { - q = q.filter({ - $or: [filterByAccount, filterByPayee], - }); - } - } - return q.orderBy({ next_date: 'desc' }); - }; - }, [params.id]); + const transform = useDefaultSchedulesQueryTransform(params.id); return ( <SchedulesProvider transform={transform}> diff --git a/packages/desktop-client/src/components/mobile/accounts/AccountTransactions.jsx b/packages/desktop-client/src/components/mobile/accounts/AccountTransactions.jsx index cf01dba15ee2c4d5e65c039a7075572585496423..4711d0523c6a9dff7aebb7ea894facad46c96471 100644 --- a/packages/desktop-client/src/components/mobile/accounts/AccountTransactions.jsx +++ b/packages/desktop-client/src/components/mobile/accounts/AccountTransactions.jsx @@ -7,7 +7,6 @@ import React, { } from 'react'; import { useDispatch } from 'react-redux'; -import memoizeOne from 'memoize-one'; import { useDebounceCallback } from 'usehooks-ts'; import { @@ -20,7 +19,10 @@ import { syncAndDownload, updateAccount, } from 'loot-core/client/actions'; -import { SchedulesProvider } from 'loot-core/client/data-hooks/schedules'; +import { + SchedulesProvider, + useDefaultSchedulesQueryTransform, +} from 'loot-core/client/data-hooks/schedules'; import * as queries from 'loot-core/client/queries'; import { pagedQuery } from 'loot-core/client/query-helpers'; import { listen, send } from 'loot-core/platform/client/fetch'; @@ -39,6 +41,7 @@ import { AddTransactionButton } from '../transactions/AddTransactionButton'; import { TransactionListWithBalances } from '../transactions/TransactionListWithBalances'; export function AccountTransactions({ account, pending, failed }) { + const schedulesTransform = useDefaultSchedulesQueryTransform(account.id); return ( <Page header={ @@ -52,7 +55,7 @@ export function AccountTransactions({ account, pending, failed }) { } padding={0} > - <SchedulesProvider transform={getSchedulesTransform(account.id)}> + <SchedulesProvider transform={schedulesTransform}> <TransactionListWithPreviews account={account} /> </SchedulesProvider> </Page> @@ -132,15 +135,6 @@ function AccountName({ account, pending, failed }) { ); } -const getSchedulesTransform = memoizeOne(id => { - const filter = queries.getAccountFilter(id, '_account'); - - return q => { - q = q.filter({ $and: [filter, { '_account.closed': false }] }); - return q.orderBy({ next_date: 'desc' }); - }; -}); - function TransactionListWithPreviews({ account }) { const [currentQuery, setCurrentQuery] = useState(); const [isSearching, setIsSearching] = useState(false); diff --git a/packages/desktop-client/src/components/transactions/TransactionsTable.jsx b/packages/desktop-client/src/components/transactions/TransactionsTable.jsx index d3225f37192ba9bb72c0dd6583b59affce9bd113..f0880f907de9c7f39414cc1776860282e75cfa9a 100644 --- a/packages/desktop-client/src/components/transactions/TransactionsTable.jsx +++ b/packages/desktop-client/src/components/transactions/TransactionsTable.jsx @@ -604,17 +604,17 @@ function PayeeIcons({ transferAccount, onNavigateToTransferAccount, onNavigateToSchedule, - children, }) { const scheduleId = transaction.schedule; const scheduleData = useCachedSchedules(); - const schedule = scheduleData - ? scheduleData.schedules.find(s => s.id === scheduleId) - : null; + const schedule = + scheduleId && scheduleData + ? scheduleData.schedules.find(s => s.id === scheduleId) + : null; if (schedule == null && transferAccount == null) { // Neither a valid scheduled transaction nor a transfer. - return children; + return null; } const buttonStyle = { diff --git a/packages/loot-core/migrations/1720310586000_link_transfer_schedules.sql b/packages/loot-core/migrations/1720310586000_link_transfer_schedules.sql new file mode 100644 index 0000000000000000000000000000000000000000..f1f6e11d48a2c449328472a7fa26638164ffd437 --- /dev/null +++ b/packages/loot-core/migrations/1720310586000_link_transfer_schedules.sql @@ -0,0 +1,19 @@ +BEGIN TRANSACTION; + +UPDATE transactions AS t1 +SET schedule = ( + SELECT t2.schedule FROM transactions AS t2 + WHERE t2.id = t1.transferred_id + AND t2.schedule IS NOT NULL + LIMIT 1 +) +WHERE t1.schedule IS NULL +AND t1.transferred_id IS NOT NULL +AND EXISTS ( + SELECT 1 FROM transactions AS t2 + WHERE t2.id = t1.transferred_id + AND t2.schedule IS NOT NULL + LIMIT 1 +); + +COMMIT; diff --git a/packages/loot-core/src/client/data-hooks/schedules.tsx b/packages/loot-core/src/client/data-hooks/schedules.tsx index 2f6117dea84da4984e0b5dd33fc328185989ea6a..5c18d877906e865d39a3d5ca6a9b4644d42673a8 100644 --- a/packages/loot-core/src/client/data-hooks/schedules.tsx +++ b/packages/loot-core/src/client/data-hooks/schedules.tsx @@ -1,9 +1,16 @@ // @ts-strict-ignore -import React, { createContext, useEffect, useState, useContext } from 'react'; +import React, { + createContext, + useEffect, + useState, + useContext, + useMemo, +} from 'react'; import { q, type Query } from '../../shared/query'; import { getStatus, getHasTransactionsQuery } from '../../shared/schedules'; import { type ScheduleEntity } from '../../types/models'; +import { getAccountFilter } from '../queries'; import { liveQuery } from '../query-helpers'; export type ScheduleStatusType = ReturnType<typeof getStatus>; @@ -84,3 +91,26 @@ export function SchedulesProvider({ transform, children }) { export function useCachedSchedules() { return useContext(SchedulesContext); } + +export function useDefaultSchedulesQueryTransform(accountId) { + return useMemo(() => { + const filterByAccount = getAccountFilter(accountId, '_account'); + const filterByPayee = getAccountFilter(accountId, '_payee.transfer_acct'); + + return (q: Query) => { + q = q.filter({ + $and: [{ '_account.closed': false }], + }); + if (accountId) { + if (accountId === 'uncategorized') { + q = q.filter({ next_date: null }); + } else { + q = q.filter({ + $or: [filterByAccount, filterByPayee], + }); + } + } + return q.orderBy({ next_date: 'desc' }); + }; + }, [accountId]); +} diff --git a/packages/loot-core/src/server/accounts/transfer.ts b/packages/loot-core/src/server/accounts/transfer.ts index f3c41e4346b73ccaa0ad1acff2d9cbea1261f46b..04545bf78533136be6eb52d37b374b96a57458e7 100644 --- a/packages/loot-core/src/server/accounts/transfer.ts +++ b/packages/loot-core/src/server/accounts/transfer.ts @@ -80,6 +80,7 @@ export async function addTransfer(transaction, transferredAccount) { date: transaction.date, transfer_id: transaction.id, notes: transaction.notes || null, + schedule: transaction.schedule, cleared: false, }); @@ -130,6 +131,7 @@ export async function updateTransfer(transaction, transferredAccount) { date: transaction.date, notes: transaction.notes, amount: -transaction.amount, + schedule: transaction.schedule, }); const categoryCleared = await clearCategory(transaction, transferredAccount); diff --git a/upcoming-release-notes/2990.md b/upcoming-release-notes/2990.md new file mode 100644 index 0000000000000000000000000000000000000000..17da167567ac7dd9dfa58a6f1e18a6ab5a9ab3f1 --- /dev/null +++ b/upcoming-release-notes/2990.md @@ -0,0 +1,6 @@ +--- +category: Bugfix +authors: [joel-jeremy] +--- + +Assign schedule to both transactions if schedule is a transfer