diff --git a/src/libs/ReportNameUtils.ts b/src/libs/ReportNameUtils.ts index 4d318f77c5415..a328ac95d1ae5 100644 --- a/src/libs/ReportNameUtils.ts +++ b/src/libs/ReportNameUtils.ts @@ -149,6 +149,15 @@ Onyx.connect({ }, }); +/** + * Strips accounting-style parentheses from currency amounts in report names. + * The backend formats negative amounts with parentheses (e.g., "($25.00)") instead of + * a minus sign. This function converts them to the standard format (e.g., "$25.00"). + */ +function stripAccountingBrackets(reportName: string): string { + return reportName.replaceAll(/\(([^)]*\d[^)]*)\)/g, '$1'); +} + function generateArchivedReportName(reportName: string): string { // eslint-disable-next-line @typescript-eslint/no-deprecated return `${reportName} (${translateLocal('common.archived')}) `; @@ -335,7 +344,7 @@ function getMoneyRequestReportName({report, policy, invoiceReceiverPolicy}: {rep } if (report?.reportName && isExpenseReport(report)) { - return report.reportName; + return stripAccountingBrackets(report.reportName); } const moneyRequestTotal = getMoneyRequestSpendBreakdown(report).totalDisplaySpend; @@ -780,7 +789,7 @@ function computeReportName( } if (report?.reportName && report.type === CONST.REPORT.TYPE.EXPENSE) { - return report?.reportName; + return stripAccountingBrackets(report.reportName); } if (isTaskReport(report)) { diff --git a/src/libs/ReportUtils.ts b/src/libs/ReportUtils.ts index 14666a3201f96..bb0e4a6d4b96d 100644 --- a/src/libs/ReportUtils.ts +++ b/src/libs/ReportUtils.ts @@ -6727,7 +6727,7 @@ function buildOptimisticExpenseReport({ const storedNonReimbursableTotal = nonReimbursableTotal * -1; const report = chatReportID ? getReportOrDraftReport(chatReportID) : undefined; const policyName = getPolicyName({report}); - const formattedTotal = convertToDisplayString(storedTotal, currency); + const formattedTotal = convertToDisplayString(Math.abs(storedTotal), currency); // This will be fixed as part of https://github.com/Expensify/Expensify/issues/507850 // eslint-disable-next-line @typescript-eslint/no-deprecated const policyReal = getPolicy(policyID); diff --git a/tests/unit/ReportNameUtilsTest.ts b/tests/unit/ReportNameUtilsTest.ts index c99d6004434f3..1a2c137d6ef3c 100644 --- a/tests/unit/ReportNameUtilsTest.ts +++ b/tests/unit/ReportNameUtilsTest.ts @@ -744,6 +744,25 @@ describe('ReportNameUtils', () => { expect(reportName).toBe(CONST.REPORT.DEFAULT_EXPENSE_REPORT_NAME); }); + it('should strip accounting-style parentheses from expense report reportName', () => { + // Given an expense report with a reportName containing accounting-style parenthesized amount + const expenseReport: Report = { + ...createExpenseReport(202), + reportID: '202', + reportName: 'Workspace owes ($25.00)', + policyID: '202', + type: CONST.REPORT.TYPE.EXPENSE, + total: -2500, + currency: 'USD', + }; + + // When we get the money request report name + const reportName = getMoneyRequestReportName({report: expenseReport}); + + // Then it should strip the accounting-style parentheses + expect(reportName).toBe('Workspace owes $25.00'); + }); + it('should not return empty string for expense report with empty reportName when policy has a normal fieldList', () => { // Given an expense report with empty reportName const expenseReport: Report = { diff --git a/tests/unit/ReportUtilsTest.ts b/tests/unit/ReportUtilsTest.ts index 071e3c90a7c91..d8bc958c9b15f 100644 --- a/tests/unit/ReportUtilsTest.ts +++ b/tests/unit/ReportUtilsTest.ts @@ -10098,7 +10098,7 @@ describe('ReportUtils', () => { const total = 100; const currency = CONST.CURRENCY.USD; const expenseReport = buildOptimisticExpenseReport({chatReportID, policyID: undefined, payeeAccountID: 1, total, currency, betas: [CONST.BETAS.ALL]}); - expect(expenseReport.reportName).toBe(`${fakePolicy.name} owes ${convertToDisplayString(-total, currency)}`); + expect(expenseReport.reportName).toBe(`${fakePolicy.name} owes ${convertToDisplayString(total, currency)}`); }); it('should set reportName to "New Report" when policy field list is empty', async () => { diff --git a/tests/unit/libs/getClipboardTextTest.ts b/tests/unit/libs/getClipboardTextTest.ts index 042120d6357b8..15c2480f9aed1 100644 --- a/tests/unit/libs/getClipboardTextTest.ts +++ b/tests/unit/libs/getClipboardTextTest.ts @@ -1,5 +1,5 @@ -import Parser from '@libs/Parser'; import getClipboardText from '@libs/Clipboard/getClipboardText'; +import Parser from '@libs/Parser'; jest.mock('@libs/Parser', () => ({ // eslint-disable-next-line @typescript-eslint/naming-convention