diff --git a/packages/desktop-client/e2e/rules.test.js-snapshots/Rules-creates-a-split-transaction-rule-and-makes-sure-it-is-applied-when-creating-a-transaction-3-chromium-linux.png b/packages/desktop-client/e2e/rules.test.js-snapshots/Rules-creates-a-split-transaction-rule-and-makes-sure-it-is-applied-when-creating-a-transaction-3-chromium-linux.png index 7490e7d3318415efa6680634f50a629830804b4c..b6bd1b7d2876b6fbf07c0babec89d5fb4de32021 100644 Binary files a/packages/desktop-client/e2e/rules.test.js-snapshots/Rules-creates-a-split-transaction-rule-and-makes-sure-it-is-applied-when-creating-a-transaction-3-chromium-linux.png and b/packages/desktop-client/e2e/rules.test.js-snapshots/Rules-creates-a-split-transaction-rule-and-makes-sure-it-is-applied-when-creating-a-transaction-3-chromium-linux.png differ diff --git a/packages/desktop-client/src/components/table.tsx b/packages/desktop-client/src/components/table.tsx index 81516a418db02f684c4460aab7521b89440939c0..b354c6b3536c20befd7409cf8875ee765adac140 100644 --- a/packages/desktop-client/src/components/table.tsx +++ b/packages/desktop-client/src/components/table.tsx @@ -325,6 +325,12 @@ function InputValue({ ...props }: InputValueProps) { const [value, setValue] = useState(defaultValue); + const [prevDefaultValue, setPrevDefaultValue] = useState(defaultValue); + + if (prevDefaultValue !== defaultValue) { + setValue(defaultValue); + setPrevDefaultValue(defaultValue); + } function onBlur_(e) { if (onBlur) { diff --git a/packages/desktop-client/src/components/transactions/TransactionList.jsx b/packages/desktop-client/src/components/transactions/TransactionList.jsx index 95c6e66fb5f262cb42b3c391ab24f6be6c47a189..137cc61bc5ffc2222e4ee0697886919836659c2b 100644 --- a/packages/desktop-client/src/components/transactions/TransactionList.jsx +++ b/packages/desktop-client/src/components/transactions/TransactionList.jsx @@ -137,25 +137,44 @@ export function TransactionList({ return changes.diff.added[0].id; }, []); - const onApplyRules = useCallback(async transaction => { - const afterRules = await send('rules-run', { transaction }); - const diff = getChangedValues(transaction, afterRules); - - const newTransaction = { ...transaction }; - if (diff) { - Object.keys(diff).forEach(field => { + const onApplyRules = useCallback( + async (transaction, updatedFieldName = null) => { + const afterRules = await send('rules-run', { transaction }); + const diff = getChangedValues(transaction, afterRules); + + const newTransaction = { ...transaction }; + if (diff) { + Object.keys(diff).forEach(field => { + if ( + newTransaction[field] == null || + newTransaction[field] === '' || + newTransaction[field] === 0 || + newTransaction[field] === false + ) { + newTransaction[field] = diff[field]; + } + }); + + // When a rule updates a parent transaction, overwrite all changes to the current field in subtransactions. if ( - newTransaction[field] == null || - newTransaction[field] === '' || - newTransaction[field] === 0 || - newTransaction[field] === false + transaction.is_parent && + diff.subtransactions !== undefined && + updatedFieldName !== null ) { - newTransaction[field] = diff[field]; + newTransaction.subtransactions = diff.subtransactions.map( + (st, idx) => ({ + ...(newTransaction.subtransactions[idx] || st), + ...(st[updatedFieldName] != null && { + [updatedFieldName]: st[updatedFieldName], + }), + }), + ); } - }); - } - return newTransaction; - }, []); + } + return newTransaction; + }, + [], + ); const onManagePayees = useCallback(id => { navigate('/payees', { state: { selectedPayee: id } }); diff --git a/packages/desktop-client/src/components/transactions/TransactionsTable.jsx b/packages/desktop-client/src/components/transactions/TransactionsTable.jsx index 3633f8fa9b0e18ecb1da942232a7c3877859ef01..b860929876c1625ae1cea82b874fbde57f2603b0 100644 --- a/packages/desktop-client/src/components/transactions/TransactionsTable.jsx +++ b/packages/desktop-client/src/components/transactions/TransactionsTable.jsx @@ -818,7 +818,10 @@ const Transaction = memo(function Transaction({ // it's always showing the formatted result setTransaction(serializeTransaction(deserialized, showZeroInDeposit)); - onSave(deserialized, subtransactions); + const deserializedName = ['credit', 'debit'].includes(name) + ? 'amount' + : name; + onSave(deserialized, subtransactions, deserializedName); } } @@ -2053,7 +2056,7 @@ export const TransactionTable = forwardRef((props, ref) => { }, [props.onAdd, newNavigator.onEdit]); const onSave = useCallback( - async (transaction, subtransactions = null) => { + async (transaction, subtransactions = null, updatedFieldName = null) => { savePending.current = true; let groupedTransaction = subtransactions @@ -2062,7 +2065,10 @@ export const TransactionTable = forwardRef((props, ref) => { if (isTemporaryId(transaction.id)) { if (props.onApplyRules) { - groupedTransaction = await props.onApplyRules(groupedTransaction); + groupedTransaction = await props.onApplyRules( + groupedTransaction, + updatedFieldName, + ); } const newTrans = latestState.current.newTransactions; diff --git a/packages/loot-core/src/shared/transactions.ts b/packages/loot-core/src/shared/transactions.ts index 773d59fac70c2f1d6c897f1d0d1fb25880bdfa12..d56389ca3e1c4b3a82cb10496809862f68da6641 100644 --- a/packages/loot-core/src/shared/transactions.ts +++ b/packages/loot-core/src/shared/transactions.ts @@ -241,7 +241,9 @@ export function updateTransaction( return replaceTransactions(transactions, transaction.id, trans => { if (trans.is_parent) { const parent = trans.id === transaction.id ? transaction : trans; - const sub = trans.subtransactions?.map(t => { + const originalSubtransactions = + parent.subtransactions ?? trans.subtransactions; + const sub = originalSubtransactions?.map(t => { // Make sure to update the children to reflect the updated // properties (if the parent updated) diff --git a/upcoming-release-notes/2834.md b/upcoming-release-notes/2834.md new file mode 100644 index 0000000000000000000000000000000000000000..e0a2a73c108d92c594f1c48d939359231a91055c --- /dev/null +++ b/upcoming-release-notes/2834.md @@ -0,0 +1,6 @@ +--- +category: Enhancements +authors: [jfdoming] +--- + +Reapply rules to split transactions when the parent changes