@@ -186,6 +186,7 @@ import {
186186 isSettled,
187187 isTestTransactionReport,
188188 isTrackExpenseReport,
189+ populateOptimisticReportFormula,
189190 prepareOnboardingOnyxData,
190191 shouldCreateNewMoneyRequestReport as shouldCreateNewMoneyRequestReportReportUtils,
191192 shouldEnableNegative,
@@ -3272,6 +3273,37 @@ function getDeleteTrackExpenseInformation(
32723273 return {parameters, optimisticData, successData, failureData, shouldDeleteTransactionThread, chatReport};
32733274}
32743275
3276+ /**
3277+ * Recalculates the report name using the policy's custom title formula.
3278+ * This is needed when report totals change (e.g., adding expenses or changing reimbursable status)
3279+ * to ensure the report title reflects the updated values like {report:reimbursable}.
3280+ */
3281+ function recalculateOptimisticReportName(iouReport: OnyxTypes.Report, policy: OnyxEntry<OnyxTypes.Policy>): string | undefined {
3282+ if (!policy?.fieldList?.[CONST.POLICY.FIELDS.FIELD_LIST_TITLE]) {
3283+ return undefined;
3284+ }
3285+ const titleFormula = policy.fieldList[CONST.POLICY.FIELDS.FIELD_LIST_TITLE]?.defaultValue ?? '';
3286+ if (!titleFormula) {
3287+ return undefined;
3288+ }
3289+ return populateOptimisticReportFormula(titleFormula, iouReport as Parameters<typeof populateOptimisticReportFormula>[1], policy);
3290+ }
3291+
3292+ function maybeUpdateReportNameForFormulaTitle(iouReport: OnyxTypes.Report, policy: OnyxEntry<OnyxTypes.Policy>): OnyxTypes.Report {
3293+ const reportNameValuePairs = allReportNameValuePairs?.[`${ONYXKEYS.COLLECTION.REPORT_NAME_VALUE_PAIRS}${iouReport.reportID}`];
3294+ const titleField = reportNameValuePairs?.expensify_text_title;
3295+ if (titleField?.type !== CONST.REPORT_FIELD_TYPES.FORMULA) {
3296+ return iouReport;
3297+ }
3298+
3299+ const updatedReportName = recalculateOptimisticReportName(iouReport, policy);
3300+ if (!updatedReportName) {
3301+ return iouReport;
3302+ }
3303+
3304+ return {...iouReport, reportName: updatedReportName};
3305+ }
3306+
32753307/**
32763308 * Gathers all the data needed to submit an expense. It attempts to find existing reports, iouReports, and receipts. If it doesn't find them, then
32773309 * it creates optimistic versions of them and uses those instead
@@ -3436,6 +3468,8 @@ function getMoneyRequestInformation(moneyRequestInformation: MoneyRequestInforma
34363468 iouReport.nonReimbursableTotal = (iouReport.nonReimbursableTotal ?? 0) - amount;
34373469 }
34383470 }
3471+
3472+ iouReport = maybeUpdateReportNameForFormulaTitle(iouReport, policy);
34393473 }
34403474 if (typeof iouReport.unheldTotal === 'number') {
34413475 // Use newReportTotal in scenarios where the total is based on more than just the current transaction amount, and we need to override it manually
@@ -4609,6 +4643,11 @@ function getUpdateMoneyRequestParams(params: GetUpdateMoneyRequestParamsType): U
46094643 updatedMoneyRequestReport.unheldNonReimbursableTotal += updatedTransaction.reimbursable ? -updatedTransaction.amount : updatedTransaction.amount;
46104644 }
46114645 }
4646+
4647+ // Only recalculate reportName when reimbursable status changes and the report uses a formula title
4648+ if ('reimbursable' in transactionChanges) {
4649+ updatedMoneyRequestReport = maybeUpdateReportNameForFormulaTitle(updatedMoneyRequestReport, policy);
4650+ }
46124651 } else {
46134652 updatedMoneyRequestReport = updateIOUOwnerAndTotal(
46144653 iouReport,
0 commit comments