Skip to content
Draft
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
Original file line number Diff line number Diff line change
Expand Up @@ -203,11 +203,12 @@
};

// Payment button derivations
const canIOUBePaid = canIOUBePaidAction(moneyRequestReport, chatReport, policy, bankAccountList, undefined, false, undefined, invoiceReceiverPolicy);

Check failure on line 206 in src/components/MoneyReportHeaderActions/MoneyReportHeaderSecondaryActions.tsx

View workflow job for this annotation

GitHub Actions / typecheck

Argument of type 'undefined' is not assignable to parameter of type 'string'.
const onlyShowPayElsewhere = !canIOUBePaid && canIOUBePaidAction(moneyRequestReport, chatReport, policy, bankAccountList, undefined, true, undefined, invoiceReceiverPolicy);

Check failure on line 207 in src/components/MoneyReportHeaderActions/MoneyReportHeaderSecondaryActions.tsx

View workflow job for this annotation

GitHub Actions / typecheck

Argument of type 'undefined' is not assignable to parameter of type 'string'.
const shouldShowPayButton = isPaidAnimationRunning || canIOUBePaid || onlyShowPayElsewhere;
const hasOnlyPendingTransactions = allTransactions.length > 0 && allTransactions.every((t) => isExpensifyCardTransaction(t) && isPending(t));
const shouldShowApproveButton = (canApproveIOU(moneyRequestReport, policy, reportMetadata, allTransactions) && !hasOnlyPendingTransactions) || isApprovedAnimationRunning;
const shouldShowApproveButton =
(canApproveIOU(moneyRequestReport, policy, reportMetadata, currentUserPersonalDetails.accountID, allTransactions) && !hasOnlyPendingTransactions) || isApprovedAnimationRunning;
const isApproveDisabled = shouldShowApproveButton && !isAllowedToApproveExpenseReport(moneyRequestReport);

const totalAmount = getTotalAmountForIOUReportPreviewButton(moneyRequestReport, policy, CONST.REPORT.PRIMARY_ACTIONS.PAY, nonPendingDeleteTransactions);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,11 +65,11 @@
const hasOnlyPendingTransactions = transactions.length > 0 && transactions.every((t) => isExpensifyCardTransaction(t) && isPending(t));
const nonPendingDeleteTransactions = transactions.filter((t): t is Transaction => !!t && (isOffline || t.pendingAction !== CONST.RED_BRICK_ROAD_PENDING_ACTION.DELETE));

const canIOUBePaid = canIOUBePaidAction(moneyRequestReport, chatReport, policy, bankAccountList, transaction ? [transaction] : undefined, false, undefined, invoiceReceiverPolicy);

Check failure on line 68 in src/components/MoneyReportHeaderPrimaryAction/PayPrimaryAction.tsx

View workflow job for this annotation

GitHub Actions / typecheck

Argument of type '({ amount: number; accountant?: Accountant | undefined; convertedAmount?: number | undefined; currencyConversionRate?: string | undefined; taxAmount?: number | undefined; ... 56 more ...; transactionType?: string | undefined; } & OfflineFeedback<...>)[] | undefined' is not assignable to parameter of type 'string'.
const onlyShowPayElsewhere =
!canIOUBePaid && canIOUBePaidAction(moneyRequestReport, chatReport, policy, bankAccountList, transaction ? [transaction] : undefined, true, undefined, invoiceReceiverPolicy);

Check failure on line 70 in src/components/MoneyReportHeaderPrimaryAction/PayPrimaryAction.tsx

View workflow job for this annotation

GitHub Actions / typecheck

