Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 44 additions & 3 deletions src/libs/PolicyUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,15 @@ import ROUTES from '@src/ROUTES';
import INPUT_IDS from '@src/types/form/NetSuiteCustomFieldForm';
import type {
OnyxInputOrEntry,
Pages,
PersonalDetailsList,
Policy,
PolicyCategories,
PolicyEmployeeList,
PolicyTagLists,
PolicyTags,
Report,
ReportActions,
TaxRate,
Transaction,
TravelSettings,
Expand All @@ -41,6 +43,7 @@ import type {
Tenant,
} from '@src/types/onyx/Policy';
import type PolicyEmployee from '@src/types/onyx/PolicyEmployee';
import type ReportAction from '@src/types/onyx/ReportAction';
import {isEmptyObject} from '@src/types/utils/EmptyObject';
import {getBankAccountFromID} from './actions/BankAccounts';
import {hasSynchronizationErrorMessage, isConnectionUnverified} from './actions/connections';
Expand Down Expand Up @@ -1244,12 +1247,50 @@ function getSubmitToAccountID(policy: OnyxEntry<Policy>, expenseReport: OnyxEntr
return getManagerAccountID(policy, expenseReport);
}

function getSubmitReportManagerAccountID(policy: OnyxEntry<Policy>, expenseReport: OnyxEntry<Report>): number {
function isReportLevelApproverOverrideAction(reportAction: OnyxEntry<ReportAction>): boolean {
return reportAction?.actionName === CONST.REPORT.ACTIONS.TYPE.TAKE_CONTROL || reportAction?.actionName === CONST.REPORT.ACTIONS.TYPE.REROUTE;
}

function isSubmittedOrReportLevelApproverOverrideAction(reportAction: OnyxEntry<ReportAction>): boolean {
return reportAction?.actionName === CONST.REPORT.ACTIONS.TYPE.SUBMITTED || isReportLevelApproverOverrideAction(reportAction);
}

function getActiveReportLevelApproverOverrideStatus(reportActions: ReportActions | undefined, reportActionPages?: Pages): boolean | undefined {
const newestActionPage = reportActionPages?.find((page) => page.at(0) === CONST.PAGINATION_START_ID);
if (!newestActionPage) {
return;
}

for (const reportActionID of newestActionPage) {
if (reportActionID === CONST.PAGINATION_START_ID || reportActionID === CONST.PAGINATION_END_ID) {
continue;
}

const reportAction = reportActions?.[reportActionID];
if (!reportAction) {
return;
}

if (!isSubmittedOrReportLevelApproverOverrideAction(reportAction)) {
continue;
}

return isReportLevelApproverOverrideAction(reportAction);
}

return newestActionPage.includes(CONST.PAGINATION_END_ID) ? false : undefined;
}

function getSubmitReportManagerAccountID(policy: OnyxEntry<Policy>, expenseReport: OnyxEntry<Report>, reportActions?: ReportActions, reportActionPages?: Pages): number {
const existingManagerID = expenseReport?.managerID ?? CONST.DEFAULT_NUMBER_ID;
const ownerAccountID = expenseReport?.ownerAccountID ?? CONST.DEFAULT_NUMBER_ID;
const employeeLogin = getLoginByAccountID(ownerAccountID) ?? '';
const hasEmployeeData = !!policy?.employeeList?.[employeeLogin];
const hasValidExistingManager = existingManagerID > CONST.DEFAULT_NUMBER_ID && existingManagerID !== ownerAccountID;
const activeReportLevelApproverOverride = getActiveReportLevelApproverOverrideStatus(reportActions, reportActionPages);

if (existingManagerID > CONST.DEFAULT_NUMBER_ID && existingManagerID !== ownerAccountID) {
// Existing reports may already have a server-computed or manually changed approver.
if (hasValidExistingManager && (!hasEmployeeData || activeReportLevelApproverOverride !== false)) {
// Preserve known-good report managers when policy employee data is missing, when report action history may be incomplete, or when the report was explicitly rerouted.
return existingManagerID;
}

Expand Down
18 changes: 18 additions & 0 deletions src/libs/ReportActionsUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import type {
CompanyCardFeed,
OnyxInputOrEntry,
OriginalMessageIOU,
Pages,
PersonalDetails,
PersonalDetailsList,
Policy,
Expand Down Expand Up @@ -103,6 +104,18 @@ Onyx.connect({
},
});

let allReportActionPages: OnyxCollection<Pages>;
Onyx.connectWithoutView({
key: ONYXKEYS.COLLECTION.REPORT_ACTIONS_PAGES,
waitForCollectionCallback: true,
callback: (pages) => {
if (!pages) {
return;
}
allReportActionPages = pages;
},
});

let allReports: OnyxCollection<Report>;
Onyx.connect({
key: ONYXKEYS.COLLECTION.REPORT,
Expand Down Expand Up @@ -2008,6 +2021,10 @@ function getAllReportActions(reportID: string | undefined): ReportActions {
return allReportActions?.[`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${reportID}`] ?? {};
}

function getReportActionPages(reportID: string | undefined): Pages {
return allReportActionPages?.[`${ONYXKEYS.COLLECTION.REPORT_ACTIONS_PAGES}${reportID}`] ?? [];
}

/**
* Check whether a report action is an attachment (a file, such as an image or a zip).
*
Expand Down Expand Up @@ -4557,6 +4574,7 @@ export {
getHtmlWithAttachmentID,
getActionableMentionWhisperMessage,
getAllReportActions,
getReportActionPages,
getCombinedReportActions,
getDismissedViolationMessageText,
getFirstVisibleReportActionID,
Expand Down
4 changes: 2 additions & 2 deletions src/libs/actions/IOU/ReportWorkflow.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import Navigation from '@libs/Navigation/Navigation';
import {getIsOffline} from '@libs/NetworkState';
import {buildNextStepNew, buildOptimisticNextStep} from '@libs/NextStepUtils';
import {arePaymentsEnabled, getSubmitReportManagerAccountID, hasDynamicExternalWorkflow, isPaidGroupPolicy, isPolicyAdmin, isSubmitAndClose} from '@libs/PolicyUtils';
import {getAllReportActions, getReportActionHtml, getReportActionText, hasPendingDEWApprove, isCreatedAction, isDeletedAction} from '@libs/ReportActionsUtils';
import {getAllReportActions, getReportActionHtml, getReportActionPages, getReportActionText, hasPendingDEWApprove, isCreatedAction, isDeletedAction} from '@libs/ReportActionsUtils';
import {
buildOptimisticApprovedReportAction,
buildOptimisticChangeApproverReportAction,
Expand Down Expand Up @@ -1299,7 +1299,7 @@ function submitReport({
isASAPSubmitBetaEnabled,
isUnapprove: true,
});
const managerID = getSubmitReportManagerAccountID(policy, expenseReport);
const managerID = getSubmitReportManagerAccountID(policy, expenseReport, getAllReportActions(expenseReport.reportID), getReportActionPages(expenseReport.reportID));

const optimisticData: Array<
OnyxUpdate<typeof ONYXKEYS.COLLECTION.REPORT_ACTIONS | typeof ONYXKEYS.COLLECTION.REPORT | typeof ONYXKEYS.COLLECTION.NEXT_STEP | typeof ONYXKEYS.COLLECTION.REPORT_METADATA>
Expand Down
3 changes: 2 additions & 1 deletion src/libs/actions/Search.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ import enhanceParameters from '@libs/Network/enhanceParameters';
import {rand64} from '@libs/NumberUtils';
import {getActivePaymentType} from '@libs/PaymentUtils';
import {getSubmitReportManagerAccountID, getValidConnectedIntegration, isDelayedSubmissionEnabled} from '@libs/PolicyUtils';
import {getAllReportActions, getReportActionPages} from '@libs/ReportActionsUtils';
import type {OptimisticExportIntegrationAction} from '@libs/ReportUtils';
import {
buildOptimisticExportIntegrationAction,
Expand Down Expand Up @@ -661,7 +662,7 @@ function submitMoneyRequestOnSearch(hash: number, reportList: Report[], policy:
const report = (reportList.at(0) ?? {}) as Report;
const parameters: SubmitReportParams = {
reportID: report.reportID,
managerAccountID: getSubmitReportManagerAccountID(policy.at(0), report),
managerAccountID: getSubmitReportManagerAccountID(policy.at(0), report, getAllReportActions(report.reportID), getReportActionPages(report.reportID)),
reportActionID: rand64(),
};

Expand Down
Loading
Loading