Skip to content

Commit 7558a80

Browse files
authored
Merge pull request Expensify#64852 from gijoe0295/gijoe/64376
fix: admin cannot pay the invoice if previously paid as business
2 parents 03e83c3 + d75564e commit 7558a80

3 files changed

Lines changed: 65 additions & 10 deletions

File tree

src/components/MoneyReportHeader.tsx

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -177,6 +177,10 @@ function MoneyReportHeader({
177177
});
178178
const [dismissedHoldUseExplanation, dismissedHoldUseExplanationResult] = useOnyx(ONYXKEYS.NVP_DISMISSED_HOLD_USE_EXPLANATION, {initialValue: true, canBeMissing: true});
179179
const isLoadingHoldUseExplained = isLoadingOnyxValue(dismissedHoldUseExplanationResult);
180+
const [invoiceReceiverPolicy] = useOnyx(
181+
`${ONYXKEYS.COLLECTION.POLICY}${chatReport?.invoiceReceiver && 'policyID' in chatReport.invoiceReceiver ? chatReport.invoiceReceiver.policyID : undefined}`,
182+
{canBeMissing: true},
183+
);
180184

181185
const isExported = isExportedUtils(reportActions);
182186
const integrationNameFromExportMessage = isExported ? getIntegrationNameFromExportMessageUtils(reportActions) : null;
@@ -434,8 +438,9 @@ function MoneyReportHeader({
434438
reportNameValuePairs,
435439
reportActions,
436440
isChatReportArchived,
441+
invoiceReceiverPolicy,
437442
});
438-
}, [isPaidAnimationRunning, moneyRequestReport, reportNameValuePairs, policy, transactions, violations, reportActions, isChatReportArchived, chatReport]);
443+
}, [isPaidAnimationRunning, moneyRequestReport, reportNameValuePairs, policy, transactions, violations, reportActions, isChatReportArchived, chatReport, invoiceReceiverPolicy]);
439444

