Skip to content

Commit b424509

Browse files
Merge pull request Expensify#72362 from FitseTLT/fix-disallowing-requestor-from-editing-amount-of-distance-request
Fix - Distance - Employee is not able to edit distance expense amount, when the admin can do it
2 parents 73a784d + 60ccd7c commit b424509

3 files changed

Lines changed: 51 additions & 56 deletions

File tree

src/libs/ReportUtils.ts

Lines changed: 29 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ import type {NotificationPreference, Participants, Participant as ReportParticip
7272
import type {Message, OldDotReportAction, ReportActions} from '@src/types/onyx/ReportAction';
7373
import type {PendingChatMember} from '@src/types/onyx/ReportMetadata';
7474
import type {OnyxData} from '@src/types/onyx/Request';
75-
import type {SearchReport, SearchTransaction} from '@src/types/onyx/SearchResults';
75+
import type {SearchTransaction} from '@src/types/onyx/SearchResults';
7676
import type {Comment, TransactionChanges, WaypointCollection} from '@src/types/onyx/Transaction';
7777
import type {FileObject} from '@src/types/utils/Attachment';
7878
import {isEmptyObject} from '@src/types/utils/EmptyObject';
@@ -908,8 +908,7 @@ type GetPolicyNameParams = {
908908
returnEmptyIfNotFound?: boolean;
909909
policy?: OnyxInputOrEntry<Policy>;
910910
policies?: Policy[];
911-
// eslint-disable-next-line @typescript-eslint/no-deprecated
912-
reports?: SearchReport[];
911+
reports?: Report[];
913912
};
914913

915914
type GetReportNameParams = {
@@ -919,8 +918,7 @@ type GetReportNameParams = {
919918
personalDetails?: Partial<PersonalDetailsList>;
920919
invoiceReceiverPolicy?: OnyxEntry<Policy>;
921920
transactions?: SearchTransaction[];
922-
// eslint-disable-next-line @typescript-eslint/no-deprecated
923-
reports?: SearchReport[];
921+
reports?: Report[];
924922
policies?: Policy[];
925923
isReportArchived?: boolean;
926924
};
@@ -1209,8 +1207,7 @@ function getChatType(report: OnyxInputOrEntry<Report> | Participant): ValueOf<ty
12091207
/**
12101208
* Get the report or draft report given a reportID
12111209
*/
1212-
// eslint-disable-next-line @typescript-eslint/no-deprecated
1213-
function getReportOrDraftReport(reportID: string | undefined, searchReports?: SearchReport[], fallbackReport?: Report): OnyxEntry<Report> | SearchReport {
1210+
function getReportOrDraftReport(reportID: string | undefined, searchReports?: Report[], fallbackReport?: Report): OnyxEntry<Report> {
12141211
const searchReport = searchReports?.find((report) => report.reportID === reportID);
12151212
const onyxReport = allReports?.[`${ONYXKEYS.COLLECTION.REPORT}${reportID}`];
12161213
return searchReport ?? onyxReport ?? allReportsDraft?.[`${ONYXKEYS.COLLECTION.REPORT_DRAFT}${reportID}`] ?? fallbackReport;
@@ -1244,8 +1241,7 @@ function isDraftReport(reportID: string | undefined): boolean {
12441241
/**
12451242
* @private
12461243
*/
1247-
// eslint-disable-next-line @typescript-eslint/no-deprecated
1248-
function isSearchReportArray(object: SearchReport[] | OnyxCollection<Report>): object is SearchReport[] {
1244+
function isSearchReportArray(object: Report[] | OnyxCollection<Report>): object is Report[] {
12491245
if (!Array.isArray(object)) {
12501246
return false;
12511247
}
@@ -1257,8 +1253,7 @@ function isSearchReportArray(object: SearchReport[] | OnyxCollection<Report>): o
12571253
* @private
12581254
* Returns the report
12591255
*/
1260-
// eslint-disable-next-line @typescript-eslint/no-deprecated
1261-
function getReport(reportID: string, reports: SearchReport[] | OnyxCollection<Report>): OnyxEntry<Report> | SearchReport {
1256+
function getReport(reportID: string, reports: Report[] | OnyxCollection<Report>): OnyxEntry<Report> | Report {
12621257
if (isSearchReportArray(reports)) {
12631258
reports?.find((report) => report.reportID === reportID);
12641259
} else {
@@ -1287,8 +1282,8 @@ function getRootParentReport({
12871282
visitedReportIDs = new Set<string>(),
12881283
}: {
12891284
report: OnyxEntry<Report>;
1290-
// eslint-disable-next-line @typescript-eslint/no-deprecated
1291-
reports?: SearchReport[];
1285+
1286+
reports?: Report[];
12921287
visitedReportIDs?: Set<string>;
12931288
}): OnyxEntry<Report> {
12941289
if (!report) {
@@ -1376,8 +1371,7 @@ function isChatReport(report: OnyxEntry<Report>): boolean {
13761371
return report?.type === CONST.REPORT.TYPE.CHAT;
13771372
}
13781373

1379-
// eslint-disable-next-line @typescript-eslint/no-deprecated
1380-
function isInvoiceReport(reportOrID: OnyxInputOrEntry<Report> | SearchReport | string): boolean {
1374+
function isInvoiceReport(reportOrID: OnyxInputOrEntry<Report> | string): boolean {
13811375
const report = typeof reportOrID === 'string' ? (getReport(reportOrID, allReports) ?? null) : reportOrID;
13821376
return report?.type === CONST.REPORT.TYPE.INVOICE;
13831377
}
@@ -1411,17 +1405,15 @@ function isReportIDApproved(reportID: string | undefined) {
14111405
/**
14121406
* Checks if a report is an Expense report.
14131407
*/
1414-
// eslint-disable-next-line @typescript-eslint/no-deprecated
1415-
function isExpenseReport(reportOrID: OnyxInputOrEntry<Report> | SearchReport | string): boolean {
1408+
function isExpenseReport(reportOrID: OnyxInputOrEntry<Report> | string): boolean {
14161409
const report = typeof reportOrID === 'string' ? (getReport(reportOrID, allReports) ?? null) : reportOrID;
14171410
return report?.type === CONST.REPORT.TYPE.EXPENSE;
14181411
}
14191412

14201413
/**
14211414
* Checks if a report is an IOU report using report or reportID
14221415
*/
1423-
// eslint-disable-next-line @typescript-eslint/no-deprecated
1424-
function isIOUReport(reportOrID: OnyxInputOrEntry<Report> | SearchReport | string): boolean {
1416+
function isIOUReport(reportOrID: OnyxInputOrEntry<Report> | string): boolean {
14251417
const report = typeof reportOrID === 'string' ? (getReport(reportOrID, allReports) ?? null) : reportOrID;
14261418
return report?.type === CONST.REPORT.TYPE.IOU;
14271419
}
@@ -1530,8 +1522,7 @@ function hasParticipantInArray(report: OnyxEntry<Report>, memberAccountIDs: numb
15301522
/**
15311523
* Whether the Money Request report is settled
15321524
*/
1533-
// eslint-disable-next-line @typescript-eslint/no-deprecated
1534-
function isSettled(reportOrID: OnyxInputOrEntry<Report> | SearchReport | string | undefined, reports?: SearchReport[] | OnyxCollection<Report>): boolean {
1525+
function isSettled(reportOrID: OnyxInputOrEntry<Report> | string | undefined, reports?: Report[] | OnyxCollection<Report>): boolean {
15351526
if (!reportOrID) {
15361527
return false;
15371528
}
@@ -2178,8 +2169,7 @@ function isClosedExpenseReportWithNoExpenses(report: OnyxEntry<Report>, transact
21782169
/**
21792170
* Whether the provided report is an archived room
21802171
*/
2181-
// eslint-disable-next-line @typescript-eslint/no-deprecated
2182-
function isArchivedNonExpenseReport(report: OnyxInputOrEntry<Report> | SearchReport, isReportArchived = false): boolean {
2172+
function isArchivedNonExpenseReport(report: OnyxInputOrEntry<Report>, isReportArchived = false): boolean {
21832173
return isReportArchived && !(isExpenseReport(report) || isExpenseRequest(report));
21842174
}
21852175

@@ -2204,8 +2194,7 @@ function isArchivedNonExpenseReportWithID(report?: OnyxInputOrEntry<Report>, isR
22042194
/**
22052195
* Whether the provided report is a closed report
22062196
*/
2207-
// eslint-disable-next-line @typescript-eslint/no-deprecated
2208-
function isClosedReport(report: OnyxInputOrEntry<Report> | SearchReport): boolean {
2197+
function isClosedReport(report: OnyxInputOrEntry<Report>): boolean {
22092198
return report?.statusNum === CONST.REPORT.STATUS_NUM.CLOSED;
22102199
}
22112200

@@ -2390,8 +2379,7 @@ function isMoneyRequest(reportOrID: OnyxEntry<Report> | string): boolean {
23902379
/**
23912380
* Checks if a report is an IOU or expense report.
23922381
*/
2393-
// eslint-disable-next-line @typescript-eslint/no-deprecated
2394-
function isMoneyRequestReport(reportOrID: OnyxInputOrEntry<Report> | SearchReport | string, reports?: SearchReport[] | OnyxCollection<Report>): boolean {
2382+
function isMoneyRequestReport(reportOrID: OnyxInputOrEntry<Report> | string, reports?: Report[] | OnyxCollection<Report>): boolean {
23952383
const report = typeof reportOrID === 'string' ? (getReport(reportOrID, reports ?? allReports) ?? null) : reportOrID;
23962384
return isIOUReport(report) || isExpenseReport(report);
23972385
}
@@ -3749,11 +3737,9 @@ function getReimbursementQueuedActionMessage({
37493737
personalDetails,
37503738
}: {
37513739
reportAction: OnyxEntry<ReportAction<typeof CONST.REPORT.ACTIONS.TYPE.REIMBURSEMENT_QUEUED>>;
3752-
// eslint-disable-next-line @typescript-eslint/no-deprecated
3753-
reportOrID: OnyxEntry<Report> | string | SearchReport;
3740+
reportOrID: OnyxEntry<Report> | string;
37543741
shouldUseShortDisplayName?: boolean;
3755-
// eslint-disable-next-line @typescript-eslint/no-deprecated
3756-
reports?: SearchReport[];
3742+
reports?: Report[];
37573743
personalDetails?: Partial<PersonalDetailsList>;
37583744
}): string {
37593745
const report = typeof reportOrID === 'string' ? getReport(reportOrID, reports ?? allReports) : reportOrID;
@@ -3774,8 +3760,7 @@ function getReimbursementQueuedActionMessage({
37743760
*/
37753761
function getReimbursementDeQueuedOrCanceledActionMessage(
37763762
reportAction: OnyxEntry<ReportAction<typeof CONST.REPORT.ACTIONS.TYPE.REIMBURSEMENT_DEQUEUED | typeof CONST.REPORT.ACTIONS.TYPE.REIMBURSEMENT_ACH_CANCELED>>,
3777-
// eslint-disable-next-line @typescript-eslint/no-deprecated
3778-
reportOrID: OnyxEntry<Report> | string | SearchReport,
3763+
reportOrID: OnyxEntry<Report> | string,
37793764
): string {
37803765
const report = typeof reportOrID === 'string' ? getReport(reportOrID, allReports) : reportOrID;
37813766
const originalMessage = getOriginalMessage(reportAction);
@@ -4072,8 +4057,7 @@ function hasNonReimbursableTransactions(iouReportID: string | undefined, reports
40724057
return transactions.filter((transaction) => transaction.reimbursable === false).length > 0;
40734058
}
40744059

4075-
// eslint-disable-next-line @typescript-eslint/no-deprecated
4076-
function getMoneyRequestSpendBreakdown(report: OnyxInputOrEntry<Report>, searchReports?: SearchReport[]): SpendBreakdown {
4060+
function getMoneyRequestSpendBreakdown(report: OnyxInputOrEntry<Report>, searchReports?: Report[]): SpendBreakdown {
40774061
const reports = searchReports ?? allReports;
40784062
let moneyRequestReport: OnyxEntry<Report>;
40794063
if (report && (isMoneyRequestReport(report, searchReports) || isInvoiceReport(report))) {
@@ -4373,8 +4357,7 @@ function getTransactionCommentObject(transaction: OnyxEntry<Transaction>): Comme
43734357
function canEditMoneyRequest(
43744358
reportAction: OnyxInputOrEntry<ReportAction<typeof CONST.REPORT.ACTIONS.TYPE.IOU>>,
43754359
isChatReportArchived = false,
4376-
// eslint-disable-next-line @typescript-eslint/no-deprecated
4377-
report?: OnyxInputOrEntry<Report> | SearchReport,
4360+
report?: OnyxInputOrEntry<Report>,
43784361
policy?: OnyxEntry<Policy>,
43794362
linkedTransaction?: OnyxEntry<Transaction> | SearchTransaction,
43804363
): boolean {
@@ -4519,8 +4502,7 @@ function canEditFieldOfMoneyRequest(
45194502
isChatReportArchived = false,
45204503
outstandingReportsByPolicyID?: OutstandingReportsByPolicyIDDerivedValue,
45214504
linkedTransaction?: OnyxEntry<Transaction> | SearchTransaction,
4522-
// eslint-disable-next-line @typescript-eslint/no-deprecated
4523-
report?: OnyxInputOrEntry<Report> | SearchReport,
4505+
report?: OnyxInputOrEntry<Report>,
45244506
policy?: OnyxEntry<Policy>,
45254507
): boolean {
45264508
// A list of fields that cannot be edited by anyone, once an expense has been settled
@@ -4576,7 +4558,7 @@ function canEditFieldOfMoneyRequest(
45764558
}
45774559

45784560
if ((fieldToEdit === CONST.EDIT_REQUEST_FIELD.AMOUNT || fieldToEdit === CONST.EDIT_REQUEST_FIELD.CURRENCY) && isDistanceRequest(transaction)) {
4579-
return isAdmin || isManager;
4561+
return isAdmin || isManager || isRequestor;
45804562
}
45814563

45824564
if (
@@ -4889,8 +4871,7 @@ function getTransactionReportName({
48894871
}: {
48904872
reportAction: OnyxEntry<ReportAction | OptimisticIOUReportAction>;
48914873
transactions?: SearchTransaction[];
4892-
// eslint-disable-next-line @typescript-eslint/no-deprecated
4893-
reports?: SearchReport[];
4874+
reports?: Report[];
48944875
}): string {
48954876
if (isReversedTransaction(reportAction)) {
48964877
// eslint-disable-next-line @typescript-eslint/no-deprecated
@@ -5394,8 +5375,7 @@ function getReportActionMessage({
53945375
reportAction: OnyxEntry<ReportAction>;
53955376
reportID?: string;
53965377
childReportID?: string;
5397-
// eslint-disable-next-line @typescript-eslint/no-deprecated
5398-
reports?: SearchReport[];
5378+
reports?: Report[];
53995379
personalDetails?: Partial<PersonalDetailsList>;
54005380
}) {
54015381
if (isEmptyObject(reportAction)) {
@@ -5525,8 +5505,7 @@ function getReportName(
55255505
reportAttributes?: ReportAttributesDerivedValue['reports'],
55265506
transactions?: SearchTransaction[],
55275507
isReportArchived?: boolean,
5528-
// eslint-disable-next-line @typescript-eslint/no-deprecated
5529-
reports?: SearchReport[],
5508+
reports?: Report[],
55305509
policies?: Policy[],
55315510
): string {
55325511
// Check if we can use report name in derived values - only when we have report but no other params
@@ -9245,14 +9224,12 @@ function getAllPolicyReports(policyID: string): Array<OnyxEntry<Report>> {
92459224
/**
92469225
* Returns true if Chronos is one of the chat participants (1:1)
92479226
*/
9248-
// eslint-disable-next-line @typescript-eslint/no-deprecated
9249-
function chatIncludesChronos(report: OnyxInputOrEntry<Report> | SearchReport): boolean {
9227+
function chatIncludesChronos(report: OnyxInputOrEntry<Report>): boolean {
92509228
const participantAccountIDs = Object.keys(report?.participants ?? {}).map(Number);
92519229
return participantAccountIDs.includes(CONST.ACCOUNT_ID.CHRONOS);
92529230
}
92539231

9254-
// eslint-disable-next-line @typescript-eslint/no-deprecated
9255-
function chatIncludesChronosWithID(reportOrID?: string | SearchReport): boolean {
9232+
function chatIncludesChronosWithID(reportOrID?: string | Report): boolean {
92569233
if (!reportOrID) {
92579234
return false;
92589235
}
@@ -10584,7 +10561,7 @@ function shouldCreateNewMoneyRequestReport(
1058410561
}
1058510562

1058610563
function getTripIDFromTransactionParentReportID(transactionParentReportID: string | undefined): string | undefined {
10587-
return (getReportOrDraftReport(transactionParentReportID) as OnyxEntry<Report>)?.tripData?.tripID;
10564+
return getReportOrDraftReport(transactionParentReportID)?.tripData?.tripID;
1058810565
}
1058910566

1059010567
/**
@@ -12072,8 +12049,7 @@ function getGroupChatDraft() {
1207212049
return newGroupChatDraft;
1207312050
}
1207412051

12075-
// eslint-disable-next-line @typescript-eslint/no-deprecated
12076-
function getChatListItemReportName(action: ReportAction & {reportName?: string}, report: SearchReport | undefined): string {
12052+
function getChatListItemReportName(action: ReportAction & {reportName?: string}, report: Report | undefined): string {
1207712053
if (report && isInvoiceReport(report)) {
1207812054
const properInvoiceReport = report;
1207912055
properInvoiceReport.chatReportID = report.parentReportID;

src/pages/iou/SplitExpensePage.tsx

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,6 @@ import {getChildTransactions, isManagedCardTransaction, isPerDiemRequest} from '
4747
import CONST from '@src/CONST';
4848
import ONYXKEYS from '@src/ONYXKEYS';
4949
import type SCREENS from '@src/SCREENS';
50-
import type {Report} from '@src/types/onyx';
5150
import {isEmptyObject} from '@src/types/utils/EmptyObject';
5251

5352
type SplitExpensePageProps = PlatformStackScreenProps<SplitExpenseParamList, typeof SCREENS.MONEY_REQUEST.SPLIT_EXPENSE>;
@@ -239,7 +238,7 @@ function SplitExpensePage({route}: SplitExpensePageProps) {
239238
const items: SplitListItemType[] = (draftTransaction?.comment?.splitExpenses ?? []).map((item): SplitListItemType => {
240239
const previewHeaderText: TranslationPathOrText[] = [showCashOrCard];
241240
const currentTransaction = allTransactions?.[`${ONYXKEYS.COLLECTION.TRANSACTION}${item?.transactionID}`];
242-
const currentReport = getReportOrDraftReport(currentTransaction?.reportID) as Report;
241+
const currentReport = getReportOrDraftReport(currentTransaction?.reportID);
243242
const isApproved = isReportApproved({report: currentReport});
244243
const isSettled = isSettledReportUtils(currentReport?.reportID);
245244
const isCancelled = currentReport && currentReport?.isCancelledIOU;

tests/unit/canEditFieldOfMoneyRequestTest.ts

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -172,7 +172,13 @@ describe('canEditFieldOfMoneyRequest', () => {
172172
},
173173
};
174174

175-
const moneyRequestTransaction = {...createRandomTransaction(Number(IOUTransactionID)), reportID: IOUReportID, transactionID: IOUTransactionID, amount: EXPENSE_AMOUNT};
175+
const moneyRequestTransaction = {
176+
...createRandomTransaction(Number(IOUTransactionID)),
177+
reportID: IOUReportID,
178+
managedCard: false,
179+
transactionID: IOUTransactionID,
180+
amount: EXPENSE_AMOUNT,
181+
};
176182

177183
const expenseReport = {
178184
...createExpenseReport(Number(IOUReportID)),
@@ -196,6 +202,20 @@ describe('canEditFieldOfMoneyRequest', () => {
196202
return waitForBatchedUpdates();
197203
});
198204

205+
it('should return true for submitter of a distance request for amount and currency fields', async () => {
206+
await Onyx.merge(`${ONYXKEYS.COLLECTION.REPORT}${IOUReportID}`, expenseReport);
207+
await Onyx.merge(`${ONYXKEYS.COLLECTION.TRANSACTION}${moneyRequestTransaction.transactionID}`, {iouRequestType: CONST.IOU.REQUEST_TYPE.DISTANCE});
208+
await waitForBatchedUpdates();
209+
210+
// If it is the submitter of a distance request
211+
const canEditReportFieldAmount = canEditFieldOfMoneyRequest(reportAction, CONST.EDIT_REQUEST_FIELD.AMOUNT, undefined, undefined);
212+
const canEditReportFieldCurrency = canEditFieldOfMoneyRequest(reportAction, CONST.EDIT_REQUEST_FIELD.CURRENCY, undefined, undefined);
213+
214+
// Then we should allow editing amount and currency fields.
215+
expect(canEditReportFieldAmount).toBe(true);
216+
expect(canEditReportFieldCurrency).toBe(true);
217+
});
218+
199219
it('should return true for submitter when there are multiple outstanding reports', async () => {
200220
// Given that there are multiple outstanding expense reports in the same policy
201221
await Onyx.merge(`${ONYXKEYS.COLLECTION.REPORT}${IOUReportID}`, expenseReport);

0 commit comments

Comments
 (0)