Argument of type '({ amount: number; accountant?: Accountant | undefined; convertedAmount?: number | undefined; currencyConversionRate?: string | undefined; taxAmount?: number | undefined; ... 56 more ...; transactionType?: string | undefined; } & OfflineFeedback<...>)[] | undefined' is not assignable to parameter of type 'string'.
const shouldShowPayButton = isPaidAnimationRunning || canIOUBePaid || onlyShowPayElsewhere;
const shouldShowApproveButton = (canApproveIOU(moneyRequestReport, policy, reportMetadata, transactions) && !hasOnlyPendingTransactions) || isApprovedAnimationRunning;
const shouldShowApproveButton = (canApproveIOU(moneyRequestReport, policy, reportMetadata, accountID, transactions) && !hasOnlyPendingTransactions) || isApprovedAnimationRunning;
const shouldDisableApproveButton = shouldShowApproveButton && !isAllowedToApproveExpenseReport(moneyRequestReport);
const canAllowSettlement = hasUpdatedTotal(moneyRequestReport, policy);
const totalAmount = getTotalAmountForIOUReportPreviewButton(moneyRequestReport, policy, CONST.REPORT.PRIMARY_ACTIONS.PAY, nonPendingDeleteTransactions);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import {SearchScopeProvider} from '@components/Search/SearchScopeProvider';
import SettlementButton from '@components/SettlementButton';
import type {PaymentActionParams} from '@components/SettlementButton/types';
import {useCurrencyListActions} from '@hooks/useCurrencyList';
import useCurrentUserPersonalDetails from '@hooks/useCurrentUserPersonalDetails';
import useNetwork from '@hooks/useNetwork';
import useOnyx from '@hooks/useOnyx';
import usePolicy from '@hooks/usePolicy';
Expand Down Expand Up @@ -39,8 +40,11 @@ function PayActionCell({isLoading, policyID, reportID, hash, amount, extraSmall,
const [chatReport] = useOnyx(`${ONYXKEYS.COLLECTION.REPORT}${iouReport?.chatReportID}`);
const invoiceReceiverPolicyID = chatReport?.invoiceReceiver && 'policyID' in chatReport.invoiceReceiver ? chatReport.invoiceReceiver.policyID : undefined;
const invoiceReceiverPolicy = usePolicy(invoiceReceiverPolicyID);
const canBePaid = canIOUBePaid(iouReport, chatReport, policy, bankAccountList, transactions, false, undefined, invoiceReceiverPolicy);
const shouldOnlyShowElsewhere = !canBePaid && canIOUBePaid(iouReport, chatReport, policy, bankAccountList, transactions, true, undefined, invoiceReceiverPolicy);
const {email: currentUserLogin = '', accountID: currentUserAccountID} = useCurrentUserPersonalDetails();

const canBePaid = canIOUBePaid(iouReport, chatReport, policy, bankAccountList, currentUserLogin, currentUserAccountID, transactions, false, undefined, invoiceReceiverPolicy);
const shouldOnlyShowElsewhere =
!canBePaid && canIOUBePaid(iouReport, chatReport, policy, bankAccountList, currentUserLogin, currentUserAccountID, transactions, true, undefined, invoiceReceiverPolicy);

const {currency} = iouReport ?? {};

Expand Down
2 changes: 1 addition & 1 deletion src/hooks/useOptimisticNextStep.ts
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ function useOptimisticNextStep(reportID: string | undefined) {
optimisticNextStep = buildOptimisticNextStepForDEWOffline();
}
} else if (moneyRequestReport?.statusNum === CONST.REPORT.STATUS_NUM.SUBMITTED) {
const gbrResult = getReasonAndReportActionThatRequiresAttention(moneyRequestReport, undefined, isArchivedReport);
const gbrResult = getReasonAndReportActionThatRequiresAttention(moneyRequestReport, email ?? '', accountID, undefined, isArchivedReport);
const hasDEWApproveFailed = gbrResult?.reason === CONST.REQUIRES_ATTENTION_REASONS.HAS_DEW_APPROVE_FAILED;
const isCurrentUserTheApprover = moneyRequestReport?.managerID === accountID;
if (hasDEWApproveFailed && isCurrentUserTheApprover) {
Expand Down
36 changes: 33 additions & 3 deletions src/hooks/useSearchBulkActions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -326,11 +326,41 @@ function useSearchBulkActions({queryJSON}: UseSearchBulkActionsParams) {
const invoiceReceiverPolicy = invoiceReceiverPolicyID ? currentSearchResults?.data?.[`${ONYXKEYS.COLLECTION.POLICY}${invoiceReceiverPolicyID}`] : undefined;
return (
report &&
!canIOUBePaid(report, chatReport, selectedPolicy, bankAccountList, undefined, false, undefined, invoiceReceiverPolicy) &&
canIOUBePaid(report, chatReport, selectedPolicy, bankAccountList, undefined, true, undefined, invoiceReceiverPolicy)
!canIOUBePaid(
report,
chatReport,
selectedPolicy,
bankAccountList,
currentUserPersonalDetails?.email ?? '',
currentUserPersonalDetails.accountID,
undefined,
false,
undefined,
invoiceReceiverPolicy,
) &&
canIOUBePaid(
report,
chatReport,
selectedPolicy,
bankAccountList,
currentUserPersonalDetails?.email ?? '',
currentUserPersonalDetails.accountID,
undefined,
true,
undefined,
invoiceReceiverPolicy,
)
);
});
}, [currentSearchResults?.data, selectedPolicyIDs, selectedReportIDs, selectedTransactionReportIDs, bankAccountList]);
}, [
selectedPolicyIDs,
currentSearchResults?.data,
selectedTransactionReportIDs,
selectedReportIDs,
bankAccountList,
currentUserPersonalDetails?.email,
currentUserPersonalDetails.accountID,
]);