440445
const confirmExport = useCallback(() => {
441446
setExportModalStatus(null);

src/libs/ReportPrimaryActionUtils.ts

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ type GetReportPrimaryActionParams = {
5555
reportNameValuePairs?: ReportNameValuePairs;
5656
reportActions?: ReportAction[];
5757
isChatReportArchived?: boolean;
58+
invoiceReceiverPolicy?: Policy;
5859
};
5960

6061
function isAddExpenseAction(report: Report, reportTransactions: Transaction[], isChatReportArchived = false) {
@@ -140,7 +141,7 @@ function isApproveAction(report: Report, reportTransactions: Transaction[], poli
140141
return false;
141142
}
142143

143-
function isPrimaryPayAction(report: Report, policy?: Policy, reportNameValuePairs?: ReportNameValuePairs, isChatReportArchived?: boolean) {
144+
function isPrimaryPayAction(report: Report, policy?: Policy, reportNameValuePairs?: ReportNameValuePairs, isChatReportArchived?: boolean, invoiceReceiverPolicy?: Policy) {
144145
if (isArchivedReport(reportNameValuePairs) || isChatReportArchived) {
145146
return false;
146147
}
@@ -182,7 +183,7 @@ function isPrimaryPayAction(report: Report, policy?: Policy, reportNameValuePair
182183
return parentReport?.invoiceReceiver?.accountID === getCurrentUserAccountID();
183184
}
184185

185-
return policy?.role === CONST.POLICY.ROLE.ADMIN;
186+
return invoiceReceiverPolicy?.role === CONST.POLICY.ROLE.ADMIN;
186187
}
187188

188189
function isExportAction(report: Report, policy?: Policy, reportActions?: ReportAction[]) {
@@ -302,7 +303,7 @@ function getAllExpensesToHoldIfApplicable(report?: Report, reportActions?: Repor
302303
}
303304

304305
function getReportPrimaryAction(params: GetReportPrimaryActionParams): ValueOf<typeof CONST.REPORT.PRIMARY_ACTIONS> | '' {
305-
const {report, reportTransactions, violations, policy, reportNameValuePairs, reportActions, isChatReportArchived, chatReport} = params;
306+
const {report, reportTransactions, violations, policy, reportNameValuePairs, reportActions, isChatReportArchived, chatReport, invoiceReceiverPolicy} = params;
306307

307308
const isPayActionWithAllExpensesHeld = isPrimaryPayAction(report, policy, reportNameValuePairs, isChatReportArchived) && hasOnlyHeldExpenses(report?.reportID);
308309

@@ -330,7 +331,7 @@ function getReportPrimaryAction(params: GetReportPrimaryActionParams): ValueOf<t
330331
return CONST.REPORT.PRIMARY_ACTIONS.APPROVE;
331332
}
332333

333-
if (isPrimaryPayAction(report, policy, reportNameValuePairs, isChatReportArchived)) {
334+
if (isPrimaryPayAction(report, policy, reportNameValuePairs, isChatReportArchived, invoiceReceiverPolicy)) {
334335
return CONST.REPORT.PRIMARY_ACTIONS.PAY;
335336
}
336337

tests/unit/ReportPrimaryActionUtilsTest.ts

Lines changed: 54 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,9 @@ const PERSONAL_DETAILS = {
2323
};
2424

2525
const REPORT_ID = 1;
26+
const CHAT_REPORT_ID = 2;
27+
const POLICY_ID = 3;
28+
const INVOICE_SENDER_ACCOUNT_ID = 4;
2629

2730
// This keeps the error "@rnmapbox/maps native code not available." from causing the tests to fail
2831
jest.mock('@components/ConfirmedRoute.tsx');
@@ -124,23 +127,33 @@ describe('getPrimaryAction', () => {
124127
expect(getReportPrimaryAction({report, chatReport, reportTransactions: [transaction], violations: {}, policy: policy as Policy})).toBe('');
125128
});
126129

127-
it('should return PAY for submitted invoice report', async () => {
130+
it('should return PAY for submitted invoice report if paid as personal', async () => {
128131
const report = {
129132
reportID: REPORT_ID,
130133
type: CONST.REPORT.TYPE.INVOICE,
131-
ownerAccountID: CURRENT_USER_ACCOUNT_ID,
134+
ownerAccountID: INVOICE_SENDER_ACCOUNT_ID,
135+
parentReportID: CHAT_REPORT_ID,
132136
statusNum: CONST.REPORT.STATUS_NUM.SUBMITTED,
133137
stateNum: CONST.REPORT.STATE_NUM.SUBMITTED,
134138
} as unknown as Report;
139+
const parentReport = {
140+
reportID: CHAT_REPORT_ID,
141+
invoiceReceiver: {
142+
type: CONST.REPORT.INVOICE_RECEIVER_TYPE.INDIVIDUAL,
143+
accountID: CURRENT_USER_ACCOUNT_ID,
144+
},
145+
} as unknown as Report;
135146
await Onyx.merge(`${ONYXKEYS.COLLECTION.REPORT}${REPORT_ID}`, report);
136-
const policy = {
147+
await Onyx.merge(`${ONYXKEYS.COLLECTION.REPORT}${CHAT_REPORT_ID}`, parentReport);
148+
const policy = {} as Policy;
149+
const invoiceReceiverPolicy = {
137150
role: CONST.POLICY.ROLE.ADMIN,
138-
};
151+
} as Policy;
139152
const transaction = {
140153
reportID: `${REPORT_ID}`,
141154
} as unknown as Transaction;
142155

143-
expect(getReportPrimaryAction({report, chatReport, reportTransactions: [transaction], violations: {}, policy: policy as Policy})).toBe(CONST.REPORT.PRIMARY_ACTIONS.PAY);
156+
expect(getReportPrimaryAction({report, chatReport, reportTransactions: [transaction], violations: {}, policy, invoiceReceiverPolicy})).toBe(CONST.REPORT.PRIMARY_ACTIONS.PAY);
144157
});
145158

146159
it('should return PAY for expense report with payments enabled', async () => {
@@ -557,4 +570,40 @@ describe('getTransactionThreadPrimaryAction', () => {
557570
}),
558571
).toBe('');
559572
});
573+
574+
it('should return PAY for submitted invoice report if paid as business and the payer is the policy admin', async () => {
575+
const report = {
576+
reportID: REPORT_ID,
577+
type: CONST.REPORT.TYPE.INVOICE,
578+
ownerAccountID: INVOICE_SENDER_ACCOUNT_ID,
579+
parentReportID: CHAT_REPORT_ID,
580+
statusNum: CONST.REPORT.STATUS_NUM.SUBMITTED,
581+
stateNum: CONST.REPORT.STATE_NUM.SUBMITTED,
582+
} as unknown as Report;
583+
const parentReport = {
584+
reportID: CHAT_REPORT_ID,
585+
invoiceReceiver: {
586+
type: CONST.REPORT.INVOICE_RECEIVER_TYPE.BUSINESS,
587+
policyID: POLICY_ID,
588+
},
589+
} as unknown as Report;
590+
await Onyx.merge(`${ONYXKEYS.COLLECTION.REPORT}${REPORT_ID}`, report);
591+
await Onyx.merge(`${ONYXKEYS.COLLECTION.REPORT}${CHAT_REPORT_ID}`, parentReport);
592+
const invoiceReceiverPolicy = {
593+
role: CONST.POLICY.ROLE.ADMIN,
594+
};
595+
const transaction = {
596+
reportID: `${REPORT_ID}`,
597+
} as unknown as Transaction;
598+
expect(
599+
getReportPrimaryAction({
600+
report,
601+
chatReport,
602+
reportTransactions: [transaction],
603+
violations: {},
604+
policy: {} as Policy,
605+
invoiceReceiverPolicy: invoiceReceiverPolicy as Policy,
606+
}),
607+
).toBe(CONST.REPORT.PRIMARY_ACTIONS.PAY);
608+
});
560609
});

0 commit comments

Comments
 (0)