Skip to content

Commit 47b104c

Browse files
authored
Merge pull request Expensify#63212 from bernhardoj/fix/62743-approve-shows-when-receipt-scanning
2 parents 9687e9b + f305b97 commit 47b104c

6 files changed

Lines changed: 120 additions & 22 deletions

src/libs/ReportPreviewActionUtils.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,11 @@ function canApprove(report: Report, violations: OnyxCollection<TransactionViolat
7777
hasNoticeTypeViolations(report.reportID, violations, true) ||
7878
hasWarningTypeViolations(report.reportID, violations, true);
7979
const reportTransactions = transactions ?? getReportTransactions(report?.reportID);
80+
const isAnyReceiptBeingScanned = transactions?.some((transaction) => isReceiptBeingScanned(transaction));
81+
82+
if (isAnyReceiptBeingScanned) {
83+
return false;
84+
}
8085

8186
const isPreventSelfApprovalEnabled = policy?.preventSelfApproval;
8287
const isReportSubmitter = isCurrentUserSubmitter(report.reportID);

src/libs/ReportPrimaryActionUtils.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,12 @@ function isSubmitAction(report: Report, reportTransactions: Transaction[], polic
8787
}
8888

8989
function isApproveAction(report: Report, reportTransactions: Transaction[], policy?: Policy) {
90+
const isAnyReceiptBeingScanned = reportTransactions?.some((transaction) => isReceiptBeingScanned(transaction));
91+
92+
if (isAnyReceiptBeingScanned) {
93+
return false;
94+
}
95+
9096
const currentUserAccountID = getCurrentUserAccountID();
9197
const managerID = report?.managerID ?? CONST.DEFAULT_NUMBER_ID;
9298
const isCurrentUserManager = managerID === currentUserAccountID;

src/libs/ReportSecondaryActionUtils.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,12 @@ function isSubmitAction(report: Report, reportTransactions: Transaction[], polic
155155
}
156156

157157
function isApproveAction(report: Report, reportTransactions: Transaction[], violations: OnyxCollection<TransactionViolation[]>, policy?: Policy): boolean {
158+
const isAnyReceiptBeingScanned = reportTransactions?.some((transaction) => isReceiptBeingScanned(transaction));
159+
160+
if (isAnyReceiptBeingScanned) {
161+
return false;
162+
}
163+
158164
const currentUserAccountID = getCurrentUserAccountID();
159165
const managerID = report?.managerID ?? CONST.DEFAULT_NUMBER_ID;
160166
const isCurrentUserManager = managerID === currentUserAccountID;

tests/actions/ReportPreviewActionUtilsTest.ts

Lines changed: 52 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -95,30 +95,60 @@ describe('getReportPreviewAction', () => {
9595
expect(getReportPreviewAction(VIOLATIONS, report, policy, [transaction], isReportArchived.current)).toBe(CONST.REPORT.REPORT_PREVIEW_ACTIONS.SUBMIT);
9696
});
9797

98-
it('canApprove should return true for report being processed', async () => {
99-
const report = {
100-
...createRandomReport(REPORT_ID),
101-
type: CONST.REPORT.TYPE.EXPENSE,
102-
ownerAccountID: CURRENT_USER_ACCOUNT_ID,
103-
stateNum: CONST.REPORT.STATE_NUM.SUBMITTED,
104-
statusNum: CONST.REPORT.STATUS_NUM.SUBMITTED,
105-
managerID: CURRENT_USER_ACCOUNT_ID,
106-
isWaitingOnBankAccount: false,
107-
};
108-
109-
const policy = createRandomPolicy(0);
110-
policy.type = CONST.POLICY.TYPE.CORPORATE;
111-
policy.approver = CURRENT_USER_EMAIL;
112-
policy.approvalMode = CONST.POLICY.APPROVAL_MODE.BASIC;
113-
policy.preventSelfApproval = false;
98+
describe('canApprove', () => {
99+
it('should return true for report being processed', async () => {
100+
const report = {
101+
...createRandomReport(REPORT_ID),
102+
type: CONST.REPORT.TYPE.EXPENSE,
103+
ownerAccountID: CURRENT_USER_ACCOUNT_ID,
104+
stateNum: CONST.REPORT.STATE_NUM.SUBMITTED,
105+
statusNum: CONST.REPORT.STATUS_NUM.SUBMITTED,
106+
managerID: CURRENT_USER_ACCOUNT_ID,
107+
isWaitingOnBankAccount: false,
108+
};
109+
110+
const policy = createRandomPolicy(0);
111+
policy.type = CONST.POLICY.TYPE.CORPORATE;
112+
policy.approver = CURRENT_USER_EMAIL;
113+
policy.approvalMode = CONST.POLICY.APPROVAL_MODE.BASIC;
114+
policy.preventSelfApproval = false;
115+
116+
await Onyx.merge(`${ONYXKEYS.COLLECTION.REPORT}${REPORT_ID}`, report);
117+
const transaction = {
118+
reportID: `${REPORT_ID}`,
119+
} as unknown as Transaction;
120+
121+
const {result: isReportArchived} = renderHook(() => useReportIsArchived(report?.parentReportID));
122+
expect(getReportPreviewAction(VIOLATIONS, report, policy, [transaction], isReportArchived.current)).toBe(CONST.REPORT.REPORT_PREVIEW_ACTIONS.APPROVE);
123+
});
114124

115-
await Onyx.merge(`${ONYXKEYS.COLLECTION.REPORT}${REPORT_ID}`, report);
116-
const transaction = {
117-
reportID: `${REPORT_ID}`,
118-
} as unknown as Transaction;
125+
it('should return false for report with scanning expenses', async () => {
126+
const report = {
127+
...createRandomReport(REPORT_ID),
128+
type: CONST.REPORT.TYPE.EXPENSE,
129+
ownerAccountID: CURRENT_USER_ACCOUNT_ID,
130+
stateNum: CONST.REPORT.STATE_NUM.SUBMITTED,
131+
statusNum: CONST.REPORT.STATUS_NUM.SUBMITTED,
132+
managerID: CURRENT_USER_ACCOUNT_ID,
133+
isWaitingOnBankAccount: false,
134+
};
135+
136+
const policy = createRandomPolicy(0);
137+
policy.type = CONST.POLICY.TYPE.CORPORATE;
138+
policy.approver = CURRENT_USER_EMAIL;
139+
policy.approvalMode = CONST.POLICY.APPROVAL_MODE.BASIC;
140+
policy.preventSelfApproval = false;
141+
142+
await Onyx.merge(`${ONYXKEYS.COLLECTION.REPORT}${REPORT_ID}`, report);
143+
const transaction = {
144+
reportID: `${REPORT_ID}`,
145+
receipt: {
146+
state: CONST.IOU.RECEIPT_STATE.SCANNING,
147+
},
148+
} as unknown as Transaction;
119149

120-
const {result: isReportArchived} = renderHook(() => useReportIsArchived(report?.parentReportID));
121-
expect(getReportPreviewAction(VIOLATIONS, report, policy, [transaction], isReportArchived.current)).toBe(CONST.REPORT.REPORT_PREVIEW_ACTIONS.APPROVE);
150+
expect(getReportPreviewAction(VIOLATIONS, report, policy, [transaction], false)).toBe(CONST.REPORT.REPORT_PREVIEW_ACTIONS.VIEW);
151+
});
122152
});
123153

124154
it('canPay should return true for expense report with payments enabled', async () => {

tests/unit/ReportPrimaryActionUtilsTest.ts

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,33 @@ describe('getPrimaryAction', () => {
8989
expect(getReportPrimaryAction(report, [transaction], {}, policy as Policy)).toBe(CONST.REPORT.PRIMARY_ACTIONS.APPROVE);
9090
});
9191

92+
it('should return empty for report being processed but transactions are scanning', async () => {
93+
const report = {
94+
reportID: REPORT_ID,
95+
type: CONST.REPORT.TYPE.EXPENSE,
96+
ownerAccountID: CURRENT_USER_ACCOUNT_ID,
97+
stateNum: CONST.REPORT.STATE_NUM.SUBMITTED,
98+
statusNum: CONST.REPORT.STATUS_NUM.SUBMITTED,
99+
managerID: CURRENT_USER_ACCOUNT_ID,
100+
} as unknown as Report;
101+
await Onyx.merge(`${ONYXKEYS.COLLECTION.REPORT}${REPORT_ID}`, report);
102+
const policy = {
103+
approver: CURRENT_USER_EMAIL,
104+
approvalMode: CONST.POLICY.APPROVAL_MODE.BASIC,
105+
};
106+
const transaction = {
107+
reportID: `${REPORT_ID}`,
108+
comment: {
109+
hold: 'Hold',
110+
},
111+
receipt: {
112+
state: CONST.IOU.RECEIPT_STATE.SCANNING,
113+
},
114+
} as unknown as Transaction;
115+
116+
expect(getReportPrimaryAction(report, [transaction], {}, policy as Policy)).toBe('');
117+
});
118+
92119
it('should return PAY for submitted invoice report', async () => {
93120
const report = {
94121
reportID: REPORT_ID,

tests/unit/ReportSecondaryActionUtilsTest.ts

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -182,6 +182,30 @@ describe('getSecondaryAction', () => {
182182
expect(result.includes(CONST.REPORT.SECONDARY_ACTIONS.APPROVE)).toBe(true);
183183
});
184184

185+
it('does not include APPROVE option for report with transactions are being scanned', () => {
186+
const report = {
187+
reportID: REPORT_ID,
188+
type: CONST.REPORT.TYPE.EXPENSE,
189+
ownerAccountID: EMPLOYEE_ACCOUNT_ID,
190+
stateNum: CONST.REPORT.STATE_NUM.SUBMITTED,
191+
statusNum: CONST.REPORT.STATUS_NUM.SUBMITTED,
192+
managerID: EMPLOYEE_ACCOUNT_ID,
193+
} as unknown as Report;
194+
const policy = {
195+
approver: EMPLOYEE_EMAIL,
196+
} as unknown as Policy;
197+
const TRANSACTION_ID = 'TRANSACTION_ID';
198+
const transaction = {
199+
transactionID: TRANSACTION_ID,
200+
receipt: {
201+
state: CONST.IOU.RECEIPT_STATE.SCANNING,
202+
},
203+
} as unknown as Transaction;
204+
205+
const result = getSecondaryReportActions(report, [transaction], {}, policy);
206+
expect(result.includes(CONST.REPORT.SECONDARY_ACTIONS.APPROVE)).toBe(false);
207+
});
208+
185209
it('includes UNAPPROVE option', () => {
186210
const report = {
187211
reportID: REPORT_ID,

0 commit comments

Comments
 (0)