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
24 changes: 3 additions & 21 deletions src/components/MoneyReportHeader.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -447,7 +447,7 @@ function MoneyReportHeader({

const isFromPaidPolicy = policyType === CONST.POLICY.TYPE.TEAM || policyType === CONST.POLICY.TYPE.CORPORATE;

const hasDuplicates = hasDuplicateTransactions(email ?? '', accountID, moneyRequestReport, policy, allTransactionViolations);
const hasDuplicates = hasDuplicateTransactions(email ?? '', accountID, moneyRequestReport, policy);
const shouldShowMarkAsResolved = isMarkAsResolvedAction(moneyRequestReport, transactionViolations);
const shouldShowStatusBar =
hasAllPendingRTERViolations ||
Expand Down Expand Up @@ -674,16 +674,7 @@ function MoneyReportHeader({
};

const getFirstDuplicateThreadID = (transactionsList: OnyxTypes.Transaction[], allReportActions: OnyxTypes.ReportAction[]) => {
const duplicateTransaction = transactionsList.find((reportTransaction) =>
isDuplicate(
reportTransaction,
email ?? '',
accountID,
moneyRequestReport,
policy,
allTransactionViolations?.[ONYXKEYS.COLLECTION.TRANSACTION_VIOLATIONS + reportTransaction.transactionID],
),
);
const duplicateTransaction = transactionsList.find((reportTransaction) => isDuplicate(reportTransaction, email ?? '', accountID, moneyRequestReport, policy));
if (!duplicateTransaction) {
return null;
}
Expand Down Expand Up @@ -998,16 +989,7 @@ function MoneyReportHeader({
onPress={() => {
let threadID = transactionThreadReportID ?? getFirstDuplicateThreadID(transactions, reportActions);
if (!threadID) {
const duplicateTransaction = transactions.find((reportTransaction) =>
isDuplicate(
reportTransaction,
email ?? '',
accountID,
moneyRequestReport,
policy,
allTransactionViolations?.[ONYXKEYS.COLLECTION.TRANSACTION_VIOLATIONS + reportTransaction.transactionID],
),
);
const duplicateTransaction = transactions.find((reportTransaction) => isDuplicate(reportTransaction, email ?? '', accountID, moneyRequestReport, policy));
const transactionID = duplicateTransaction?.transactionID;
const iouAction = getIOUActionForReportID(moneyRequestReport?.reportID, transactionID);
const createdTransactionThreadReport = createTransactionThreadReport(moneyRequestReport, iouAction);
Expand Down
22 changes: 4 additions & 18 deletions src/libs/ReportPrimaryActionUtils.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import type {OnyxCollection, OnyxEntry} from 'react-native-onyx';
import type {ValueOf} from 'type-fest';
import CONST from '@src/CONST';
import ONYXKEYS from '@src/ONYXKEYS';
import type {Policy, Report, ReportAction, ReportNameValuePairs, Transaction, TransactionViolation} from '@src/types/onyx';
import {isApprover as isApproverUtils} from './actions/Policy/Member';
import {getCurrentUserAccountID} from './actions/Report';
Expand Down Expand Up @@ -281,17 +280,8 @@ function isRemoveHoldAction(report: Report, chatReport: OnyxEntry<Report>, repor
return isHolder;
}

function isReviewDuplicatesAction(
report: Report,
reportTransactions: Transaction[],
currentUserEmail: string,
currentUserAccountID: number,
policy: Policy | undefined,
violations: OnyxCollection<TransactionViolation[]>,
) {
const hasDuplicates = reportTransactions.some((transaction) =>
isDuplicate(transaction, currentUserEmail, currentUserAccountID, report, policy, violations?.[ONYXKEYS.COLLECTION.TRANSACTION_VIOLATIONS + transaction.transactionID]),
);
function isReviewDuplicatesAction(report: Report, reportTransactions: Transaction[], currentUserEmail: string, currentUserAccountID: number, policy: Policy | undefined) {
const hasDuplicates = reportTransactions.some((transaction) => isDuplicate(transaction, currentUserEmail, currentUserAccountID, report, policy));

if (!hasDuplicates) {
return false;
Expand Down Expand Up @@ -433,7 +423,7 @@ function getReportPrimaryAction(params: GetReportPrimaryActionParams): ValueOf<t
return CONST.REPORT.PRIMARY_ACTIONS.MARK_AS_CASH;
}

if (isReviewDuplicatesAction(report, reportTransactions, currentUserEmail, currentUserAccountID, policy, violations)) {
if (isReviewDuplicatesAction(report, reportTransactions, currentUserEmail, currentUserAccountID, policy)) {
return CONST.REPORT.PRIMARY_ACTIONS.REVIEW_DUPLICATES;
}

Expand Down Expand Up @@ -505,11 +495,7 @@ function getTransactionThreadPrimaryAction(
return CONST.REPORT.TRANSACTION_PRIMARY_ACTIONS.REMOVE_HOLD;
}

const transactionViolations: OnyxCollection<TransactionViolation[]> = {
[`${ONYXKEYS.COLLECTION.TRANSACTION_VIOLATIONS}${reportTransaction.transactionID}`]: violations,
};

if (isReviewDuplicatesAction(parentReport, [reportTransaction], currentUserLogin, currentUserAccountID, policy, transactionViolations)) {
if (isReviewDuplicatesAction(parentReport, [reportTransaction], currentUserLogin, currentUserAccountID, policy)) {
return isFromReviewDuplicates ? CONST.REPORT.TRANSACTION_PRIMARY_ACTIONS.KEEP_THIS_ONE : CONST.REPORT.TRANSACTION_PRIMARY_ACTIONS.REVIEW_DUPLICATES;
}

Expand Down
4 changes: 1 addition & 3 deletions src/libs/ReportSecondaryActionUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -246,9 +246,7 @@ function isApproveAction(currentUserLogin: string, report: Report, reportTransac
return false;
}
const isExpenseReport = isExpenseReportUtils(report);
const reportHasDuplicatedTransactions = reportTransactions.some((transaction) =>
isDuplicate(transaction, currentUserLogin, currentUserAccountID, report, policy, violations?.[ONYXKEYS.COLLECTION.TRANSACTION_VIOLATIONS + transaction.transactionID]),
);
const reportHasDuplicatedTransactions = reportTransactions.some((transaction) => isDuplicate(transaction, currentUserLogin, currentUserAccountID, report, policy));

if (isExpenseReport && isProcessingReport && reportHasDuplicatedTransactions) {
return true;
Expand Down
30 changes: 6 additions & 24 deletions src/libs/TransactionUtils/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,7 @@
};

let deprecatedAllReports: OnyxCollection<Report> = {};
Onyx.connect({

Check warning on line 128 in src/libs/TransactionUtils/index.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 All @@ -134,7 +134,7 @@
});

let deprecatedAllTransactionViolations: OnyxCollection<TransactionViolations> = {};
Onyx.connect({

Check warning on line 137 in src/libs/TransactionUtils/index.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_VIOLATIONS,
waitForCollectionCallback: true,
callback: (value) => (deprecatedAllTransactionViolations = value),
Expand Down Expand Up @@ -1507,18 +1507,11 @@
* Check if transaction has duplicatedTransaction violation.
* @param transactionID - the transaction to check
*/
function isDuplicate(
transaction: OnyxEntry<Transaction>,
currentUserEmail: string,
currentUserAccountID: number,
iouReport: OnyxEntry<Report>,
policy: OnyxEntry<Policy>,
transactionViolation?: OnyxEntry<TransactionViolations>,
): boolean {
function isDuplicate(transaction: OnyxEntry<Transaction>, currentUserEmail: string, currentUserAccountID: number, iouReport: OnyxEntry<Report>, policy: OnyxEntry<Policy>): boolean {
if (!transaction) {
return false;
}
const duplicatedTransactionViolation = (transactionViolation ?? deprecatedAllTransactionViolations?.[`${ONYXKEYS.COLLECTION.TRANSACTION_VIOLATIONS}${transaction.transactionID}`])?.find(
const duplicatedTransactionViolation = deprecatedAllTransactionViolations?.[`${ONYXKEYS.COLLECTION.TRANSACTION_VIOLATIONS}${transaction.transactionID}`]?.find(
(violation: TransactionViolation) => violation.name === CONST.VIOLATIONS.DUPLICATED_TRANSACTION,
);
const hasDuplicatedTransactionViolation = !!duplicatedTransactionViolation;
Expand Down Expand Up @@ -1628,24 +1621,13 @@
currentUserAccountID: number,
iouReport: OnyxEntry<Report>,
policy: OnyxEntry<Policy>,
allTransactionViolations: OnyxCollection<TransactionViolation[]>,
// eslint-disable-next-line @typescript-eslint/no-deprecated
allReportTransactions?: SearchTransaction[],
): boolean {
const transactionsByIouReportID = getReportTransactions(iouReport?.reportID);
const reportTransactions = transactionsByIouReportID;
const reportTransactions = allReportTransactions ?? transactionsByIouReportID;

return (
reportTransactions.length > 0 &&
reportTransactions.some((transaction) =>
isDuplicate(
transaction,
currentUserEmail,
currentUserAccountID,
iouReport,
policy,
allTransactionViolations?.[ONYXKEYS.COLLECTION.TRANSACTION_VIOLATIONS + transaction.transactionID],
),
)
);
return reportTransactions.length > 0 && reportTransactions.some((transaction) => isDuplicate(transaction, currentUserEmail, currentUserAccountID, iouReport, policy));
}

/**
Expand Down
15 changes: 4 additions & 11 deletions src/libs/actions/IOU.ts
Original file line number Diff line number Diff line change
Expand Up @@ -757,7 +757,7 @@
};

let allPersonalDetails: OnyxTypes.PersonalDetailsList = {};
Onyx.connect({

Check warning on line 760 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
key: ONYXKEYS.PERSONAL_DETAILS_LIST,
callback: (value) => {
allPersonalDetails = value ?? {};
Expand Down Expand Up @@ -853,7 +853,7 @@
};

let allTransactions: NonNullable<OnyxCollection<OnyxTypes.Transaction>> = {};
Onyx.connect({

Check warning on line 856 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
key: ONYXKEYS.COLLECTION.TRANSACTION,
waitForCollectionCallback: true,
callback: (value) => {
Expand All @@ -867,7 +867,7 @@
});

let allTransactionDrafts: NonNullable<OnyxCollection<OnyxTypes.Transaction>> = {};
Onyx.connect({

Check warning on line 870 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
key: ONYXKEYS.COLLECTION.TRANSACTION_DRAFT,
waitForCollectionCallback: true,
callback: (value) => {
Expand All @@ -876,7 +876,7 @@
});

let allTransactionViolations: NonNullable<OnyxCollection<OnyxTypes.TransactionViolations>> = {};
Onyx.connect({

Check warning on line 879 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
key: ONYXKEYS.COLLECTION.TRANSACTION_VIOLATIONS,
waitForCollectionCallback: true,
callback: (value) => {
Expand All @@ -890,7 +890,7 @@
});

let allNextSteps: NonNullable<OnyxCollection<OnyxTypes.ReportNextStepDeprecated>> = {};
Onyx.connect({

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
key: ONYXKEYS.COLLECTION.NEXT_STEP,
waitForCollectionCallback: true,
callback: (value) => {
Expand All @@ -902,14 +902,14 @@
// `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`.
let allRecentlyUsedTags: OnyxCollection<RecentlyUsedTags> = {};
Onyx.connect({

Check warning on line 905 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
key: ONYXKEYS.COLLECTION.POLICY_RECENTLY_USED_TAGS,
waitForCollectionCallback: true,
callback: (val) => (allRecentlyUsedTags = val),
});

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

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
key: ONYXKEYS.COLLECTION.REPORT,
waitForCollectionCallback: true,
callback: (value) => {
Expand All @@ -918,7 +918,7 @@
});

let allReportNameValuePairs: OnyxCollection<OnyxTypes.ReportNameValuePairs>;
Onyx.connect({

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
key: ONYXKEYS.COLLECTION.REPORT_NAME_VALUE_PAIRS,
waitForCollectionCallback: true,
callback: (value) => {
Expand Down Expand Up @@ -10935,7 +10935,7 @@

let total = expenseReport.total ?? 0;
const hasHeldExpenses = hasHeldExpensesReportUtils(expenseReport.reportID);
const hasDuplicates = hasDuplicateTransactions(currentUserEmailParam, currentUserAccountIDParam, expenseReport, policy, allTransactionViolations);
const hasDuplicates = hasDuplicateTransactions(currentUserEmailParam, currentUserAccountIDParam, expenseReport, policy);
if (hasHeldExpenses && !full && !!expenseReport.unheldTotal) {
total = expenseReport.unheldTotal;
}
Expand Down Expand Up @@ -11109,18 +11109,11 @@

// Remove duplicates violations if we approve the report
if (hasDuplicates) {
let transactions = getReportTransactions(expenseReport.reportID).filter((transaction) =>
isDuplicate(
transaction,
currentUserEmailParam,
currentUserAccountIDParam,
expenseReport,
policy,
allTransactionViolations?.[ONYXKEYS.COLLECTION.TRANSACTION_VIOLATIONS + transaction.transactionID],
),
const transactions = getReportTransactions(expenseReport.reportID).filter((transaction) =>
isDuplicate(transaction, currentUserEmailParam, currentUserAccountIDParam, expenseReport, policy),
);
if (!full) {
transactions = transactions.filter((transaction) => !isOnHold(transaction));
transactions.filter((transaction) => !isOnHold(transaction));
}

for (const transaction of transactions) {
Expand Down
41 changes: 19 additions & 22 deletions tests/unit/ReportPrimaryActionUtilsTest.ts
Original file line number Diff line number Diff line change
Expand Up @@ -878,15 +878,13 @@ describe('isReviewDuplicatesAction', () => {
} as unknown as Transaction;

await Onyx.merge(`${ONYXKEYS.COLLECTION.TRANSACTION}${TRANSACTION_ID}`, transaction);
const violation = {
[`${ONYXKEYS.COLLECTION.TRANSACTION_VIOLATIONS}${TRANSACTION_ID}`]: [
{
name: CONST.VIOLATIONS.DUPLICATED_TRANSACTION,
} as TransactionViolation,
],
};
await Onyx.set(`${ONYXKEYS.COLLECTION.TRANSACTION_VIOLATIONS}${TRANSACTION_ID}`, [
{
name: CONST.VIOLATIONS.DUPLICATED_TRANSACTION,
} as TransactionViolation,
]);

expect(isReviewDuplicatesAction(report, [transaction], CURRENT_USER_EMAIL, CURRENT_USER_ACCOUNT_ID, undefined, violation)).toBe(true);
expect(isReviewDuplicatesAction(report, [transaction], CURRENT_USER_EMAIL, CURRENT_USER_ACCOUNT_ID, undefined)).toBe(true);
});

it('should return false when report approver has no duplicated transactions', async () => {
Expand All @@ -906,7 +904,7 @@ describe('isReviewDuplicatesAction', () => {

await Onyx.merge(`${ONYXKEYS.COLLECTION.TRANSACTION}${TRANSACTION_ID}`, transaction);

expect(isReviewDuplicatesAction(report, [transaction], CURRENT_USER_EMAIL, CURRENT_USER_ACCOUNT_ID, undefined, undefined)).toBe(false);
expect(isReviewDuplicatesAction(report, [transaction], CURRENT_USER_EMAIL, CURRENT_USER_ACCOUNT_ID, undefined)).toBe(false);
});

it('should return false when current user is neither the report submitter nor approver', async () => {
Expand All @@ -925,16 +923,13 @@ describe('isReviewDuplicatesAction', () => {
} as unknown as Transaction;

await Onyx.merge(`${ONYXKEYS.COLLECTION.TRANSACTION}${TRANSACTION_ID}`, transaction);
await Onyx.set(`${ONYXKEYS.COLLECTION.TRANSACTION_VIOLATIONS}${TRANSACTION_ID}`, [
{
name: CONST.VIOLATIONS.DUPLICATED_TRANSACTION,
} as TransactionViolation,
]);

expect(
isReviewDuplicatesAction(report, [transaction], CURRENT_USER_EMAIL, CURRENT_USER_ACCOUNT_ID, undefined, {
[`${ONYXKEYS.COLLECTION.TRANSACTION_VIOLATIONS}${TRANSACTION_ID}`]: [
{
name: CONST.VIOLATIONS.DUPLICATED_TRANSACTION,
} as TransactionViolation,
],
}),
).toBe(false);
expect(isReviewDuplicatesAction(report, [transaction], CURRENT_USER_EMAIL, CURRENT_USER_ACCOUNT_ID, undefined)).toBe(false);
});
});

Expand Down Expand Up @@ -1001,11 +996,13 @@ describe('getTransactionThreadPrimaryAction', () => {
} as unknown as Transaction;

await Onyx.merge(`${ONYXKEYS.COLLECTION.TRANSACTION}${TRANSACTION_ID}`, transaction);
const violation = {
name: CONST.VIOLATIONS.DUPLICATED_TRANSACTION,
} as unknown as TransactionViolation;
await Onyx.set(`${ONYXKEYS.COLLECTION.TRANSACTION_VIOLATIONS}${TRANSACTION_ID}`, [
{
name: CONST.VIOLATIONS.DUPLICATED_TRANSACTION,
} as TransactionViolation,
]);

expect(getTransactionThreadPrimaryAction(CURRENT_USER_EMAIL, CURRENT_USER_ACCOUNT_ID, {} as Report, report, transaction, [violation], policy as Policy, false)).toBe(
expect(getTransactionThreadPrimaryAction(CURRENT_USER_EMAIL, CURRENT_USER_ACCOUNT_ID, {} as Report, report, transaction, [], policy as Policy, false)).toBe(
CONST.REPORT.TRANSACTION_PRIMARY_ACTIONS.REVIEW_DUPLICATES,
);
});
Expand Down
Loading