diff --git a/src/components/ReportActionItem/MoneyRequestReportPreview/MoneyRequestReportPreviewContent.tsx b/src/components/ReportActionItem/MoneyRequestReportPreview/MoneyRequestReportPreviewContent.tsx index 7d86814c077a..30c37b093948 100644 --- a/src/components/ReportActionItem/MoneyRequestReportPreview/MoneyRequestReportPreviewContent.tsx +++ b/src/components/ReportActionItem/MoneyRequestReportPreview/MoneyRequestReportPreviewContent.tsx @@ -439,7 +439,7 @@ function MoneyRequestReportPreviewContent({ if (isPaidAnimationRunning) { return CONST.REPORT.REPORT_PREVIEW_ACTIONS.PAY; } - return getReportPreviewAction(violations, isIouReportArchived || isChatReportArchived, iouReport, policy, transactions, reportActions, invoiceReceiverPolicy); + return getReportPreviewAction(violations, isIouReportArchived || isChatReportArchived, iouReport, policy, transactions, invoiceReceiverPolicy); }, [isPaidAnimationRunning, violations, iouReport, policy, transactions, isIouReportArchived, reportActions, invoiceReceiverPolicy, isChatReportArchived]); const addExpenseDropdownOptions = useMemo( diff --git a/src/libs/DebugUtils.ts b/src/libs/DebugUtils.ts index 410386bccaf8..533b125072d3 100644 --- a/src/libs/DebugUtils.ts +++ b/src/libs/DebugUtils.ts @@ -472,6 +472,9 @@ function validateReportDraftProperty(key: keyof Report | keyof ReportNameValuePa case 'isDeletedParentAction': case 'isWaitingOnBankAccount': case 'isCancelledIOU': + case 'hasReportBeenReopened': + case 'isExportedToIntegration': + case 'hasExportError': return validateBoolean(value); case 'exportFailedTime': case 'lastReadSequenceNumber': @@ -623,6 +626,9 @@ function validateReportDraftProperty(key: keyof Report | keyof ReportNameValuePa unheldNonReimbursableTotal: CONST.RED_BRICK_ROAD_PENDING_ACTION, isWaitingOnBankAccount: CONST.RED_BRICK_ROAD_PENDING_ACTION, isCancelledIOU: CONST.RED_BRICK_ROAD_PENDING_ACTION, + hasReportBeenReopened: CONST.RED_BRICK_ROAD_PENDING_ACTION, + isExportedToIntegration: CONST.RED_BRICK_ROAD_PENDING_ACTION, + hasExportError: CONST.RED_BRICK_ROAD_PENDING_ACTION, iouReportID: CONST.RED_BRICK_ROAD_PENDING_ACTION, preexistingReportID: CONST.RED_BRICK_ROAD_PENDING_ACTION, nonReimbursableTotal: CONST.RED_BRICK_ROAD_PENDING_ACTION, diff --git a/src/libs/ReportPreviewActionUtils.ts b/src/libs/ReportPreviewActionUtils.ts index dde1d473a52b..b0f69a253d77 100644 --- a/src/libs/ReportPreviewActionUtils.ts +++ b/src/libs/ReportPreviewActionUtils.ts @@ -1,7 +1,7 @@ -import type {OnyxCollection, OnyxEntry} from 'react-native-onyx'; +import type {OnyxCollection} from 'react-native-onyx'; import type {ValueOf} from 'type-fest'; import CONST from '@src/CONST'; -import type {Policy, Report, ReportAction, ReportActions, Transaction, TransactionViolation} from '@src/types/onyx'; +import type {Policy, Report, Transaction, TransactionViolation} from '@src/types/onyx'; import {getCurrentUserAccountID} from './actions/Report'; import { arePaymentsEnabled, @@ -18,13 +18,10 @@ import { getParentReport, getReportTransactions, hasAnyViolations as hasAnyViolationsUtil, - hasExportError as hasExportErrorUtil, hasMissingSmartscanFields, - hasReportBeenReopened, isClosedReport, isCurrentUserSubmitter, isExpenseReport, - isExported as isExportedUtil, isInvoiceReport, isIOUReport, isOpenExpenseReport, @@ -38,14 +35,7 @@ import { import {getSession} from './SessionUtils'; import {allHavePendingRTERViolation, isPending, isScanning, shouldShowBrokenConnectionViolationForMultipleTransactions} from './TransactionUtils'; -function canSubmit( - report: Report, - violations: OnyxCollection, - isReportArchived: boolean, - reportActions?: OnyxEntry | ReportAction[], - policy?: Policy, - transactions?: Transaction[], -) { +function canSubmit(report: Report, violations: OnyxCollection, isReportArchived: boolean, policy?: Policy, transactions?: Transaction[]) { if (isReportArchived) { return false; } @@ -55,7 +45,7 @@ function canSubmit( const isOpen = isOpenReport(report); const isManager = report.managerID === getCurrentUserAccountID(); const isAdmin = policy?.role === CONST.POLICY.ROLE.ADMIN; - const hasBeenReopened = hasReportBeenReopened(reportActions); + const hasBeenReopened = report.hasReportBeenReopened ?? false; const isManualSubmitEnabled = getCorrectedAutoReportingFrequency(policy) === CONST.POLICY.AUTO_REPORTING_FREQUENCIES.MANUAL; if (!!transactions && transactions?.length > 0 && transactions.every((transaction) => isPending(transaction))) { @@ -164,7 +154,7 @@ function canPay( return invoiceReceiverPolicy?.role === CONST.POLICY.ROLE.ADMIN && reimbursableSpend > 0; } -function canExport(report: Report, violations: OnyxCollection, policy?: Policy, reportActions?: OnyxEntry | ReportAction[]) { +function canExport(report: Report, violations: OnyxCollection, policy?: Policy) { const isExpense = isExpenseReport(report); const isExporter = policy ? isPreferredExporter(policy) : false; const isReimbursed = isSettled(report); @@ -178,12 +168,12 @@ function canExport(report: Report, violations: OnyxCollection | ReportAction[], invoiceReceiverPolicy?: Policy, ): ValueOf { if (!report) { @@ -243,7 +232,7 @@ function getReportPreviewAction( if (isAddExpenseAction(report, transactions ?? [], isReportArchived)) { return CONST.REPORT.REPORT_PREVIEW_ACTIONS.ADD_EXPENSE; } - if (canSubmit(report, violations, isReportArchived, reportActions, policy, transactions)) { + if (canSubmit(report, violations, isReportArchived, policy, transactions)) { return CONST.REPORT.REPORT_PREVIEW_ACTIONS.SUBMIT; } if (canApprove(report, violations, policy, transactions)) { @@ -252,7 +241,7 @@ function getReportPreviewAction( if (canPay(report, violations, isReportArchived, policy, invoiceReceiverPolicy)) { return CONST.REPORT.REPORT_PREVIEW_ACTIONS.PAY; } - if (canExport(report, violations, policy, reportActions)) { + if (canExport(report, violations, policy)) { return CONST.REPORT.REPORT_PREVIEW_ACTIONS.EXPORT_TO_ACCOUNTING; } if (canReview(report, violations, isReportArchived, policy, transactions)) { diff --git a/src/libs/ReportUtils.ts b/src/libs/ReportUtils.ts index d9981d9d2666..0c1bf2758062 100644 --- a/src/libs/ReportUtils.ts +++ b/src/libs/ReportUtils.ts @@ -10832,7 +10832,13 @@ function getIntegrationNameFromExportMessage(reportActions: OnyxEntry | ReportAction[]) { +function isExported(reportActions: OnyxEntry | ReportAction[], report?: OnyxEntry): boolean { + // If report object is provided and has the property, use it directly + if (report?.isExportedToIntegration !== undefined) { + return report.isExportedToIntegration; + } + + // Fallback to checking actions for backward compatibility if (!reportActions) { return false; } @@ -10860,7 +10866,13 @@ function isExported(reportActions: OnyxEntry | ReportAction[]) { return exportIntegrationActionsCount > integrationMessageActionsCount; } -function hasExportError(reportActions: OnyxEntry | ReportAction[]) { +function hasExportError(reportActions: OnyxEntry | ReportAction[], report?: OnyxEntry) { + // If report object is provided and has the property, use it directly + if (report?.hasExportError !== undefined) { + return report.hasExportError; + } + + // Fallback to checking actions for backward compatibility if (!reportActions) { return false; } @@ -11137,7 +11149,13 @@ function findReportIDForAction(action?: ReportAction): string | undefined { ?.replace(`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}`, ''); } -function hasReportBeenReopened(reportActions: OnyxEntry | ReportAction[]): boolean { +function hasReportBeenReopened(reportActions: OnyxEntry | ReportAction[], report?: OnyxEntry): boolean { + // If report object is provided and has the property, use it directly + if (report?.hasReportBeenReopened !== undefined) { + return report.hasReportBeenReopened; + } + + // Fallback to checking actions for backward compatibility if (!reportActions) { return false; } diff --git a/src/types/onyx/Report.ts b/src/types/onyx/Report.ts index b6ba318ab743..cea4963592cf 100644 --- a/src/types/onyx/Report.ts +++ b/src/types/onyx/Report.ts @@ -194,6 +194,15 @@ type Report = OnyxCommon.OnyxValueWithOfflineFeedback< /** Whether the report is cancelled */ isCancelledIOU?: boolean; + /** Whether the report has been reopened */ + hasReportBeenReopened?: boolean; + + /** Whether the report has been exported to integration */ + isExportedToIntegration?: boolean; + + /** Whether the report has any export errors */ + hasExportError?: boolean; + /** The ID of the IOU report */ iouReportID?: string; diff --git a/src/types/utils/whitelistedReportKeys.ts b/src/types/utils/whitelistedReportKeys.ts index 847efeb1c7ae..6c4f4771c2d1 100644 --- a/src/types/utils/whitelistedReportKeys.ts +++ b/src/types/utils/whitelistedReportKeys.ts @@ -50,6 +50,9 @@ type WhitelistedReport = OnyxCommon.OnyxValueWithOfflineFeedback< errors: unknown; isWaitingOnBankAccount: unknown; isCancelledIOU: unknown; + hasReportBeenReopened: unknown; + isExportedToIntegration: unknown; + hasExportError: unknown; iouReportID: unknown; preexistingReportID: unknown; nonReimbursableTotal: unknown; diff --git a/tests/actions/ReportPreviewActionUtilsTest.ts b/tests/actions/ReportPreviewActionUtilsTest.ts index 61560e5d6a6b..da7f9af809dd 100644 --- a/tests/actions/ReportPreviewActionUtilsTest.ts +++ b/tests/actions/ReportPreviewActionUtilsTest.ts @@ -287,7 +287,7 @@ describe('getReportPreviewAction', () => { } as unknown as Transaction; const {result: isReportArchived} = renderHook(() => useReportIsArchived(report?.parentReportID)); - expect(getReportPreviewAction(VIOLATIONS, isReportArchived.current, report, policy, [transaction], undefined, invoiceReceiverPolicy)).toBe(CONST.REPORT.REPORT_PREVIEW_ACTIONS.PAY); + expect(getReportPreviewAction(VIOLATIONS, isReportArchived.current, report, policy, [transaction], invoiceReceiverPolicy)).toBe(CONST.REPORT.REPORT_PREVIEW_ACTIONS.PAY); }); it('getReportPreviewAction should return VIEW action for zero value invoice', async () => { @@ -332,7 +332,7 @@ describe('getReportPreviewAction', () => { const {result: isReportArchived} = renderHook(() => useReportIsArchived(report.parentReportID)); - expect(getReportPreviewAction(VIOLATIONS, isReportArchived.current, report, policy, [transaction], undefined, invoiceReceiverPolicy)).toBe(CONST.REPORT.REPORT_PREVIEW_ACTIONS.VIEW); + expect(getReportPreviewAction(VIOLATIONS, isReportArchived.current, report, policy, [transaction], invoiceReceiverPolicy)).toBe(CONST.REPORT.REPORT_PREVIEW_ACTIONS.VIEW); }); it('canPay should return false for archived invoice', async () => { @@ -364,7 +364,7 @@ describe('getReportPreviewAction', () => { reportID: `${REPORT_ID}`, } as unknown as Transaction; const {result: isReportArchived} = renderHook(() => useReportIsArchived(report?.parentReportID)); - expect(getReportPreviewAction(VIOLATIONS, isReportArchived.current, report, policy, [transaction], undefined, invoiceReceiverPolicy)).toBe(CONST.REPORT.REPORT_PREVIEW_ACTIONS.PAY); + expect(getReportPreviewAction(VIOLATIONS, isReportArchived.current, report, policy, [transaction], invoiceReceiverPolicy)).toBe(CONST.REPORT.REPORT_PREVIEW_ACTIONS.PAY); }); it('getReportPreviewAction should return VIEW action for invoice when the chat report is archived', async () => {