From c1a5e67ef3d15b6704a9664aba775e5c0518d8d5 Mon Sep 17 00:00:00 2001 From: Rushat Gabhane Date: Sun, 7 Jul 2024 15:28:38 +0300 Subject: [PATCH 01/26] add build approval chain --- src/libs/PolicyUtils.ts | 43 ++++++++++++++++++++++++++++++++++++++++- 1 file changed, 42 insertions(+), 1 deletion(-) diff --git a/src/libs/PolicyUtils.ts b/src/libs/PolicyUtils.ts index 4c071317907b9..d3b42ed2c1eeb 100644 --- a/src/libs/PolicyUtils.ts +++ b/src/libs/PolicyUtils.ts @@ -7,7 +7,7 @@ import type {SelectorType} from '@components/SelectionScreen'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import ROUTES from '@src/ROUTES'; -import type {OnyxInputOrEntry, Policy, PolicyCategories, PolicyEmployeeList, PolicyTagList, PolicyTags, TaxRate} from '@src/types/onyx'; +import type {OnyxInputOrEntry, Policy, PolicyCategories, PolicyEmployeeList, PolicyTagList, PolicyTags, Report, TaxRate} from '@src/types/onyx'; import type {ConnectionLastSync, Connections, CustomUnit, NetSuiteConnection, PolicyFeatureName, Rate, Tenant} from '@src/types/onyx/Policy'; import type PolicyEmployee from '@src/types/onyx/PolicyEmployee'; import {isEmptyObject} from '@src/types/utils/EmptyObject'; @@ -383,6 +383,10 @@ function getApprovalWorkflow(policy: OnyxEntry): ValueOf): boolean { + return policy?.approvalMode === CONST.POLICY.APPROVAL_MODE.ADVANCED; +} + function getDefaultApprover(policy: OnyxEntry): string { return policy?.approver ?? policy?.owner ?? ''; } @@ -407,6 +411,42 @@ function getSubmitToAccountID(policy: OnyxEntry, employeeAccountID: numb return getAccountIDsByLogins([employee.submitsTo ?? defaultApprover])[0]; } +function getSubmitToEmail(policy: OnyxEntry, employeeAccountID: number): string { + const submitToAccountID = getSubmitToAccountID(policy, employeeAccountID); + return getLoginsByAccountIDs([submitToAccountID])[0] ?? ''; +} + +function getForwardsToAccount(policy: OnyxEntry, employeeEmail: string, reportTotal: number): string { + if (!hasAdvancedApprovalEnabled(policy)) { + return ''; + } + + const employee = policy?.employeeList?.[employeeEmail]; + if (!employee) { + return ''; + } + + const positiveReportTotal = Math.abs(reportTotal); + if (employee.approvalLimit && positiveReportTotal > employee.approvalLimit) { + return employee.overLimitForwardsTo ?? ''; + } + + return employee.forwardsTo ?? ''; +} + +function buildApprovalChain(policy: OnyxEntry, employeeAccountID: number, reportTotal: number): string[] { + const approvalChain: string[] = []; + + let nextApproverEmail = getSubmitToEmail(policy, employeeAccountID); + + while (!approvalChain.includes(nextApproverEmail)) { + approvalChain.push(nextApproverEmail); + nextApproverEmail = getForwardsToAccount(policy, nextApproverEmail, reportTotal); + } + + return approvalChain.filter((approverEmail) => !!approverEmail); +} + function getPersonalPolicy() { return Object.values(allPolicies ?? {}).find((policy) => policy?.type === CONST.POLICY.TYPE.PERSONAL); } @@ -682,6 +722,7 @@ export { getIntegrationLastSuccessfulDate, getCurrentConnectionName, getCustomersOrJobsLabelNetSuite, + buildApprovalChain, }; export type {MemberEmailsToAccountIDs}; From a8e29ef11478d045bea7621792604a118706007c Mon Sep 17 00:00:00 2001 From: Rushat Gabhane Date: Sun, 7 Jul 2024 15:43:40 +0300 Subject: [PATCH 02/26] fix lint --- src/libs/PolicyUtils.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libs/PolicyUtils.ts b/src/libs/PolicyUtils.ts index d3b42ed2c1eeb..21b8764060bde 100644 --- a/src/libs/PolicyUtils.ts +++ b/src/libs/PolicyUtils.ts @@ -7,7 +7,7 @@ import type {SelectorType} from '@components/SelectionScreen'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import ROUTES from '@src/ROUTES'; -import type {OnyxInputOrEntry, Policy, PolicyCategories, PolicyEmployeeList, PolicyTagList, PolicyTags, Report, TaxRate} from '@src/types/onyx'; +import type {OnyxInputOrEntry, Policy, PolicyCategories, PolicyEmployeeList, PolicyTagList, PolicyTags, TaxRate} from '@src/types/onyx'; import type {ConnectionLastSync, Connections, CustomUnit, NetSuiteConnection, PolicyFeatureName, Rate, Tenant} from '@src/types/onyx/Policy'; import type PolicyEmployee from '@src/types/onyx/PolicyEmployee'; import {isEmptyObject} from '@src/types/utils/EmptyObject'; From a9afa160f1e14136f44f3c273e9c33ba6fe34353 Mon Sep 17 00:00:00 2001 From: Rushat Gabhane Date: Sun, 7 Jul 2024 16:27:23 +0300 Subject: [PATCH 03/26] rename to get --- src/libs/PolicyUtils.ts | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/libs/PolicyUtils.ts b/src/libs/PolicyUtils.ts index 21b8764060bde..6c966a89d3b9b 100644 --- a/src/libs/PolicyUtils.ts +++ b/src/libs/PolicyUtils.ts @@ -430,20 +430,17 @@ function getForwardsToAccount(policy: OnyxEntry, employeeEmail: string, if (employee.approvalLimit && positiveReportTotal > employee.approvalLimit) { return employee.overLimitForwardsTo ?? ''; } - return employee.forwardsTo ?? ''; } -function buildApprovalChain(policy: OnyxEntry, employeeAccountID: number, reportTotal: number): string[] { +function getApprovalChain(policy: OnyxEntry, employeeAccountID: number, reportTotal: number): string[] { const approvalChain: string[] = []; - let nextApproverEmail = getSubmitToEmail(policy, employeeAccountID); while (!approvalChain.includes(nextApproverEmail)) { approvalChain.push(nextApproverEmail); nextApproverEmail = getForwardsToAccount(policy, nextApproverEmail, reportTotal); } - return approvalChain.filter((approverEmail) => !!approverEmail); } @@ -722,7 +719,8 @@ export { getIntegrationLastSuccessfulDate, getCurrentConnectionName, getCustomersOrJobsLabelNetSuite, - buildApprovalChain, + getApprovalChain, + hasAdvancedApprovalEnabled, }; export type {MemberEmailsToAccountIDs}; From a7adbbaaff2ba70c13b5e454e7d019e15a523ba8 Mon Sep 17 00:00:00 2001 From: Rushat Gabhane Date: Sun, 7 Jul 2024 16:27:35 +0300 Subject: [PATCH 04/26] add next steps for multiple approvers --- src/libs/NextStepUtils.ts | 56 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 56 insertions(+) diff --git a/src/libs/NextStepUtils.ts b/src/libs/NextStepUtils.ts index 0ac2878b68572..6c30f4462cccd 100644 --- a/src/libs/NextStepUtils.ts +++ b/src/libs/NextStepUtils.ts @@ -270,6 +270,62 @@ function buildNextStep(report: OnyxEntry, predictedNextStatus: ValueOf Date: Mon, 8 Jul 2024 11:34:26 +0300 Subject: [PATCH 05/26] Update src/libs/PolicyUtils.ts Co-authored-by: Alex Beaman --- src/libs/PolicyUtils.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libs/PolicyUtils.ts b/src/libs/PolicyUtils.ts index 6c966a89d3b9b..7252e3a8344da 100644 --- a/src/libs/PolicyUtils.ts +++ b/src/libs/PolicyUtils.ts @@ -427,8 +427,8 @@ function getForwardsToAccount(policy: OnyxEntry, employeeEmail: string, } const positiveReportTotal = Math.abs(reportTotal); - if (employee.approvalLimit && positiveReportTotal > employee.approvalLimit) { - return employee.overLimitForwardsTo ?? ''; + if (employee.approvalLimit && employee.overLimitForwardsTo && positiveReportTotal > employee.approvalLimit) { + return employee.overLimitForwardsTo; } return employee.forwardsTo ?? ''; } From 5500e9c181a89c4fff2a56a4353a0c3541e37d4b Mon Sep 17 00:00:00 2001 From: Rushat Gabhane Date: Mon, 8 Jul 2024 11:36:48 +0300 Subject: [PATCH 06/26] Update src/libs/PolicyUtils.ts Co-authored-by: Alex Beaman --- src/libs/PolicyUtils.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libs/PolicyUtils.ts b/src/libs/PolicyUtils.ts index 7252e3a8344da..68b9b22008c3b 100644 --- a/src/libs/PolicyUtils.ts +++ b/src/libs/PolicyUtils.ts @@ -437,7 +437,7 @@ function getApprovalChain(policy: OnyxEntry, employeeAccountID: number, const approvalChain: string[] = []; let nextApproverEmail = getSubmitToEmail(policy, employeeAccountID); - while (!approvalChain.includes(nextApproverEmail)) { + while (nextApproverEmail && !approvalChain.includes(nextApproverEmail)) { approvalChain.push(nextApproverEmail); nextApproverEmail = getForwardsToAccount(policy, nextApproverEmail, reportTotal); } From a4fdf8e47fbde24fbfb16aab38624b2b9202d284 Mon Sep 17 00:00:00 2001 From: Rushat Gabhane Date: Mon, 8 Jul 2024 11:37:05 +0300 Subject: [PATCH 07/26] Update src/libs/PolicyUtils.ts --- src/libs/PolicyUtils.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libs/PolicyUtils.ts b/src/libs/PolicyUtils.ts index 68b9b22008c3b..23cb8a39bd6ef 100644 --- a/src/libs/PolicyUtils.ts +++ b/src/libs/PolicyUtils.ts @@ -441,7 +441,7 @@ function getApprovalChain(policy: OnyxEntry, employeeAccountID: number, approvalChain.push(nextApproverEmail); nextApproverEmail = getForwardsToAccount(policy, nextApproverEmail, reportTotal); } - return approvalChain.filter((approverEmail) => !!approverEmail); + return approvalChain; } function getPersonalPolicy() { From 5aa1ce95949c574e426334c5a1da01dbb29dd281 Mon Sep 17 00:00:00 2001 From: Rushat Gabhane Date: Fri, 2 Aug 2024 04:12:19 +0300 Subject: [PATCH 08/26] fix conflict --- src/libs/NextStepUtils.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/libs/NextStepUtils.ts b/src/libs/NextStepUtils.ts index d1f636be0ea6d..b7cb28dfd8924 100644 --- a/src/libs/NextStepUtils.ts +++ b/src/libs/NextStepUtils.ts @@ -221,7 +221,7 @@ function buildNextStep(report: OnyxEntry, predictedNextStatus: ValueOf, predictedNextStatus: ValueOf Date: Mon, 5 Aug 2024 13:49:30 +0300 Subject: [PATCH 09/26] rm next approval step --- src/libs/NextStepUtils.ts | 56 --------------------------------------- 1 file changed, 56 deletions(-) diff --git a/src/libs/NextStepUtils.ts b/src/libs/NextStepUtils.ts index b7cb28dfd8924..6572b18876143 100644 --- a/src/libs/NextStepUtils.ts +++ b/src/libs/NextStepUtils.ts @@ -215,62 +215,6 @@ function buildNextStep(report: OnyxEntry, predictedNextStatus: ValueOf Date: Mon, 5 Aug 2024 13:49:54 +0300 Subject: [PATCH 10/26] rm has advanced approval --- src/libs/PolicyUtils.ts | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/src/libs/PolicyUtils.ts b/src/libs/PolicyUtils.ts index 594a1a6dc5952..90c0fbe0af152 100644 --- a/src/libs/PolicyUtils.ts +++ b/src/libs/PolicyUtils.ts @@ -437,10 +437,6 @@ function getApprovalWorkflow(policy: OnyxEntry): ValueOf): boolean { - return policy?.approvalMode === CONST.POLICY.APPROVAL_MODE.ADVANCED; -} - function getDefaultApprover(policy: OnyxEntry): string { return policy?.approver ?? policy?.owner ?? ''; } @@ -471,7 +467,7 @@ function getSubmitToEmail(policy: OnyxEntry, employeeAccountID: number): } function getForwardsToAccount(policy: OnyxEntry, employeeEmail: string, reportTotal: number): string { - if (!hasAdvancedApprovalEnabled(policy)) { + if (!isControlOnAdvancedApprovalMode(policy)) { return ''; } @@ -1013,7 +1009,6 @@ export { getCurrentConnectionName, getCustomersOrJobsLabelNetSuite, getApprovalChain, - hasAdvancedApprovalEnabled, getReimburserAccountID, isControlPolicy, isNetSuiteCustomSegmentRecord, From c2f23521b688dee34d0e8da0abf90e35f2557a61 Mon Sep 17 00:00:00 2001 From: Rushat Gabhane Date: Mon, 5 Aug 2024 13:50:23 +0300 Subject: [PATCH 11/26] keep state as submitted if more than one approver --- src/libs/actions/IOU.ts | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/src/libs/actions/IOU.ts b/src/libs/actions/IOU.ts index e63204452551c..15c26d486623a 100644 --- a/src/libs/actions/IOU.ts +++ b/src/libs/actions/IOU.ts @@ -6733,7 +6733,14 @@ function approveMoneyRequest(expenseReport: OnyxEntry, full?: total = expenseReport?.unheldTotal; } const optimisticApprovedReportAction = ReportUtils.buildOptimisticApprovedReportAction(total, expenseReport?.currency ?? '', expenseReport?.reportID ?? '-1'); - const optimisticNextStep = NextStepUtils.buildNextStep(expenseReport, CONST.REPORT.STATUS_NUM.APPROVED); + + const approvalChain = PolicyUtils.getApprovalChain(PolicyUtils.getPolicy(expenseReport?.policyID), userAccountID, expenseReport?.total ?? 0); + const isLastApprover = approvalChain.length === 1; + + const predictedNextStatus = isLastApprover ? CONST.REPORT.STATUS_NUM.APPROVED : CONST.REPORT.STATUS_NUM.SUBMITTED; + const predictedNextState = isLastApprover ? CONST.REPORT.STATE_NUM.APPROVED : CONST.REPORT.STATE_NUM.SUBMITTED; + + const optimisticNextStep = NextStepUtils.buildNextStep(expenseReport, predictedNextStatus); const chatReport = getReportOrDraftReport(expenseReport?.chatReportID); const optimisticReportActionsData: OnyxUpdate = { @@ -6753,8 +6760,8 @@ function approveMoneyRequest(expenseReport: OnyxEntry, full?: ...expenseReport, lastMessageText: ReportActionsUtils.getReportActionText(optimisticApprovedReportAction), lastMessageHtml: ReportActionsUtils.getReportActionHtml(optimisticApprovedReportAction), - stateNum: CONST.REPORT.STATE_NUM.APPROVED, - statusNum: CONST.REPORT.STATUS_NUM.APPROVED, + stateNum: predictedNextState, + statusNum: predictedNextStatus, pendingFields: { partial: full ? null : CONST.RED_BRICK_ROAD_PENDING_ACTION.UPDATE, }, From 5f2be7679faf9c45888922b7fb4ba176ec4aa3f4 Mon Sep 17 00:00:00 2001 From: Rushat Gabhane Date: Mon, 5 Aug 2024 14:30:58 +0300 Subject: [PATCH 12/26] get display name for next approver --- src/libs/NextStepUtils.ts | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/libs/NextStepUtils.ts b/src/libs/NextStepUtils.ts index 6572b18876143..70f1c366515b3 100644 --- a/src/libs/NextStepUtils.ts +++ b/src/libs/NextStepUtils.ts @@ -10,6 +10,7 @@ import type {Message} from '@src/types/onyx/ReportNextStep'; import type DeepValueOf from '@src/types/utils/DeepValueOf'; import DateUtils from './DateUtils'; import EmailUtils from './EmailUtils'; +import * as PersonalDetailsUtils from './PersonalDetailsUtils'; import * as PolicyUtils from './PolicyUtils'; import * as ReportUtils from './ReportUtils'; @@ -78,7 +79,13 @@ function buildNextStep(report: OnyxEntry, predictedNextStatus: ValueOf 0) { + nextApproverDisplayName = PersonalDetailsUtils.getPersonalDetailByEmail(approvalChain[0])?.displayName ?? approvalChain[0]; + } + const reimburserAccountID = PolicyUtils.getReimburserAccountID(policy); const reimburserDisplayName = ReportUtils.getDisplayNameForParticipant(reimburserAccountID); const type: ReportNextStep['type'] = 'neutral'; @@ -180,7 +187,7 @@ function buildNextStep(report: OnyxEntry, predictedNextStatus: ValueOf Date: Mon, 5 Aug 2024 14:31:19 +0300 Subject: [PATCH 13/26] early return if AA is not enabled --- src/libs/PolicyUtils.ts | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/libs/PolicyUtils.ts b/src/libs/PolicyUtils.ts index 90c0fbe0af152..df049f965f290 100644 --- a/src/libs/PolicyUtils.ts +++ b/src/libs/PolicyUtils.ts @@ -485,6 +485,12 @@ function getForwardsToAccount(policy: OnyxEntry, employeeEmail: string, function getApprovalChain(policy: OnyxEntry, employeeAccountID: number, reportTotal: number): string[] { const approvalChain: string[] = []; + + // If the policy is not on advanced approval mode, we should not use the approval chain even if it exists. + if (!isControlOnAdvancedApprovalMode(policy)) { + return approvalChain; + } + let nextApproverEmail = getSubmitToEmail(policy, employeeAccountID); while (nextApproverEmail && !approvalChain.includes(nextApproverEmail)) { From 2e5612cc1e8672fadc9308ea2b8c36a04f7e8aa3 Mon Sep 17 00:00:00 2001 From: Rushat Gabhane Date: Mon, 5 Aug 2024 14:32:20 +0300 Subject: [PATCH 14/26] check if last approver --- src/libs/actions/IOU.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libs/actions/IOU.ts b/src/libs/actions/IOU.ts index 15c26d486623a..b846d80b3a265 100644 --- a/src/libs/actions/IOU.ts +++ b/src/libs/actions/IOU.ts @@ -6735,7 +6735,7 @@ function approveMoneyRequest(expenseReport: OnyxEntry, full?: const optimisticApprovedReportAction = ReportUtils.buildOptimisticApprovedReportAction(total, expenseReport?.currency ?? '', expenseReport?.reportID ?? '-1'); const approvalChain = PolicyUtils.getApprovalChain(PolicyUtils.getPolicy(expenseReport?.policyID), userAccountID, expenseReport?.total ?? 0); - const isLastApprover = approvalChain.length === 1; + const isLastApprover = approvalChain.length === 0; const predictedNextStatus = isLastApprover ? CONST.REPORT.STATUS_NUM.APPROVED : CONST.REPORT.STATUS_NUM.SUBMITTED; const predictedNextState = isLastApprover ? CONST.REPORT.STATE_NUM.APPROVED : CONST.REPORT.STATE_NUM.SUBMITTED; From 0d5ce301841bae1d51b927344b36ec8095655847 Mon Sep 17 00:00:00 2001 From: Rushat Gabhane Date: Mon, 5 Aug 2024 16:59:42 +0300 Subject: [PATCH 15/26] fix last approver logic --- src/libs/actions/IOU.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libs/actions/IOU.ts b/src/libs/actions/IOU.ts index b846d80b3a265..8afabbf3fa02d 100644 --- a/src/libs/actions/IOU.ts +++ b/src/libs/actions/IOU.ts @@ -6735,7 +6735,7 @@ function approveMoneyRequest(expenseReport: OnyxEntry, full?: const optimisticApprovedReportAction = ReportUtils.buildOptimisticApprovedReportAction(total, expenseReport?.currency ?? '', expenseReport?.reportID ?? '-1'); const approvalChain = PolicyUtils.getApprovalChain(PolicyUtils.getPolicy(expenseReport?.policyID), userAccountID, expenseReport?.total ?? 0); - const isLastApprover = approvalChain.length === 0; + const isLastApprover = approvalChain[approvalChain.length - 1] === currentUserEmail ?? true; const predictedNextStatus = isLastApprover ? CONST.REPORT.STATUS_NUM.APPROVED : CONST.REPORT.STATUS_NUM.SUBMITTED; const predictedNextState = isLastApprover ? CONST.REPORT.STATE_NUM.APPROVED : CONST.REPORT.STATE_NUM.SUBMITTED; From 7f0d770d0d600f2d9dd824a40170a118ddb7a5b6 Mon Sep 17 00:00:00 2001 From: Rushat Gabhane Date: Mon, 5 Aug 2024 17:00:08 +0300 Subject: [PATCH 16/26] fix next approver logic --- src/libs/NextStepUtils.ts | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/libs/NextStepUtils.ts b/src/libs/NextStepUtils.ts index 70f1c366515b3..ad511ae2934e9 100644 --- a/src/libs/NextStepUtils.ts +++ b/src/libs/NextStepUtils.ts @@ -79,11 +79,12 @@ function buildNextStep(report: OnyxEntry, predictedNextStatus: ValueOf 0) { - nextApproverDisplayName = PersonalDetailsUtils.getPersonalDetailByEmail(approvalChain[0])?.displayName ?? approvalChain[0]; + const nextApproverEmail = approvalChain.length === 1 ? approvalChain[0] : approvalChain[approvalChain.indexOf(currentUserEmail) + 1]; + nextApproverDisplayName = PersonalDetailsUtils.getPersonalDetailByEmail(nextApproverEmail)?.displayName ?? nextApproverEmail; } const reimburserAccountID = PolicyUtils.getReimburserAccountID(policy); From a78ce472cd748b5b1ec3108b86dcf8587be893ed Mon Sep 17 00:00:00 2001 From: Rushat Gabhane Date: Mon, 5 Aug 2024 17:59:32 +0300 Subject: [PATCH 17/26] use ownerAccountID for building approval chain --- src/libs/actions/IOU.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libs/actions/IOU.ts b/src/libs/actions/IOU.ts index 8afabbf3fa02d..86799967fce5c 100644 --- a/src/libs/actions/IOU.ts +++ b/src/libs/actions/IOU.ts @@ -6734,7 +6734,7 @@ function approveMoneyRequest(expenseReport: OnyxEntry, full?: } const optimisticApprovedReportAction = ReportUtils.buildOptimisticApprovedReportAction(total, expenseReport?.currency ?? '', expenseReport?.reportID ?? '-1'); - const approvalChain = PolicyUtils.getApprovalChain(PolicyUtils.getPolicy(expenseReport?.policyID), userAccountID, expenseReport?.total ?? 0); + const approvalChain = PolicyUtils.getApprovalChain(PolicyUtils.getPolicy(expenseReport?.policyID), expenseReport?.ownerAccountID ?? -1, expenseReport?.total ?? 0); const isLastApprover = approvalChain[approvalChain.length - 1] === currentUserEmail ?? true; const predictedNextStatus = isLastApprover ? CONST.REPORT.STATUS_NUM.APPROVED : CONST.REPORT.STATUS_NUM.SUBMITTED; From ecbbbaa20cf61ae7855719a6e8c8f7f59c506704 Mon Sep 17 00:00:00 2001 From: Rushat Gabhane Date: Mon, 5 Aug 2024 18:00:05 +0300 Subject: [PATCH 18/26] fix crash when next approver is undefined --- src/libs/NextStepUtils.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/libs/NextStepUtils.ts b/src/libs/NextStepUtils.ts index ad511ae2934e9..cc31795edf96f 100644 --- a/src/libs/NextStepUtils.ts +++ b/src/libs/NextStepUtils.ts @@ -84,7 +84,9 @@ function buildNextStep(report: OnyxEntry, predictedNextStatus: ValueOf 0) { const nextApproverEmail = approvalChain.length === 1 ? approvalChain[0] : approvalChain[approvalChain.indexOf(currentUserEmail) + 1]; - nextApproverDisplayName = PersonalDetailsUtils.getPersonalDetailByEmail(nextApproverEmail)?.displayName ?? nextApproverEmail; + if (nextApproverEmail) { + nextApproverDisplayName = PersonalDetailsUtils.getPersonalDetailByEmail(nextApproverEmail)?.displayName ?? nextApproverEmail; + } } const reimburserAccountID = PolicyUtils.getReimburserAccountID(policy); From 1bbbc2430e07bbd27d370c69086fc9de84bfd97f Mon Sep 17 00:00:00 2001 From: Rushat Gabhane Date: Wed, 7 Aug 2024 03:23:09 +0300 Subject: [PATCH 19/26] extract display name to a func --- src/libs/NextStepUtils.ts | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/src/libs/NextStepUtils.ts b/src/libs/NextStepUtils.ts index cc31795edf96f..b49c2692599e5 100644 --- a/src/libs/NextStepUtils.ts +++ b/src/libs/NextStepUtils.ts @@ -60,6 +60,20 @@ function parseMessage(messages: Message[] | undefined) { return `${formattedHtml}`; } +function getNextApproverDisplayName(policy: Policy, ownerAccountID: number, submitToAccountID: number, report: OnyxEntry) { + const approvalChain = PolicyUtils.getApprovalChain(policy, ownerAccountID, report?.total ?? 0); + if (approvalChain.length === 0) { + return ReportUtils.getDisplayNameForParticipant(submitToAccountID); + } + + const nextApproverEmail = approvalChain.length === 1 ? approvalChain[0] : approvalChain[approvalChain.indexOf(currentUserEmail) + 1]; + if (!nextApproverEmail) { + return ReportUtils.getDisplayNameForParticipant(submitToAccountID); + } + + return PersonalDetailsUtils.getPersonalDetailByEmail(nextApproverEmail)?.displayName ?? nextApproverEmail; +} + /** * Generates an optimistic nextStep based on a current report status and other properties. * @@ -79,15 +93,7 @@ function buildNextStep(report: OnyxEntry, predictedNextStatus: ValueOf 0) { - const nextApproverEmail = approvalChain.length === 1 ? approvalChain[0] : approvalChain[approvalChain.indexOf(currentUserEmail) + 1]; - if (nextApproverEmail) { - nextApproverDisplayName = PersonalDetailsUtils.getPersonalDetailByEmail(nextApproverEmail)?.displayName ?? nextApproverEmail; - } - } + const nextApproverDisplayName = getNextApproverDisplayName(policy, ownerAccountID, submitToAccountID, report); const reimburserAccountID = PolicyUtils.getReimburserAccountID(policy); const reimburserDisplayName = ReportUtils.getDisplayNameForParticipant(reimburserAccountID); From 7f5885c875806126775c5ebae7e8a12901dae57c Mon Sep 17 00:00:00 2001 From: Rushat Gabhane Date: Wed, 7 Aug 2024 03:54:37 +0300 Subject: [PATCH 20/26] move approval chain, related methods to report utils --- src/libs/NextStepUtils.ts | 4 +-- src/libs/PolicyUtils.ts | 65 ++------------------------------------ src/libs/ReportUtils.ts | 66 +++++++++++++++++++++++++++++++++++++-- src/libs/actions/IOU.ts | 4 +-- 4 files changed, 71 insertions(+), 68 deletions(-) diff --git a/src/libs/NextStepUtils.ts b/src/libs/NextStepUtils.ts index b49c2692599e5..4a6e38e53888d 100644 --- a/src/libs/NextStepUtils.ts +++ b/src/libs/NextStepUtils.ts @@ -61,7 +61,7 @@ function parseMessage(messages: Message[] | undefined) { } function getNextApproverDisplayName(policy: Policy, ownerAccountID: number, submitToAccountID: number, report: OnyxEntry) { - const approvalChain = PolicyUtils.getApprovalChain(policy, ownerAccountID, report?.total ?? 0); + const approvalChain = ReportUtils.getApprovalChain(policy, ownerAccountID, report?.total ?? 0); if (approvalChain.length === 0) { return ReportUtils.getDisplayNameForParticipant(submitToAccountID); } @@ -91,7 +91,7 @@ function buildNextStep(report: OnyxEntry, predictedNextStatus: ValueOf; @@ -441,65 +441,6 @@ function getDefaultApprover(policy: OnyxEntry): string { return policy?.approver ?? policy?.owner ?? ''; } -/** - * Returns the accountID to whom the given employeeAccountID submits reports to in the given Policy. - */ -function getSubmitToAccountID(policy: OnyxEntry, employeeAccountID: number): number { - const employeeLogin = getLoginsByAccountIDs([employeeAccountID])[0]; - const defaultApprover = getDefaultApprover(policy); - - // For policy using the optional or basic workflow, the manager is the policy default approver. - if (([CONST.POLICY.APPROVAL_MODE.OPTIONAL, CONST.POLICY.APPROVAL_MODE.BASIC] as Array>).includes(getApprovalWorkflow(policy))) { - return getAccountIDsByLogins([defaultApprover])[0]; - } - - const employee = policy?.employeeList?.[employeeLogin]; - if (!employee) { - return -1; - } - - return getAccountIDsByLogins([employee.submitsTo ?? defaultApprover])[0]; -} - -function getSubmitToEmail(policy: OnyxEntry, employeeAccountID: number): string { - const submitToAccountID = getSubmitToAccountID(policy, employeeAccountID); - return getLoginsByAccountIDs([submitToAccountID])[0] ?? ''; -} - -function getForwardsToAccount(policy: OnyxEntry, employeeEmail: string, reportTotal: number): string { - if (!isControlOnAdvancedApprovalMode(policy)) { - return ''; - } - - const employee = policy?.employeeList?.[employeeEmail]; - if (!employee) { - return ''; - } - - const positiveReportTotal = Math.abs(reportTotal); - if (employee.approvalLimit && employee.overLimitForwardsTo && positiveReportTotal > employee.approvalLimit) { - return employee.overLimitForwardsTo; - } - return employee.forwardsTo ?? ''; -} - -function getApprovalChain(policy: OnyxEntry, employeeAccountID: number, reportTotal: number): string[] { - const approvalChain: string[] = []; - - // If the policy is not on advanced approval mode, we should not use the approval chain even if it exists. - if (!isControlOnAdvancedApprovalMode(policy)) { - return approvalChain; - } - - let nextApproverEmail = getSubmitToEmail(policy, employeeAccountID); - - while (nextApproverEmail && !approvalChain.includes(nextApproverEmail)) { - approvalChain.push(nextApproverEmail); - nextApproverEmail = getForwardsToAccount(policy, nextApproverEmail, reportTotal); - } - return approvalChain; -} - /** * Returns the accountID of the policy reimburser, if not available — falls back to the policy owner. */ @@ -947,7 +888,6 @@ export { getPolicyBrickRoadIndicatorStatus, getPolicyEmployeeListByIdWithoutCurrentUser, getSortedTagKeys, - getSubmitToAccountID, getTagList, getTagListName, getTagLists, @@ -1014,7 +954,8 @@ export { getIntegrationLastSuccessfulDate, getCurrentConnectionName, getCustomersOrJobsLabelNetSuite, - getApprovalChain, + getDefaultApprover, + getApprovalWorkflow, getReimburserAccountID, isControlPolicy, isNetSuiteCustomSegmentRecord, diff --git a/src/libs/ReportUtils.ts b/src/libs/ReportUtils.ts index 4baf05773878d..d76b603c8ad2b 100644 --- a/src/libs/ReportUtils.ts +++ b/src/libs/ReportUtils.ts @@ -76,6 +76,7 @@ import * as NumberUtils from './NumberUtils'; import Parser from './Parser'; import Permissions from './Permissions'; import * as PersonalDetailsUtils from './PersonalDetailsUtils'; +import {getAccountIDsByLogins, getLoginsByAccountIDs} from './PersonalDetailsUtils'; import * as PhoneNumber from './PhoneNumber'; import * as PolicyUtils from './PolicyUtils'; import type {LastVisibleMessage} from './ReportActionsUtils'; @@ -4175,7 +4176,7 @@ function buildOptimisticExpenseReport( }; // Get the approver/manager for this report to properly display the optimistic data - const submitToAccountID = PolicyUtils.getSubmitToAccountID(policy, payeeAccountID); + const submitToAccountID = getSubmitToAccountID(policy, payeeAccountID); if (submitToAccountID) { expenseReport.managerID = submitToAccountID; } @@ -7070,7 +7071,7 @@ function isAllowedToApproveExpenseReport(report: OnyxEntry, approverAcco function isAllowedToSubmitDraftExpenseReport(report: OnyxEntry): boolean { const policy = getPolicy(report?.policyID); - const submitToAccountID = PolicyUtils.getSubmitToAccountID(policy, report?.ownerAccountID ?? -1); + const submitToAccountID = getSubmitToAccountID(policy, report?.ownerAccountID ?? -1); return isAllowedToApproveExpenseReport(report, submitToAccountID); } @@ -7451,6 +7452,65 @@ function isExported(reportActions: OnyxEntry) { return Object.values(reportActions).some((action) => ReportActionsUtils.isExportIntegrationAction(action)); } +/** + * Returns the accountID to whom the given employeeAccountID submits reports to in the given Policy. + */ +function getSubmitToAccountID(policy: OnyxEntry, employeeAccountID: number): number { + const employeeLogin = getLoginsByAccountIDs([employeeAccountID])[0]; + const defaultApprover = PolicyUtils.getDefaultApprover(policy); + + // For policy using the optional or basic workflow, the manager is the policy default approver. + if (([CONST.POLICY.APPROVAL_MODE.OPTIONAL, CONST.POLICY.APPROVAL_MODE.BASIC] as Array>).includes(PolicyUtils.getApprovalWorkflow(policy))) { + return getAccountIDsByLogins([defaultApprover])[0]; + } + + const employee = policy?.employeeList?.[employeeLogin]; + if (!employee) { + return -1; + } + + return getAccountIDsByLogins([employee.submitsTo ?? defaultApprover])[0]; +} + +function getSubmitToEmail(policy: OnyxEntry, employeeAccountID: number): string { + const submitToAccountID = getSubmitToAccountID(policy, employeeAccountID); + return getLoginsByAccountIDs([submitToAccountID])[0] ?? ''; +} + +function getForwardsToAccount(policy: OnyxEntry, employeeEmail: string, reportTotal: number): string { + if (!PolicyUtils.isControlOnAdvancedApprovalMode(policy)) { + return ''; + } + + const employee = policy?.employeeList?.[employeeEmail]; + if (!employee) { + return ''; + } + + const positiveReportTotal = Math.abs(reportTotal); + if (employee.approvalLimit && employee.overLimitForwardsTo && positiveReportTotal > employee.approvalLimit) { + return employee.overLimitForwardsTo; + } + return employee.forwardsTo ?? ''; +} + +function getApprovalChain(policy: OnyxEntry, employeeAccountID: number, reportTotal: number): string[] { + const approvalChain: string[] = []; + + // If the policy is not on advanced approval mode, we should not use the approval chain even if it exists. + if (!PolicyUtils.isControlOnAdvancedApprovalMode(policy)) { + return approvalChain; + } + + let nextApproverEmail = getSubmitToEmail(policy, employeeAccountID); + + while (nextApproverEmail && !approvalChain.includes(nextApproverEmail)) { + approvalChain.push(nextApproverEmail); + nextApproverEmail = getForwardsToAccount(policy, nextApproverEmail, reportTotal); + } + return approvalChain; +} + export { addDomainToShortMention, completeShortMention, @@ -7746,6 +7806,8 @@ export { getReport, getReportNameValuePairs, hasReportViolations, + getApprovalChain, + getSubmitToAccountID, }; export type { diff --git a/src/libs/actions/IOU.ts b/src/libs/actions/IOU.ts index a3c59dd79ce8a..d6b5f3b02b5e0 100644 --- a/src/libs/actions/IOU.ts +++ b/src/libs/actions/IOU.ts @@ -6777,7 +6777,7 @@ function approveMoneyRequest(expenseReport: OnyxEntry, full?: } const optimisticApprovedReportAction = ReportUtils.buildOptimisticApprovedReportAction(total, expenseReport?.currency ?? '', expenseReport?.reportID ?? '-1'); - const approvalChain = PolicyUtils.getApprovalChain(PolicyUtils.getPolicy(expenseReport?.policyID), expenseReport?.ownerAccountID ?? -1, expenseReport?.total ?? 0); + const approvalChain = ReportUtils.getApprovalChain(PolicyUtils.getPolicy(expenseReport?.policyID), expenseReport?.ownerAccountID ?? -1, expenseReport?.total ?? 0); const isLastApprover = approvalChain[approvalChain.length - 1] === currentUserEmail ?? true; const predictedNextStatus = isLastApprover ? CONST.REPORT.STATUS_NUM.APPROVED : CONST.REPORT.STATUS_NUM.SUBMITTED; @@ -7137,7 +7137,7 @@ function submitReport(expenseReport: OnyxTypes.Report) { const parameters: SubmitReportParams = { reportID: expenseReport.reportID, - managerAccountID: PolicyUtils.getSubmitToAccountID(policy, expenseReport.ownerAccountID ?? -1) ?? expenseReport.managerID, + managerAccountID: ReportUtils.getSubmitToAccountID(policy, expenseReport.ownerAccountID ?? -1) ?? expenseReport.managerID, reportActionID: optimisticSubmittedReportAction.reportActionID, }; From 1fea5eacac97bf77bc155c8b834ddaa72821541e Mon Sep 17 00:00:00 2001 From: Rushat Gabhane Date: Wed, 7 Aug 2024 03:59:38 +0300 Subject: [PATCH 21/26] add docs --- src/libs/ReportUtils.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/libs/ReportUtils.ts b/src/libs/ReportUtils.ts index d76b603c8ad2b..6934baff23ca5 100644 --- a/src/libs/ReportUtils.ts +++ b/src/libs/ReportUtils.ts @@ -7477,6 +7477,10 @@ function getSubmitToEmail(policy: OnyxEntry, employeeAccountID: number): return getLoginsByAccountIDs([submitToAccountID])[0] ?? ''; } +/** + * Returns the email of the account to forward the report to depending on the approver's approval limit. + * Used for advanced approval mode only. + */ function getForwardsToAccount(policy: OnyxEntry, employeeEmail: string, reportTotal: number): string { if (!PolicyUtils.isControlOnAdvancedApprovalMode(policy)) { return ''; From cd89b9e952627f9610c3be47c3bb68c79ee68fbb Mon Sep 17 00:00:00 2001 From: Rushat Gabhane Date: Wed, 7 Aug 2024 06:31:05 +0300 Subject: [PATCH 22/26] move submit to policyutils --- src/libs/NextStepUtils.ts | 2 +- src/libs/PolicyUtils.ts | 51 ++++++++++++++++++++++++++++++++++- src/libs/ReportUtils.ts | 56 +++------------------------------------ src/libs/actions/IOU.ts | 2 +- 4 files changed, 56 insertions(+), 55 deletions(-) diff --git a/src/libs/NextStepUtils.ts b/src/libs/NextStepUtils.ts index 4a6e38e53888d..3338210b76d19 100644 --- a/src/libs/NextStepUtils.ts +++ b/src/libs/NextStepUtils.ts @@ -91,7 +91,7 @@ function buildNextStep(report: OnyxEntry, predictedNextStatus: ValueOf; @@ -441,6 +441,52 @@ function getDefaultApprover(policy: OnyxEntry): string { return policy?.approver ?? policy?.owner ?? ''; } +/** + * Returns the accountID to whom the given employeeAccountID submits reports to in the given Policy. + */ +function getSubmitToAccountID(policy: OnyxEntry, employeeAccountID: number): number { + const employeeLogin = getLoginsByAccountIDs([employeeAccountID])[0]; + const defaultApprover = getDefaultApprover(policy); + + // For policy using the optional or basic workflow, the manager is the policy default approver. + if (([CONST.POLICY.APPROVAL_MODE.OPTIONAL, CONST.POLICY.APPROVAL_MODE.BASIC] as Array>).includes(PolicyUtils.getApprovalWorkflow(policy))) { + return getAccountIDsByLogins([defaultApprover])[0]; + } + + const employee = policy?.employeeList?.[employeeLogin]; + if (!employee) { + return -1; + } + + return getAccountIDsByLogins([employee.submitsTo ?? defaultApprover])[0]; +} + +function getSubmitToEmail(policy: OnyxEntry, employeeAccountID: number): string { + const submitToAccountID = getSubmitToAccountID(policy, employeeAccountID); + return getLoginsByAccountIDs([submitToAccountID])[0] ?? ''; +} + +/** + * Returns the email of the account to forward the report to depending on the approver's approval limit. + * Used for advanced approval mode only. + */ +function getForwardsToAccount(policy: OnyxEntry, employeeEmail: string, reportTotal: number): string { + if (!isControlOnAdvancedApprovalMode(policy)) { + return ''; + } + + const employee = policy?.employeeList?.[employeeEmail]; + if (!employee) { + return ''; + } + + const positiveReportTotal = Math.abs(reportTotal); + if (employee.approvalLimit && employee.overLimitForwardsTo && positiveReportTotal > employee.approvalLimit) { + return employee.overLimitForwardsTo; + } + return employee.forwardsTo ?? ''; +} + /** * Returns the accountID of the policy reimburser, if not available — falls back to the policy owner. */ @@ -966,6 +1012,9 @@ export { getCurrentTaxID, areSettingsInErrorFields, settingsPendingAction, + getSubmitToEmail, + getForwardsToAccount, + getSubmitToAccountID, }; export type {MemberEmailsToAccountIDs}; diff --git a/src/libs/ReportUtils.ts b/src/libs/ReportUtils.ts index 6934baff23ca5..ebb79b5261d05 100644 --- a/src/libs/ReportUtils.ts +++ b/src/libs/ReportUtils.ts @@ -76,7 +76,6 @@ import * as NumberUtils from './NumberUtils'; import Parser from './Parser'; import Permissions from './Permissions'; import * as PersonalDetailsUtils from './PersonalDetailsUtils'; -import {getAccountIDsByLogins, getLoginsByAccountIDs} from './PersonalDetailsUtils'; import * as PhoneNumber from './PhoneNumber'; import * as PolicyUtils from './PolicyUtils'; import type {LastVisibleMessage} from './ReportActionsUtils'; @@ -4176,7 +4175,7 @@ function buildOptimisticExpenseReport( }; // Get the approver/manager for this report to properly display the optimistic data - const submitToAccountID = getSubmitToAccountID(policy, payeeAccountID); + const submitToAccountID = PolicyUtils.getSubmitToAccountID(policy, payeeAccountID); if (submitToAccountID) { expenseReport.managerID = submitToAccountID; } @@ -7071,7 +7070,7 @@ function isAllowedToApproveExpenseReport(report: OnyxEntry, approverAcco function isAllowedToSubmitDraftExpenseReport(report: OnyxEntry): boolean { const policy = getPolicy(report?.policyID); - const submitToAccountID = getSubmitToAccountID(policy, report?.ownerAccountID ?? -1); + const submitToAccountID = PolicyUtils.getSubmitToAccountID(policy, report?.ownerAccountID ?? -1); return isAllowedToApproveExpenseReport(report, submitToAccountID); } @@ -7452,52 +7451,6 @@ function isExported(reportActions: OnyxEntry) { return Object.values(reportActions).some((action) => ReportActionsUtils.isExportIntegrationAction(action)); } -/** - * Returns the accountID to whom the given employeeAccountID submits reports to in the given Policy. - */ -function getSubmitToAccountID(policy: OnyxEntry, employeeAccountID: number): number { - const employeeLogin = getLoginsByAccountIDs([employeeAccountID])[0]; - const defaultApprover = PolicyUtils.getDefaultApprover(policy); - - // For policy using the optional or basic workflow, the manager is the policy default approver. - if (([CONST.POLICY.APPROVAL_MODE.OPTIONAL, CONST.POLICY.APPROVAL_MODE.BASIC] as Array>).includes(PolicyUtils.getApprovalWorkflow(policy))) { - return getAccountIDsByLogins([defaultApprover])[0]; - } - - const employee = policy?.employeeList?.[employeeLogin]; - if (!employee) { - return -1; - } - - return getAccountIDsByLogins([employee.submitsTo ?? defaultApprover])[0]; -} - -function getSubmitToEmail(policy: OnyxEntry, employeeAccountID: number): string { - const submitToAccountID = getSubmitToAccountID(policy, employeeAccountID); - return getLoginsByAccountIDs([submitToAccountID])[0] ?? ''; -} - -/** - * Returns the email of the account to forward the report to depending on the approver's approval limit. - * Used for advanced approval mode only. - */ -function getForwardsToAccount(policy: OnyxEntry, employeeEmail: string, reportTotal: number): string { - if (!PolicyUtils.isControlOnAdvancedApprovalMode(policy)) { - return ''; - } - - const employee = policy?.employeeList?.[employeeEmail]; - if (!employee) { - return ''; - } - - const positiveReportTotal = Math.abs(reportTotal); - if (employee.approvalLimit && employee.overLimitForwardsTo && positiveReportTotal > employee.approvalLimit) { - return employee.overLimitForwardsTo; - } - return employee.forwardsTo ?? ''; -} - function getApprovalChain(policy: OnyxEntry, employeeAccountID: number, reportTotal: number): string[] { const approvalChain: string[] = []; @@ -7506,11 +7459,11 @@ function getApprovalChain(policy: OnyxEntry, employeeAccountID: number, return approvalChain; } - let nextApproverEmail = getSubmitToEmail(policy, employeeAccountID); + let nextApproverEmail = PolicyUtils.getSubmitToEmail(policy, employeeAccountID); while (nextApproverEmail && !approvalChain.includes(nextApproverEmail)) { approvalChain.push(nextApproverEmail); - nextApproverEmail = getForwardsToAccount(policy, nextApproverEmail, reportTotal); + nextApproverEmail = PolicyUtils.getForwardsToAccount(policy, nextApproverEmail, reportTotal); } return approvalChain; } @@ -7811,7 +7764,6 @@ export { getReportNameValuePairs, hasReportViolations, getApprovalChain, - getSubmitToAccountID, }; export type { diff --git a/src/libs/actions/IOU.ts b/src/libs/actions/IOU.ts index d6b5f3b02b5e0..fdafc3ff2fdfa 100644 --- a/src/libs/actions/IOU.ts +++ b/src/libs/actions/IOU.ts @@ -7137,7 +7137,7 @@ function submitReport(expenseReport: OnyxTypes.Report) { const parameters: SubmitReportParams = { reportID: expenseReport.reportID, - managerAccountID: ReportUtils.getSubmitToAccountID(policy, expenseReport.ownerAccountID ?? -1) ?? expenseReport.managerID, + managerAccountID: PolicyUtils.getSubmitToAccountID(policy, expenseReport.ownerAccountID ?? -1) ?? expenseReport.managerID, reportActionID: optimisticSubmittedReportAction.reportActionID, }; From 38441ea7b07006298ccc459f39b51af16c2079dd Mon Sep 17 00:00:00 2001 From: Rushat Gabhane Date: Wed, 7 Aug 2024 06:34:00 +0300 Subject: [PATCH 23/26] handle self submit --- src/libs/NextStepUtils.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/libs/NextStepUtils.ts b/src/libs/NextStepUtils.ts index 3338210b76d19..0c6e22da53585 100644 --- a/src/libs/NextStepUtils.ts +++ b/src/libs/NextStepUtils.ts @@ -63,6 +63,9 @@ function parseMessage(messages: Message[] | undefined) { function getNextApproverDisplayName(policy: Policy, ownerAccountID: number, submitToAccountID: number, report: OnyxEntry) { const approvalChain = ReportUtils.getApprovalChain(policy, ownerAccountID, report?.total ?? 0); if (approvalChain.length === 0) { + if (submitToAccountID === currentUserAccountID) { + return 'you'; + } return ReportUtils.getDisplayNameForParticipant(submitToAccountID); } From dcb4926b1fedcff7a4591ea8807e200adca42a2e Mon Sep 17 00:00:00 2001 From: Rushat Gabhane Date: Wed, 7 Aug 2024 06:38:04 +0300 Subject: [PATCH 24/26] Revert "handle self submit" This reverts commit 38441ea7b07006298ccc459f39b51af16c2079dd. --- src/libs/NextStepUtils.ts | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/libs/NextStepUtils.ts b/src/libs/NextStepUtils.ts index 0c6e22da53585..3338210b76d19 100644 --- a/src/libs/NextStepUtils.ts +++ b/src/libs/NextStepUtils.ts @@ -63,9 +63,6 @@ function parseMessage(messages: Message[] | undefined) { function getNextApproverDisplayName(policy: Policy, ownerAccountID: number, submitToAccountID: number, report: OnyxEntry) { const approvalChain = ReportUtils.getApprovalChain(policy, ownerAccountID, report?.total ?? 0); if (approvalChain.length === 0) { - if (submitToAccountID === currentUserAccountID) { - return 'you'; - } return ReportUtils.getDisplayNameForParticipant(submitToAccountID); } From ab691ac22539a8473b587b8048023bbbfcdd6318 Mon Sep 17 00:00:00 2001 From: Rushat Gabhane Date: Wed, 7 Aug 2024 06:48:03 +0300 Subject: [PATCH 25/26] cleanup --- src/libs/PolicyUtils.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libs/PolicyUtils.ts b/src/libs/PolicyUtils.ts index 69aecd24928ab..9beae253f0df3 100644 --- a/src/libs/PolicyUtils.ts +++ b/src/libs/PolicyUtils.ts @@ -449,7 +449,7 @@ function getSubmitToAccountID(policy: OnyxEntry, employeeAccountID: numb const defaultApprover = getDefaultApprover(policy); // For policy using the optional or basic workflow, the manager is the policy default approver. - if (([CONST.POLICY.APPROVAL_MODE.OPTIONAL, CONST.POLICY.APPROVAL_MODE.BASIC] as Array>).includes(PolicyUtils.getApprovalWorkflow(policy))) { + if (([CONST.POLICY.APPROVAL_MODE.OPTIONAL, CONST.POLICY.APPROVAL_MODE.BASIC] as Array>).includes(getApprovalWorkflow(policy))) { return getAccountIDsByLogins([defaultApprover])[0]; } From 916ba40d29f673b15cd78a579f639b49f3a2c5b4 Mon Sep 17 00:00:00 2001 From: Rushat Gabhane Date: Fri, 9 Aug 2024 07:14:41 +0300 Subject: [PATCH 26/26] improve readability of last approver --- src/libs/actions/IOU.ts | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/libs/actions/IOU.ts b/src/libs/actions/IOU.ts index fdafc3ff2fdfa..9ebff102ee8bc 100644 --- a/src/libs/actions/IOU.ts +++ b/src/libs/actions/IOU.ts @@ -6763,6 +6763,13 @@ function hasIOUToApproveOrPay(chatReport: OnyxEntry, excludedI }); } +function isLastApprover(approvalChain: string[]): boolean { + if (approvalChain.length === 0) { + return true; + } + return approvalChain[approvalChain.length - 1] === currentUserEmail; +} + function approveMoneyRequest(expenseReport: OnyxEntry, full?: boolean) { if (expenseReport?.policyID && SubscriptionUtils.shouldRestrictUserBillableActions(expenseReport.policyID)) { Navigation.navigate(ROUTES.RESTRICTED_ACTION.getRoute(expenseReport.policyID)); @@ -6778,10 +6785,9 @@ function approveMoneyRequest(expenseReport: OnyxEntry, full?: const optimisticApprovedReportAction = ReportUtils.buildOptimisticApprovedReportAction(total, expenseReport?.currency ?? '', expenseReport?.reportID ?? '-1'); const approvalChain = ReportUtils.getApprovalChain(PolicyUtils.getPolicy(expenseReport?.policyID), expenseReport?.ownerAccountID ?? -1, expenseReport?.total ?? 0); - const isLastApprover = approvalChain[approvalChain.length - 1] === currentUserEmail ?? true; - const predictedNextStatus = isLastApprover ? CONST.REPORT.STATUS_NUM.APPROVED : CONST.REPORT.STATUS_NUM.SUBMITTED; - const predictedNextState = isLastApprover ? CONST.REPORT.STATE_NUM.APPROVED : CONST.REPORT.STATE_NUM.SUBMITTED; + const predictedNextStatus = isLastApprover(approvalChain) ? CONST.REPORT.STATUS_NUM.APPROVED : CONST.REPORT.STATUS_NUM.SUBMITTED; + const predictedNextState = isLastApprover(approvalChain) ? CONST.REPORT.STATE_NUM.APPROVED : CONST.REPORT.STATE_NUM.SUBMITTED; const optimisticNextStep = NextStepUtils.buildNextStep(expenseReport, predictedNextStatus); const chatReport = getReportOrDraftReport(expenseReport?.chatReportID);