Skip to content
1 change: 1 addition & 0 deletions __mocks__/reportData/violations.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ const receiptErrorsR14932: ReceiptErrors = {
retryParams: {
transactionID: RECEIPT_ERRORS_TRANSACTION_ID_R14932,
source: CONST.POLICY.ID_FAKE,
transactionPolicy: undefined,
},
},
};
Expand Down
2 changes: 1 addition & 1 deletion src/components/MoneyReportHeader.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import {useRoute} from '@react-navigation/native';
import {isUserValidatedSelector} from '@selectors/Account';
import getArchiveReason from '@selectors/Report';
import {getArchiveReason} from '@selectors/Report';
import React, {useCallback, useContext, useEffect, useMemo, useRef, useState} from 'react';
import {InteractionManager, View} from 'react-native';
import type {OnyxEntry} from 'react-native-onyx';
Expand Down
6 changes: 5 additions & 1 deletion src/components/TestDrive/Modal/EmployeeTestDriveModal.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import {useRoute} from '@react-navigation/native';
import {format} from 'date-fns';
import {Str} from 'expensify-common';
import React, {useCallback, useState} from 'react';
import React, {useCallback, useMemo, useState} from 'react';
import {InteractionManager} from 'react-native';
import TestReceipt from '@assets/images/fake-test-drive-employee-receipt.jpg';
import TextInput from '@components/TextInput';
Expand All @@ -25,6 +25,7 @@ import Log from '@libs/Log';
import Navigation from '@libs/Navigation/Navigation';
import type {PlatformStackRouteProp} from '@libs/Navigation/PlatformStackNavigation/types';
import type {TestDriveModalNavigatorParamList} from '@libs/Navigation/types';
import {hasOnlyPersonalPolicies as hasOnlyPersonalPoliciesUtil} from '@libs/PolicyUtils';
import {generateReportID} from '@libs/ReportUtils';
import {generateAccountID} from '@libs/UserUtils';
import CONST from '@src/CONST';
Expand All @@ -45,6 +46,8 @@ function EmployeeTestDriveModal() {
const [isLoading, setIsLoading] = useState(false);
const {testDrive} = useOnboardingMessages();
const currentUserPersonalDetails = useCurrentUserPersonalDetails();
const [allPolicies] = useOnyx(ONYXKEYS.COLLECTION.POLICY, {canBeMissing: true});
const hasOnlyPersonalPolicies = useMemo(() => hasOnlyPersonalPoliciesUtil(allPolicies), [allPolicies]);

const onBossEmailChange = useCallback((value: string) => {
setBossEmail(value);
Expand Down Expand Up @@ -78,6 +81,7 @@ function EmployeeTestDriveModal() {
parentReport,
currentDate,
currentUserPersonalDetails,
hasOnlyPersonalPolicies,
});

setMoneyRequestReceipt(transactionID, source, filename, true, CONST.TEST_RECEIPT.FILE_TYPE, false, true);
Expand Down
57 changes: 22 additions & 35 deletions src/libs/actions/IOU.ts
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,6 @@
getPolicy,
getSubmitToAccountID,
hasDependentTags,
hasOnlyPersonalPolicies,
isControlPolicy,
isDelayedSubmissionEnabled,
isPaidGroupPolicy,
Expand Down Expand Up @@ -299,6 +298,7 @@
currentDate: string | undefined;
lastSelectedDistanceRates?: OnyxEntry<OnyxTypes.LastSelectedDistanceRates>;
currentUserPersonalDetails: CurrentUserPersonalDetails;
hasOnlyPersonalPolicies: boolean;
};

type MoneyRequestInformation = {
Expand Down Expand Up @@ -354,6 +354,7 @@
};

type TrackedExpensePolicyParams = {
policy: OnyxEntry<OnyxTypes.Policy>;
policyID: string | undefined;
isDraftPolicy?: boolean;
};
Expand Down Expand Up @@ -738,7 +739,7 @@
let allPersonalDetails: OnyxTypes.PersonalDetailsList = {};
Onyx.connect({
key: ONYXKEYS.PERSONAL_DETAILS_LIST,
callback: (value) => {

Check warning on line 742 in src/libs/actions/IOU.ts

View workflow job for this annotation

GitHub Actions / Changed files ESLint check

Onyx.connect() is deprecated. Use useOnyx() hook instead and pass the data as parameters to a pure function
allPersonalDetails = value ?? {};
},
});
Expand Down Expand Up @@ -787,6 +788,7 @@
file?: File;
source: string;
transactionPolicyCategories?: OnyxEntry<OnyxTypes.PolicyCategories>;
transactionPolicy: OnyxEntry<OnyxTypes.Policy>;
};

