From 8ad07ecd3259b5fb8692fe46f85ed7447439256d Mon Sep 17 00:00:00 2001 From: "ahmedGaber93 (via MelvinBot)" Date: Tue, 3 Mar 2026 16:02:17 +0000 Subject: [PATCH 1/3] Treat invoice reports like expense reports when computing isFromExpenseReport during amount edit Invoice transactions store amounts as negative (like expense reports), but getUpdateMoneyRequestParams and calculateDiffAmount only checked isExpenseReport(), which returns false for invoices. This caused modifiedAmount to be stored as positive, while the display path (which uses isPaidGroupPolicy) negated it, showing a minus sign. Co-authored-by: ahmedGaber93 --- src/libs/actions/IOU/index.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libs/actions/IOU/index.ts b/src/libs/actions/IOU/index.ts index 2d6b7272ce79..fc5050c5e350 100644 --- a/src/libs/actions/IOU/index.ts +++ b/src/libs/actions/IOU/index.ts @@ -4426,7 +4426,7 @@ function calculateDiffAmount( if (!iouReport) { return 0; } - const isExpenseReportLocal = isExpenseReport(iouReport); + const isExpenseReportLocal = isExpenseReport(iouReport) || isInvoiceReportReportUtils(iouReport); const updatedCurrency = getCurrency(updatedTransaction); const currentCurrency = getCurrency(transaction); @@ -4541,7 +4541,7 @@ function getUpdateMoneyRequestParams(params: GetUpdateMoneyRequestParamsType): U const transaction = allTransactions?.[`${ONYXKEYS.COLLECTION.TRANSACTION}${transactionID}`]; const isTransactionOnHold = isOnHold(transaction); - const isFromExpenseReport = isExpenseReport(iouReport); + const isFromExpenseReport = isExpenseReport(iouReport) || isInvoiceReportReportUtils(iouReport); const updatedTransaction: OnyxEntry = transaction ? getUpdatedTransaction({ transaction, From 5bdf9f7215cd9475fe50f96b4ef4f17951784a8c Mon Sep 17 00:00:00 2001 From: "ahmedGaber93 (via MelvinBot)" Date: Wed, 4 Mar 2026 14:18:47 +0000 Subject: [PATCH 2/3] Add unit tests for calculateDiffAmount with invoice reports Co-authored-by: ahmedGaber93 --- tests/actions/IOUTest.ts | 66 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 66 insertions(+) diff --git a/tests/actions/IOUTest.ts b/tests/actions/IOUTest.ts index e022574ef85f..b3e6bca97e65 100644 --- a/tests/actions/IOUTest.ts +++ b/tests/actions/IOUTest.ts @@ -10646,6 +10646,72 @@ describe('actions/IOU', () => { expect(calculateDiffAmount(fakeReport, updatedTransaction, fakeTransaction)).toBeNull(); }); + + it('should return 0 when the currency and amount of the transactions are the same for an invoice report', () => { + const fakeReport: Report = { + ...createRandomReport(1, undefined), + type: CONST.REPORT.TYPE.INVOICE, + policyID: '1', + stateNum: CONST.REPORT.STATE_NUM.APPROVED, + statusNum: CONST.REPORT.STATUS_NUM.APPROVED, + managerID: RORY_ACCOUNT_ID, + }; + const fakeTransaction: Transaction = { + ...createRandomTransaction(1), + reportID: fakeReport.reportID, + amount: 100, + currency: 'USD', + }; + + expect(calculateDiffAmount(fakeReport, fakeTransaction, fakeTransaction)).toBe(0); + }); + + it('should return the correct diff for an invoice report (same sign convention as expense reports)', () => { + const fakeReport: Report = { + ...createRandomReport(1, undefined), + type: CONST.REPORT.TYPE.INVOICE, + policyID: '1', + stateNum: CONST.REPORT.STATE_NUM.APPROVED, + statusNum: CONST.REPORT.STATUS_NUM.APPROVED, + managerID: RORY_ACCOUNT_ID, + currency: 'USD', + }; + const fakeTransaction: Transaction = { + ...createRandomTransaction(1), + amount: 100, + currency: 'USD', + }; + const updatedTransaction = { + ...fakeTransaction, + amount: 200, + currency: 'USD', + }; + + expect(calculateDiffAmount(fakeReport, updatedTransaction, fakeTransaction)).toBe(-100); + }); + + it('should return null when the currency of the updated and current transactions differ for an invoice report', () => { + const fakeReport: Report = { + ...createRandomReport(1, undefined), + type: CONST.REPORT.TYPE.INVOICE, + policyID: '1', + stateNum: CONST.REPORT.STATE_NUM.APPROVED, + statusNum: CONST.REPORT.STATUS_NUM.APPROVED, + managerID: RORY_ACCOUNT_ID, + }; + const fakeTransaction: Transaction = { + ...createRandomTransaction(1), + amount: 100, + currency: 'USD', + }; + const updatedTransaction = { + ...fakeTransaction, + amount: 200, + currency: 'EUR', + }; + + expect(calculateDiffAmount(fakeReport, updatedTransaction, fakeTransaction)).toBeNull(); + }); }); describe('initMoneyRequest', () => { From f32b18c9848f84d90ad4ab91038affc8858fb10c Mon Sep 17 00:00:00 2001 From: "ahmedGaber93 (via MelvinBot)" Date: Wed, 4 Mar 2026 15:23:15 +0000 Subject: [PATCH 3/3] Add tests for getUpdatedTransaction modifiedAmount negation Verify that modifiedAmount is negated when isFromExpenseReport is true and left positive when isFromExpenseReport is false. Co-authored-by: ahmedGaber93 --- tests/unit/TransactionUtilsTest.ts | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/tests/unit/TransactionUtilsTest.ts b/tests/unit/TransactionUtilsTest.ts index 179593ce91b5..d50857a61e00 100644 --- a/tests/unit/TransactionUtilsTest.ts +++ b/tests/unit/TransactionUtilsTest.ts @@ -390,6 +390,32 @@ describe('TransactionUtils', () => { merchant: CONST.RED_BRICK_ROAD_PENDING_ACTION.UPDATE, }); }); + + it('should negate modifiedAmount when isFromExpenseReport is true', () => { + const transaction = generateTransaction(); + const newAmount = 500; + + const updatedTransaction = TransactionUtils.getUpdatedTransaction({ + transaction, + isFromExpenseReport: true, + transactionChanges: {amount: newAmount}, + }); + + expect(updatedTransaction.modifiedAmount).toBe(-newAmount); + }); + + it('should not negate modifiedAmount when isFromExpenseReport is false', () => { + const transaction = generateTransaction(); + const newAmount = 500; + + const updatedTransaction = TransactionUtils.getUpdatedTransaction({ + transaction, + isFromExpenseReport: false, + transactionChanges: {amount: newAmount}, + }); + + expect(updatedTransaction.modifiedAmount).toBe(newAmount); + }); }); describe('getTransactionType', () => {