-
Notifications
You must be signed in to change notification settings - Fork 3.9k
Improve creating expenses on Collect with Instant Submit #36388
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
9bc5b38
34917e5
99d1542
4fc82e7
f165755
771eef6
4eb5cbf
9587d19
a2675fe
72ddbc8
f5a5959
5be0b3f
206cd78
f0a99eb
933e0d8
902f45c
9cccb7e
267de9d
4e9ccc9
c0371b2
9eb9b97
8496f5d
ee17782
6a464b3
1777c68
9d9caf6
3fcd191
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -7,7 +7,6 @@ import useThemeStyles from '@hooks/useThemeStyles'; | |
| import useWindowDimensions from '@hooks/useWindowDimensions'; | ||
| import * as HeaderUtils from '@libs/HeaderUtils'; | ||
| import Navigation from '@libs/Navigation/Navigation'; | ||
| import * as PolicyUtils from '@libs/PolicyUtils'; | ||
| import * as ReportActionsUtils from '@libs/ReportActionsUtils'; | ||
| import * as ReportUtils from '@libs/ReportUtils'; | ||
| import * as TransactionUtils from '@libs/TransactionUtils'; | ||
|
|
@@ -79,16 +78,11 @@ function MoneyRequestHeader({session, parentReport, report, parentReportAction, | |
| const isScanning = TransactionUtils.hasReceipt(transaction) && TransactionUtils.isReceiptBeingScanned(transaction); | ||
| const isPending = TransactionUtils.isExpensifyCardTransaction(transaction) && TransactionUtils.isPending(transaction); | ||
|
|
||
| const isRequestModifiable = !isSettled && !isApproved && !ReportActionsUtils.isDeletedAction(parentReportAction); | ||
| const canModifyRequest = isActionOwner && !isSettled && !isApproved && !ReportActionsUtils.isDeletedAction(parentReportAction); | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I also removed this one, because we aren't really modifying the request in the header. We just need to check for permission to hold/unhold, and delete.
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @youssef-lr
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yup it doesn't. We used |
||
| let canDeleteRequest = canModifyRequest; | ||
| const isDeletedParentAction = ReportActionsUtils.isDeletedAction(parentReportAction); | ||
| const canHoldOrUnholdRequest = !isSettled && !isApproved && !isDeletedParentAction; | ||
|
|
||
| if (ReportUtils.isPaidGroupPolicyExpenseReport(moneyRequestReport)) { | ||
| // If it's a paid policy expense report, only allow deleting the request if it's in draft state or instantly submitted state or the user is the policy admin | ||
| canDeleteRequest = | ||
| canDeleteRequest && | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Confirmed in Slack that the admin should not be able to delete requests, the backend also throws an error if we try to. This check was also never true
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. As confirmed here #36202 (comment), the current logic of delete action is: user is not only
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. That PR is outdated given the new logic of instant submit. The backend will not throw if the policy has it enabled. |
||
| (ReportUtils.isDraftExpenseReport(moneyRequestReport) || ReportUtils.isExpenseReportWithInstantSubmittedState(moneyRequestReport) || PolicyUtils.isPolicyAdmin(policy)); | ||
| } | ||
| // If the report supports adding transactions to it, then it also supports deleting transactions from it. | ||
| const canDeleteRequest = isActionOwner && ReportUtils.canAddOrDeleteTransactions(moneyRequestReport) && !isDeletedParentAction; | ||
|
|
||
| const changeMoneyRequestStatus = () => { | ||
| if (isOnHold) { | ||
|
|
@@ -108,7 +102,7 @@ function MoneyRequestHeader({session, parentReport, report, parentReportAction, | |
| }, [canDeleteRequest]); | ||
|
|
||
| const threeDotsMenuItems = [HeaderUtils.getPinMenuItem(report)]; | ||
| if (isRequestModifiable) { | ||
| if (canHoldOrUnholdRequest) { | ||
| const isRequestIOU = parentReport?.type === 'iou'; | ||
| const isHoldCreator = ReportUtils.isHoldCreator(transaction, report?.reportID) && isRequestIOU; | ||
| const canModifyStatus = isPolicyAdmin || isActionOwner || isApprover; | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -959,14 +959,6 @@ function isProcessingReport(report: OnyxEntry<Report> | EmptyObject): boolean { | |
| return report?.stateNum === CONST.REPORT.STATE_NUM.SUBMITTED && report?.statusNum === CONST.REPORT.STATUS_NUM.SUBMITTED; | ||
| } | ||
|
|
||
| /** | ||
| * Returns true if the policy has `instant` reporting frequency and if the report is still being processed (i.e. submitted state) | ||
| */ | ||
| function isExpenseReportWithInstantSubmittedState(report: OnyxEntry<Report> | EmptyObject): boolean { | ||
| const policy = allPolicies?.[`${ONYXKEYS.COLLECTION.POLICY}${report?.policyID}`] ?? null; | ||
| return isExpenseReport(report) && isProcessingReport(report) && PolicyUtils.isInstantSubmitEnabled(policy); | ||
| } | ||
|
|
||
| /** | ||
| * Check if the report is a single chat report that isn't a thread | ||
| * and personal detail of participant is optimistic data | ||
|
|
@@ -1256,6 +1248,29 @@ function getChildReportNotificationPreference(reportAction: OnyxEntry<ReportActi | |
| return isActionCreator(reportAction) ? CONST.REPORT.NOTIFICATION_PREFERENCE.ALWAYS : CONST.REPORT.NOTIFICATION_PREFERENCE.HIDDEN; | ||
| } | ||
|
|
||
| /** | ||
| * Checks whether the supplied report supports adding more transactions to it. | ||
| * Return true if: | ||
| * - report is a non-settled IOU | ||
| * - report is a draft | ||
| * - report is a processing expense report and its policy has Instant reporting frequency | ||
| */ | ||
| function canAddOrDeleteTransactions(moneyRequestReport: OnyxEntry<Report>): boolean { | ||
| if (!isMoneyRequestReport(moneyRequestReport)) { | ||
| return false; | ||
| } | ||
|
|
||
| if (isReportApproved(moneyRequestReport) || isSettled(moneyRequestReport?.reportID)) { | ||
| return false; | ||
| } | ||
|
|
||
| if (isGroupPolicy(moneyRequestReport) && isProcessingReport(moneyRequestReport) && !PolicyUtils.isInstantSubmitEnabled(getPolicy(moneyRequestReport?.policyID))) { | ||
| return false; | ||
| } | ||
|
|
||
| return true; | ||
| } | ||
|
|
||
| /** | ||
| * Can only delete if the author is this user and the action is an ADDCOMMENT action or an IOU action in an unsettled report, or if the user is a | ||
| * policy admin | ||
|
|
@@ -1270,14 +1285,13 @@ function canDeleteReportAction(reportAction: OnyxEntry<ReportAction>, reportID: | |
| // For now, users cannot delete split actions | ||
| const isSplitAction = reportAction?.originalMessage?.type === CONST.IOU.REPORT_ACTION_TYPE.SPLIT; | ||
|
|
||
| if (isSplitAction || isSettled(String(reportAction?.originalMessage?.IOUReportID)) || (!isEmptyObject(report) && isReportApproved(report))) { | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I removed this logic as it's already handled in |
||
| if (isSplitAction) { | ||
| return false; | ||
| } | ||
|
|
||
| if (isActionOwner) { | ||
| if (!isEmptyObject(report) && isPaidGroupPolicyExpenseReport(report)) { | ||
| // If it's a paid policy expense report, only allow deleting the request if it's a draft or is instantly submitted or the user is the policy admin | ||
| return isDraftExpenseReport(report) || isExpenseReportWithInstantSubmittedState(report) || PolicyUtils.isPolicyAdmin(policy); | ||
| if (!isEmptyObject(report) && isMoneyRequestReport(report)) { | ||
| return canAddOrDeleteTransactions(report); | ||
| } | ||
| return true; | ||
| } | ||
|
|
@@ -2957,11 +2971,10 @@ function buildOptimisticExpenseReport(chatReportID: string, policyID: string, pa | |
| const formattedTotal = CurrencyUtils.convertToDisplayString(storedTotal, currency); | ||
| const policy = getPolicy(policyID); | ||
|
|
||
| const isFree = policy?.type === CONST.POLICY.TYPE.FREE; | ||
| const isInstantSubmitEnabled = PolicyUtils.isInstantSubmitEnabled(policy); | ||
|
|
||
| // Define the state and status of the report based on whether the policy is free or paid | ||
| const stateNum = isFree ? CONST.REPORT.STATE_NUM.SUBMITTED : CONST.REPORT.STATE_NUM.OPEN; | ||
| const statusNum = isFree ? CONST.REPORT.STATUS_NUM.SUBMITTED : CONST.REPORT.STATUS_NUM.OPEN; | ||
| const stateNum = isInstantSubmitEnabled ? CONST.REPORT.STATE_NUM.SUBMITTED : CONST.REPORT.STATE_NUM.OPEN; | ||
| const statusNum = isInstantSubmitEnabled ? CONST.REPORT.STATUS_NUM.SUBMITTED : CONST.REPORT.STATUS_NUM.OPEN; | ||
|
|
||
| const expenseReport: OptimisticExpenseReport = { | ||
| reportID: generateReportID(), | ||
|
|
@@ -4287,7 +4300,6 @@ function canRequestMoney(report: OnyxEntry<Report>, policy: OnyxEntry<Policy>, o | |
| return false; | ||
| } | ||
|
|
||
| // In case of expense reports, we have to look at the parent workspace chat to get the isOwnPolicyExpenseChat property | ||
| let isOwnPolicyExpenseChat = report?.isOwnPolicyExpenseChat ?? false; | ||
| if (isExpenseReport(report) && getParentReport(report)) { | ||
| isOwnPolicyExpenseChat = Boolean(getParentReport(report)?.isOwnPolicyExpenseChat); | ||
|
|
@@ -4301,12 +4313,8 @@ function canRequestMoney(report: OnyxEntry<Report>, policy: OnyxEntry<Policy>, o | |
| // User can request money in any IOU report, unless paid, but user can only request money in an expense report | ||
| // which is tied to their workspace chat. | ||
| if (isMoneyRequestReport(report)) { | ||
| const isOwnExpenseReport = isExpenseReport(report) && isOwnPolicyExpenseChat; | ||
| if (isOwnExpenseReport && PolicyUtils.isPaidGroupPolicy(policy)) { | ||
| return isDraftExpenseReport(report) || isExpenseReportWithInstantSubmittedState(report); | ||
| } | ||
|
|
||
| return (isOwnExpenseReport || isIOUReport(report)) && !isReportApproved(report) && !isSettled(report?.reportID); | ||
| const canAddTransactions = canAddOrDeleteTransactions(report); | ||
| return isGroupPolicy(report) ? isOwnPolicyExpenseChat && canAddTransactions : canAddTransactions; | ||
| } | ||
|
|
||
| // In case of policy expense chat, users can only request money from their own policy expense chat | ||
|
|
@@ -5075,6 +5083,17 @@ function canBeAutoReimbursed(report: OnyxEntry<Report>, policy: OnyxEntry<Policy | |
| return isAutoReimbursable; | ||
| } | ||
|
|
||
| /** | ||
| * Used from money request actions to decide if we need to build an optimistic money request report. | ||
| Create a new report if: | ||
| - we don't have an iouReport set in the chatReport | ||
| - we have one, but it's waiting on the payee adding a bank account | ||
| - we have one but we can't add more transactions to it due to: report is approved or settled, or report is processing and policy isn't on Instant submit reporting frequency | ||
| */ | ||
| function shouldCreateNewMoneyRequestReport(existingIOUReport: OnyxEntry<Report> | undefined | null, chatReport: OnyxEntry<Report> | null): boolean { | ||
| return !existingIOUReport || hasIOUWaitingOnCurrentUserBankAccount(chatReport) || !canAddOrDeleteTransactions(existingIOUReport); | ||
| } | ||
|
|
||
| export { | ||
| getReportParticipantsTitle, | ||
| isReportMessageAttachment, | ||
|
|
@@ -5106,7 +5125,6 @@ export { | |
| isPublicAnnounceRoom, | ||
| isConciergeChatReport, | ||
| isProcessingReport, | ||
| isExpenseReportWithInstantSubmittedState, | ||
| isCurrentUserTheOnlyParticipant, | ||
| hasAutomatedExpensifyAccountIDs, | ||
| hasExpensifyGuidesEmails, | ||
|
|
@@ -5278,6 +5296,8 @@ export { | |
| canEditRoomVisibility, | ||
| canEditPolicyDescription, | ||
| getPolicyDescriptionText, | ||
| canAddOrDeleteTransactions, | ||
| shouldCreateNewMoneyRequestReport, | ||
| }; | ||
|
|
||
| export type { | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.