From 463aa4355c2f78d29640f1c731b35b10c0564293 Mon Sep 17 00:00:00 2001 From: DJ Mountney Date: Mon, 26 Feb 2024 09:43:06 -0800 Subject: [PATCH 1/3] Adds option to make a transfer from two selected transactions - Transactions amount must match - Transactions must be from different acounts - Split transactions not eligible --- .../src/components/accounts/Account.jsx | 58 +++++++++++++++++++ .../src/components/accounts/Header.jsx | 6 ++ .../transactions/SelectedTransactions.jsx | 37 ++++++++++++ 3 files changed, 101 insertions(+) diff --git a/packages/desktop-client/src/components/accounts/Account.jsx b/packages/desktop-client/src/components/accounts/Account.jsx index 48f30a99a44..64f124c52c2 100644 --- a/packages/desktop-client/src/components/accounts/Account.jsx +++ b/packages/desktop-client/src/components/accounts/Account.jsx @@ -1059,6 +1059,63 @@ class AccountInternal extends PureComponent { this.props.pushModal('edit-rule', { rule }); }; + onSetTransfer = async ids => { + const onConfirmTransfer = async ids => { + this.setState({ workingHard: true }); + + const payees = await this.props.getPayees(); + + // not already a transfer + // no subtransactions, parent or singles only + const { data: transactions } = await runQuery( + q('transactions') + .filter({ id: { $oneof: ids }, is_child: false, transfer_id: null }) + .select('*'), + ); + + const [fromTrans, toTrans] = transactions; + + // only two selected + // belong to two different accounts + // amount must zero each other out + if ( + transactions.length === 2 && + fromTrans.account !== toTrans.account && + fromTrans.amount + toTrans.amount === 0 + ) { + const fromPayee = payees.find( + p => p.transfer_acct === fromTrans.account, + ); + const toPayee = payees.find(p => p.transfer_acct === toTrans.account); + + const changes = { + updated: [ + { + ...fromTrans, + payee: toPayee.id, + transfer_id: toTrans.id, + }, + { + ...toTrans, + payee: fromPayee.id, + transfer_id: fromTrans.id, + }, + ], + }; + + await send('transactions-batch-update', changes); + } + + await this.refetchTransactions(); + }; + + await this.checkForReconciledTransactions( + ids, + 'batchEditWithReconciled', + onConfirmTransfer, + ); + }; + onCondOpChange = (value, filters) => { this.setState({ conditionsOp: value }); this.setState({ filterId: { ...this.state.filterId, status: 'changed' } }); @@ -1443,6 +1500,7 @@ class AccountInternal extends PureComponent { onDeleteFilter={this.onDeleteFilter} onApplyFilter={this.onApplyFilter} onScheduleAction={this.onScheduleAction} + onSetTransfer={this.onSetTransfer} /> diff --git a/packages/desktop-client/src/components/accounts/Header.jsx b/packages/desktop-client/src/components/accounts/Header.jsx index 789131335bb..eaade96bfb2 100644 --- a/packages/desktop-client/src/components/accounts/Header.jsx +++ b/packages/desktop-client/src/components/accounts/Header.jsx @@ -79,6 +79,7 @@ export function AccountHeader({ onCondOpChange, onDeleteFilter, onScheduleAction, + onSetTransfer, }) { const [menuOpen, setMenuOpen] = useState(false); const searchInput = useRef(null); @@ -94,6 +95,9 @@ export function AccountHeader({ canSync = !!accounts.find(account => !!account.account_id) && isUsingServer; } + // Only show the ability to make linked transfers on multi-account views. + const showMakeTransfer = !account; + function onToggleSplits() { if (tableRef.current) { splitsExpanded.dispatch({ @@ -276,8 +280,10 @@ export function AccountHeader({ onEdit={onBatchEdit} onUnlink={onBatchUnlink} onCreateRule={onCreateRule} + onSetTransfer={onSetTransfer} onScheduleAction={onScheduleAction} pushModal={pushModal} + showMakeTransfer={showMakeTransfer} /> )}