Skip to content

Commit 67f3cf6

Browse files
committed
Merge remote-tracking branch 'upstream/main' into 78247/admin-can-pay-report-newdot
2 parents a6f6124 + 0ab568c commit 67f3cf6

9 files changed

Lines changed: 52 additions & 3 deletions

src/libs/ReportPrimaryActionUtils.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import {
1111
getValidConnectedIntegration,
1212
hasDynamicExternalWorkflow,
1313
hasIntegrationAutoSync,
14+
isPaidGroupPolicy,
1415
isPolicyAdmin as isPolicyAdminPolicyUtils,
1516
isPreferredExporter,
1617
} from './PolicyUtils';
@@ -418,6 +419,11 @@ function getReportPrimaryAction(params: GetReportPrimaryActionParams): ValueOf<t
418419
isSubmittingAnimationRunning,
419420
} = params;
420421

422+
// The expense report of personal policy shouldn't have any action
423+
if (isExpenseReportUtils(report) && !isPaidGroupPolicy(policy)) {
424+
return '';
425+
}
426+
421427
// We want to have action displayed for either paid or approved animations
422428
// eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing
423429
if (isPaidAnimationRunning || isApprovedAnimationRunning) {

src/libs/ReportSecondaryActionUtils.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import {
1616
hasDynamicExternalWorkflow,
1717
hasIntegrationAutoSync,
1818
isInstantSubmitEnabled,
19+
isPaidGroupPolicy,
1920
isPolicyAdmin,
2021
isPolicyMember,
2122
isPreferredExporter,
@@ -204,7 +205,7 @@ function isSubmitAction({
204205

205206
const isExpenseReport = isExpenseReportUtils(report);
206207

207-
if (!isExpenseReport || (report?.total === 0 && reportTransactions.length === 0)) {
208+
if (!isExpenseReport || (report?.total === 0 && reportTransactions.length === 0) || !isPaidGroupPolicy(policy)) {
208209
return false;
209210
}
210211

src/libs/ReportUtils.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2799,12 +2799,18 @@ function canAddOrDeleteTransactions(moneyRequestReport: OnyxEntry<Report>, isRep
27992799
* - if current user is not the submitter of an expense report
28002800
*/
28012801
function canAddTransaction(moneyRequestReport: OnyxEntry<Report>, isReportArchived = false, isMovingTransaction = false): boolean {
2802-
if (!isMoneyRequestReport(moneyRequestReport) || (isExpenseReport(moneyRequestReport) && !isCurrentUserSubmitter(moneyRequestReport))) {
2802+
if (!isMoneyRequestReport(moneyRequestReport)) {
28032803
return false;
28042804
}
2805+
28052806
// This will be fixed as part of https://github.com/Expensify/Expensify/issues/507850
28062807
// eslint-disable-next-line @typescript-eslint/no-deprecated
28072808
const policy = getPolicy(moneyRequestReport?.policyID);
2809+
2810+
if (isExpenseReport(moneyRequestReport) && (!isCurrentUserSubmitter(moneyRequestReport) || !isPaidGroupPolicyPolicyUtils(policy))) {
2811+
return false;
2812+
}
2813+
28082814
if (
28092815
isInstantSubmitEnabled(policy) &&
28102816
isSubmitAndClose(policy) &&

tests/actions/IOUTest.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,8 @@ import {getMicroSecondOnyxErrorWithTranslationKey} from '@libs/ErrorUtils';
6767
import Navigation from '@libs/Navigation/Navigation';
6868
import {rand64} from '@libs/NumberUtils';
6969
import {getLoginsByAccountIDs} from '@libs/PersonalDetailsUtils';
70+
// eslint-disable-next-line no-restricted-syntax
71+
import type * as PolicyUtils from '@libs/PolicyUtils';
7072
import {
7173
getOriginalMessage,
7274
getReportActionHtml,
@@ -174,6 +176,12 @@ jest.mock('@src/libs/SearchQueryUtils', () => {
174176
};
175177
});
176178

179+
jest.mock('@libs/PolicyUtils', () => ({
180+
...jest.requireActual<typeof PolicyUtils>('@libs/PolicyUtils'),
181+
isPaidGroupPolicy: jest.fn().mockReturnValue(true),
182+
isPolicyOwner: jest.fn().mockImplementation((policy?: OnyxEntry<Policy>, currentUserAccountID?: number) => !!currentUserAccountID && policy?.ownerAccountID === currentUserAccountID),
183+
}));
184+
177185
const CARLOS_EMAIL = 'cmartins@expensifail.com';
178186
const CARLOS_ACCOUNT_ID = 1;
179187
const CARLOS_PARTICIPANT: Participant = {notificationPreference: CONST.REPORT.NOTIFICATION_PREFERENCE.ALWAYS, role: 'member'};

tests/actions/ReportPreviewActionUtilsTest.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ jest.mock('@libs/PolicyUtils', () => ({
4141
isPreferredExporter: jest.fn().mockReturnValue(true),
4242
hasAccountingConnections: jest.fn().mockReturnValue(true),
4343
getValidConnectedIntegration: jest.fn().mockReturnValue('netsuite'),
44+
isPaidGroupPolicy: jest.fn().mockReturnValue(true),
4445
}));
4546
jest.mock('@src/libs/SearchUIUtils', () => ({
4647
getSuggestedSearches: jest.fn().mockReturnValue({}),
@@ -70,7 +71,7 @@ describe('getReportPreviewAction', () => {
7071
} as unknown as Report;
7172
await Onyx.merge(`${ONYXKEYS.COLLECTION.REPORT}${REPORT_ID}`, report);
7273

73-
const policy = createRandomPolicy(0, CONST.POLICY.TYPE.PERSONAL);
74+
const policy = createRandomPolicy(0, CONST.POLICY.TYPE.CORPORATE);
7475
expect(
7576
getReportPreviewAction({
7677
isReportArchived: false,

tests/unit/QuickActionUtilsTest.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -185,6 +185,8 @@ describe('QuickActionUtils', () => {
185185
ABCDEF: perDiemCustomUnit,
186186
},
187187
} as unknown as Policy;
188+
mockedPolicyUtils.isPaidGroupPolicy.mockReturnValue(true);
189+
188190
expect(isQuickActionAllowed(perDiemAction, report, policy, false, false)).toBe(true);
189191
});
190192
it("should not allow per diem action when policy doesn't have per diem rates", () => {

tests/unit/ReportPrimaryActionUtilsTest.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ jest.mock('@libs/PolicyUtils', () => ({
3838
...jest.requireActual<typeof PolicyUtils>('@libs/PolicyUtils'),
3939
isPolicyAdmin: jest.fn().mockImplementation((policy?: Policy) => policy?.role === 'admin'),
4040
getValidConnectedIntegration: jest.fn(),
41+
isPaidGroupPolicy: jest.fn().mockReturnValue(true),
4142
}));
4243

4344
describe('getPrimaryAction', () => {

tests/unit/ReportSecondaryActionUtilsTest.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ jest.mock('@libs/PolicyUtils', () => ({
3939
hasAccountingConnections: jest.fn().mockReturnValue(true),
4040
isPolicyAdmin: jest.fn().mockReturnValue(true),
4141
getValidConnectedIntegration: jest.fn().mockReturnValue('netsuite'),
42+
isPaidGroupPolicy: jest.fn().mockReturnValue(true),
4243
}));
4344

4445
describe('getSecondaryAction', () => {
@@ -88,6 +89,7 @@ describe('getSecondaryAction', () => {
8889
harvesting: {
8990
enabled: true,
9091
},
92+
type: CONST.POLICY.TYPE.CORPORATE,
9193
} as unknown as Policy;
9294
await Onyx.merge(`${ONYXKEYS.COLLECTION.REPORT}${REPORT_ID}`, report);
9395
const TRANSACTION_ID = 'TRANSACTION_ID';
@@ -124,6 +126,7 @@ describe('getSecondaryAction', () => {
124126
harvesting: {
125127
enabled: true,
126128
},
129+
type: CONST.POLICY.TYPE.CORPORATE,
127130
} as unknown as Policy;
128131
await Onyx.merge(`${ONYXKEYS.COLLECTION.REPORT}${REPORT_ID}`, report);
129132

@@ -155,6 +158,7 @@ describe('getSecondaryAction', () => {
155158
enabled: true,
156159
},
157160
role: CONST.POLICY.ROLE.ADMIN,
161+
type: CONST.POLICY.TYPE.CORPORATE,
158162
} as unknown as Policy;
159163
await Onyx.merge(`${ONYXKEYS.COLLECTION.REPORT}${REPORT_ID}`, report);
160164

@@ -186,6 +190,7 @@ describe('getSecondaryAction', () => {
186190
harvesting: {
187191
enabled: true,
188192
},
193+
type: CONST.POLICY.TYPE.CORPORATE,
189194
} as unknown as Policy;
190195
await Onyx.merge(`${ONYXKEYS.COLLECTION.REPORT}${REPORT_ID}`, report);
191196

@@ -264,6 +269,7 @@ describe('getSecondaryAction', () => {
264269
enabled: true,
265270
},
266271
role: CONST.POLICY.ROLE.USER,
272+
type: CONST.POLICY.TYPE.CORPORATE,
267273
} as unknown as Policy;
268274

269275
const transaction = {
@@ -311,6 +317,7 @@ describe('getSecondaryAction', () => {
311317
enabled: true,
312318
},
313319
role: CONST.POLICY.ROLE.AUDITOR,
320+
type: CONST.POLICY.TYPE.CORPORATE,
314321
} as unknown as Policy;
315322
await Onyx.merge(`${ONYXKEYS.COLLECTION.REPORT}${REPORT_ID}`, report);
316323

tests/unit/ReportUtilsTest.ts

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@ import {translate} from '@libs/Localize';
1919
import getReportURLForCurrentContext from '@libs/Navigation/helpers/getReportURLForCurrentContext';
2020
import isSearchTopmostFullScreenRoute from '@libs/Navigation/helpers/isSearchTopmostFullScreenRoute';
2121
import Navigation from '@libs/Navigation/Navigation';
22+
// eslint-disable-next-line no-restricted-syntax
23+
import * as PolicyUtils from '@libs/PolicyUtils';
2224
import {getOriginalMessage, getReportAction, isWhisperAction} from '@libs/ReportActionsUtils';
2325
import {buildReportNameFromParticipantNames, computeReportName, getGroupChatName, getPolicyExpenseChatName, getReportName} from '@libs/ReportNameUtils';
2426
import type {OptionData} from '@libs/ReportUtils';
@@ -189,6 +191,14 @@ jest.mock('@libs/Navigation/Navigation', () => ({
189191
},
190192
}));
191193

194+
jest.mock('@libs/PolicyUtils', () => ({
195+
...jest.requireActual<typeof PolicyUtils>('@libs/PolicyUtils'),
196+
isPolicyAdmin: jest.fn().mockImplementation((policy?: Policy) => policy?.role === 'admin'),
197+
isPaidGroupPolicy: jest.fn().mockImplementation((policy?: Policy) => policy?.type === 'corporate' || policy?.type === 'team'),
198+
}));
199+
200+
const mockedPolicyUtils = PolicyUtils as jest.Mocked<typeof PolicyUtils>;
201+
192202
const testDate = DateUtils.getDBTime();
193203
const currentUserEmail = 'bjorn@vikings.net';
194204
const currentUserAccountID = 5;
@@ -2915,6 +2925,7 @@ describe('ReportUtils', () => {
29152925
type: CONST.REPORT.TYPE.EXPENSE,
29162926
ownerAccountID: currentUserAccountID,
29172927
};
2928+
mockedPolicyUtils.isPaidGroupPolicy.mockReturnValue(true);
29182929
const moneyRequestOptions = temporary_getMoneyRequestOptions(report, undefined, [currentUserAccountID]);
29192930
expect(moneyRequestOptions.length).toBe(2);
29202931
expect(moneyRequestOptions.includes(CONST.IOU.TYPE.SUBMIT)).toBe(true);
@@ -6096,6 +6107,8 @@ describe('ReportUtils', () => {
60966107
};
60976108
await Onyx.set(`${ONYXKEYS.COLLECTION.REPORT}${report.reportID}`, report);
60986109

6110+
mockedPolicyUtils.isPaidGroupPolicy.mockReturnValue(true);
6111+
60996112
// When it's checked if the transactions can be added
61006113
// Simulate how components determined if a report is archived by using this hook
61016114
const {result: isReportArchived} = renderHook(() => useReportIsArchived(report?.reportID));
@@ -6114,6 +6127,8 @@ describe('ReportUtils', () => {
61146127
};
61156128
await Onyx.set(`${ONYXKEYS.COLLECTION.REPORT}${report.reportID}`, report);
61166129

6130+
mockedPolicyUtils.isPaidGroupPolicy.mockReturnValue(true);
6131+
61176132
const result = canAddTransaction(report, false);
61186133

61196134
// Then the result is false
@@ -6158,6 +6173,8 @@ describe('ReportUtils', () => {
61586173

61596174
const {result: isReportArchived} = renderHook(() => useReportIsArchived(report?.reportID));
61606175

6176+
mockedPolicyUtils.isPaidGroupPolicy.mockReturnValue(true);
6177+
61616178
// If the canAddTransaction is used for the case of adding expense into the report
61626179
const result = canAddTransaction(report, isReportArchived.current);
61636180

0 commit comments

Comments
 (0)