Skip to content
Merged
6 changes: 5 additions & 1 deletion src/libs/ReportPreviewActionUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ import {
isSettled,
} from './ReportUtils';
import {getSession} from './SessionUtils';
import {allHavePendingRTERViolation, isScanning, shouldShowBrokenConnectionViolationForMultipleTransactions} from './TransactionUtils';
import {allHavePendingRTERViolation, isPending, isScanning, shouldShowBrokenConnectionViolationForMultipleTransactions} from './TransactionUtils';

function canSubmit(
report: Report,
Expand All @@ -60,6 +60,10 @@ function canSubmit(
const hasBeenReopened = hasReportBeenReopened(reportActions);
const isManualSubmitEnabled = getCorrectedAutoReportingFrequency(policy) === CONST.POLICY.AUTO_REPORTING_FREQUENCIES.MANUAL;

if (!!transactions && transactions?.length > 0 && transactions.every((transaction) => isPending(transaction))) {
return false;
}

const hasAnyViolations =
hasMissingSmartscanFields(report.reportID, transactions) ||
hasViolations(report.reportID, violations) ||
Expand Down
5 changes: 5 additions & 0 deletions src/libs/ReportPrimaryActionUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ import {
hasPendingRTERViolation as hasPendingRTERViolationTransactionUtils,
isDuplicate,
isOnHold as isOnHoldTransactionUtils,
isPending,
isScanning,
shouldShowBrokenConnectionViolationForMultipleTransactions,
shouldShowBrokenConnectionViolation as shouldShowBrokenConnectionViolationTransactionUtils,
Expand Down Expand Up @@ -81,6 +82,10 @@ function isSubmitAction(report: Report, reportTransactions: Transaction[], polic
const isManualSubmitEnabled = getCorrectedAutoReportingFrequency(policy) === CONST.POLICY.AUTO_REPORTING_FREQUENCIES.MANUAL;
const transactionAreComplete = reportTransactions.every((transaction) => transaction.amount !== 0 || transaction.modifiedAmount !== 0);

if (reportTransactions.length > 0 && reportTransactions.every((transaction) => isPending(transaction))) {
return false;
}

const isAnyReceiptBeingScanned = reportTransactions?.some((transaction) => isScanning(transaction));
const hasReportBeenReopened = hasReportBeenReopenedUtils(reportActions);

Expand Down
4 changes: 4 additions & 0 deletions src/libs/ReportSecondaryActionUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,10 @@ function isSubmitAction(
return false;
}

if (reportTransactions.length > 0 && reportTransactions.every((transaction) => isPending(transaction))) {
return false;
}

const isExpenseReport = isExpenseReportUtils(report);

if (!isExpenseReport || report?.total === 0) {
Expand Down
30 changes: 30 additions & 0 deletions tests/actions/ReportPreviewActionUtilsTest.ts
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,36 @@ describe('getReportPreviewAction', () => {
expect(getReportPreviewAction(VIOLATIONS, report, policy, [transaction], isReportArchived.current)).toBe(CONST.REPORT.REPORT_PREVIEW_ACTIONS.SUBMIT);
});

it('canSubmit should return false for expense preview report with only pending transactions', async () => {
const report: Report = {
...createRandomReport(REPORT_ID),
type: CONST.REPORT.TYPE.EXPENSE,
ownerAccountID: CURRENT_USER_ACCOUNT_ID,
stateNum: CONST.REPORT.STATE_NUM.OPEN,
statusNum: CONST.REPORT.STATUS_NUM.OPEN,
isWaitingOnBankAccount: false,
};

const policy = createRandomPolicy(0);
policy.autoReportingFrequency = CONST.POLICY.AUTO_REPORTING_FREQUENCIES.IMMEDIATE;
policy.type = CONST.POLICY.TYPE.CORPORATE;
if (policy.harvesting) {
policy.harvesting.enabled = false;
}
await Onyx.merge(`${ONYXKEYS.COLLECTION.REPORT}${REPORT_ID}`, report);
const transaction = {
reportID: `${REPORT_ID}`,
status: CONST.TRANSACTION.STATUS.PENDING,
amount: 10,
merchant: 'Merchant',
date: '2025-01-01',
} as unknown as Transaction;

// Simulate how components use a hook to pass the isReportArchived parameter
const {result: isReportArchived} = renderHook(() => useReportIsArchived(report?.parentReportID));
expect(getReportPreviewAction(VIOLATIONS, report, policy, [transaction], isReportArchived.current)).toBe(CONST.REPORT.REPORT_PREVIEW_ACTIONS.VIEW);
});

describe('canApprove', () => {
it('should return true for report being processed', async () => {
const report = {
Expand Down
24 changes: 24 additions & 0 deletions tests/unit/ReportPrimaryActionUtilsTest.ts
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,30 @@ describe('getPrimaryAction', () => {
expect(getReportPrimaryAction({report, chatReport, reportTransactions: [transaction], violations: {}, policy: policy as Policy})).toBe(CONST.REPORT.PRIMARY_ACTIONS.SUBMIT);
});

it('should not return SUBMIT option for admin with only pending transactions', async () => {
const report = {
reportID: REPORT_ID,
type: CONST.REPORT.TYPE.EXPENSE,
ownerAccountID: CURRENT_USER_ACCOUNT_ID,
stateNum: CONST.REPORT.STATE_NUM.OPEN,
statusNum: CONST.REPORT.STATUS_NUM.OPEN,
} as unknown as Report;
await Onyx.merge(`${ONYXKEYS.COLLECTION.REPORT}${REPORT_ID}`, report);

const policy = {
autoReportingFrequency: CONST.POLICY.AUTO_REPORTING_FREQUENCIES.IMMEDIATE,
};
const transaction = {
reportID: `${REPORT_ID}`,
status: CONST.TRANSACTION.STATUS.PENDING,
amount: 10,
merchant: 'Merchant',
date: '2025-01-01',
} as unknown as Transaction;

expect(getReportPrimaryAction({report, chatReport, reportTransactions: [transaction], violations: {}, policy: policy as Policy})).toBe('');
});

it('should return Approve for report being processed', async () => {
const report = {
reportID: REPORT_ID,
Expand Down
29 changes: 29 additions & 0 deletions tests/unit/ReportSecondaryActionUtilsTest.ts
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,35 @@ describe('getSecondaryAction', () => {
expect(result.includes(CONST.REPORT.SECONDARY_ACTIONS.SUBMIT)).toBe(true);
});

it('should not include SUBMIT option for admin with only pending transactions', async () => {
const report = {
reportID: REPORT_ID,
type: CONST.REPORT.TYPE.EXPENSE,
stateNum: CONST.REPORT.STATE_NUM.OPEN,
statusNum: CONST.REPORT.STATUS_NUM.OPEN,
total: 10,
} as unknown as Report;
const policy = {
autoReportingFrequency: CONST.POLICY.AUTO_REPORTING_FREQUENCIES.INSTANT,
harvesting: {
enabled: true,
},
role: CONST.POLICY.ROLE.ADMIN,
} as unknown as Policy;
await Onyx.merge(`${ONYXKEYS.COLLECTION.REPORT}${REPORT_ID}`, report);

const transaction = {
transactionID: 'TRANSACTION_ID',
status: CONST.TRANSACTION.STATUS.PENDING,
amount: 10,
merchant: 'Merchant',
date: '2025-01-01',
} as unknown as Transaction;

const result = getSecondaryReportActions({report, chatReport, reportTransactions: [transaction], violations: {}, policy});
expect(result.includes(CONST.REPORT.SECONDARY_ACTIONS.SUBMIT)).toBe(false);
});

it('includes APPROVE option for approver and report with duplicates', async () => {
const report = {
reportID: REPORT_ID,
Expand Down
Loading