From dc82257d36b0d98205b707ca92524057d63b6e2f Mon Sep 17 00:00:00 2001 From: Jasper Huang Date: Wed, 1 Apr 2026 14:01:14 -0700 Subject: [PATCH] Revert "follow-up: Start & End date does not matches Title format with Trip-based Auto-reporting" --- src/libs/Formula.ts | 26 +++----------- src/libs/actions/IOU/index.ts | 39 +++++---------------- tests/unit/FormulaTest.ts | 65 ----------------------------------- 3 files changed, 13 insertions(+), 117 deletions(-) diff --git a/src/libs/Formula.ts b/src/libs/Formula.ts index 4df5072b2d01..bcae1e52494e 100644 --- a/src/libs/Formula.ts +++ b/src/libs/Formula.ts @@ -330,7 +330,7 @@ function computeAutoReportingInfo(part: FormulaPart, context: FormulaContext, su return part.definition; } - const {startDate, endDate} = getAutoReportingDates(policy, report, new Date(), context); + const {startDate, endDate} = getAutoReportingDates(policy, report); switch (subField.toLowerCase()) { case 'start': @@ -658,21 +658,6 @@ function getAllReportTransactionsWithContext(reportID: string, context?: Formula const transactions = [...getReportTransactions(reportID)]; const contextTransaction = context?.transaction; - // Merge optimistic transactions not yet in Onyx, passed via FormulaContext.allTransactions. - if (context?.allTransactions) { - for (const ctxTransaction of Object.values(context.allTransactions)) { - if (!ctxTransaction?.transactionID || ctxTransaction.reportID !== reportID) { - continue; - } - const existingIndex = transactions.findIndex((t) => t?.transactionID === ctxTransaction.transactionID); - if (existingIndex >= 0) { - transactions[existingIndex] = ctxTransaction; - } else { - transactions.push(ctxTransaction); - } - } - } - if (contextTransaction?.transactionID && contextTransaction.reportID === reportID) { const transactionIndex = transactions.findIndex((transaction) => transaction?.transactionID === contextTransaction.transactionID); if (transactionIndex >= 0) { @@ -784,7 +769,7 @@ function getMonthlyLastBusinessDayPeriod(currentDate: Date): {startDate: Date; e /** * Calculate the start and end dates for auto-reporting based on the frequency and current date */ -function getAutoReportingDates(policy: OnyxEntry, report: Report, currentDate = new Date(), context?: FormulaContext): {startDate: Date | undefined; endDate: Date | undefined} { +function getAutoReportingDates(policy: OnyxEntry, report: Report, currentDate = new Date()): {startDate: Date | undefined; endDate: Date | undefined} { const frequency = policy?.autoReportingFrequency; const offset = policy?.autoReportingOffset; @@ -837,11 +822,10 @@ function getAutoReportingDates(policy: OnyxEntry, report: Report, curren } case CONST.POLICY.AUTO_REPORTING_FREQUENCIES.TRIP: { - // For trip-based, use oldest transaction as start and newest transaction as end - const oldestTransactionDateString = getOldestTransactionDate(report.reportID, context); - const newestTransactionDateString = getNewestTransactionDate(report.reportID, context); + // For trip-based, use oldest transaction as start + const oldestTransactionDateString = getOldestTransactionDate(report.reportID); startDate = oldestTransactionDateString ? new Date(oldestTransactionDateString) : currentDate; - endDate = newestTransactionDateString ? new Date(newestTransactionDateString) : currentDate; + endDate = currentDate; break; } diff --git a/src/libs/actions/IOU/index.ts b/src/libs/actions/IOU/index.ts index 201eed6d02ba..1518d312f94a 100644 --- a/src/libs/actions/IOU/index.ts +++ b/src/libs/actions/IOU/index.ts @@ -138,7 +138,6 @@ import { canEditFieldOfMoneyRequest, canSubmitAndIsAwaitingForCurrentUser, canUserPerformWriteAction as canUserPerformWriteActionReportUtils, - computeOptimisticReportName, findSelfDMReportID, generateReportID, getAllHeldTransactions as getAllHeldTransactionsReportUtils, @@ -189,6 +188,7 @@ import { isSettled, isTestTransactionReport, isTrackExpenseReport, + populateOptimisticReportFormula, prepareOnboardingOnyxData, shouldCreateNewMoneyRequestReport as shouldCreateNewMoneyRequestReportReportUtils, shouldEnableNegative, @@ -3192,7 +3192,7 @@ function getDeleteTrackExpenseInformation( * This is needed when report totals change (e.g., adding expenses or changing reimbursable status) * to ensure the report title reflects the updated values like {report:reimbursable}. */ -function recalculateOptimisticReportName(iouReport: OnyxTypes.Report, policy: OnyxEntry, newTransaction?: OnyxTypes.Transaction): string | undefined { +function recalculateOptimisticReportName(iouReport: OnyxTypes.Report, policy: OnyxEntry): string | undefined { if (!policy?.fieldList?.[CONST.POLICY.FIELDS.FIELD_LIST_TITLE]) { return undefined; } @@ -3200,37 +3200,17 @@ function recalculateOptimisticReportName(iouReport: OnyxTypes.Report, policy: On if (!titleFormula) { return undefined; } - - // Gather existing transactions + the optimistic one not yet in Onyx. - const existingTransactions = getReportTransactions(iouReport.reportID); - const transactionsRecord: Record = {}; - for (const transaction of existingTransactions) { - if (transaction?.transactionID) { - transactionsRecord[transaction.transactionID] = transaction; - } - } - if (newTransaction?.transactionID) { - transactionsRecord[newTransaction.transactionID] = newTransaction; - } - - const computedName = computeOptimisticReportName(iouReport, policy, iouReport.policyID, transactionsRecord); - return computedName ?? undefined; + return populateOptimisticReportFormula(titleFormula, iouReport as Parameters[1], policy); } -function maybeUpdateReportNameForFormulaTitle(iouReport: OnyxTypes.Report, policy: OnyxEntry, newTransaction?: OnyxTypes.Transaction): OnyxTypes.Report { +function maybeUpdateReportNameForFormulaTitle(iouReport: OnyxTypes.Report, policy: OnyxEntry): OnyxTypes.Report { const reportNameValuePairs = allReportNameValuePairs?.[`${ONYXKEYS.COLLECTION.REPORT_NAME_VALUE_PAIRS}${iouReport.reportID}`]; const titleField = reportNameValuePairs?.expensify_text_title; - - // Fall back to policy.fieldList when reportNameValuePairs doesn't exist yet (optimistic reports). - const isFormulaTitle = reportNameValuePairs - ? titleField?.type === CONST.REPORT_FIELD_TYPES.FORMULA - : policy?.fieldList?.[CONST.POLICY.FIELDS.FIELD_LIST_TITLE]?.type === CONST.REPORT_FIELD_TYPES.FORMULA; - - if (!isFormulaTitle) { + if (titleField?.type !== CONST.REPORT_FIELD_TYPES.FORMULA) { return iouReport; } - const updatedReportName = recalculateOptimisticReportName(iouReport, policy, newTransaction); + const updatedReportName = recalculateOptimisticReportName(iouReport, policy); if (!updatedReportName) { return iouReport; } @@ -3414,6 +3394,8 @@ function getMoneyRequestInformation(moneyRequestInformation: MoneyRequestInforma iouReport.nonReimbursableTotal = (iouReport.nonReimbursableTotal ?? 0) - amount; } } + + iouReport = maybeUpdateReportNameForFormulaTitle(iouReport, policy); } if (typeof iouReport.unheldTotal === 'number') { // Use newReportTotal in scenarios where the total is based on more than just the current transaction amount, and we need to override it manually @@ -3515,11 +3497,6 @@ function getMoneyRequestInformation(moneyRequestInformation: MoneyRequestInforma } } - // Recalculate report name after STEP 3 so the optimistic transaction is included in formula computation. - if (!shouldCreateNewMoneyRequestReport && isPolicyExpenseChat) { - iouReport = maybeUpdateReportNameForFormulaTitle(iouReport, policy, optimisticTransaction); - } - // STEP 4: Build optimistic reportActions. We need: // 1. CREATED action for the chatReport // 2. CREATED action for the iouReport diff --git a/tests/unit/FormulaTest.ts b/tests/unit/FormulaTest.ts index eb9f870d8c5c..934905044208 100644 --- a/tests/unit/FormulaTest.ts +++ b/tests/unit/FormulaTest.ts @@ -675,71 +675,6 @@ describe('CustomFormula', () => { const context = createMockContext(policy); expect(compute('{report:autoreporting:start}', context)).toBe('2025-01-08'); - expect(compute('{report:autoreporting:end}', context)).toBe('2025-01-14'); - }); - - test('should use context.transaction for trip end date when adding a new expense to existing report', () => { - // First transaction already in Onyx (oldest expense, dated Jan 8) - mockReportUtils.getReportTransactions.mockReturnValue([ - {transactionID: 'existing1', reportID: '123', created: '2025-01-08T12:00:00Z', merchant: 'Hotel', amount: 5000} as Transaction, - ]); - - const policy = {autoReportingFrequency: CONST.POLICY.AUTO_REPORTING_FREQUENCIES.TRIP} as Policy; - // Second transaction passed via context (newest expense, dated Jan 14 — not in Onyx yet) - const context: FormulaContext = { - report: mockReport, - policy, - transaction: {transactionID: 'optimistic1', reportID: '123', created: '2025-01-14T16:00:00Z', merchant: 'Restaurant', amount: 3000} as Transaction, - }; - - // Start should be oldest (Jan 8 from Onyx), end should be newest (Jan 14 from context) - expect(compute('{report:autoreporting:start}', context)).toBe('2025-01-08'); - expect(compute('{report:autoreporting:end}', context)).toBe('2025-01-14'); - }); - - test('should use allTransactions for trip dates when Onyx is empty (new report optimistic flow)', () => { - mockReportUtils.getReportTransactions.mockReturnValue([]); - - const policy = {autoReportingFrequency: CONST.POLICY.AUTO_REPORTING_FREQUENCIES.TRIP} as Policy; - const context: FormulaContext = { - report: mockReport, - policy, - allTransactions: { - trans1: {transactionID: 'trans1', reportID: '123', created: '2025-01-08T12:00:00Z', merchant: 'Hotel', amount: 5000} as Transaction, - }, - }; - - expect(compute('{report:autoreporting:start}', context)).toBe('2025-01-08'); - expect(compute('{report:autoreporting:end}', context)).toBe('2025-01-08'); - }); - - test('should use allTransactions to merge Onyx + optimistic transaction for trip date range', () => { - mockReportUtils.getReportTransactions.mockReturnValue([ - {transactionID: 'existing1', reportID: '123', created: '2025-01-08T12:00:00Z', merchant: 'Hotel', amount: 5000} as Transaction, - ]); - - const policy = {autoReportingFrequency: CONST.POLICY.AUTO_REPORTING_FREQUENCIES.TRIP} as Policy; - const context: FormulaContext = { - report: mockReport, - policy, - allTransactions: { - existing1: {transactionID: 'existing1', reportID: '123', created: '2025-01-08T12:00:00Z', merchant: 'Hotel', amount: 5000} as Transaction, - optimistic1: {transactionID: 'optimistic1', reportID: '123', created: '2025-01-14T16:00:00Z', merchant: 'Restaurant', amount: 3000} as Transaction, - }, - }; - - expect(compute('{report:autoreporting:start}', context)).toBe('2025-01-08'); - expect(compute('{report:autoreporting:end}', context)).toBe('2025-01-14'); - }); - - test('should fallback to current date for trip frequency when no transactions', () => { - mockReportUtils.getReportTransactions.mockReturnValue([]); - - const policy = {autoReportingFrequency: CONST.POLICY.AUTO_REPORTING_FREQUENCIES.TRIP} as Policy; - const context = createMockContext(policy); - - // Should fall back to current date (2025-01-19 from jest.setSystemTime) - expect(compute('{report:autoreporting:start}', context)).toBe('2025-01-19'); expect(compute('{report:autoreporting:end}', context)).toBe('2025-01-19'); });