From 979f57ca1799b0c41ab79f5fd3d1235d2ccda05d Mon Sep 17 00:00:00 2001 From: Shubham Agrawal Date: Wed, 19 Mar 2025 13:43:39 +0530 Subject: [PATCH 1/2] Prevent going to confirmation page when active policy has no expense chat --- src/pages/iou/request/step/IOURequestStepScan/index.native.tsx | 2 +- src/pages/iou/request/step/IOURequestStepScan/index.tsx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/pages/iou/request/step/IOURequestStepScan/index.native.tsx b/src/pages/iou/request/step/IOURequestStepScan/index.native.tsx index 6a00b329a2b6..950163a14ea6 100644 --- a/src/pages/iou/request/step/IOURequestStepScan/index.native.tsx +++ b/src/pages/iou/request/step/IOURequestStepScan/index.native.tsx @@ -318,7 +318,7 @@ function IOURequestStepScan({ // If the user started this flow using the Create expense option (combined submit/track flow), they should be redirected to the participants page. // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing if ((transaction?.isFromGlobalCreate && iouType !== CONST.IOU.TYPE.TRACK && !report?.reportID) || iouType === CONST.IOU.TYPE.CREATE) { - if (activePolicy && isPaidGroupPolicy(activePolicy) && !shouldRestrictUserBillableActions(activePolicy.id)) { + if (activePolicy && isPaidGroupPolicy(activePolicy) && activePolicy?.isPolicyExpenseChatEnabled && !shouldRestrictUserBillableActions(activePolicy.id)) { const activePolicyExpenseChat = getPolicyExpenseChat(currentUserPersonalDetails.accountID, activePolicy?.id); setMoneyRequestParticipantsFromReport(transactionID, activePolicyExpenseChat).then(() => { Navigation.navigate( diff --git a/src/pages/iou/request/step/IOURequestStepScan/index.tsx b/src/pages/iou/request/step/IOURequestStepScan/index.tsx index 2cef346c2125..ab6b5f656013 100644 --- a/src/pages/iou/request/step/IOURequestStepScan/index.tsx +++ b/src/pages/iou/request/step/IOURequestStepScan/index.tsx @@ -341,7 +341,7 @@ function IOURequestStepScan({ // If the user started this flow using the Create expense option (combined submit/track flow), they should be redirected to the participants page. // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing if ((transaction?.isFromGlobalCreate && iouType !== CONST.IOU.TYPE.TRACK && !report?.reportID) || iouType === CONST.IOU.TYPE.CREATE) { - if (activePolicy && isPaidGroupPolicy(activePolicy) && !shouldRestrictUserBillableActions(activePolicy.id)) { + if (activePolicy && isPaidGroupPolicy(activePolicy) && activePolicy?.isPolicyExpenseChatEnabled && !shouldRestrictUserBillableActions(activePolicy.id)) { const activePolicyExpenseChat = getPolicyExpenseChat(currentUserPersonalDetails.accountID, activePolicy?.id); setMoneyRequestParticipantsFromReport(transactionID, activePolicyExpenseChat).then(() => { Navigation.navigate( From 66635adb180cf19f5a11e4b16fdacb82832d4254 Mon Sep 17 00:00:00 2001 From: Shubham Agrawal Date: Mon, 31 Mar 2025 13:45:41 +0530 Subject: [PATCH 2/2] Fix conditions in scan request --- .../step/IOURequestStepScan/index.native.tsx | 258 +++++++++--------- .../request/step/IOURequestStepScan/index.tsx | 257 ++++++++--------- 2 files changed, 261 insertions(+), 254 deletions(-) diff --git a/src/pages/iou/request/step/IOURequestStepScan/index.native.tsx b/src/pages/iou/request/step/IOURequestStepScan/index.native.tsx index d89eabb834e2..e81e0fc157ad 100644 --- a/src/pages/iou/request/step/IOURequestStepScan/index.native.tsx +++ b/src/pages/iou/request/step/IOURequestStepScan/index.native.tsx @@ -307,6 +307,7 @@ function IOURequestStepScan({ }, [currentUserPersonalDetails.accountID, currentUserPersonalDetails.login, iouType, report, transaction?.attendees, transaction?.created, transaction?.currency], ); + const navigateToConfirmationStep = useCallback( (file: FileObject, source: string, locationPermissionGranted = false, isTestTransaction = false) => { if (backTo) { @@ -314,147 +315,149 @@ function IOURequestStepScan({ return; } - // If the transaction was created from the global create, the person needs to select participants, so take them there. - // If the user started this flow using the Create expense option (combined submit/track flow), they should be redirected to the participants page. - // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing - if ((transaction?.isFromGlobalCreate && iouType !== CONST.IOU.TYPE.TRACK && !report?.reportID) || iouType === CONST.IOU.TYPE.CREATE) { - if (activePolicy && isPaidGroupPolicy(activePolicy) && activePolicy?.isPolicyExpenseChatEnabled && !shouldRestrictUserBillableActions(activePolicy.id)) { - const activePolicyExpenseChat = getPolicyExpenseChat(currentUserPersonalDetails.accountID, activePolicy?.id); - setMoneyRequestParticipantsFromReport(transactionID, activePolicyExpenseChat).then(() => { - Navigation.navigate( - ROUTES.MONEY_REQUEST_STEP_CONFIRMATION.getRoute( - CONST.IOU.ACTION.CREATE, - iouType === CONST.IOU.TYPE.CREATE ? CONST.IOU.TYPE.SUBMIT : iouType, - transactionID, - activePolicyExpenseChat?.reportID, - ), + // If a reportID exists in the report object, it's because either: + // - The user started this flow from using the + button in the composer inside a report. + // - The user started this flow from using the global create menu by selecting the Track expense option. + // In this case, the participants can be automatically assigned from the report and the user can skip the participants step and go straight + // to the confirm step. + // If the user is started this flow using the Create expense option (combined submit/track flow), they should be redirected to the participants page. + if (report?.reportID && !isArchivedReport(reportNameValuePairs) && iouType !== CONST.IOU.TYPE.CREATE) { + const selectedParticipants = getMoneyRequestParticipantsFromReport(report); + const participants = selectedParticipants.map((participant) => { + const participantAccountID = participant?.accountID ?? CONST.DEFAULT_NUMBER_ID; + return participantAccountID ? getParticipantsOption(participant, personalDetails) : getReportOption(participant); + }); + + if (shouldSkipConfirmation) { + const receipt: Receipt = file; + receipt.source = source; + receipt.state = CONST.IOU.RECEIPT_STATE.SCANREADY; + if (iouType === CONST.IOU.TYPE.SPLIT) { + playSound(SOUNDS.DONE); + startSplitBill({ + participants, + currentUserLogin: currentUserPersonalDetails?.login ?? '', + currentUserAccountID: currentUserPersonalDetails.accountID, + comment: '', + receipt, + existingSplitChatReportID: reportID, + billable: false, + category: '', + tag: '', + currency: transaction?.currency ?? 'USD', + taxCode: transactionTaxCode, + taxAmount: transactionTaxAmount, + }); + return; + } + const participant = participants.at(0); + if (!participant) { + return; + } + if (locationPermissionGranted) { + getCurrentPosition( + (successData) => { + playSound(SOUNDS.DONE); + if (iouType === CONST.IOU.TYPE.TRACK && report) { + trackExpense({ + report, + isDraftPolicy: false, + participantParams: { + payeeEmail: currentUserPersonalDetails.login, + payeeAccountID: currentUserPersonalDetails.accountID, + participant, + }, + policyParams: { + policy, + }, + transactionParams: { + amount: 0, + currency: transaction?.currency ?? 'USD', + created: transaction?.created, + receipt, + billable: false, + gpsPoints: { + lat: successData.coords.latitude, + long: successData.coords.longitude, + }, + }, + }); + } else { + requestMoney({ + report, + participantParams: { + payeeEmail: currentUserPersonalDetails.login, + payeeAccountID: currentUserPersonalDetails.accountID, + participant, + }, + policyParams: { + policy, + }, + gpsPoints: { + lat: successData.coords.latitude, + long: successData.coords.longitude, + }, + transactionParams: { + amount: 0, + attendees: transaction?.attendees, + currency: transaction?.currency ?? 'USD', + created: transaction?.created ?? '', + merchant: '', + receipt, + billable: false, + }, + }); + } + }, + (errorData) => { + Log.info('[IOURequestStepScan] getCurrentPosition failed', false, errorData); + // When there is an error, the money can still be requested, it just won't include the GPS coordinates + playSound(SOUNDS.DONE); + createTransaction(receipt, participant); + }, + { + maximumAge: CONST.GPS.MAX_AGE, + timeout: CONST.GPS.TIMEOUT, + }, ); - }); - } else { - if (isTestTransaction) { - const managerMcTestParticipant = getManagerMcTestParticipant() ?? {}; - setMoneyRequestParticipants(transactionID, [{...managerMcTestParticipant, selected: true}]); - navigateToConfirmationPage(true); return; } - navigateToParticipantPage(); + playSound(SOUNDS.DONE); + createTransaction(receipt, participant); + return; } + setMoneyRequestParticipantsFromReport(transactionID, report).then(() => { + navigateToConfirmationPage(); + }); return; } - // If the transaction was created from the + menu from the composer inside of a chat, the participants can automatically - // be added to the transaction (taken from the chat report participants) and then the person is taken to the confirmation step. - const selectedParticipants = getMoneyRequestParticipantsFromReport(report); - const participants = selectedParticipants.map((participant) => { - const participantAccountID = participant?.accountID ?? CONST.DEFAULT_NUMBER_ID; - return participantAccountID ? getParticipantsOption(participant, personalDetails) : getReportOption(participant); - }); - - if (shouldSkipConfirmation) { - const receipt: Receipt = file; - receipt.source = source; - receipt.state = CONST.IOU.RECEIPT_STATE.SCANREADY; - if (iouType === CONST.IOU.TYPE.SPLIT) { - playSound(SOUNDS.DONE); - startSplitBill({ - participants, - currentUserLogin: currentUserPersonalDetails?.login ?? '', - currentUserAccountID: currentUserPersonalDetails.accountID, - comment: '', - receipt, - existingSplitChatReportID: reportID, - billable: false, - category: '', - tag: '', - currency: transaction?.currency ?? 'USD', - taxCode: transactionTaxCode, - taxAmount: transactionTaxAmount, - }); - return; - } - const participant = participants.at(0); - if (!participant) { - return; - } - if (locationPermissionGranted) { - getCurrentPosition( - (successData) => { - playSound(SOUNDS.DONE); - if (iouType === CONST.IOU.TYPE.TRACK && report) { - trackExpense({ - report, - isDraftPolicy: false, - participantParams: { - payeeEmail: currentUserPersonalDetails.login, - payeeAccountID: currentUserPersonalDetails.accountID, - participant, - }, - policyParams: { - policy, - }, - transactionParams: { - amount: 0, - currency: transaction?.currency ?? 'USD', - created: transaction?.created, - receipt, - billable: false, - gpsPoints: { - lat: successData.coords.latitude, - long: successData.coords.longitude, - }, - }, - }); - } else { - requestMoney({ - report, - participantParams: { - payeeEmail: currentUserPersonalDetails.login, - payeeAccountID: currentUserPersonalDetails.accountID, - participant, - }, - policyParams: { - policy, - }, - gpsPoints: { - lat: successData.coords.latitude, - long: successData.coords.longitude, - }, - transactionParams: { - amount: 0, - attendees: transaction?.attendees, - currency: transaction?.currency ?? 'USD', - created: transaction?.created ?? '', - merchant: '', - receipt, - billable: false, - }, - }); - } - }, - (errorData) => { - Log.info('[IOURequestStepScan] getCurrentPosition failed', false, errorData); - // When there is an error, the money can still be requested, it just won't include the GPS coordinates - playSound(SOUNDS.DONE); - createTransaction(receipt, participant); - }, - { - maximumAge: CONST.GPS.MAX_AGE, - timeout: CONST.GPS.TIMEOUT, - }, + // If there was no reportID, then that means the user started this flow from the global + menu + // and an optimistic reportID was generated. In that case, the next step is to select the participants for this expense. + if (iouType === CONST.IOU.TYPE.CREATE && isPaidGroupPolicy(activePolicy) && activePolicy?.isPolicyExpenseChatEnabled && !shouldRestrictUserBillableActions(activePolicy.id)) { + const activePolicyExpenseChat = getPolicyExpenseChat(currentUserPersonalDetails.accountID, activePolicy?.id); + setMoneyRequestParticipantsFromReport(transactionID, activePolicyExpenseChat).then(() => { + Navigation.navigate( + ROUTES.MONEY_REQUEST_STEP_CONFIRMATION.getRoute( + CONST.IOU.ACTION.CREATE, + iouType === CONST.IOU.TYPE.CREATE ? CONST.IOU.TYPE.SUBMIT : iouType, + transactionID, + activePolicyExpenseChat?.reportID, + ), ); + }); + } else { + if (isTestTransaction) { + const managerMcTestParticipant = getManagerMcTestParticipant() ?? {}; + setMoneyRequestParticipants(transactionID, [{...managerMcTestParticipant, selected: true}]); + navigateToConfirmationPage(true); return; } - playSound(SOUNDS.DONE); - createTransaction(receipt, participant); - return; + navigateToParticipantPage(); } - setMoneyRequestParticipantsFromReport(transactionID, report).then(() => { - navigateToConfirmationPage(); - }); }, [ backTo, - transaction?.isFromGlobalCreate, transaction?.currency, transaction?.created, transaction?.attendees, @@ -473,6 +476,7 @@ function IOURequestStepScan({ transactionTaxCode, transactionTaxAmount, policy, + reportNameValuePairs, ], ); diff --git a/src/pages/iou/request/step/IOURequestStepScan/index.tsx b/src/pages/iou/request/step/IOURequestStepScan/index.tsx index 5c8e349c471a..a45ded57a83f 100644 --- a/src/pages/iou/request/step/IOURequestStepScan/index.tsx +++ b/src/pages/iou/request/step/IOURequestStepScan/index.tsx @@ -337,147 +337,149 @@ function IOURequestStepScan({ return; } - // If the transaction was created from the global create, the person needs to select participants, so take them there. - // If the user started this flow using the Create expense option (combined submit/track flow), they should be redirected to the participants page. - // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing - if ((transaction?.isFromGlobalCreate && iouType !== CONST.IOU.TYPE.TRACK && !report?.reportID) || iouType === CONST.IOU.TYPE.CREATE) { - if (activePolicy && isPaidGroupPolicy(activePolicy) && activePolicy?.isPolicyExpenseChatEnabled && !shouldRestrictUserBillableActions(activePolicy.id)) { - const activePolicyExpenseChat = getPolicyExpenseChat(currentUserPersonalDetails.accountID, activePolicy?.id); - setMoneyRequestParticipantsFromReport(transactionID, activePolicyExpenseChat).then(() => { - Navigation.navigate( - ROUTES.MONEY_REQUEST_STEP_CONFIRMATION.getRoute( - CONST.IOU.ACTION.CREATE, - iouType === CONST.IOU.TYPE.CREATE ? CONST.IOU.TYPE.SUBMIT : iouType, - transactionID, - activePolicyExpenseChat?.reportID, - ), + // If a reportID exists in the report object, it's because either: + // - The user started this flow from using the + button in the composer inside a report. + // - The user started this flow from using the global create menu by selecting the Track expense option. + // In this case, the participants can be automatically assigned from the report and the user can skip the participants step and go straight + // to the confirm step. + // If the user is started this flow using the Create expense option (combined submit/track flow), they should be redirected to the participants page. + if (report?.reportID && !isArchivedReport(reportNameValuePairs) && iouType !== CONST.IOU.TYPE.CREATE) { + const selectedParticipants = getMoneyRequestParticipantsFromReport(report); + const participants = selectedParticipants.map((participant) => { + const participantAccountID = participant?.accountID ?? CONST.DEFAULT_NUMBER_ID; + return participantAccountID ? getParticipantsOption(participant, personalDetails) : getReportOption(participant); + }); + + if (shouldSkipConfirmation) { + const receipt: Receipt = file; + receipt.source = source; + receipt.state = CONST.IOU.RECEIPT_STATE.SCANREADY; + if (iouType === CONST.IOU.TYPE.SPLIT) { + playSound(SOUNDS.DONE); + startSplitBill({ + participants, + currentUserLogin: currentUserPersonalDetails?.login ?? '', + currentUserAccountID: currentUserPersonalDetails.accountID, + comment: '', + receipt, + existingSplitChatReportID: reportID, + billable: false, + category: '', + tag: '', + currency: transaction?.currency ?? 'USD', + taxCode: transactionTaxCode, + taxAmount: transactionTaxAmount, + }); + return; + } + const participant = participants.at(0); + if (!participant) { + return; + } + if (locationPermissionGranted) { + getCurrentPosition( + (successData) => { + playSound(SOUNDS.DONE); + if (iouType === CONST.IOU.TYPE.TRACK && report) { + trackExpense({ + report, + isDraftPolicy: false, + participantParams: { + payeeEmail: currentUserPersonalDetails.login, + payeeAccountID: currentUserPersonalDetails.accountID, + participant, + }, + policyParams: { + policy, + }, + transactionParams: { + amount: 0, + currency: transaction?.currency ?? 'USD', + created: transaction?.created, + receipt, + billable: false, + gpsPoints: { + lat: successData.coords.latitude, + long: successData.coords.longitude, + }, + }, + }); + } else { + requestMoney({ + report, + participantParams: { + payeeEmail: currentUserPersonalDetails.login, + payeeAccountID: currentUserPersonalDetails.accountID, + participant, + }, + policyParams: { + policy, + }, + gpsPoints: { + lat: successData.coords.latitude, + long: successData.coords.longitude, + }, + transactionParams: { + amount: 0, + attendees: transaction?.attendees, + currency: transaction?.currency ?? 'USD', + created: transaction?.created ?? '', + merchant: '', + receipt, + billable: false, + }, + }); + } + }, + (errorData) => { + Log.info('[IOURequestStepScan] getCurrentPosition failed', false, errorData); + // When there is an error, the money can still be requested, it just won't include the GPS coordinates + playSound(SOUNDS.DONE); + createTransaction(receipt, participant); + }, + { + maximumAge: CONST.GPS.MAX_AGE, + timeout: CONST.GPS.TIMEOUT, + }, ); - }); - } else { - if (isTestTransaction) { - const managerMcTestParticipant = getManagerMcTestParticipant() ?? {}; - setMoneyRequestParticipants(transactionID, [{...managerMcTestParticipant, selected: true}]); - navigateToConfirmationPage(true); return; } - navigateToParticipantPage(); + playSound(SOUNDS.DONE); + createTransaction(receipt, participant); + return; } + setMoneyRequestParticipantsFromReport(transactionID, report).then(() => { + navigateToConfirmationPage(); + }); return; } - // If the transaction was created from the + menu from the composer inside of a chat, the participants can automatically - // be added to the transaction (taken from the chat report participants) and then the person is taken to the confirmation step. - const selectedParticipants = getMoneyRequestParticipantsFromReport(report); - const participants = selectedParticipants.map((participant) => { - const participantAccountID = participant?.accountID ?? CONST.DEFAULT_NUMBER_ID; - return participantAccountID ? getParticipantsOption(participant, personalDetails) : getReportOption(participant); - }); - - if (shouldSkipConfirmation) { - const receipt: Receipt = file; - receipt.source = source; - receipt.state = CONST.IOU.RECEIPT_STATE.SCANREADY; - if (iouType === CONST.IOU.TYPE.SPLIT) { - playSound(SOUNDS.DONE); - startSplitBill({ - participants, - currentUserLogin: currentUserPersonalDetails?.login ?? '', - currentUserAccountID: currentUserPersonalDetails.accountID, - comment: '', - receipt, - existingSplitChatReportID: reportID, - billable: false, - category: '', - tag: '', - currency: transaction?.currency ?? 'USD', - taxCode: transactionTaxCode, - taxAmount: transactionTaxAmount, - }); - return; - } - const participant = participants.at(0); - if (!participant) { - return; - } - if (locationPermissionGranted) { - getCurrentPosition( - (successData) => { - playSound(SOUNDS.DONE); - if (iouType === CONST.IOU.TYPE.TRACK && report) { - trackExpense({ - report, - isDraftPolicy: false, - participantParams: { - payeeEmail: currentUserPersonalDetails.login, - payeeAccountID: currentUserPersonalDetails.accountID, - participant, - }, - policyParams: { - policy, - }, - transactionParams: { - amount: 0, - currency: transaction?.currency ?? 'USD', - created: transaction?.created, - receipt, - billable: false, - gpsPoints: { - lat: successData.coords.latitude, - long: successData.coords.longitude, - }, - }, - }); - } else { - requestMoney({ - report, - participantParams: { - payeeEmail: currentUserPersonalDetails.login, - payeeAccountID: currentUserPersonalDetails.accountID, - participant, - }, - policyParams: { - policy, - }, - gpsPoints: { - lat: successData.coords.latitude, - long: successData.coords.longitude, - }, - transactionParams: { - amount: 0, - attendees: transaction?.attendees, - currency: transaction?.currency ?? 'USD', - created: transaction?.created ?? '', - merchant: '', - receipt, - billable: false, - }, - }); - } - }, - (errorData) => { - Log.info('[IOURequestStepScan] getCurrentPosition failed', false, errorData); - // When there is an error, the money can still be requested, it just won't include the GPS coordinates - playSound(SOUNDS.DONE); - createTransaction(receipt, participant); - }, - { - maximumAge: CONST.GPS.MAX_AGE, - timeout: CONST.GPS.TIMEOUT, - }, + // If there was no reportID, then that means the user started this flow from the global + menu + // and an optimistic reportID was generated. In that case, the next step is to select the participants for this expense. + if (iouType === CONST.IOU.TYPE.CREATE && isPaidGroupPolicy(activePolicy) && activePolicy?.isPolicyExpenseChatEnabled && !shouldRestrictUserBillableActions(activePolicy.id)) { + const activePolicyExpenseChat = getPolicyExpenseChat(currentUserPersonalDetails.accountID, activePolicy?.id); + setMoneyRequestParticipantsFromReport(transactionID, activePolicyExpenseChat).then(() => { + Navigation.navigate( + ROUTES.MONEY_REQUEST_STEP_CONFIRMATION.getRoute( + CONST.IOU.ACTION.CREATE, + iouType === CONST.IOU.TYPE.CREATE ? CONST.IOU.TYPE.SUBMIT : iouType, + transactionID, + activePolicyExpenseChat?.reportID, + ), ); + }); + } else { + if (isTestTransaction) { + const managerMcTestParticipant = getManagerMcTestParticipant() ?? {}; + setMoneyRequestParticipants(transactionID, [{...managerMcTestParticipant, selected: true}]); + navigateToConfirmationPage(true); return; } - playSound(SOUNDS.DONE); - createTransaction(receipt, participant); - return; + navigateToParticipantPage(); } - setMoneyRequestParticipantsFromReport(transactionID, report).then(() => { - navigateToConfirmationPage(); - }); }, [ backTo, - transaction?.isFromGlobalCreate, transaction?.currency, transaction?.created, transaction?.attendees, @@ -496,6 +498,7 @@ function IOURequestStepScan({ transactionTaxCode, transactionTaxAmount, policy, + reportNameValuePairs, ], );