From e2cd62201cd8f68ef8cc4573f247a8a471de009c Mon Sep 17 00:00:00 2001 From: TaduJR Date: Sat, 15 Nov 2025 19:19:32 +0300 Subject: [PATCH 01/10] fix: Start & End date does not matches Title format with Trip-based Auto-reporting --- src/libs/Formula.ts | 22 ++++++++++++++-------- tests/unit/FormulaTest.ts | 2 +- 2 files changed, 15 insertions(+), 9 deletions(-) diff --git a/src/libs/Formula.ts b/src/libs/Formula.ts index b64fd91c7858..23848dc0d082 100644 --- a/src/libs/Formula.ts +++ b/src/libs/Formula.ts @@ -317,9 +317,9 @@ function computeAutoReportingInfo(part: FormulaPart, context: FormulaContext, su switch (subField.toLowerCase()) { case 'start': - return formatDate(startDate?.toISOString(), format); + return formatDate(startDate ? startDate.toISOString() : undefined, format); case 'end': - return formatDate(endDate?.toISOString(), format); + return formatDate(endDate ? endDate.toISOString() : undefined, format); default: return part.definition; } @@ -680,7 +680,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()): {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; @@ -689,8 +689,15 @@ function getAutoReportingDates(policy: OnyxEntry, report: Report, curren return {startDate: undefined, endDate: undefined}; } - let startDate: Date; - let endDate: Date; + // For auto-reporting formulas, if there are no transactions, return undefined dates + const oldestTransactionDateString = getOldestTransactionDate(report.reportID); + const newestTransactionDateString = getNewestTransactionDate(report.reportID); + if (!oldestTransactionDateString || !newestTransactionDateString) { + return {startDate: '', endDate: ''}; + } + + let startDate: Date | undefined; + let endDate: Date | undefined; switch (frequency) { case CONST.POLICY.AUTO_REPORTING_FREQUENCIES.WEEKLY: { @@ -733,10 +740,9 @@ function getAutoReportingDates(policy: OnyxEntry, report: Report, curren } case CONST.POLICY.AUTO_REPORTING_FREQUENCIES.TRIP: { - // For trip-based, use oldest transaction as start - const oldestTransactionDateString = getOldestTransactionDate(report.reportID); + // For trip-based, use oldest transaction as start and newest transaction as end startDate = oldestTransactionDateString ? new Date(oldestTransactionDateString) : currentDate; - endDate = currentDate; + endDate = newestTransactionDateString ? new Date(newestTransactionDateString) : currentDate; break; } diff --git a/tests/unit/FormulaTest.ts b/tests/unit/FormulaTest.ts index 97930088a033..4a569bcd8312 100644 --- a/tests/unit/FormulaTest.ts +++ b/tests/unit/FormulaTest.ts @@ -640,7 +640,7 @@ 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-19'); + expect(compute('{report:autoreporting:end}', context)).toBe('2025-01-14'); }); test('should apply custom date formats', () => { From 275b6e1ff653b90da8fec223de78e4bfeae4b0e5 Mon Sep 17 00:00:00 2001 From: TaduJR Date: Wed, 7 Jan 2026 09:02:51 +0300 Subject: [PATCH 02/10] refactor: Remove unnecessary empty string type and move transaction fetching to TRIP case only --- src/libs/Formula.ts | 19 +++++++------------ 1 file changed, 7 insertions(+), 12 deletions(-) diff --git a/src/libs/Formula.ts b/src/libs/Formula.ts index 6830b3836c50..f0f4b2b00826 100644 --- a/src/libs/Formula.ts +++ b/src/libs/Formula.ts @@ -329,9 +329,9 @@ function computeAutoReportingInfo(part: FormulaPart, context: FormulaContext, su switch (subField.toLowerCase()) { case 'start': - return formatDate(startDate ? startDate.toISOString() : undefined, format); + return formatDate(startDate?.toISOString(), format); case 'end': - return formatDate(endDate ? endDate.toISOString() : undefined, format); + return formatDate(endDate?.toISOString(), format); default: return part.definition; } @@ -726,7 +726,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()): {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; @@ -735,15 +735,8 @@ function getAutoReportingDates(policy: OnyxEntry, report: Report, curren return {startDate: undefined, endDate: undefined}; } - // For auto-reporting formulas, if there are no transactions, return undefined dates - const oldestTransactionDateString = getOldestTransactionDate(report.reportID); - const newestTransactionDateString = getNewestTransactionDate(report.reportID); - if (!oldestTransactionDateString || !newestTransactionDateString) { - return {startDate: '', endDate: ''}; - } - - let startDate: Date | undefined; - let endDate: Date | undefined; + let startDate: Date; + let endDate: Date; switch (frequency) { case CONST.POLICY.AUTO_REPORTING_FREQUENCIES.WEEKLY: { @@ -787,6 +780,8 @@ 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); + const newestTransactionDateString = getNewestTransactionDate(report.reportID); startDate = oldestTransactionDateString ? new Date(oldestTransactionDateString) : currentDate; endDate = newestTransactionDateString ? new Date(newestTransactionDateString) : currentDate; break; From 16770efb395b6f33e1e65386721387d6d2c3acd1 Mon Sep 17 00:00:00 2001 From: TaduJR Date: Wed, 7 Jan 2026 09:21:12 +0300 Subject: [PATCH 03/10] test: Add unit test for TRIP auto-reporting fallback when no transactions --- tests/unit/FormulaTest.ts | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/tests/unit/FormulaTest.ts b/tests/unit/FormulaTest.ts index e4ba6bdf706d..5222d7b6b929 100644 --- a/tests/unit/FormulaTest.ts +++ b/tests/unit/FormulaTest.ts @@ -678,6 +678,17 @@ describe('CustomFormula', () => { 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'); + }); + test('should apply custom date formats', () => { const policy = {autoReportingFrequency: CONST.POLICY.AUTO_REPORTING_FREQUENCIES.WEEKLY} as Policy; const context = createMockContext(policy); From 95deb4ac47fb7e52f8d31e0291f439abfa62d21c Mon Sep 17 00:00:00 2001 From: TaduJR Date: Mon, 12 Jan 2026 23:35:57 +0300 Subject: [PATCH 04/10] revert: Unwanted Changes --- Mobile-Expensify | 2 +- android/app/build.gradle | 4 ++-- ios/NewExpensify/Info.plist | 2 +- ios/NotificationServiceExtension/Info.plist | 2 +- ios/ShareViewController/Info.plist | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Mobile-Expensify b/Mobile-Expensify index 24ad08565f12..4746c9b43040 160000 --- a/Mobile-Expensify +++ b/Mobile-Expensify @@ -1 +1 @@ -Subproject commit 24ad08565f1298eaa08ce29e6e7bc44b30a98def +Subproject commit 4746c9b43040491267ce7aa40f05c23c175c3a74 diff --git a/android/app/build.gradle b/android/app/build.gradle index cfaaf3f4262c..1257dae5efe9 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -114,8 +114,8 @@ android { minSdkVersion rootProject.ext.minSdkVersion targetSdkVersion rootProject.ext.targetSdkVersion multiDexEnabled rootProject.ext.multiDexEnabled - versionCode 1009029905 - versionName "9.2.99-5" + versionCode 1009029904 + versionName "9.2.99-4" // Supported language variants must be declared here to avoid from being removed during the compilation. // This also helps us to not include unnecessary language variants in the APK. resConfigs "en", "es" diff --git a/ios/NewExpensify/Info.plist b/ios/NewExpensify/Info.plist index 038cb56394ab..b3ef15b35dd3 100644 --- a/ios/NewExpensify/Info.plist +++ b/ios/NewExpensify/Info.plist @@ -44,7 +44,7 @@ CFBundleVersion - 9.2.99.5 + 9.2.99.4 FullStory OrgId diff --git a/ios/NotificationServiceExtension/Info.plist b/ios/NotificationServiceExtension/Info.plist index 60747e9de61b..d78e3b795192 100644 --- a/ios/NotificationServiceExtension/Info.plist +++ b/ios/NotificationServiceExtension/Info.plist @@ -13,7 +13,7 @@ CFBundleShortVersionString 9.2.99 CFBundleVersion - 9.2.99.5 + 9.2.99.4 NSExtension NSExtensionPointIdentifier diff --git a/ios/ShareViewController/Info.plist b/ios/ShareViewController/Info.plist index aedb5d672888..657302259906 100644 --- a/ios/ShareViewController/Info.plist +++ b/ios/ShareViewController/Info.plist @@ -13,7 +13,7 @@ CFBundleShortVersionString 9.2.99 CFBundleVersion - 9.2.99.5 + 9.2.99.4 NSExtension NSExtensionAttributes From 6bd519427d17c7699c016d9c2931c6a6ac8c4fc3 Mon Sep 17 00:00:00 2001 From: TaduJR Date: Mon, 12 Jan 2026 23:36:32 +0300 Subject: [PATCH 05/10] revert: Unwanted Changes --- package-lock.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index f6e50e156d27..d5f69c2c6fb0 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "new.expensify", - "version": "9.2.99-5", + "version": "9.2.99-4", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "new.expensify", - "version": "9.2.99-5", + "version": "9.2.99-4", "hasInstallScript": true, "license": "MIT", "dependencies": { From bd460292a968a22951355df1b26e4fd875a09329 Mon Sep 17 00:00:00 2001 From: TaduJR Date: Wed, 14 Jan 2026 22:13:10 +0300 Subject: [PATCH 06/10] revert: Unwanted Changes --- Mobile-Expensify | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Mobile-Expensify b/Mobile-Expensify index 4746c9b43040..187983a613fc 160000 --- a/Mobile-Expensify +++ b/Mobile-Expensify @@ -1 +1 @@ -Subproject commit 4746c9b43040491267ce7aa40f05c23c175c3a74 +Subproject commit 187983a613fcb256535b7737b4cbf529418a336b From 2aabfc04fc90b60bec879c4d6f2fe0ec0b07f372 Mon Sep 17 00:00:00 2001 From: TaduJR Date: Fri, 27 Mar 2026 13:45:52 +0300 Subject: [PATCH 07/10] fix: pass FormulaContext to getAutoReportingDates for trip frequency date --- src/libs/Formula.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/libs/Formula.ts b/src/libs/Formula.ts index fc6041363ac2..22c90fc287dc 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); + const {startDate, endDate} = getAutoReportingDates(policy, report, new Date(), context); switch (subField.toLowerCase()) { case 'start': @@ -769,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()): {startDate: Date | undefined; endDate: Date | undefined} { +function getAutoReportingDates(policy: OnyxEntry, report: Report, currentDate = new Date(), context?: FormulaContext): {startDate: Date | undefined; endDate: Date | undefined} { const frequency = policy?.autoReportingFrequency; const offset = policy?.autoReportingOffset; @@ -823,8 +823,8 @@ 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); - const newestTransactionDateString = getNewestTransactionDate(report.reportID); + const oldestTransactionDateString = getOldestTransactionDate(report.reportID, context); + const newestTransactionDateString = getNewestTransactionDate(report.reportID, context); startDate = oldestTransactionDateString ? new Date(oldestTransactionDateString) : currentDate; endDate = newestTransactionDateString ? new Date(newestTransactionDateString) : currentDate; break; From c59151133a4d8f5a2f4cbf130cbb307de8b0b4e2 Mon Sep 17 00:00:00 2001 From: TaduJR Date: Fri, 27 Mar 2026 13:52:18 +0300 Subject: [PATCH 08/10] test: verify trip autoreporting uses context.transaction for optimistic expense dates --- tests/unit/FormulaTest.ts | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/tests/unit/FormulaTest.ts b/tests/unit/FormulaTest.ts index 78398b6194d9..60b34d1e9474 100644 --- a/tests/unit/FormulaTest.ts +++ b/tests/unit/FormulaTest.ts @@ -678,6 +678,25 @@ describe('CustomFormula', () => { 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 fallback to current date for trip frequency when no transactions', () => { mockReportUtils.getReportTransactions.mockReturnValue([]); From eb5436b9f772a2708e563ccd5ee4e4b58cc9ace4 Mon Sep 17 00:00:00 2001 From: TaduJR Date: Fri, 27 Mar 2026 16:31:49 +0300 Subject: [PATCH 09/10] fix: use full Formula engine for trip report name recalculation on existing reports --- src/libs/Formula.ts | 15 ++++++++++++++ src/libs/actions/IOU/index.ts | 39 ++++++++++++++++++++++++++++------- 2 files changed, 46 insertions(+), 8 deletions(-) diff --git a/src/libs/Formula.ts b/src/libs/Formula.ts index 22c90fc287dc..4df5072b2d01 100644 --- a/src/libs/Formula.ts +++ b/src/libs/Formula.ts @@ -658,6 +658,21 @@ 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) { diff --git a/src/libs/actions/IOU/index.ts b/src/libs/actions/IOU/index.ts index 5e835767cd9c..ab7358d55d09 100644 --- a/src/libs/actions/IOU/index.ts +++ b/src/libs/actions/IOU/index.ts @@ -132,6 +132,7 @@ import { canBeAutoReimbursed, canSubmitAndIsAwaitingForCurrentUser, canUserPerformWriteAction as canUserPerformWriteActionReportUtils, + computeOptimisticReportName, findSelfDMReportID, generateReportID, getAllHeldTransactions as getAllHeldTransactionsReportUtils, @@ -181,7 +182,6 @@ import { isSettled, isTestTransactionReport, isTrackExpenseReport, - populateOptimisticReportFormula, prepareOnboardingOnyxData, shouldCreateNewMoneyRequestReport as shouldCreateNewMoneyRequestReportReportUtils, shouldEnableNegative, @@ -3184,7 +3184,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): string | undefined { +function recalculateOptimisticReportName(iouReport: OnyxTypes.Report, policy: OnyxEntry, newTransaction?: OnyxTypes.Transaction): string | undefined { if (!policy?.fieldList?.[CONST.POLICY.FIELDS.FIELD_LIST_TITLE]) { return undefined; } @@ -3192,17 +3192,37 @@ function recalculateOptimisticReportName(iouReport: OnyxTypes.Report, policy: On if (!titleFormula) { return undefined; } - return populateOptimisticReportFormula(titleFormula, iouReport as Parameters[1], policy); + + // 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; } -function maybeUpdateReportNameForFormulaTitle(iouReport: OnyxTypes.Report, policy: OnyxEntry): OnyxTypes.Report { +function maybeUpdateReportNameForFormulaTitle(iouReport: OnyxTypes.Report, policy: OnyxEntry, newTransaction?: OnyxTypes.Transaction): OnyxTypes.Report { const reportNameValuePairs = allReportNameValuePairs?.[`${ONYXKEYS.COLLECTION.REPORT_NAME_VALUE_PAIRS}${iouReport.reportID}`]; const titleField = reportNameValuePairs?.expensify_text_title; - if (titleField?.type !== CONST.REPORT_FIELD_TYPES.FORMULA) { + + // 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) { return iouReport; } - const updatedReportName = recalculateOptimisticReportName(iouReport, policy); + const updatedReportName = recalculateOptimisticReportName(iouReport, policy, newTransaction); if (!updatedReportName) { return iouReport; } @@ -3386,8 +3406,6 @@ 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 @@ -3489,6 +3507,11 @@ 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 From d0981ea5b33b7b4de0c2a58a34a0449a5d8c5c55 Mon Sep 17 00:00:00 2001 From: TaduJR Date: Fri, 27 Mar 2026 16:36:26 +0300 Subject: [PATCH 10/10] test: cover allTransactions merge with Onyx + optimistic transaction for trip date range --- tests/unit/FormulaTest.ts | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/tests/unit/FormulaTest.ts b/tests/unit/FormulaTest.ts index 60b34d1e9474..eb9f870d8c5c 100644 --- a/tests/unit/FormulaTest.ts +++ b/tests/unit/FormulaTest.ts @@ -697,6 +697,41 @@ describe('CustomFormula', () => { 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([]);