From 10e34a68998ccc74ecba3f7b981afa8231bdf947 Mon Sep 17 00:00:00 2001 From: Carlos Barros <765936+barros001@users.noreply.github.com> Date: Mon, 26 Feb 2024 17:29:53 -0500 Subject: [PATCH 01/20] disable submit button when user is self approving but self approval is disabled --- src/components/MoneyReportHeader.tsx | 3 +++ src/components/ReportActionItem/ReportPreview.tsx | 2 ++ src/libs/ReportUtils.ts | 10 ++++++++++ 3 files changed, 15 insertions(+) diff --git a/src/components/MoneyReportHeader.tsx b/src/components/MoneyReportHeader.tsx index 3f551da788f5e..2e4e9c0802245 100644 --- a/src/components/MoneyReportHeader.tsx +++ b/src/components/MoneyReportHeader.tsx @@ -91,6 +91,7 @@ function MoneyReportHeader({session, policy, chatReport, nextStep, report: money }, [isPaidGroupPolicy, isManager, isDraft, isApproved, isSettled, isOnInstantSubmitPolicy, isOnSubmitAndClosePolicy]); const shouldShowSettlementButton = shouldShowPayButton || shouldShowApproveButton; const shouldShowSubmitButton = isDraft && reimbursableSpend !== 0; + const shouldDisableSubmitButton = !ReportUtils.isAllowedToSubmitDraftExpenseReport(moneyRequestReport); const isFromPaidPolicy = policyType === CONST.POLICY.TYPE.TEAM || policyType === CONST.POLICY.TYPE.CORPORATE; const shouldShowNextStep = isFromPaidPolicy && !!nextStep?.message?.length; const shouldShowAnyButton = shouldShowSettlementButton || shouldShowApproveButton || shouldShowSubmitButton || shouldShowNextStep; @@ -157,6 +158,7 @@ function MoneyReportHeader({session, policy, chatReport, nextStep, report: money text={translate('common.submit')} style={[styles.mnw120, styles.pv2, styles.pr0]} onPress={() => IOU.submitReport(moneyRequestReport)} + isDisabled={shouldDisableSubmitButton} /> )} @@ -188,6 +190,7 @@ function MoneyReportHeader({session, policy, chatReport, nextStep, report: money text={translate('common.submit')} style={[styles.w100, styles.pr0]} onPress={() => IOU.submitReport(moneyRequestReport)} + isDisabled={shouldDisableSubmitButton} /> )} diff --git a/src/components/ReportActionItem/ReportPreview.tsx b/src/components/ReportActionItem/ReportPreview.tsx index 591767234b8b5..b984972ace7b3 100644 --- a/src/components/ReportActionItem/ReportPreview.tsx +++ b/src/components/ReportActionItem/ReportPreview.tsx @@ -156,6 +156,7 @@ function ReportPreview({ }); const shouldShowSubmitButton = isDraftExpenseReport && reimbursableSpend !== 0; + const shouldDisableSubmitButton = !ReportUtils.isAllowedToSubmitDraftExpenseReport(iouReport); // The submit button should be success green colour only if the user is submitter and the policy does not have Scheduled Submit turned on const isWaitingForSubmissionFromCurrentUser = useMemo( @@ -331,6 +332,7 @@ function ReportPreview({ text={translate('common.submit')} style={styles.mt3} onPress={() => iouReport && IOU.submitReport(iouReport)} + isDisabled={shouldDisableSubmitButton} /> )} diff --git a/src/libs/ReportUtils.ts b/src/libs/ReportUtils.ts index 8813501e2b3f6..69c903bc74d18 100644 --- a/src/libs/ReportUtils.ts +++ b/src/libs/ReportUtils.ts @@ -5011,6 +5011,15 @@ function canBeAutoReimbursed(report: OnyxEntry, policy: OnyxEntry): boolean { + const policy = getPolicy(report?.policyID); + const {submitsTo, isPreventSelfApprovalEnabled, preventSelfApprovalEnabled} = policy; + + const isSelfApproval = currentUserAccountID === submitsTo; + + return !((isPreventSelfApprovalEnabled ?? preventSelfApprovalEnabled) && isSelfApproval); +} + export { getReportParticipantsTitle, isReportMessageAttachment, @@ -5211,6 +5220,7 @@ export { canEditRoomVisibility, canEditPolicyDescription, getPolicyDescriptionText, + isAllowedToSubmitDraftExpenseReport, }; export type { From 1bd040a987d028eab44cf597ae92856210ab25d9 Mon Sep 17 00:00:00 2001 From: Carlos Barros <765936+barros001@users.noreply.github.com> Date: Mon, 26 Feb 2024 17:43:08 -0500 Subject: [PATCH 02/20] do not show pay buttons if report is not yet approved --- src/components/MoneyReportHeader.tsx | 16 ++++++++++++---- .../ReportActionItem/ReportPreview.tsx | 16 ++++++++++++---- 2 files changed, 24 insertions(+), 8 deletions(-) diff --git a/src/components/MoneyReportHeader.tsx b/src/components/MoneyReportHeader.tsx index 2e4e9c0802245..9cedc09bbd268 100644 --- a/src/components/MoneyReportHeader.tsx +++ b/src/components/MoneyReportHeader.tsx @@ -76,10 +76,6 @@ function MoneyReportHeader({session, policy, chatReport, nextStep, report: money const isOnInstantSubmitPolicy = PolicyUtils.isInstantSubmitEnabled(policy); const isOnSubmitAndClosePolicy = PolicyUtils.isSubmitAndClose(policy); - const shouldShowPayButton = useMemo( - () => isPayer && !isDraft && !isSettled && !moneyRequestReport.isWaitingOnBankAccount && reimbursableSpend !== 0 && !ReportUtils.isArchivedRoom(chatReport) && !isAutoReimbursable, - [isPayer, isDraft, isSettled, moneyRequestReport, reimbursableSpend, chatReport, isAutoReimbursable], - ); const shouldShowApproveButton = useMemo(() => { if (!isPaidGroupPolicy) { return false; @@ -89,6 +85,18 @@ function MoneyReportHeader({session, policy, chatReport, nextStep, report: money } return isManager && !isDraft && !isApproved && !isSettled; }, [isPaidGroupPolicy, isManager, isDraft, isApproved, isSettled, isOnInstantSubmitPolicy, isOnSubmitAndClosePolicy]); + const shouldShowPayButton = useMemo( + () => + isPayer && + !isDraft && + !isSettled && + !shouldShowApproveButton && + !moneyRequestReport.isWaitingOnBankAccount && + reimbursableSpend !== 0 && + !ReportUtils.isArchivedRoom(chatReport) && + !isAutoReimbursable, + [isPayer, isDraft, isSettled, moneyRequestReport, reimbursableSpend, chatReport, isAutoReimbursable, shouldShowApproveButton], + ); const shouldShowSettlementButton = shouldShowPayButton || shouldShowApproveButton; const shouldShowSubmitButton = isDraft && reimbursableSpend !== 0; const shouldDisableSubmitButton = !ReportUtils.isAllowedToSubmitDraftExpenseReport(moneyRequestReport); diff --git a/src/components/ReportActionItem/ReportPreview.tsx b/src/components/ReportActionItem/ReportPreview.tsx index b984972ace7b3..5a4bde217b1dd 100644 --- a/src/components/ReportActionItem/ReportPreview.tsx +++ b/src/components/ReportActionItem/ReportPreview.tsx @@ -217,10 +217,6 @@ function ReportPreview({ : isPolicyAdmin || (isMoneyRequestReport && isCurrentUserManager); const isOnInstantSubmitPolicy = PolicyUtils.isInstantSubmitEnabled(policy); const isOnSubmitAndClosePolicy = PolicyUtils.isSubmitAndClose(policy); - const shouldShowPayButton = useMemo( - () => isPayer && !isDraftExpenseReport && !iouSettled && !iouReport?.isWaitingOnBankAccount && reimbursableSpend !== 0 && !iouCanceled && !isAutoReimbursable, - [isPayer, isDraftExpenseReport, iouSettled, reimbursableSpend, iouCanceled, isAutoReimbursable, iouReport], - ); const shouldShowApproveButton = useMemo(() => { if (!isPaidGroupPolicy) { return false; @@ -230,6 +226,18 @@ function ReportPreview({ } return isCurrentUserManager && !isDraftExpenseReport && !isApproved && !iouSettled; }, [isPaidGroupPolicy, isCurrentUserManager, isDraftExpenseReport, isApproved, isOnInstantSubmitPolicy, isOnSubmitAndClosePolicy, iouSettled]); + const shouldShowPayButton = useMemo( + () => + isPayer && + !isDraftExpenseReport && + !iouSettled && + !shouldShowApproveButton && + !iouReport?.isWaitingOnBankAccount && + reimbursableSpend !== 0 && + !iouCanceled && + !isAutoReimbursable, + [isPayer, isDraftExpenseReport, iouSettled, reimbursableSpend, iouCanceled, isAutoReimbursable, iouReport, shouldShowApproveButton], + ); const shouldShowSettlementButton = shouldShowPayButton || shouldShowApproveButton; /* From b1290026a2be9945632cb8fc56e9c438bc9776ea Mon Sep 17 00:00:00 2001 From: Carlos Barros <765936+barros001@users.noreply.github.com> Date: Mon, 26 Feb 2024 18:01:18 -0500 Subject: [PATCH 03/20] disable approve button if user is self approving but self approval is disabled --- src/components/MoneyReportHeader.tsx | 7 ++++--- src/components/ReportActionItem/ReportPreview.tsx | 5 +++-- src/libs/ReportUtils.ts | 11 +++++++++++ 3 files changed, 18 insertions(+), 5 deletions(-) diff --git a/src/components/MoneyReportHeader.tsx b/src/components/MoneyReportHeader.tsx index 9cedc09bbd268..3c84da5cba57c 100644 --- a/src/components/MoneyReportHeader.tsx +++ b/src/components/MoneyReportHeader.tsx @@ -99,7 +99,8 @@ function MoneyReportHeader({session, policy, chatReport, nextStep, report: money ); const shouldShowSettlementButton = shouldShowPayButton || shouldShowApproveButton; const shouldShowSubmitButton = isDraft && reimbursableSpend !== 0; - const shouldDisableSubmitButton = !ReportUtils.isAllowedToSubmitDraftExpenseReport(moneyRequestReport); + const shouldDisableSubmitButton = shouldShowSubmitButton && !ReportUtils.isAllowedToSubmitDraftExpenseReport(moneyRequestReport); + const shouldDisableSettlementButton = shouldShowSettlementButton && shouldShowApproveButton && !ReportUtils.isAllowedToApproveExpenseReport(moneyRequestReport); const isFromPaidPolicy = policyType === CONST.POLICY.TYPE.TEAM || policyType === CONST.POLICY.TYPE.CORPORATE; const shouldShowNextStep = isFromPaidPolicy && !!nextStep?.message?.length; const shouldShowAnyButton = shouldShowSettlementButton || shouldShowApproveButton || shouldShowSubmitButton || shouldShowNextStep; @@ -154,7 +155,7 @@ function MoneyReportHeader({session, policy, chatReport, nextStep, report: money shouldShowApproveButton={shouldShowApproveButton} style={[styles.pv2]} formattedAmount={formattedAmount} - isDisabled={!canAllowSettlement} + isDisabled={!canAllowSettlement || shouldDisableSettlementButton} /> )} @@ -186,7 +187,7 @@ function MoneyReportHeader({session, policy, chatReport, nextStep, report: money shouldHidePaymentOptions={!shouldShowPayButton} shouldShowApproveButton={shouldShowApproveButton} formattedAmount={formattedAmount} - isDisabled={!canAllowSettlement} + isDisabled={!canAllowSettlement || shouldDisableSettlementButton} /> )} diff --git a/src/components/ReportActionItem/ReportPreview.tsx b/src/components/ReportActionItem/ReportPreview.tsx index 5a4bde217b1dd..4bf7c1af03b90 100644 --- a/src/components/ReportActionItem/ReportPreview.tsx +++ b/src/components/ReportActionItem/ReportPreview.tsx @@ -156,7 +156,7 @@ function ReportPreview({ }); const shouldShowSubmitButton = isDraftExpenseReport && reimbursableSpend !== 0; - const shouldDisableSubmitButton = !ReportUtils.isAllowedToSubmitDraftExpenseReport(iouReport); + const shouldDisableSubmitButton = shouldShowSubmitButton && !ReportUtils.isAllowedToSubmitDraftExpenseReport(iouReport); // The submit button should be success green colour only if the user is submitter and the policy does not have Scheduled Submit turned on const isWaitingForSubmissionFromCurrentUser = useMemo( @@ -239,6 +239,7 @@ function ReportPreview({ [isPayer, isDraftExpenseReport, iouSettled, reimbursableSpend, iouCanceled, isAutoReimbursable, iouReport, shouldShowApproveButton], ); const shouldShowSettlementButton = shouldShowPayButton || shouldShowApproveButton; + const shouldDisableSettlementButton = shouldShowSettlementButton && shouldShowApproveButton && !ReportUtils.isAllowedToApproveExpenseReport(iouReport); /* Show subtitle if at least one of the money requests is not being smart scanned, and either: @@ -330,7 +331,7 @@ function ReportPreview({ horizontal: CONST.MODAL.ANCHOR_ORIGIN_HORIZONTAL.RIGHT, vertical: CONST.MODAL.ANCHOR_ORIGIN_VERTICAL.BOTTOM, }} - isDisabled={!canAllowSettlement} + isDisabled={!canAllowSettlement || shouldDisableSettlementButton} /> )} {shouldShowSubmitButton && ( diff --git a/src/libs/ReportUtils.ts b/src/libs/ReportUtils.ts index 69c903bc74d18..b082ec8789e5e 100644 --- a/src/libs/ReportUtils.ts +++ b/src/libs/ReportUtils.ts @@ -5020,6 +5020,16 @@ function isAllowedToSubmitDraftExpenseReport(report: OnyxEntry): boolean return !((isPreventSelfApprovalEnabled ?? preventSelfApprovalEnabled) && isSelfApproval); } +function isAllowedToApproveExpenseReport(report: OnyxEntry): boolean { + const policy = getPolicy(report?.policyID); + const {approver, submitsTo, isPreventSelfApprovalEnabled, preventSelfApprovalEnabled} = policy; + + // TODO: check if we should be using "approver" here instead of the same "submitsTo". "approver" is "undefined" currently. + const isSelfApproval = currentUserAccountID === (approver ?? submitsTo); + + return !((isPreventSelfApprovalEnabled ?? preventSelfApprovalEnabled) && isSelfApproval); +} + export { getReportParticipantsTitle, isReportMessageAttachment, @@ -5221,6 +5231,7 @@ export { canEditPolicyDescription, getPolicyDescriptionText, isAllowedToSubmitDraftExpenseReport, + isAllowedToApproveExpenseReport, }; export type { From fc7670078ef0da6c4865c6dc37b16552c262a727 Mon Sep 17 00:00:00 2001 From: Carlos Barros <765936+barros001@users.noreply.github.com> Date: Tue, 27 Feb 2024 06:49:57 -0500 Subject: [PATCH 04/20] build optimistic next step message saying you are not allowed to approve your own reports --- src/libs/NextStepUtils.ts | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/src/libs/NextStepUtils.ts b/src/libs/NextStepUtils.ts index f03c34b1696ed..9a931af925186 100644 --- a/src/libs/NextStepUtils.ts +++ b/src/libs/NextStepUtils.ts @@ -244,6 +244,32 @@ function buildNextStep( ]; } + // Prevented self approval + if ((isPreventSelfApprovalEnabled ?? preventSelfApprovalEnabled) && isSelfApproval) { + optimisticNextStep.message = [ + { + text: "Oops! Looks like you're ", + }, + { + text: isManager ? 'reviewing' : 'approving', + }, + { + text: ' your own report. ', + type: 'strong', + }, + { + text: 'Approving your own reports is ', + }, + { + text: 'forbidden', + type: 'strong', + }, + { + text: ' by your policy.', + }, + ]; + } + break; } From 0c353fd3501046b18a2eba7be862438260aaa159 Mon Sep 17 00:00:00 2001 From: Carlos Barros <765936+barros001@users.noreply.github.com> Date: Tue, 27 Feb 2024 15:30:30 -0500 Subject: [PATCH 05/20] remove isAllowedToApproveExpenseReport method --- src/components/MoneyReportHeader.tsx | 2 +- src/components/ReportActionItem/ReportPreview.tsx | 2 +- src/libs/ReportUtils.ts | 11 ----------- 3 files changed, 2 insertions(+), 13 deletions(-) diff --git a/src/components/MoneyReportHeader.tsx b/src/components/MoneyReportHeader.tsx index 3c84da5cba57c..d78255afa0a37 100644 --- a/src/components/MoneyReportHeader.tsx +++ b/src/components/MoneyReportHeader.tsx @@ -100,7 +100,7 @@ function MoneyReportHeader({session, policy, chatReport, nextStep, report: money const shouldShowSettlementButton = shouldShowPayButton || shouldShowApproveButton; const shouldShowSubmitButton = isDraft && reimbursableSpend !== 0; const shouldDisableSubmitButton = shouldShowSubmitButton && !ReportUtils.isAllowedToSubmitDraftExpenseReport(moneyRequestReport); - const shouldDisableSettlementButton = shouldShowSettlementButton && shouldShowApproveButton && !ReportUtils.isAllowedToApproveExpenseReport(moneyRequestReport); + const shouldDisableSettlementButton = shouldShowSettlementButton && shouldShowApproveButton && !ReportUtils.isAllowedToSubmitDraftExpenseReport(moneyRequestReport); const isFromPaidPolicy = policyType === CONST.POLICY.TYPE.TEAM || policyType === CONST.POLICY.TYPE.CORPORATE; const shouldShowNextStep = isFromPaidPolicy && !!nextStep?.message?.length; const shouldShowAnyButton = shouldShowSettlementButton || shouldShowApproveButton || shouldShowSubmitButton || shouldShowNextStep; diff --git a/src/components/ReportActionItem/ReportPreview.tsx b/src/components/ReportActionItem/ReportPreview.tsx index 4bf7c1af03b90..7c68291c5e786 100644 --- a/src/components/ReportActionItem/ReportPreview.tsx +++ b/src/components/ReportActionItem/ReportPreview.tsx @@ -239,7 +239,7 @@ function ReportPreview({ [isPayer, isDraftExpenseReport, iouSettled, reimbursableSpend, iouCanceled, isAutoReimbursable, iouReport, shouldShowApproveButton], ); const shouldShowSettlementButton = shouldShowPayButton || shouldShowApproveButton; - const shouldDisableSettlementButton = shouldShowSettlementButton && shouldShowApproveButton && !ReportUtils.isAllowedToApproveExpenseReport(iouReport); + const shouldDisableSettlementButton = shouldShowSettlementButton && shouldShowApproveButton && !ReportUtils.isAllowedToSubmitDraftExpenseReport(iouReport); /* Show subtitle if at least one of the money requests is not being smart scanned, and either: diff --git a/src/libs/ReportUtils.ts b/src/libs/ReportUtils.ts index b082ec8789e5e..69c903bc74d18 100644 --- a/src/libs/ReportUtils.ts +++ b/src/libs/ReportUtils.ts @@ -5020,16 +5020,6 @@ function isAllowedToSubmitDraftExpenseReport(report: OnyxEntry): boolean return !((isPreventSelfApprovalEnabled ?? preventSelfApprovalEnabled) && isSelfApproval); } -function isAllowedToApproveExpenseReport(report: OnyxEntry): boolean { - const policy = getPolicy(report?.policyID); - const {approver, submitsTo, isPreventSelfApprovalEnabled, preventSelfApprovalEnabled} = policy; - - // TODO: check if we should be using "approver" here instead of the same "submitsTo". "approver" is "undefined" currently. - const isSelfApproval = currentUserAccountID === (approver ?? submitsTo); - - return !((isPreventSelfApprovalEnabled ?? preventSelfApprovalEnabled) && isSelfApproval); -} - export { getReportParticipantsTitle, isReportMessageAttachment, @@ -5231,7 +5221,6 @@ export { canEditPolicyDescription, getPolicyDescriptionText, isAllowedToSubmitDraftExpenseReport, - isAllowedToApproveExpenseReport, }; export type { From cb6108686f33371ded80a94de04b848740398103 Mon Sep 17 00:00:00 2001 From: Carlos Barros <765936+barros001@users.noreply.github.com> Date: Tue, 27 Feb 2024 15:33:38 -0500 Subject: [PATCH 06/20] updated shouldDisableSettlementButton logic --- src/components/MoneyReportHeader.tsx | 7 ++++--- src/components/ReportActionItem/ReportPreview.tsx | 4 ++-- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/src/components/MoneyReportHeader.tsx b/src/components/MoneyReportHeader.tsx index d78255afa0a37..697f8aa202652 100644 --- a/src/components/MoneyReportHeader.tsx +++ b/src/components/MoneyReportHeader.tsx @@ -100,7 +100,8 @@ function MoneyReportHeader({session, policy, chatReport, nextStep, report: money const shouldShowSettlementButton = shouldShowPayButton || shouldShowApproveButton; const shouldShowSubmitButton = isDraft && reimbursableSpend !== 0; const shouldDisableSubmitButton = shouldShowSubmitButton && !ReportUtils.isAllowedToSubmitDraftExpenseReport(moneyRequestReport); - const shouldDisableSettlementButton = shouldShowSettlementButton && shouldShowApproveButton && !ReportUtils.isAllowedToSubmitDraftExpenseReport(moneyRequestReport); + const shouldDisableSettlementButton = + !canAllowSettlement || (shouldShowSettlementButton && shouldShowApproveButton && !ReportUtils.isAllowedToSubmitDraftExpenseReport(moneyRequestReport)); const isFromPaidPolicy = policyType === CONST.POLICY.TYPE.TEAM || policyType === CONST.POLICY.TYPE.CORPORATE; const shouldShowNextStep = isFromPaidPolicy && !!nextStep?.message?.length; const shouldShowAnyButton = shouldShowSettlementButton || shouldShowApproveButton || shouldShowSubmitButton || shouldShowNextStep; @@ -155,7 +156,7 @@ function MoneyReportHeader({session, policy, chatReport, nextStep, report: money shouldShowApproveButton={shouldShowApproveButton} style={[styles.pv2]} formattedAmount={formattedAmount} - isDisabled={!canAllowSettlement || shouldDisableSettlementButton} + isDisabled={shouldDisableSettlementButton} /> )} @@ -187,7 +188,7 @@ function MoneyReportHeader({session, policy, chatReport, nextStep, report: money shouldHidePaymentOptions={!shouldShowPayButton} shouldShowApproveButton={shouldShowApproveButton} formattedAmount={formattedAmount} - isDisabled={!canAllowSettlement || shouldDisableSettlementButton} + isDisabled={shouldDisableSettlementButton} /> )} diff --git a/src/components/ReportActionItem/ReportPreview.tsx b/src/components/ReportActionItem/ReportPreview.tsx index 7c68291c5e786..c77839b03ad95 100644 --- a/src/components/ReportActionItem/ReportPreview.tsx +++ b/src/components/ReportActionItem/ReportPreview.tsx @@ -239,7 +239,7 @@ function ReportPreview({ [isPayer, isDraftExpenseReport, iouSettled, reimbursableSpend, iouCanceled, isAutoReimbursable, iouReport, shouldShowApproveButton], ); const shouldShowSettlementButton = shouldShowPayButton || shouldShowApproveButton; - const shouldDisableSettlementButton = shouldShowSettlementButton && shouldShowApproveButton && !ReportUtils.isAllowedToSubmitDraftExpenseReport(iouReport); + const shouldDisableSettlementButton = !canAllowSettlement || (shouldShowSettlementButton && shouldShowApproveButton && !ReportUtils.isAllowedToSubmitDraftExpenseReport(iouReport)); /* Show subtitle if at least one of the money requests is not being smart scanned, and either: @@ -331,7 +331,7 @@ function ReportPreview({ horizontal: CONST.MODAL.ANCHOR_ORIGIN_HORIZONTAL.RIGHT, vertical: CONST.MODAL.ANCHOR_ORIGIN_VERTICAL.BOTTOM, }} - isDisabled={!canAllowSettlement || shouldDisableSettlementButton} + isDisabled={shouldDisableSettlementButton} /> )} {shouldShowSubmitButton && ( From 03c5f52f25456c04c7da5638e8d5a29dba947237 Mon Sep 17 00:00:00 2001 From: Carlos Barros <765936+barros001@users.noreply.github.com> Date: Tue, 27 Feb 2024 16:20:57 -0500 Subject: [PATCH 07/20] added isAllowedToApproveExpenseReport; added test case for nextStep --- src/components/MoneyReportHeader.tsx | 3 +- .../ReportActionItem/ReportPreview.tsx | 2 +- src/libs/NextStepUtils.ts | 47 +++++++++---------- src/libs/ReportUtils.ts | 11 +++++ tests/unit/NextStepUtilsTest.ts | 32 +++++++++++++ 5 files changed, 67 insertions(+), 28 deletions(-) diff --git a/src/components/MoneyReportHeader.tsx b/src/components/MoneyReportHeader.tsx index 697f8aa202652..dc89ce1bdc3a3 100644 --- a/src/components/MoneyReportHeader.tsx +++ b/src/components/MoneyReportHeader.tsx @@ -100,8 +100,7 @@ function MoneyReportHeader({session, policy, chatReport, nextStep, report: money const shouldShowSettlementButton = shouldShowPayButton || shouldShowApproveButton; const shouldShowSubmitButton = isDraft && reimbursableSpend !== 0; const shouldDisableSubmitButton = shouldShowSubmitButton && !ReportUtils.isAllowedToSubmitDraftExpenseReport(moneyRequestReport); - const shouldDisableSettlementButton = - !canAllowSettlement || (shouldShowSettlementButton && shouldShowApproveButton && !ReportUtils.isAllowedToSubmitDraftExpenseReport(moneyRequestReport)); + const shouldDisableSettlementButton = !canAllowSettlement || (shouldShowSettlementButton && shouldShowApproveButton && !ReportUtils.isAllowedToApproveExpenseReport(moneyRequestReport)); const isFromPaidPolicy = policyType === CONST.POLICY.TYPE.TEAM || policyType === CONST.POLICY.TYPE.CORPORATE; const shouldShowNextStep = isFromPaidPolicy && !!nextStep?.message?.length; const shouldShowAnyButton = shouldShowSettlementButton || shouldShowApproveButton || shouldShowSubmitButton || shouldShowNextStep; diff --git a/src/components/ReportActionItem/ReportPreview.tsx b/src/components/ReportActionItem/ReportPreview.tsx index c77839b03ad95..b03c0efce81ab 100644 --- a/src/components/ReportActionItem/ReportPreview.tsx +++ b/src/components/ReportActionItem/ReportPreview.tsx @@ -239,7 +239,7 @@ function ReportPreview({ [isPayer, isDraftExpenseReport, iouSettled, reimbursableSpend, iouCanceled, isAutoReimbursable, iouReport, shouldShowApproveButton], ); const shouldShowSettlementButton = shouldShowPayButton || shouldShowApproveButton; - const shouldDisableSettlementButton = !canAllowSettlement || (shouldShowSettlementButton && shouldShowApproveButton && !ReportUtils.isAllowedToSubmitDraftExpenseReport(iouReport)); + const shouldDisableSettlementButton = !canAllowSettlement || (shouldShowSettlementButton && shouldShowApproveButton && !ReportUtils.isAllowedToApproveExpenseReport(iouReport)); /* Show subtitle if at least one of the money requests is not being smart scanned, and either: diff --git a/src/libs/NextStepUtils.ts b/src/libs/NextStepUtils.ts index 9a931af925186..f8db5fdd2c6bc 100644 --- a/src/libs/NextStepUtils.ts +++ b/src/libs/NextStepUtils.ts @@ -242,32 +242,29 @@ function buildNextStep( text: ' %expenses.', }, ]; - } - // Prevented self approval - if ((isPreventSelfApprovalEnabled ?? preventSelfApprovalEnabled) && isSelfApproval) { - optimisticNextStep.message = [ - { - text: "Oops! Looks like you're ", - }, - { - text: isManager ? 'reviewing' : 'approving', - }, - { - text: ' your own report. ', - type: 'strong', - }, - { - text: 'Approving your own reports is ', - }, - { - text: 'forbidden', - type: 'strong', - }, - { - text: ' by your policy.', - }, - ]; + // Prevented self approval + if ((isPreventSelfApprovalEnabled ?? preventSelfApprovalEnabled) && isSelfApproval) { + optimisticNextStep.message = [ + { + text: "Oops! Looks like you're reviewing", + }, + { + text: ' your own report. ', + type: 'strong', + }, + { + text: 'Approving your own reports is ', + }, + { + text: 'forbidden', + type: 'strong', + }, + { + text: ' by your policy.', + }, + ]; + } } break; diff --git a/src/libs/ReportUtils.ts b/src/libs/ReportUtils.ts index 69c903bc74d18..d0c3d3e6603d6 100644 --- a/src/libs/ReportUtils.ts +++ b/src/libs/ReportUtils.ts @@ -5020,6 +5020,16 @@ function isAllowedToSubmitDraftExpenseReport(report: OnyxEntry): boolean return !((isPreventSelfApprovalEnabled ?? preventSelfApprovalEnabled) && isSelfApproval); } +function isAllowedToApproveExpenseReport(report: OnyxEntry): boolean { + const policy = getPolicy(report?.policyID); + const {ownerAccountID, submitsTo, isPreventSelfApprovalEnabled, preventSelfApprovalEnabled} = policy; + + const isOwner = currentUserAccountID === ownerAccountID; + const isSelfApproval = currentUserAccountID === submitsTo; + + return !((isPreventSelfApprovalEnabled ?? preventSelfApprovalEnabled) && isOwner && isSelfApproval); +} + export { getReportParticipantsTitle, isReportMessageAttachment, @@ -5221,6 +5231,7 @@ export { canEditPolicyDescription, getPolicyDescriptionText, isAllowedToSubmitDraftExpenseReport, + isAllowedToApproveExpenseReport, }; export type { diff --git a/tests/unit/NextStepUtilsTest.ts b/tests/unit/NextStepUtilsTest.ts index 622881bc7979a..9c202ca4ebd99 100644 --- a/tests/unit/NextStepUtilsTest.ts +++ b/tests/unit/NextStepUtilsTest.ts @@ -440,6 +440,38 @@ describe('libs/NextStepUtils', () => { expect(result).toMatchObject(optimisticNextStep); }); + + test('prevented self approval', () => { + optimisticNextStep.title = 'Next Steps:'; + optimisticNextStep.message = [ + { + text: "Oops! Looks like you're reviewing", + }, + { + text: ' your own report. ', + type: 'strong', + }, + { + text: 'Approving your own reports is ', + }, + { + text: 'forbidden', + type: 'strong', + }, + { + text: ' by your policy.', + }, + ]; + + return Onyx.merge(`${ONYXKEYS.COLLECTION.POLICY}${policyID}`, { + submitsTo: currentUserAccountID, + preventSelfApprovalEnabled: true, + }).then(() => { + const result = NextStepUtils.buildNextStep(report, CONST.REPORT.STATUS_NUM.SUBMITTED); + + expect(result).toMatchObject(optimisticNextStep); + }); + }); }); describe('it generates an optimistic nextStep once a report has been approved', () => { From eea5225703ec2ff14de8b395acbbdba1e387667f Mon Sep 17 00:00:00 2001 From: Carlos Barros <765936+barros001@users.noreply.github.com> Date: Tue, 27 Feb 2024 16:29:42 -0500 Subject: [PATCH 08/20] updated shouldDisableSettlementButton logic --- src/components/MoneyReportHeader.tsx | 3 ++- src/components/ReportActionItem/ReportPreview.tsx | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/components/MoneyReportHeader.tsx b/src/components/MoneyReportHeader.tsx index dc89ce1bdc3a3..ec3340b6f0f02 100644 --- a/src/components/MoneyReportHeader.tsx +++ b/src/components/MoneyReportHeader.tsx @@ -100,7 +100,8 @@ function MoneyReportHeader({session, policy, chatReport, nextStep, report: money const shouldShowSettlementButton = shouldShowPayButton || shouldShowApproveButton; const shouldShowSubmitButton = isDraft && reimbursableSpend !== 0; const shouldDisableSubmitButton = shouldShowSubmitButton && !ReportUtils.isAllowedToSubmitDraftExpenseReport(moneyRequestReport); - const shouldDisableSettlementButton = !canAllowSettlement || (shouldShowSettlementButton && shouldShowApproveButton && !ReportUtils.isAllowedToApproveExpenseReport(moneyRequestReport)); + const shouldDisableSettlementButton = + shouldShowSettlementButton && ((shouldShowPayButton && !canAllowSettlement) || (shouldShowApproveButton && !ReportUtils.isAllowedToApproveExpenseReport(moneyRequestReport))); const isFromPaidPolicy = policyType === CONST.POLICY.TYPE.TEAM || policyType === CONST.POLICY.TYPE.CORPORATE; const shouldShowNextStep = isFromPaidPolicy && !!nextStep?.message?.length; const shouldShowAnyButton = shouldShowSettlementButton || shouldShowApproveButton || shouldShowSubmitButton || shouldShowNextStep; diff --git a/src/components/ReportActionItem/ReportPreview.tsx b/src/components/ReportActionItem/ReportPreview.tsx index b03c0efce81ab..9b7eb5a360a5a 100644 --- a/src/components/ReportActionItem/ReportPreview.tsx +++ b/src/components/ReportActionItem/ReportPreview.tsx @@ -239,7 +239,8 @@ function ReportPreview({ [isPayer, isDraftExpenseReport, iouSettled, reimbursableSpend, iouCanceled, isAutoReimbursable, iouReport, shouldShowApproveButton], ); const shouldShowSettlementButton = shouldShowPayButton || shouldShowApproveButton; - const shouldDisableSettlementButton = !canAllowSettlement || (shouldShowSettlementButton && shouldShowApproveButton && !ReportUtils.isAllowedToApproveExpenseReport(iouReport)); + const shouldDisableSettlementButton = + shouldShowSettlementButton && ((shouldShowPayButton && !canAllowSettlement) || (shouldShowApproveButton && !ReportUtils.isAllowedToApproveExpenseReport(iouReport))); /* Show subtitle if at least one of the money requests is not being smart scanned, and either: From 7bafaae42eab51930b32172001734180c1fc046e Mon Sep 17 00:00:00 2001 From: Carlos Barros <765936+barros001@users.noreply.github.com> Date: Fri, 8 Mar 2024 09:28:38 -0500 Subject: [PATCH 09/20] reverted unnecessary logic to show/hide pay button; reverted optimistic data for self-approving --- .../ReportActionItem/ReportPreview.tsx | 71 ++----------------- src/libs/NextStepUtils.ts | 23 ------ tests/unit/NextStepUtilsTest.ts | 32 --------- 3 files changed, 4 insertions(+), 122 deletions(-) diff --git a/src/components/ReportActionItem/ReportPreview.tsx b/src/components/ReportActionItem/ReportPreview.tsx index e3ebfaa3ea6a5..064d87ea5bd3f 100644 --- a/src/components/ReportActionItem/ReportPreview.tsx +++ b/src/components/ReportActionItem/ReportPreview.tsx @@ -213,6 +213,10 @@ function ReportPreview({ const isPayer = ReportUtils.isPayer(session, iouReport); const isOnInstantSubmitPolicy = PolicyUtils.isInstantSubmitEnabled(policy); const isOnSubmitAndClosePolicy = PolicyUtils.isSubmitAndClose(policy); + const shouldShowPayButton = useMemo( + () => isPayer && !isDraftExpenseReport && !iouSettled && !iouReport?.isWaitingOnBankAccount && reimbursableSpend !== 0 && !iouCanceled && !isAutoReimbursable, + [isPayer, isDraftExpenseReport, iouSettled, reimbursableSpend, iouCanceled, isAutoReimbursable, iouReport], + ); const shouldShowApproveButton = useMemo(() => { if (!isPaidGroupPolicy) { return false; @@ -222,21 +226,7 @@ function ReportPreview({ } return isCurrentUserManager && !isDraftExpenseReport && !isApproved && !iouSettled; }, [isPaidGroupPolicy, isCurrentUserManager, isDraftExpenseReport, isApproved, isOnInstantSubmitPolicy, isOnSubmitAndClosePolicy, iouSettled]); - const shouldShowPayButton = useMemo( - () => - isPayer && - !isDraftExpenseReport && - !iouSettled && - !shouldShowApproveButton && - !iouReport?.isWaitingOnBankAccount && - reimbursableSpend !== 0 && - !iouCanceled && - !isAutoReimbursable, - [isPayer, isDraftExpenseReport, iouSettled, reimbursableSpend, iouCanceled, isAutoReimbursable, iouReport, shouldShowApproveButton], - ); const shouldShowSettlementButton = shouldShowPayButton || shouldShowApproveButton; - const shouldDisableSettlementButton = - shouldShowSettlementButton && ((shouldShowPayButton && !canAllowSettlement) || (shouldShowApproveButton && !ReportUtils.isAllowedToApproveExpenseReport(iouReport))); /* Show subtitle if at least one of the money requests is not being smart scanned, and either: @@ -344,59 +334,6 @@ function ReportPreview({ /> )} - - - {getDisplayAmount()} - {ReportUtils.isSettled(iouReportID) && ( - - - - )} - - - {shouldShowSubtitle && ( - - - {previewSubtitle || moneyRequestComment} - - - )} - {shouldShowSettlementButton && ( - chatReport && iouReport && paymentType && IOU.payMoneyRequest(paymentType, chatReport, iouReport)} - enablePaymentsRoute={ROUTES.ENABLE_PAYMENTS} - addBankAccountRoute={bankAccountRoute} - shouldHidePaymentOptions={!shouldShowPayButton} - shouldShowApproveButton={shouldShowApproveButton} - style={[styles.mt3]} - kycWallAnchorAlignment={{ - horizontal: CONST.MODAL.ANCHOR_ORIGIN_HORIZONTAL.LEFT, - vertical: CONST.MODAL.ANCHOR_ORIGIN_VERTICAL.BOTTOM, - }} - paymentMethodDropdownAnchorAlignment={{ - horizontal: CONST.MODAL.ANCHOR_ORIGIN_HORIZONTAL.RIGHT, - vertical: CONST.MODAL.ANCHOR_ORIGIN_VERTICAL.BOTTOM, - }} - isDisabled={shouldDisableSettlementButton} - /> - )} - {shouldShowSubmitButton && ( -