diff --git a/src/libs/IOUUtils.ts b/src/libs/IOUUtils.ts index d70f4fc08102..1aafe09c53fe 100644 --- a/src/libs/IOUUtils.ts +++ b/src/libs/IOUUtils.ts @@ -53,9 +53,18 @@ function calculateAmount(numberOfParticipants: number, total: number, currency: * If user1 requests $17 from user2, then we have: {ownerAccountID: user1, managerID: user2, total: $7 (still a positive amount, but now owed to user1)} * * @param isDeleting - whether the user is deleting the request + * @param isUpdating - whether the user is updating the request */ -function updateIOUOwnerAndTotal>(iouReport: TReport, actorAccountID: number, amount: number, currency: string, isDeleting = false): TReport { - if (currency !== iouReport?.currency) { +function updateIOUOwnerAndTotal>( + iouReport: TReport, + actorAccountID: number, + amount: number, + currency: string, + isDeleting = false, + isUpdating = false, +): TReport { + // For the update case, we have calculated the diff amount in the calculateDiffAmount function so there is no need to compare currencies here + if ((currency !== iouReport?.currency && !isUpdating) || !iouReport) { return iouReport; } diff --git a/src/libs/actions/IOU.ts b/src/libs/actions/IOU.ts index 78ecd5a4f664..c3f7c44c86b0 100644 --- a/src/libs/actions/IOU.ts +++ b/src/libs/actions/IOU.ts @@ -982,6 +982,36 @@ function createDistanceRequest( Report.notifyNewAction(chatReport.reportID, userAccountID); } +/** + * Compute the diff amount when we update the transaction + */ +function calculateDiffAmount(iouReport: OnyxEntry, updatedTransaction: OnyxEntry, transaction: OnyxEntry): number { + if (!iouReport) { + return 0; + } + const isExpenseReport = ReportUtils.isExpenseReport(iouReport); + const updatedCurrency = TransactionUtils.getCurrency(updatedTransaction); + const currentCurrency = TransactionUtils.getCurrency(transaction); + + const currentAmount = TransactionUtils.getAmount(transaction, isExpenseReport); + const updatedAmount = TransactionUtils.getAmount(updatedTransaction, isExpenseReport); + + if (updatedCurrency === iouReport?.currency && currentCurrency !== iouReport?.currency) { + // Add the diff to the total if we change the currency from a different currency to the currency of the IOU report + return updatedAmount; + } + if (updatedCurrency !== iouReport?.currency && currentCurrency === iouReport?.currency) { + // Subtract the diff from the total if we change the currency from the currency of IOU report to a different currency + return -updatedAmount; + } + if (updatedCurrency === iouReport?.currency && updatedTransaction?.modifiedAmount) { + // Calculate the diff between the updated amount and the current amount if we change the amount and the currency of the transaction is the currency of the report + return updatedAmount - currentAmount; + } + + return 0; +} + /** * @param transactionID * @param transactionThreadReportID @@ -1098,23 +1128,21 @@ function getUpdateMoneyRequestParams( }, }, }); - } - // Step 4: Compute the IOU total and update the report preview message (and report header) so LHN amount owed is correct. - // Should only update if the transaction matches the currency of the report, else we wait for the update - // from the server with the currency conversion - let updatedMoneyRequestReport = {...iouReport}; - if ((hasPendingWaypoints || updatedTransaction?.modifiedAmount) && updatedTransaction?.currency === iouReport?.currency) { - const diff = TransactionUtils.getAmount(transaction, true) - TransactionUtils.getAmount(updatedTransaction, true); + // Step 4: Compute the IOU total and update the report preview message (and report header) so LHN amount owed is correct. + let updatedMoneyRequestReport = {...iouReport}; + const diff = calculateDiffAmount(iouReport, updatedTransaction, transaction); + if (ReportUtils.isExpenseReport(iouReport) && typeof updatedMoneyRequestReport.total === 'number') { - updatedMoneyRequestReport.total += diff; + // For expense report, the amount is negative so we should subtract total from diff + updatedMoneyRequestReport.total -= diff; } else { updatedMoneyRequestReport = iouReport - ? IOUUtils.updateIOUOwnerAndTotal(iouReport, updatedReportAction.actorAccountID ?? -1, diff, TransactionUtils.getCurrency(transaction), false) + ? IOUUtils.updateIOUOwnerAndTotal(iouReport, updatedReportAction.actorAccountID ?? -1, diff, TransactionUtils.getCurrency(transaction), false, true) : {}; } + updatedMoneyRequestReport.cachedTotal = CurrencyUtils.convertToDisplayString(updatedMoneyRequestReport.total, updatedTransaction?.modifiedCurrency); - updatedMoneyRequestReport.cachedTotal = CurrencyUtils.convertToDisplayString(updatedMoneyRequestReport.total, updatedTransaction?.currency); optimisticData.push({ onyxMethod: Onyx.METHOD.MERGE, key: `${ONYXKEYS.COLLECTION.REPORT}${iouReport?.reportID}`, @@ -2782,23 +2810,18 @@ function deleteMoneyRequest(transactionID: string, reportAction: OnyxTypes.Repor // STEP 4: Update the iouReport and reportPreview with new totals and messages if it wasn't deleted let updatedIOUReport: OnyxTypes.Report | null; + const currency = TransactionUtils.getCurrency(transaction); const updatedReportPreviewAction: OnyxTypes.ReportAction | EmptyObject = {...reportPreviewAction}; updatedReportPreviewAction.pendingAction = shouldDeleteIOUReport ? CONST.RED_BRICK_ROAD_PENDING_ACTION.DELETE : CONST.RED_BRICK_ROAD_PENDING_ACTION.UPDATE; if (iouReport && ReportUtils.isExpenseReport(iouReport)) { updatedIOUReport = {...iouReport}; - if (typeof updatedIOUReport.total === 'number') { + if (typeof updatedIOUReport.total === 'number' && currency === iouReport?.currency) { // Because of the Expense reports are stored as negative values, we add the total from the amount updatedIOUReport.total += TransactionUtils.getAmount(transaction, true); } } else { - updatedIOUReport = IOUUtils.updateIOUOwnerAndTotal( - iouReport, - reportAction.actorAccountID ?? -1, - TransactionUtils.getAmount(transaction, false), - TransactionUtils.getCurrency(transaction), - true, - ); + updatedIOUReport = IOUUtils.updateIOUOwnerAndTotal(iouReport, reportAction.actorAccountID ?? -1, TransactionUtils.getAmount(transaction, false), currency, true); } if (updatedIOUReport) {