const {bulkPayButtonOptions, businessBankAccountOptions, shouldShowBusinessBankAccountOptions} = useBulkPayOptions({
selectedPolicyID: selectedPolicyIDs.at(0),
Expand Down
2 changes: 1 addition & 1 deletion src/hooks/useSelectionModeReportActions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -165,7 +165,7 @@ function useSelectionModeReportActions({

const {nonHeldAmount, fullAmount, hasValidNonHeldAmount} = getNonHeldAndFullAmount(report, shouldShowPayButton);

const shouldShowApproveButton = canApproveIOU(report, policy, reportMetadata, transactions) && !hasOnlyPendingTransactions;
const shouldShowApproveButton = canApproveIOU(report, policy, reportMetadata, currentUserAccountID, transactions) && !hasOnlyPendingTransactions;

const shouldDisableApproveButton = shouldShowApproveButton && !isAllowedToApproveExpenseReport(report);

Expand Down
9 changes: 7 additions & 2 deletions src/libs/DebugUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1457,12 +1457,17 @@ type GBRReasonAndReportAction = {
/**
* Gets the reason and report action that is causing the GBR to show up in LHN row
*/
function getReasonAndReportActionForGBRInLHNRow(report: OnyxEntry<Report>, isReportArchived = false): GBRReasonAndReportAction | null {
function getReasonAndReportActionForGBRInLHNRow(
report: OnyxEntry<Report>,
currentUserLogin: string,
currentUserAccountID: number,
isReportArchived = false,
): GBRReasonAndReportAction | null {
if (!report) {
return null;
}

const {reason, reportAction} = getReasonAndReportActionThatRequiresAttention(report, undefined, isReportArchived) ?? {};
const {reason, reportAction} = getReasonAndReportActionThatRequiresAttention(report, currentUserLogin, currentUserAccountID, undefined, isReportArchived) ?? {};

if (reason) {
return {reason: `debug.reasonGBR.${reason}`, reportAction};
Expand Down
37 changes: 30 additions & 7 deletions src/libs/ReportUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,15 @@
import {isEmptyObject, isEmptyValueObject} from '@src/types/utils/EmptyObject';
import type IconAsset from '@src/types/utils/IconAsset';
import {getBankAccountFromID} from './actions/BankAccounts';
import {createDraftTransaction, setMoneyRequestParticipants, setMoneyRequestParticipantsFromReport, setMoneyRequestReportID, startDistanceRequest, startMoneyRequest} from './actions/IOU';
import {
createDraftTransaction,
getUserAccountID,
setMoneyRequestParticipants,
setMoneyRequestParticipantsFromReport,
setMoneyRequestReportID,
startDistanceRequest,
startMoneyRequest,
} from './actions/IOU';
import type {IOURequestType} from './actions/IOU';
import {unholdRequest} from './actions/IOU/Hold';
import {canApproveIOU, canIOUBePaid, canSubmitReport, getBadgeFromIOUReport, getIOUReportActionWithBadge} from './actions/IOU/ReportWorkflow';
Expand Down Expand Up @@ -1037,7 +1045,7 @@
};

let conciergeReportIDOnyxConnect: OnyxEntry<string>;
Onyx.connect({

Check warning on line 1048 in src/libs/ReportUtils.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
key: ONYXKEYS.CONCIERGE_REPORT_ID,
callback: (value) => {
conciergeReportIDOnyxConnect = value;
Expand All @@ -1045,7 +1053,7 @@
});

const defaultAvatarBuildingIconTestID = 'SvgDefaultAvatarBuilding Icon';
Onyx.connect({

Check warning on line 1056 in src/libs/ReportUtils.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
key: ONYXKEYS.SESSION,
callback: (value) => {
// When signed out, val is undefined
Expand All @@ -1063,7 +1071,7 @@
let allPersonalDetails: OnyxEntry<PersonalDetailsList>;
let allPersonalDetailLogins: string[];
let currentUserPersonalDetails: OnyxEntry<PersonalDetails>;
Onyx.connect({

Check warning on line 1074 in src/libs/ReportUtils.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
key: ONYXKEYS.PERSONAL_DETAILS_LIST,
callback: (value) => {
if (deprecatedCurrentUserAccountID) {
Expand All @@ -1075,7 +1083,7 @@
});

let allReportsDraft: OnyxCollection<Report>;
Onyx.connect({

Check warning on line 1086 in src/libs/ReportUtils.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
key: ONYXKEYS.COLLECTION.REPORT_DRAFT,
waitForCollectionCallback: true,
callback: (value) => (allReportsDraft = value),
Expand All @@ -1083,7 +1091,7 @@

let allPolicies: OnyxCollection<Policy>;
let policiesArray: Policy[] = [];
Onyx.connect({

Check warning on line 1094 in src/libs/ReportUtils.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
key: ONYXKEYS.COLLECTION.POLICY,
waitForCollectionCallback: true,
callback: (value) => {
Expand All @@ -1093,7 +1101,7 @@
});

let allPolicyDrafts: OnyxCollection<Policy>;
Onyx.connect({

Check warning on line 1104 in src/libs/ReportUtils.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
key: ONYXKEYS.COLLECTION.POLICY_DRAFTS,
waitForCollectionCallback: true,
callback: (value) => (allPolicyDrafts = value),
Expand All @@ -1101,7 +1109,7 @@

let deprecatedAllReports: OnyxCollection<Report>;
let deprecatedReportsByPolicyID: ReportByPolicyMap;
Onyx.connect({

Check warning on line 1112 in src/libs/ReportUtils.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
key: ONYXKEYS.COLLECTION.REPORT,
waitForCollectionCallback: true,
callback: (value) => {
Expand Down Expand Up @@ -1137,14 +1145,14 @@
});

let betaConfiguration: OnyxEntry<BetaConfiguration> = {};
Onyx.connect({

Check warning on line 1148 in src/libs/ReportUtils.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
key: ONYXKEYS.BETA_CONFIGURATION,
callback: (value) => (betaConfiguration = value ?? {}),
});

let deprecatedAllTransactions: OnyxCollection<Transaction> = {};
let deprecatedReportsTransactions: Record<string, Transaction[]> = {};
Onyx.connect({

Check warning on line 1155 in src/libs/ReportUtils.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
key: ONYXKEYS.COLLECTION.TRANSACTION,
waitForCollectionCallback: true,
callback: (value) => {
Expand Down Expand Up @@ -2891,8 +2899,8 @@
// eslint-disable-next-line @typescript-eslint/no-deprecated
const invoiceReceiverPolicy = getPolicy(invoiceReceiverPolicyID);
return (
canIOUBePaid(iouReport, chatReport, policy, bankAccountList, transactions, undefined, undefined, invoiceReceiverPolicy) ||
canApproveIOU(iouReport, policy, reportMetadata, transactions) ||
canIOUBePaid(iouReport, chatReport, policy, bankAccountList, currentUserEmailParam, currentUserAccountIDParam, transactions, undefined, undefined, invoiceReceiverPolicy) ||
canApproveIOU(iouReport, policy, reportMetadata, currentUserAccountIDParam, transactions) ||
canSubmitAndIsAwaitingForCurrentUser(
iouReport,
chatReport,
Expand Down Expand Up @@ -4186,6 +4194,8 @@

function getReasonAndReportActionThatRequiresAttention(
optionOrReport: OnyxEntry<Report> | OptionData,
currentUserLogin: string,
currentUserAccountID: number,
parentReportAction?: OnyxEntry<ReportAction>,
isReportArchived = false,
): ReasonAndReportActionThatRequiresAttention | null {
Expand Down Expand Up @@ -4242,7 +4252,9 @@

if (actionTypeForAssigneeToComplete) {
const isAssigneeExpenseAction = actionTypeForAssigneeToComplete === CONST.REPORT.ACTION_TYPES_FOR_ASSIGNEE_TO_COMPLETE.EXPENSE;
const expenseBadge = isAssigneeExpenseAction ? getBadgeFromIOUReport(optionOrReport, undefined, policy, optionReportMetadata, invoiceReceiverPolicy) : undefined;
const expenseBadge = isAssigneeExpenseAction
? getBadgeFromIOUReport(optionOrReport, undefined, policy, optionReportMetadata, invoiceReceiverPolicy, currentUserLogin, currentUserAccountID)
: undefined;
return {
reason: CONST.REQUIRES_ATTENTION_REASONS.IS_WAITING_FOR_ASSIGNEE_TO_COMPLETE_ACTION,
reportAction: Object.values(reportActions)
Expand All @@ -4254,7 +4266,14 @@
};
}

const {reportAction: iouReportActionToApproveOrPay, actionBadge} = getIOUReportActionWithBadge(optionOrReport, policy, optionReportMetadata, invoiceReceiverPolicy);
const {reportAction: iouReportActionToApproveOrPay, actionBadge} = getIOUReportActionWithBadge(
optionOrReport,
policy,
optionReportMetadata,
invoiceReceiverPolicy,
currentUserLogin,
currentUserAccountID,
);
const iouReportID = getIOUReportIDFromReportActionPreview(iouReportActionToApproveOrPay);
const transactions = getReportTransactions(iouReportID);
const hasOnlyPendingTransactions = transactions.length > 0 && transactions.every((t) => isExpensifyCardTransaction(t) && isPending(t));
Expand Down Expand Up @@ -4310,7 +4329,7 @@
* @param parentReportAction (the report action the current report is a thread of)
*/
function requiresAttentionFromCurrentUser(optionOrReport: OnyxEntry<Report> | OptionData, parentReportAction?: OnyxEntry<ReportAction>, isReportArchived = false) {
return !!getReasonAndReportActionThatRequiresAttention(optionOrReport, parentReportAction, isReportArchived);
return !!getReasonAndReportActionThatRequiresAttention(optionOrReport, getCurrentUserEmail() ?? '', getUserAccountID(), parentReportAction, isReportArchived);
}

/**
Expand Down Expand Up @@ -12865,13 +12884,17 @@
isReportArchived = false,
allTransactions,
reports,
currentUserLogin,
currentUserAccountID,
}: {
report: OnyxEntry<Report>;
chatReport: OnyxEntry<Report>;
reportActions?: OnyxCollection<ReportActions>;
transactionViolations: OnyxCollection<TransactionViolation[]>;
isReportArchived: boolean;
allTransactions: OnyxCollection<Transaction>;
currentUserLogin: string;
currentUserAccountID: number;
actionBadge?: ValueOf<typeof CONST.REPORT.ACTION_BADGE>;
actionTargetReportActionID?: string;
reports?: OnyxCollection<Report>;
Expand All @@ -12884,7 +12907,7 @@
const hasErrors = Object.entries(reportErrors ?? {}).length > 0;
const oneTransactionThreadReportID = getOneTransactionThreadReportID(report, chatReport, reportActionsList);
const parentReportAction = report?.parentReportActionID ? parentReportActionsList?.[report.parentReportActionID] : undefined;
const {reason, actionBadge, reportAction} = getReasonAndReportActionThatRequiresAttention(report, parentReportAction, isReportArchived) ?? {};
const {reason, actionBadge, reportAction} = getReasonAndReportActionThatRequiresAttention(report, currentUserLogin, currentUserAccountID, parentReportAction, isReportArchived) ?? {};

return {
hasViolationsToDisplayInLHN,
Expand Down
17 changes: 14 additions & 3 deletions src/libs/SearchUIUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2309,8 +2309,19 @@ function getActions(
: undefined;

const chatReport = getChatReport(data, report);
const canBePaid = canIOUBePaid(report, chatReport, policy, bankAccountList, allReportTransactions, false, chatReportRNVP, invoiceReceiverPolicy);
const canOnlyBePaidElsewhere = canIOUBePaid(report, chatReport, policy, bankAccountList, allReportTransactions, true, chatReportRNVP, invoiceReceiverPolicy);
const canBePaid = canIOUBePaid(report, chatReport, policy, bankAccountList, currentUserLogin, currentUserAccountID, allReportTransactions, false, chatReportRNVP, invoiceReceiverPolicy);
const canOnlyBePaidElsewhere = canIOUBePaid(
report,
chatReport,
policy,
bankAccountList,
currentUserLogin,
currentUserAccountID,
allReportTransactions,
true,
chatReportRNVP,
invoiceReceiverPolicy,
);
const shouldOnlyShowElsewhere = !canBePaid && canOnlyBePaidElsewhere;

// We're not supporting pay partial amount on search page now.
Expand All @@ -2333,7 +2344,7 @@ function getActions(

// We're not supporting approve partial amount on search page now
if (
canApproveIOU(report, policy, reportMetadata, allReportTransactions) &&
canApproveIOU(report, policy, reportMetadata, currentUserAccountID, allReportTransactions) &&
isAllowedToApproveExpenseReport &&
!hasOnlyPendingCardOrScanningTransactions &&
!hasHeldExpenses(report.reportID, allReportTransactions)
Expand Down
Loading
Loading