type GetSearchOnyxUpdateParams = {
Expand Down Expand Up @@ -832,7 +834,7 @@
Onyx.connect({
key: ONYXKEYS.COLLECTION.TRANSACTION,
waitForCollectionCallback: true,
callback: (value) => {

Check warning on line 837 in src/libs/actions/IOU.ts

View workflow job for this annotation

GitHub Actions / Changed files ESLint check

Onyx.connect() is deprecated. Use useOnyx() hook instead and pass the data as parameters to a pure function
if (!value) {
allTransactions = {};
return;
Expand All @@ -846,7 +848,7 @@
Onyx.connect({
key: ONYXKEYS.COLLECTION.TRANSACTION_DRAFT,
waitForCollectionCallback: true,
callback: (value) => {

Check warning on line 851 in src/libs/actions/IOU.ts

View workflow job for this annotation

GitHub Actions / Changed files ESLint check

Onyx.connect() is deprecated. Use useOnyx() hook instead and pass the data as parameters to a pure function
allTransactionDrafts = value ?? {};
},
});
Expand All @@ -855,7 +857,7 @@
Onyx.connect({
key: ONYXKEYS.COLLECTION.TRANSACTION_VIOLATIONS,
waitForCollectionCallback: true,
callback: (value) => {

Check warning on line 860 in src/libs/actions/IOU.ts

View workflow job for this annotation

GitHub Actions / Changed files ESLint check

Onyx.connect() is deprecated. Use useOnyx() hook instead and pass the data as parameters to a pure function
if (!value) {
allTransactionViolations = {};
return;
Expand All @@ -869,27 +871,11 @@
Onyx.connect({
key: ONYXKEYS.COLLECTION.NEXT_STEP,
waitForCollectionCallback: true,
callback: (value) => {

Check warning on line 874 in src/libs/actions/IOU.ts

View workflow job for this annotation

GitHub Actions / Changed files ESLint check

Onyx.connect() is deprecated. Use useOnyx() hook instead and pass the data as parameters to a pure function
allNextSteps = value ?? {};
},
});

const allPolicies: OnyxCollection<OnyxTypes.Policy> = {};
Onyx.connect({
key: ONYXKEYS.COLLECTION.POLICY,
callback: (val, key) => {
if (!key) {
return;
}
if (val === null || val === undefined) {
delete allPolicies[key];
return;
}

allPolicies[key] = val;
},
});

// TODO: remove `allRecentlyUsedTags` from this file (https://github.com/Expensify/App/issues/71491)
// `allRecentlyUsedTags` was moved here temporarily from `src/libs/actions/Policy/Tag.ts` during the `Deprecate Onyx.connect` refactor.
// All uses of this variable should be replaced with `useOnyx`.
Expand All @@ -897,14 +883,14 @@
Onyx.connect({
key: ONYXKEYS.COLLECTION.POLICY_RECENTLY_USED_TAGS,
waitForCollectionCallback: true,
callback: (val) => (allRecentlyUsedTags = val),

Check warning on line 886 in src/libs/actions/IOU.ts

View workflow job for this annotation

GitHub Actions / Changed files ESLint check

Onyx.connect() is deprecated. Use useOnyx() hook instead and pass the data as parameters to a pure function
});

let allReports: OnyxCollection<OnyxTypes.Report>;
Onyx.connect({
key: ONYXKEYS.COLLECTION.REPORT,
waitForCollectionCallback: true,
callback: (value) => {

Check warning on line 893 in src/libs/actions/IOU.ts

View workflow job for this annotation

GitHub Actions / Changed files ESLint check

Onyx.connect() is deprecated. Use useOnyx() hook instead and pass the data as parameters to a pure function
allReports = value;
},
});
Expand All @@ -913,7 +899,7 @@
Onyx.connect({
key: ONYXKEYS.COLLECTION.REPORT_NAME_VALUE_PAIRS,
waitForCollectionCallback: true,
callback: (value) => {

Check warning on line 902 in src/libs/actions/IOU.ts

View workflow job for this annotation

GitHub Actions / Changed files ESLint check

Onyx.connect() is deprecated. Use useOnyx() hook instead and pass the data as parameters to a pure function
allReportNameValuePairs = value;
},
});
Expand All @@ -923,7 +909,7 @@
Onyx.connect({
key: ONYXKEYS.SESSION,
callback: (value) => {
currentUserEmail = value?.email ?? '';

Check warning on line 912 in src/libs/actions/IOU.ts

View workflow job for this annotation

GitHub Actions / Changed files ESLint check

Onyx.connect() is deprecated. Use useOnyx() hook instead and pass the data as parameters to a pure function
userAccountID = value?.accountID ?? CONST.DEFAULT_NUMBER_ID;
},
});
Expand All @@ -932,7 +918,7 @@
Onyx.connect({
key: ONYXKEYS.PERSONAL_DETAILS_LIST,
callback: (value) => {
deprecatedCurrentUserPersonalDetails = value?.[userAccountID] ?? undefined;

Check warning on line 921 in src/libs/actions/IOU.ts

View workflow job for this annotation

GitHub Actions / Changed files ESLint check

Onyx.connect() is deprecated. Use useOnyx() hook instead and pass the data as parameters to a pure function
},
});

Expand Down Expand Up @@ -1054,6 +1040,7 @@
currentDate = '',
lastSelectedDistanceRates,
currentUserPersonalDetails,
hasOnlyPersonalPolicies,
}: InitMoneyRequestParams) {
// Generate a brand new transactionID
// This will be fixed as part of https://github.com/Expensify/Expensify/issues/507850
Expand Down Expand Up @@ -1094,7 +1081,7 @@
const isPolicyExpenseChat = isPolicyExpenseChatReportUtil(report) || isPolicyExpenseChatReportUtil(parentReport);
const customUnitRateID = DistanceRequestUtils.getCustomUnitRateID({reportID, isPolicyExpenseChat, policy, lastSelectedDistanceRates});
comment.customUnit = {customUnitRateID};
} else if (hasOnlyPersonalPolicies(allPolicies)) {
} else if (hasOnlyPersonalPolicies) {
comment.customUnit = {customUnitRateID: CONST.CUSTOM_UNITS.FAKE_P2P_ID};
}
if (comment.customUnit) {
Expand Down Expand Up @@ -6066,7 +6053,7 @@
successData?.push(...shareTrackedExpenseSuccessData);
failureData?.push(...shareTrackedExpenseFailureData);

const policyEmployeeList = allPolicies?.[`${ONYXKEYS.COLLECTION.POLICY}${policyParams?.policyID}`]?.employeeList;
const policyEmployeeList = policyParams?.policy?.employeeList;
if (!policyEmployeeList?.[accountantEmail]) {
const policyMemberAccountIDs = Object.values(getMemberAccountIDsForWorkspace(policyEmployeeList, false, false));
const {
Expand Down Expand Up @@ -6754,6 +6741,7 @@
};
const policyParams: TrackedExpensePolicyParams = {
policyID: chatReport?.policyID,
policy,
isDraftPolicy,
};
const reportInformation: TrackedExpenseReportInformation = {
Expand Down Expand Up @@ -6804,6 +6792,7 @@
};
const policyParams: TrackedExpensePolicyParams = {
policyID: chatReport?.policyID,
policy,
};
const reportInformation: TrackedExpenseReportInformation = {
moneyRequestPreviewReportActionID: iouAction?.reportActionID,
Expand Down Expand Up @@ -11898,13 +11887,12 @@
API.write(WRITE_COMMANDS.PAY_INVOICE, params, {optimisticData, successData, failureData});
}

function detachReceipt(transactionID: string | undefined, transactionPolicyCategories?: OnyxEntry<OnyxTypes.PolicyCategories>) {
function detachReceipt(transactionID: string | undefined, transactionPolicy: OnyxEntry<OnyxTypes.Policy>, transactionPolicyCategories?: OnyxEntry<OnyxTypes.PolicyCategories>) {
if (!transactionID) {
return;
}
const transaction = allTransactions[`${ONYXKEYS.COLLECTION.TRANSACTION}${transactionID}`];
const expenseReport = allReports?.[`${ONYXKEYS.COLLECTION.REPORT}${transaction?.reportID}`] ?? null;
const policy = allPolicies?.[`${ONYXKEYS.COLLECTION.POLICY}${expenseReport?.policyID}`];
const newTransaction = transaction
? {
...transaction,
Expand Down Expand Up @@ -11950,16 +11938,16 @@
},
];

if (policy && isPaidGroupPolicy(policy) && newTransaction) {
const policyTagList = getPolicyTagsData(policy.id);
if (transactionPolicy && isPaidGroupPolicy(transactionPolicy) && newTransaction) {
const policyTagList = getPolicyTagsData(transactionPolicy.id);
const currentTransactionViolations = allTransactionViolations[`${ONYXKEYS.COLLECTION.TRANSACTION_VIOLATIONS}${transactionID}`] ?? [];
const violationsOnyxData = ViolationsUtils.getViolationsOnyxData(
newTransaction,
currentTransactionViolations,
policy,
transactionPolicy,
policyTagList ?? {},
transactionPolicyCategories ?? {},
hasDependentTags(policy, policyTagList ?? {}),
hasDependentTags(transactionPolicy, policyTagList ?? {}),
isInvoiceReportReportUtils(expenseReport),
);
optimisticData.push(violationsOnyxData);
Expand Down Expand Up @@ -12018,22 +12006,21 @@
API.write(WRITE_COMMANDS.DETACH_RECEIPT, parameters, {optimisticData, successData, failureData});
}

function replaceReceipt({transactionID, file, source, transactionPolicyCategories}: ReplaceReceipt) {
function replaceReceipt({transactionID, file, source, transactionPolicy, transactionPolicyCategories}: ReplaceReceipt) {
if (!file) {
return;
}

const transaction = allTransactions[`${ONYXKEYS.COLLECTION.TRANSACTION}${transactionID}`];
const expenseReport = allReports?.[`${ONYXKEYS.COLLECTION.REPORT}${transaction?.reportID}`] ?? null;
const policy = allPolicies?.[`${ONYXKEYS.COLLECTION.POLICY}${expenseReport?.policyID}`];
const oldReceipt = transaction?.receipt ?? {};
const receiptOptimistic = {
source,
state: CONST.IOU.RECEIPT_STATE.OPEN,
filename: file.name,
};
const newTransaction = transaction && {...transaction, receipt: receiptOptimistic};
const retryParams: ReplaceReceipt = {transactionID, file: undefined, source, transactionPolicyCategories};
const retryParams: ReplaceReceipt = {transactionID, file: undefined, source, transactionPolicy, transactionPolicyCategories};
const currentSearchQueryJSON = getCurrentSearchQueryJSON();

const optimisticData: OnyxUpdate[] = [
Expand Down Expand Up @@ -12076,16 +12063,16 @@
},
];

if (policy && isPaidGroupPolicy(policy) && newTransaction) {
const policyTagList = getPolicyTagsData(policy.id);
if (transactionPolicy && isPaidGroupPolicy(transactionPolicy) && newTransaction) {
const policyTagList = getPolicyTagsData(transactionPolicy.id);
const currentTransactionViolations = allTransactionViolations[`${ONYXKEYS.COLLECTION.TRANSACTION_VIOLATIONS}${transactionID}`] ?? [];
const violationsOnyxData = ViolationsUtils.getViolationsOnyxData(
newTransaction,
currentTransactionViolations,
policy,
transactionPolicy,
policyTagList ?? {},
transactionPolicyCategories ?? {},
hasDependentTags(policy, policyTagList ?? {}),
hasDependentTags(transactionPolicy, policyTagList ?? {}),
isInvoiceReportReportUtils(expenseReport),
);
optimisticData.push(violationsOnyxData);
Expand Down Expand Up @@ -13307,14 +13294,14 @@
transactionID: string,
reportID: string,
comment: string,
policy: OnyxEntry<OnyxTypes.Policy>,
options?: {sharedRejectedToReportID?: string},
shouldUseBulkAction?: boolean,
): RejectMoneyRequestData | undefined {
const transaction = allTransactions[`${ONYXKEYS.COLLECTION.TRANSACTION}${transactionID}`];
const transactionAmount = getAmount(transaction);
const report = allReports?.[`${ONYXKEYS.COLLECTION.REPORT}${reportID}`];
const policyExpenseChat = allReports?.[`${ONYXKEYS.COLLECTION.REPORT}${report?.chatReportID}`];
const policy = allPolicies?.[`${ONYXKEYS.COLLECTION.POLICY}${report?.policyID}`];
const isPolicyDelayedSubmissionEnabled = policy ? isDelayedSubmissionEnabled(policy) : false;
const isIOU = isIOUReport(report);
const searchFullScreenRoutes = navigationRef.getRootState()?.routes.findLast((route) => route.name === NAVIGATORS.SEARCH_FULLSCREEN_NAVIGATOR);
Expand Down Expand Up @@ -14032,8 +14019,8 @@
return {optimisticData, successData, failureData, parameters, urlToNavigateBack: urlToNavigateBack as Route};
}

function rejectMoneyRequest(transactionID: string, reportID: string, comment: string, options?: {sharedRejectedToReportID?: string}): Route | undefined {
const data = prepareRejectMoneyRequestData(transactionID, reportID, comment, options);
function rejectMoneyRequest(transactionID: string, reportID: string, comment: string, policy: OnyxEntry<OnyxTypes.Policy>, options?: {sharedRejectedToReportID?: string}): Route | undefined {
const data = prepareRejectMoneyRequestData(transactionID, reportID, comment, policy, options);
if (!data) {
return;
}
Expand Down
8 changes: 4 additions & 4 deletions src/libs/actions/Search.ts
Original file line number Diff line number Diff line change
Expand Up @@ -724,7 +724,7 @@ function deleteMoneyRequestOnSearch(hash: number, transactionIDList: string[]) {
}
}

function rejectMoneyRequestInBulk(hash: number, reportID: string, comment: string, transactionIDs: string[]) {
function rejectMoneyRequestInBulk(hash: number, reportID: string, comment: string, policy: OnyxEntry<Policy>, transactionIDs: string[]) {
const {optimisticData, finallyData} = getOnyxLoadingData(hash);
const successData: OnyxUpdate[] = [];
const failureData: OnyxUpdate[] = [];
Expand All @@ -736,7 +736,7 @@ function rejectMoneyRequestInBulk(hash: number, reportID: string, comment: strin
}
> = {};
for (const transactionID of transactionIDs) {
const data = prepareRejectMoneyRequestData(transactionID, reportID, comment, undefined, true);
const data = prepareRejectMoneyRequestData(transactionID, reportID, comment, policy, undefined, true);
if (data) {
optimisticData.push(...data.optimisticData);
successData.push(...data.successData);
Expand Down Expand Up @@ -778,12 +778,12 @@ function rejectMoneyRequestsOnSearch(hash: number, selectedTransactions: Selecte
const policy = allPolicies?.[`${ONYXKEYS.COLLECTION.POLICY}${report?.policyID}`];
const isPolicyDelayedSubmissionEnabled = policy ? isDelayedSubmissionEnabled(policy) : false;
if (isPolicyDelayedSubmissionEnabled && areAllExpensesSelected) {
rejectMoneyRequestInBulk(hash, reportID, comment, allTransactionIDs);
rejectMoneyRequestInBulk(hash, reportID, comment, policy, allTransactionIDs);
} else {
// Share a single destination ID across all rejections from the same source report
const sharedRejectedToReportID = generateReportID();
for (const transactionID of selectedTransactionIDs) {
rejectMoneyRequest(transactionID, reportID, comment, {sharedRejectedToReportID});
rejectMoneyRequest(transactionID, reportID, comment, policy, {sharedRejectedToReportID});
}
}
}
Expand Down
4 changes: 3 additions & 1 deletion src/pages/Search/SearchPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ import {navigateToParticipantPage} from '@libs/IOUUtils';
import Navigation from '@libs/Navigation/Navigation';
import type {PlatformStackScreenProps} from '@libs/Navigation/PlatformStackNavigation/types';
import type {SearchFullscreenNavigatorParamList} from '@libs/Navigation/types';
import {getActiveAdminWorkspaces, hasDynamicExternalWorkflow, hasVBBA, isPaidGroupPolicy} from '@libs/PolicyUtils';
import {getActiveAdminWorkspaces, hasDynamicExternalWorkflow, hasOnlyPersonalPolicies as hasOnlyPersonalPoliciesUtil, hasVBBA, isPaidGroupPolicy} from '@libs/PolicyUtils';
import {
generateReportID,
getPolicyExpenseChat,
Expand Down Expand Up @@ -146,6 +146,7 @@ function SearchPage({route}: SearchPageProps) {
const selectedTransactionReportIDs = useMemo(() => [...new Set(Object.values(selectedTransactions).map((transaction) => transaction.reportID))], [selectedTransactions]);
const selectedReportIDs = Object.values(selectedReports).map((report) => report.reportID);
const isCurrencySupportedBulkWallet = isCurrencySupportWalletBulkPay(selectedReports, selectedTransactions);
const hasOnlyPersonalPolicies = useMemo(() => hasOnlyPersonalPoliciesUtil(policies), [policies]);

// Collate a list of policyIDs from the selected transactions
const selectedPolicyIDs = useMemo(
Expand Down Expand Up @@ -711,6 +712,7 @@ function SearchPage({route}: SearchPageProps) {
parentReport: newParentReport,
currentDate,
currentUserPersonalDetails,
hasOnlyPersonalPolicies,
});

const newReceiptFiles: ReceiptFile[] = [];
Expand Down
5 changes: 4 additions & 1 deletion src/pages/Share/SubmitDetailsPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import navigateAfterInteraction from '@libs/Navigation/navigateAfterInteraction'
import Navigation from '@libs/Navigation/Navigation';
import type {ShareNavigatorParamList} from '@libs/Navigation/types';
import {getParticipantsOption, getReportOption} from '@libs/OptionsListUtils';
import {hasOnlyPersonalPolicies as hasOnlyPersonalPoliciesUtil} from '@libs/PolicyUtils';
import {shouldValidateFile} from '@libs/ReceiptUtils';
import {getReportOrDraftReport, isSelfDM} from '@libs/ReportUtils';
import {getDefaultTaxCode} from '@libs/TransactionUtils';
Expand Down Expand Up @@ -73,6 +74,7 @@ function SubmitDetailsPage({
const fileUri = shouldUsePreValidatedFile ? (validFilesToUpload?.uri ?? '') : (currentAttachment?.content ?? '');
const fileName = shouldUsePreValidatedFile ? getFileName(validFilesToUpload?.uri ?? CONST.ATTACHMENT_IMAGE_DEFAULT_NAME) : getFileName(currentAttachment?.content ?? '');
const fileType = shouldUsePreValidatedFile ? (validFilesToUpload?.type ?? CONST.RECEIPT_ALLOWED_FILE_TYPES.JPEG) : (currentAttachment?.mimeType ?? '');
const [hasOnlyPersonalPolicies = false] = useOnyx(ONYXKEYS.COLLECTION.POLICY, {canBeMissing: true, selector: hasOnlyPersonalPoliciesUtil});

useEffect(() => {
if (!errorTitle || !errorMessage) {
Expand All @@ -92,8 +94,9 @@ function SubmitDetailsPage({
parentReport,
currentDate,
currentUserPersonalDetails,
hasOnlyPersonalPolicies,
});
}, [reportOrAccountID, policy, report, parentReport, currentDate, currentUserPersonalDetails]);
}, [reportOrAccountID, policy, report, parentReport, currentDate, currentUserPersonalDetails, hasOnlyPersonalPolicies]);

const selectedParticipants = unknownUserDetails ? [unknownUserDetails] : getMoneyRequestParticipantsFromReport(report, currentUserPersonalDetails.accountID);
const participants = selectedParticipants.map((participant) =>
Expand Down
Loading
Loading