Fix updateTransaction corrupting split parents with partial updates (#7242)

* [AI] Fix updateTransaction corrupting split parents with partial updates

When `api.updateTransaction(id, { notes: '...' })` is called on a split
parent, the `updateTransaction` helper replaces the parent with the
sparse update object (`{ id, notes }`) instead of merging it with
the existing transaction data.  This causes `recalculateSplit` to see
`amount` as `undefined` (→ 0), which doesn't match the children's
total and sets a `SplitTransactionError` on the parent.  `makeChild`
also inherits undefined `account`, `date`, and `cleared` values,
potentially creating broken child rows.

Fix: merge the incoming partial fields (`{ ...trans, ...transaction }`)
so all existing properties are preserved.

Add a test that performs a notes-only update on a split parent and
asserts no error is set and the amount stays intact.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* [AI] Add release notes for PR #7242

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Address review feedback: remove verbose comment and simplify release note

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

---------

Co-authored-by: L. Warren Thompson <lwarrenthompson@Warren-MBP.local>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
L. Warren Thompson
2026-04-05 01:01:06 -07:00
committed by Matt Fiddaman
parent c75a94e8b0
commit d262f7d8b2
3 changed files with 42 additions and 1 deletions

View File

@@ -201,6 +201,40 @@ describe('Transactions', () => {
expect(data.length).toBe(5);
});
test('partially updating a split parent preserves amount and does not set error', () => {
const transactions = [
makeTransaction({ amount: 2001 }),
...makeSplitTransaction({ id: 't1', amount: 2500 }, [
{ id: 't2', amount: 2000 },
{ id: 't3', amount: 500 },
]),
makeTransaction({ amount: 3002 }),
];
// Simulate a partial update (only `notes`) on the parent — this is
// how `api.updateTransaction(id, { notes: '...' })` calls it in
// `api.ts`: `updateTransaction(transactions, { id, ...fields })`.
const { data, diff } = updateTransaction(transactions, {
id: 't1',
notes: 'updated note',
} as TransactionEntity);
// The parent should get the updated notes without an error
const parent = data.find(d => d.id === 't1');
expect(parent?.notes).toBe('updated note');
expect(parent?.amount).toBe(2500);
expect(parent?.error).toBeNull();
// Children should be unchanged
expect(data.filter(t => t.parent_id === 't1').length).toBe(2);
expect(diff).toEqual({
added: [],
deleted: [],
updated: [expect.objectContaining({ id: 't1', notes: 'updated note' })],
});
});
test('deleting a split transaction works', () => {
const transactions = [
makeTransaction({ amount: 2001 }),

View File

@@ -262,7 +262,8 @@ export function updateTransaction(
) {
return replaceTransactions(transactions, transaction.id, trans => {
if (trans.is_parent) {
const parent = trans.id === transaction.id ? transaction : trans;
const parent =
trans.id === transaction.id ? { ...trans, ...transaction } : trans;
const originalSubtransactions =
parent.subtransactions ?? trans.subtransactions;
const sub = originalSubtransactions?.map(t => {

View File

@@ -0,0 +1,6 @@
---
category: Bugfixes
authors: [lwarrenthompson]
---
Fix `api.updateTransaction()` corrupting split parent transactions when doing partial updates