diff --git a/android/app/build.gradle b/android/app/build.gradle
index 7ba437feeda7..359699da7922 100644
--- a/android/app/build.gradle
+++ b/android/app/build.gradle
@@ -110,8 +110,8 @@ android {
minSdkVersion rootProject.ext.minSdkVersion
targetSdkVersion rootProject.ext.targetSdkVersion
multiDexEnabled rootProject.ext.multiDexEnabled
- versionCode 1009009424
- versionName "9.0.94-24"
+ versionCode 1009009425
+ versionName "9.0.94-25"
// Supported language variants must be declared here to avoid from being removed during the compilation.
// This also helps us to not include unnecessary language variants in the APK.
resConfigs "en", "es"
diff --git a/ios/NewExpensify/Info.plist b/ios/NewExpensify/Info.plist
index 507e9094a3a7..4dded39f4333 100644
--- a/ios/NewExpensify/Info.plist
+++ b/ios/NewExpensify/Info.plist
@@ -44,7 +44,7 @@
CFBundleVersion
- 9.0.94.24
+ 9.0.94.25
FullStory
OrgId
diff --git a/ios/NewExpensifyTests/Info.plist b/ios/NewExpensifyTests/Info.plist
index e0b61a75885f..23e9b0ef1f05 100644
--- a/ios/NewExpensifyTests/Info.plist
+++ b/ios/NewExpensifyTests/Info.plist
@@ -19,6 +19,6 @@
CFBundleSignature
????
CFBundleVersion
- 9.0.94.24
+ 9.0.94.25
diff --git a/ios/NotificationServiceExtension/Info.plist b/ios/NotificationServiceExtension/Info.plist
index 63805152d6ed..3b619f92ebfc 100644
--- a/ios/NotificationServiceExtension/Info.plist
+++ b/ios/NotificationServiceExtension/Info.plist
@@ -13,7 +13,7 @@
CFBundleShortVersionString
9.0.94
CFBundleVersion
- 9.0.94.24
+ 9.0.94.25
NSExtension
NSExtensionPointIdentifier
diff --git a/package-lock.json b/package-lock.json
index 760fb2c46d5c..0230729c4a94 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,12 +1,12 @@
{
"name": "new.expensify",
- "version": "9.0.94-24",
+ "version": "9.0.94-25",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "new.expensify",
- "version": "9.0.94-24",
+ "version": "9.0.94-25",
"hasInstallScript": true,
"license": "MIT",
"dependencies": {
diff --git a/package.json b/package.json
index 8a39fce91ffc..3bf3d67e69fa 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "new.expensify",
- "version": "9.0.94-24",
+ "version": "9.0.94-25",
"author": "Expensify, Inc.",
"homepage": "https://new.expensify.com",
"description": "New Expensify is the next generation of Expensify: a reimagination of payments based atop a foundation of chat.",
diff --git a/src/components/BrokenConnectionDescription.tsx b/src/components/BrokenConnectionDescription.tsx
index ed5ecf41078a..078cbed25631 100644
--- a/src/components/BrokenConnectionDescription.tsx
+++ b/src/components/BrokenConnectionDescription.tsx
@@ -1,12 +1,13 @@
import React from 'react';
import type {OnyxEntry} from 'react-native-onyx';
+import {useOnyx} from 'react-native-onyx';
import useLocalize from '@hooks/useLocalize';
import useThemeStyles from '@hooks/useThemeStyles';
import {isInstantSubmitEnabled, isPolicyAdmin as isPolicyAdminPolicyUtils} from '@libs/PolicyUtils';
import {isCurrentUserSubmitter, isProcessingReport, isReportApproved, isReportManuallyReimbursed} from '@libs/ReportUtils';
-import {getTransactionViolations} from '@libs/TransactionUtils';
import Navigation from '@navigation/Navigation';
import CONST from '@src/CONST';
+import ONYXKEYS from '@src/ONYXKEYS';
import ROUTES from '@src/ROUTES';
import type {Policy, Report} from '@src/types/onyx';
import TextLink from './TextLink';
@@ -14,6 +15,7 @@ import TextLink from './TextLink';
type BrokenConnectionDescriptionProps = {
/** Transaction id of the corresponding report */
transactionID: string | undefined;
+
/** Current report */
report: OnyxEntry;
@@ -24,7 +26,7 @@ type BrokenConnectionDescriptionProps = {
function BrokenConnectionDescription({transactionID, policy, report}: BrokenConnectionDescriptionProps) {
const styles = useThemeStyles();
const {translate} = useLocalize();
- const transactionViolations = getTransactionViolations(transactionID);
+ const [transactionViolations] = useOnyx(`${ONYXKEYS.COLLECTION.TRANSACTION_VIOLATIONS}${transactionID ?? CONST.DEFAULT_NUMBER_ID}`);
const brokenConnection530Error = transactionViolations?.find((violation) => violation.data?.rterType === CONST.RTER_VIOLATION_TYPES.BROKEN_CARD_CONNECTION_530);
const brokenConnectionError = transactionViolations?.find((violation) => violation.data?.rterType === CONST.RTER_VIOLATION_TYPES.BROKEN_CARD_CONNECTION);
@@ -44,12 +46,7 @@ function BrokenConnectionDescription({transactionID, policy, report}: BrokenConn
{`${translate('violations.adminBrokenConnectionError')}`}
{
- if (!policy?.id) {
- return;
- }
- Navigation.navigate(ROUTES.WORKSPACE_COMPANY_CARDS.getRoute(policy?.id));
- }}
+ onPress={() => Navigation.navigate(ROUTES.WORKSPACE_COMPANY_CARDS.getRoute(policy?.id))}
>{`${translate('workspace.common.companyCards')}`}
.
>
diff --git a/src/components/MoneyRequestHeader.tsx b/src/components/MoneyRequestHeader.tsx
index 0d0e862f36f5..268ab770059e 100644
--- a/src/components/MoneyRequestHeader.tsx
+++ b/src/components/MoneyRequestHeader.tsx
@@ -8,7 +8,6 @@ import useLocalize from '@hooks/useLocalize';
import useResponsiveLayout from '@hooks/useResponsiveLayout';
import useTheme from '@hooks/useTheme';
import useThemeStyles from '@hooks/useThemeStyles';
-import {markAsCash as markAsCashUtil} from '@libs/actions/Transaction';
import Navigation from '@libs/Navigation/Navigation';
import {isPolicyAdmin} from '@libs/PolicyUtils';
import {getOriginalMessage, isMoneyRequestAction} from '@libs/ReportActionsUtils';
@@ -26,6 +25,7 @@ import {
shouldShowBrokenConnectionViolation as shouldShowBrokenConnectionViolationTransactionUtils,
} from '@libs/TransactionUtils';
import variables from '@styles/variables';
+import {markAsCash as markAsCashAction} from '@userActions/Transaction';
import CONST from '@src/CONST';
import ONYXKEYS from '@src/ONYXKEYS';
import ROUTES from '@src/ROUTES';
@@ -61,12 +61,13 @@ function MoneyRequestHeader({report, parentReportAction, policy, onBackButtonPre
// eslint-disable-next-line rulesdir/prefer-shouldUseNarrowLayout-instead-of-isSmallScreenWidth
const {shouldUseNarrowLayout, isSmallScreenWidth} = useResponsiveLayout();
const route = useRoute();
- const [parentReport] = useOnyx(`${ONYXKEYS.COLLECTION.REPORT}${report?.parentReportID ?? CONST.DEFAULT_NUMBER_ID}`);
+ const [parentReport] = useOnyx(`${ONYXKEYS.COLLECTION.REPORT}${report?.parentReportID}`);
const [transaction] = useOnyx(
`${ONYXKEYS.COLLECTION.TRANSACTION}${
isMoneyRequestAction(parentReportAction) ? getOriginalMessage(parentReportAction)?.IOUTransactionID ?? CONST.DEFAULT_NUMBER_ID : CONST.DEFAULT_NUMBER_ID
}`,
);
+ const [transactionViolations] = useOnyx(ONYXKEYS.COLLECTION.TRANSACTION_VIOLATIONS);
const [dismissedHoldUseExplanation, dismissedHoldUseExplanationResult] = useOnyx(ONYXKEYS.NVP_DISMISSED_HOLD_USE_EXPLANATION, {initialValue: true});
const [isLoadingReportData] = useOnyx(ONYXKEYS.IS_LOADING_REPORT_DATA);
const isLoadingHoldUseExplained = isLoadingOnyxValue(dismissedHoldUseExplanationResult);
@@ -87,7 +88,7 @@ function MoneyRequestHeader({report, parentReportAction, policy, onBackButtonPre
const shouldShowMarkAsCashButton = hasAllPendingRTERViolations || (shouldShowBrokenConnectionViolation && (!isPolicyAdmin(policy) || isCurrentUserSubmitter(parentReport?.reportID)));
const markAsCash = useCallback(() => {
- markAsCashUtil(transaction?.transactionID, reportID);
+ markAsCashAction(transaction?.transactionID, reportID);
}, [reportID, transaction?.transactionID]);
const isScanning = hasReceipt(transaction) && isReceiptBeingScanned(transaction);
@@ -121,7 +122,7 @@ function MoneyRequestHeader({report, parentReportAction, policy, onBackButtonPre
),
};
}
- if (hasPendingRTERViolation(getTransactionViolations(transaction?.transactionID))) {
+ if (hasPendingRTERViolation(getTransactionViolations(transaction?.transactionID, transactionViolations))) {
return {icon: getStatusIcon(Expensicons.Hourglass), description: translate('iou.pendingMatchWithCreditCardDescription')};
}
if (isScanning) {
diff --git a/src/components/ReportActionItem/MoneyRequestPreview/MoneyRequestPreviewContent.tsx b/src/components/ReportActionItem/MoneyRequestPreview/MoneyRequestPreviewContent.tsx
index c70bda657e67..e20fe09058e1 100644
--- a/src/components/ReportActionItem/MoneyRequestPreview/MoneyRequestPreviewContent.tsx
+++ b/src/components/ReportActionItem/MoneyRequestPreview/MoneyRequestPreviewContent.tsx
@@ -112,8 +112,7 @@ function MoneyRequestPreviewContent({
const transactionID = isMoneyRequestAction ? getOriginalMessage(action)?.IOUTransactionID : undefined;
const [transaction] = useOnyx(`${ONYXKEYS.COLLECTION.TRANSACTION}${transactionID}`);
const [walletTerms] = useOnyx(ONYXKEYS.WALLET_TERMS);
- const [allViolations] = useOnyx(ONYXKEYS.COLLECTION.TRANSACTION_VIOLATIONS);
- const transactionViolations = getTransactionViolations(transaction?.transactionID);
+ const [transactionViolations] = useOnyx(ONYXKEYS.COLLECTION.TRANSACTION_VIOLATIONS);
const sessionAccountID = session?.accountID;
const managerID = iouReport?.managerID ?? CONST.DEFAULT_NUMBER_ID;
@@ -146,9 +145,9 @@ function MoneyRequestPreviewContent({
const isOnHold = isOnHoldTransactionUtils(transaction);
const isSettlementOrApprovalPartial = !!iouReport?.pendingFields?.partial;
const isPartialHold = isSettlementOrApprovalPartial && isOnHold;
- const hasViolations = hasViolationTransactionUtils(transaction?.transactionID, allViolations, true);
- const hasNoticeTypeViolations = hasNoticeTypeViolationTransactionUtils(transaction?.transactionID, allViolations, true) && isPaidGroupPolicy(iouReport);
- const hasWarningTypeViolations = hasWarningTypeViolationTransactionUtils(transaction?.transactionID, allViolations, true);
+ const hasViolations = hasViolationTransactionUtils(transaction?.transactionID, transactionViolations, true);
+ const hasNoticeTypeViolations = hasNoticeTypeViolationTransactionUtils(transaction?.transactionID, transactionViolations, true) && isPaidGroupPolicy(iouReport);
+ const hasWarningTypeViolations = hasWarningTypeViolationTransactionUtils(transaction?.transactionID, transactionViolations, true);
const hasFieldErrors = hasMissingSmartscanFields(transaction);
const isDistanceRequest = isDistanceRequestTransactionUtils(transaction);
const isPerDiemRequest = isPerDiemRequestTransactionUtils(transaction);
@@ -164,8 +163,11 @@ function MoneyRequestPreviewContent({
// Get transaction violations for given transaction id from onyx, find duplicated transactions violations and get duplicates
const allDuplicates = useMemo(
- () => transactionViolations?.find((violation) => violation.name === CONST.VIOLATIONS.DUPLICATED_TRANSACTION)?.data?.duplicates ?? [],
- [transactionViolations],
+ () =>
+ transactionViolations?.[`${ONYXKEYS.COLLECTION.TRANSACTION_VIOLATIONS}${transaction?.transactionID}`]?.find(
+ (violation) => violation.name === CONST.VIOLATIONS.DUPLICATED_TRANSACTION,
+ )?.data?.duplicates ?? [],
+ [transaction?.transactionID, transactionViolations],
);
// Remove settled transactions from duplicates
@@ -238,13 +240,14 @@ function MoneyRequestPreviewContent({
}
if (shouldShowRBR && transaction) {
+ const violations = getTransactionViolations(transaction.transactionID, transactionViolations);
if (shouldShowHoldMessage) {
return `${message} ${CONST.DOT_SEPARATOR} ${translate('violations.hold')}`;
}
- const firstViolation = transactionViolations?.at(0);
+ const firstViolation = violations?.at(0);
if (firstViolation) {
const violationMessage = ViolationsUtils.getViolationTranslation(firstViolation, translate);
- const violationsCount = transactionViolations?.filter((v) => v.type === CONST.VIOLATION_TYPES.VIOLATION).length ?? 0;
+ const violationsCount = violations?.filter((v) => v.type === CONST.VIOLATION_TYPES.VIOLATION).length ?? 0;
const isTooLong = violationsCount > 1 || violationMessage.length > 15;
const hasViolationsAndFieldErrors = violationsCount > 0 && hasFieldErrors;
@@ -284,7 +287,7 @@ function MoneyRequestPreviewContent({
if (shouldShowBrokenConnectionViolation(transaction ? [transaction.transactionID] : [], iouReport, policy)) {
return {shouldShow: true, messageIcon: Expensicons.Hourglass, messageDescription: translate('violations.brokenConnection530Error')};
}
- if (hasPendingUI(transaction, transactionViolations)) {
+ if (hasPendingUI(transaction, getTransactionViolations(transaction?.transactionID, transactionViolations))) {
return {shouldShow: true, messageIcon: Expensicons.Hourglass, messageDescription: translate('iou.pendingMatchWithCreditCard')};
}
return {shouldShow: false};
diff --git a/src/components/ReportActionItem/MoneyRequestView.tsx b/src/components/ReportActionItem/MoneyRequestView.tsx
index 54f3a8b6907f..10c72dbd8841 100644
--- a/src/components/ReportActionItem/MoneyRequestView.tsx
+++ b/src/components/ReportActionItem/MoneyRequestView.tsx
@@ -49,7 +49,6 @@ import {
getDistanceInMeters,
getTagForDisplay,
getTaxName,
- getTransactionViolations,
hasMissingSmartscanFields,
hasReceipt as hasReceiptTransactionUtils,
hasReservationList,
@@ -134,7 +133,7 @@ function MoneyRequestView({report, shouldShowAnimatedBackground, readonly = fals
const [transaction] = useOnyx(`${ONYXKEYS.COLLECTION.TRANSACTION}${linkedTransactionID ?? CONST.DEFAULT_NUMBER_ID}`);
const [transactionBackup] = useOnyx(`${ONYXKEYS.COLLECTION.TRANSACTION_BACKUP}${linkedTransactionID ?? CONST.DEFAULT_NUMBER_ID}`);
- const transactionViolations = getTransactionViolations(linkedTransactionID);
+ const [transactionViolations] = useOnyx(`${ONYXKEYS.COLLECTION.TRANSACTION_VIOLATIONS}${linkedTransactionID ?? CONST.DEFAULT_NUMBER_ID}`);
const {
created: transactionDate,
@@ -699,7 +698,7 @@ function MoneyRequestView({report, shouldShowAnimatedBackground, readonly = fals
{shouldShowTax && (
({...getThumbnailAndImageURIs(transaction), transaction}));
const transactionIDList = transactions?.map((reportTransaction) => reportTransaction.transactionID) ?? [];
- const showRTERViolationMessage = numberOfRequests === 1 && hasPendingUI(lastTransaction, getTransactionViolations(lastTransaction?.transactionID));
+ const showRTERViolationMessage = numberOfRequests === 1 && hasPendingUI(lastTransaction, getTransactionViolations(lastTransaction?.transactionID, transactionViolations));
const shouldShowBrokenConnectionViolation = numberOfRequests === 1 && shouldShowBrokenConnectionViolationTransactionUtils(transactionIDList, iouReport, policy);
let formattedMerchant = numberOfRequests === 1 ? getMerchant(lastTransaction) : null;
const formattedDescription = numberOfRequests === 1 ? getDescription(lastTransaction) : null;
@@ -250,7 +250,7 @@ function ReportPreview({
const isArchived = isArchivedReportWithID(iouReport?.reportID);
const isAdmin = policy?.role === CONST.POLICY.ROLE.ADMIN;
const filteredTransactions = transactions?.filter((transaction) => transaction) ?? [];
- const shouldShowSubmitButton = canSubmitReport(iouReport, policy, filteredTransactions);
+ const shouldShowSubmitButton = canSubmitReport(iouReport, policy, filteredTransactions, transactionViolations);
const shouldDisableSubmitButton = shouldShowSubmitButton && !isAllowedToSubmitDraftExpenseReport(iouReport);
diff --git a/src/libs/ReportActionsUtils.ts b/src/libs/ReportActionsUtils.ts
index b959479d8e63..e6f9810ab336 100644
--- a/src/libs/ReportActionsUtils.ts
+++ b/src/libs/ReportActionsUtils.ts
@@ -1614,9 +1614,9 @@ function wasActionTakenByCurrentUser(reportAction: OnyxInputOrEntry {
- if (!reportID || !transactionID) {
- return undefined;
+function getIOUActionForReportID(reportID: string | undefined, transactionID: string): OnyxEntry {
+ if (!reportID) {
+ return;
}
const report = allReports?.[`${ONYXKEYS.COLLECTION.REPORT}${reportID}`];
const reportActions = getAllReportActions(report?.reportID);
diff --git a/src/libs/ReportUtils.ts b/src/libs/ReportUtils.ts
index e95b41e755f0..1c6326f51bcb 100644
--- a/src/libs/ReportUtils.ts
+++ b/src/libs/ReportUtils.ts
@@ -1043,6 +1043,20 @@ function isInvoiceReport(report: OnyxInputOrEntry | SearchReport): boole
return report?.type === CONST.REPORT.TYPE.INVOICE;
}
+/**
+ * Checks if the report with supplied ID has been approved or not
+ */
+function isReportIDApproved(reportID: string | undefined) {
+ if (!reportID) {
+ return;
+ }
+ const report = getReport(reportID);
+ if (!report) {
+ return;
+ }
+ return isReportApproved(report);
+}
+
/**
* Checks if a report is an Expense report.
*/
@@ -9159,6 +9173,7 @@ export {
isPolicyExpenseChat,
isPolicyExpenseChatAdmin,
isProcessingReport,
+ isReportIDApproved,
isAwaitingFirstLevelApproval,
isPublicAnnounceRoom,
isPublicRoom,
diff --git a/src/libs/SearchUIUtils.ts b/src/libs/SearchUIUtils.ts
index 51f8e9428bdb..f47a0d56001d 100644
--- a/src/libs/SearchUIUtils.ts
+++ b/src/libs/SearchUIUtils.ts
@@ -340,7 +340,7 @@ function getAction(data: OnyxTypes.SearchResults['data'], key: string): SearchTr
}
// We check for isAllowedToApproveExpenseReport because if the policy has preventSelfApprovals enabled, we disable the Submit action and in that case we want to show the View action instead
- if (canSubmitReport(report, policy, allReportTransactions) && isAllowedToApproveExpenseReport) {
+ if (canSubmitReport(report, policy, allReportTransactions, allViolations) && isAllowedToApproveExpenseReport) {
return CONST.SEARCH.ACTION_TYPES.SUBMIT;
}
diff --git a/src/libs/TransactionUtils/index.ts b/src/libs/TransactionUtils/index.ts
index 474329bd6951..a8ffc240aa6f 100644
--- a/src/libs/TransactionUtils/index.ts
+++ b/src/libs/TransactionUtils/index.ts
@@ -766,11 +766,8 @@ function hasMissingSmartscanFields(transaction: OnyxInputOrEntry):
/**
* Get all transaction violations of the transaction with given tranactionID.
*/
-function getTransactionViolations(transactionID: string | undefined): TransactionViolations | null {
- if (!transactionID) {
- return null;
- }
- return allTransactionViolations?.[ONYXKEYS.COLLECTION.TRANSACTION_VIOLATIONS + transactionID]?.filter((violation) => !isViolationDismissed(transactionID, violation)) ?? null;
+function getTransactionViolations(transactionID: string | undefined, transactionViolations: OnyxCollection | null): TransactionViolations | null {
+ return transactionViolations?.[ONYXKEYS.COLLECTION.TRANSACTION_VIOLATIONS + transactionID] ?? null;
}
/**
@@ -789,8 +786,8 @@ function hasPendingRTERViolation(transactionViolations?: TransactionViolations |
/**
* Check if there is broken connection violation.
*/
-function hasBrokenConnectionViolation(transactionID?: string): boolean {
- const violations = getTransactionViolations(transactionID);
+function hasBrokenConnectionViolation(transactionID?: string, allViolations?: OnyxCollection): boolean {
+ const violations = getTransactionViolations(transactionID, allViolations ?? allTransactionViolations);
return !!violations?.find(
(violation) =>
violation.name === CONST.VIOLATIONS.RTER &&
@@ -801,8 +798,13 @@ function hasBrokenConnectionViolation(transactionID?: string): boolean {
/**
* Check if user should see broken connection violation warning.
*/
-function shouldShowBrokenConnectionViolation(transactionIDList: string[] | undefined, report: OnyxEntry | SearchReport, policy: OnyxEntry | SearchPolicy): boolean {
- const transactionsWithBrokenConnectionViolation = transactionIDList?.map((transactionID) => hasBrokenConnectionViolation(transactionID)) ?? [];
+function shouldShowBrokenConnectionViolation(
+ transactionIDList: string[] | undefined,
+ report: OnyxEntry | SearchReport,
+ policy: OnyxEntry | SearchPolicy,
+ allViolations?: OnyxCollection,
+): boolean {
+ const transactionsWithBrokenConnectionViolation = transactionIDList?.map((transactionID) => hasBrokenConnectionViolation(transactionID, allViolations)) ?? [];
return (
transactionsWithBrokenConnectionViolation.length > 0 &&
transactionsWithBrokenConnectionViolation?.some((value) => value === true) &&
@@ -813,9 +815,9 @@ function shouldShowBrokenConnectionViolation(transactionIDList: string[] | undef
/**
* Check if there is pending rter violation in all transactionViolations with given transactionIDs.
*/
-function allHavePendingRTERViolation(transactionIds: string[]): boolean {
+function allHavePendingRTERViolation(transactionIds: string[], allViolations?: OnyxCollection): boolean {
const transactionsWithRTERViolations = transactionIds.map((transactionId) => {
- const transactionViolations = getTransactionViolations(transactionId);
+ const transactionViolations = getTransactionViolations(transactionId, allViolations ?? allTransactionViolations);
return hasPendingRTERViolation(transactionViolations);
});
return transactionsWithRTERViolations.length > 0 && transactionsWithRTERViolations.every((value) => value === true);
@@ -906,20 +908,14 @@ function getRecentTransactions(transactions: Record, size = 2):
* @param checkDismissed - whether to check if the violation has already been dismissed as well
*/
function isDuplicate(transactionID: string | undefined, checkDismissed = false): boolean {
- if (!transactionID) {
- return false;
- }
- const duplicateViolation = allTransactionViolations?.[`${ONYXKEYS.COLLECTION.TRANSACTION_VIOLATIONS}${transactionID}`]?.find(
+ const hasDuplicatedViolation = !!allTransactionViolations?.[`${ONYXKEYS.COLLECTION.TRANSACTION_VIOLATIONS}${transactionID}`]?.some(
(violation: TransactionViolation) => violation.name === CONST.VIOLATIONS.DUPLICATED_TRANSACTION,
);
-
- const hasDuplicatedViolation = !!duplicateViolation;
if (!checkDismissed) {
- return !!duplicateViolation;
+ return hasDuplicatedViolation;
}
-
- const didDismissedViolation = isViolationDismissed(transactionID, duplicateViolation);
-
+ const didDismissedViolation =
+ allTransactions?.[`${ONYXKEYS.COLLECTION.TRANSACTION}${transactionID}`]?.comment?.dismissedViolations?.duplicatedTransaction?.[currentUserEmail] === `${currentUserAccountID}`;
return hasDuplicatedViolation && !didDismissedViolation;
}
@@ -945,32 +941,16 @@ function isOnHoldByTransactionID(transactionID: string | undefined | null): bool
return isOnHold(allTransactions?.[`${ONYXKEYS.COLLECTION.TRANSACTION}${transactionID}`]);
}
-/**
- * Checks if a violation is dismissed for the given transaction
- */
-function isViolationDismissed(transactionID: string | undefined, violation: TransactionViolation | undefined): boolean {
- if (!transactionID || !violation) {
- return false;
- }
- return allTransactions?.[`${ONYXKEYS.COLLECTION.TRANSACTION}${transactionID}`]?.comment?.dismissedViolations?.[violation.name]?.[currentUserEmail] === `${currentUserAccountID}`;
-}
-
/**
* Checks if any violations for the provided transaction are of type 'violation'
*/
function hasViolation(transactionID: string | undefined, transactionViolations: OnyxCollection, showInReview?: boolean): boolean {
- if (!transactionID) {
- return false;
- }
const transaction = getTransaction(transactionID);
if (isExpensifyCardTransaction(transaction) && isPending(transaction)) {
return false;
}
return !!transactionViolations?.[ONYXKEYS.COLLECTION.TRANSACTION_VIOLATIONS + transactionID]?.some(
- (violation: TransactionViolation) =>
- violation.type === CONST.VIOLATION_TYPES.VIOLATION &&
- (showInReview === undefined || showInReview === (violation.showInReview ?? false)) &&
- !isViolationDismissed(transactionID, violation),
+ (violation: TransactionViolation) => violation.type === CONST.VIOLATION_TYPES.VIOLATION && (showInReview === undefined || showInReview === (violation.showInReview ?? false)),
);
}
@@ -978,18 +958,12 @@ function hasViolation(transactionID: string | undefined, transactionViolations:
* Checks if any violations for the provided transaction are of type 'notice'
*/
function hasNoticeTypeViolation(transactionID: string | undefined, transactionViolations: OnyxCollection, showInReview?: boolean): boolean {
- if (!transactionID) {
- return false;
- }
const transaction = getTransaction(transactionID);
if (isExpensifyCardTransaction(transaction) && isPending(transaction)) {
return false;
}
return !!transactionViolations?.[ONYXKEYS.COLLECTION.TRANSACTION_VIOLATIONS + transactionID]?.some(
- (violation: TransactionViolation) =>
- violation.type === CONST.VIOLATION_TYPES.NOTICE &&
- (showInReview === undefined || showInReview === (violation.showInReview ?? false)) &&
- !isViolationDismissed(transactionID, violation),
+ (violation: TransactionViolation) => violation.type === CONST.VIOLATION_TYPES.NOTICE && (showInReview === undefined || showInReview === (violation.showInReview ?? false)),
);
}
@@ -997,9 +971,6 @@ function hasNoticeTypeViolation(transactionID: string | undefined, transactionVi
* Checks if any violations for the provided transaction are of type 'warning'
*/
function hasWarningTypeViolation(transactionID: string | undefined, transactionViolations: OnyxCollection, showInReview?: boolean): boolean {
- if (!transactionID) {
- return false;
- }
const transaction = getTransaction(transactionID);
if (isExpensifyCardTransaction(transaction) && isPending(transaction)) {
return false;
@@ -1007,10 +978,7 @@ function hasWarningTypeViolation(transactionID: string | undefined, transactionV
const violations = transactionViolations?.[ONYXKEYS.COLLECTION.TRANSACTION_VIOLATIONS + transactionID];
const warningTypeViolations =
violations?.filter(
- (violation: TransactionViolation) =>
- violation.type === CONST.VIOLATION_TYPES.WARNING &&
- (showInReview === undefined || showInReview === (violation.showInReview ?? false)) &&
- !isViolationDismissed(transactionID, violation),
+ (violation: TransactionViolation) => violation.type === CONST.VIOLATION_TYPES.WARNING && (showInReview === undefined || showInReview === (violation.showInReview ?? false)),
) ?? [];
const hasOnlyDupeDetectionViolation = warningTypeViolations?.every((violation: TransactionViolation) => violation.name === CONST.VIOLATIONS.DUPLICATED_TRANSACTION);
@@ -1483,7 +1451,6 @@ export {
getFormattedPostedDate,
getCategoryTaxCodeAndAmount,
isPerDiemRequest,
- isViolationDismissed,
};
export type {TransactionChanges};
diff --git a/src/libs/actions/IOU.ts b/src/libs/actions/IOU.ts
index 72c63789de2f..22a11941ef26 100644
--- a/src/libs/actions/IOU.ts
+++ b/src/libs/actions/IOU.ts
@@ -3854,7 +3854,7 @@ function updateMoneyRequestAttendees(
policy: OnyxEntry,
policyTagList: OnyxEntry,
policyCategories: OnyxEntry,
- violations?: OnyxEntry,
+ violations: OnyxEntry,
) {
const transactionChanges: TransactionChanges = {
attendees,
@@ -8011,14 +8011,15 @@ function canSubmitReport(
report: OnyxEntry | SearchReport,
policy: OnyxEntry | SearchPolicy,
transactions: OnyxTypes.Transaction[] | SearchTransaction[],
+ allViolations?: OnyxCollection,
) {
const currentUserAccountID = getCurrentUserAccountID();
const isOpenExpenseReport = isOpenExpenseReportReportUtils(report);
const isArchived = isArchivedReportWithID(report?.reportID);
const isAdmin = policy?.role === CONST.POLICY.ROLE.ADMIN;
const transactionIDList = transactions.map((transaction) => transaction.transactionID);
- const hasAllPendingRTERViolations = allHavePendingRTERViolation(transactionIDList);
- const hasBrokenConnectionViolation = shouldShowBrokenConnectionViolation(transactionIDList, report, policy);
+ const hasAllPendingRTERViolations = allHavePendingRTERViolation(transactionIDList, allViolations);
+ const hasBrokenConnectionViolation = shouldShowBrokenConnectionViolation(transactionIDList, report, policy, allViolations);
const hasOnlyPendingCardOrScanFailTransactions =
transactions.length > 0 &&
diff --git a/src/pages/Debug/Transaction/DebugTransactionViolations.tsx b/src/pages/Debug/Transaction/DebugTransactionViolations.tsx
index 5190d6c76e50..e13fd01fdcd7 100644
--- a/src/pages/Debug/Transaction/DebugTransactionViolations.tsx
+++ b/src/pages/Debug/Transaction/DebugTransactionViolations.tsx
@@ -1,4 +1,5 @@
import React from 'react';
+import {useOnyx} from 'react-native-onyx';
import Button from '@components/Button';
import PressableWithFeedback from '@components/Pressable/PressableWithFeedback';
import ScrollView from '@components/ScrollView';
@@ -6,7 +7,7 @@ import Text from '@components/Text';
import useLocalize from '@hooks/useLocalize';
import useThemeStyles from '@hooks/useThemeStyles';
import Navigation from '@libs/Navigation/Navigation';
-import {getTransactionViolations} from '@libs/TransactionUtils';
+import ONYXKEYS from '@src/ONYXKEYS';
import ROUTES from '@src/ROUTES';
import type {TransactionViolation} from '@src/types/onyx';
@@ -16,8 +17,7 @@ type DebugTransactionViolationsProps = {
};
function DebugTransactionViolations({transactionID}: DebugTransactionViolationsProps) {
- const transactionViolations = getTransactionViolations(transactionID);
-
+ const [transactionViolations] = useOnyx(`${ONYXKEYS.COLLECTION.TRANSACTION_VIOLATIONS}${transactionID}`);
const styles = useThemeStyles();
const {translate} = useLocalize();
diff --git a/src/pages/Debug/TransactionViolation/DebugTransactionViolationCreatePage.tsx b/src/pages/Debug/TransactionViolation/DebugTransactionViolationCreatePage.tsx
index 452925da8b86..b5f3d0d603d5 100644
--- a/src/pages/Debug/TransactionViolation/DebugTransactionViolationCreatePage.tsx
+++ b/src/pages/Debug/TransactionViolation/DebugTransactionViolationCreatePage.tsx
@@ -1,5 +1,6 @@
import React, {useCallback, useState} from 'react';
import {View} from 'react-native';
+import {useOnyx} from 'react-native-onyx';
import Button from '@components/Button';
import HeaderWithBackButton from '@components/HeaderWithBackButton';
import ScreenWrapper from '@components/ScreenWrapper';
@@ -9,11 +10,10 @@ import TextInput from '@components/TextInput';
import useLocalize from '@hooks/useLocalize';
import useThemeStyles from '@hooks/useThemeStyles';
import DebugUtils from '@libs/DebugUtils';
-import {canUseTouchScreen} from '@libs/DeviceCapabilities';
+import * as DeviceCapabilities from '@libs/DeviceCapabilities';
import Navigation from '@libs/Navigation/Navigation';
import type {PlatformStackScreenProps} from '@libs/Navigation/PlatformStackNavigation/types';
import type {DebugParamList} from '@libs/Navigation/types';
-import {getTransactionViolations} from '@libs/TransactionUtils';
import NotFoundPage from '@pages/ErrorPage/NotFoundPage';
import Debug from '@userActions/Debug';
import CONST from '@src/CONST';
@@ -62,7 +62,7 @@ function DebugTransactionViolationCreatePage({
}: DebugTransactionViolationCreatePageProps) {
const {translate} = useLocalize();
const styles = useThemeStyles();
- const transactionViolations = getTransactionViolations(transactionID);
+ const [transactionViolations] = useOnyx(`${ONYXKEYS.COLLECTION.TRANSACTION_VIOLATIONS}${transactionID}`);
const [draftTransactionViolation, setDraftTransactionViolation] = useState(() => getInitialTransactionViolation());
const [error, setError] = useState();
@@ -95,7 +95,7 @@ function DebugTransactionViolationCreatePage({
{({safeAreaPaddingBottomStyle}) => (
diff --git a/src/pages/Debug/TransactionViolation/DebugTransactionViolationPage.tsx b/src/pages/Debug/TransactionViolation/DebugTransactionViolationPage.tsx
index 1b26b0c5f72a..9db84c341d59 100644
--- a/src/pages/Debug/TransactionViolation/DebugTransactionViolationPage.tsx
+++ b/src/pages/Debug/TransactionViolation/DebugTransactionViolationPage.tsx
@@ -1,18 +1,18 @@
import React, {useCallback, useMemo} from 'react';
import {InteractionManager, View} from 'react-native';
+import {useOnyx} from 'react-native-onyx';
import HeaderWithBackButton from '@components/HeaderWithBackButton';
import ScreenWrapper from '@components/ScreenWrapper';
import useLocalize from '@hooks/useLocalize';
import useThemeStyles from '@hooks/useThemeStyles';
import Debug from '@libs/actions/Debug';
import DebugUtils from '@libs/DebugUtils';
-import {canUseTouchScreen} from '@libs/DeviceCapabilities';
+import * as DeviceCapabilities from '@libs/DeviceCapabilities';
import type {DebugTabNavigatorRoutes} from '@libs/Navigation/DebugTabNavigator';
import DebugTabNavigator from '@libs/Navigation/DebugTabNavigator';
import Navigation from '@libs/Navigation/Navigation';
import type {PlatformStackScreenProps} from '@libs/Navigation/PlatformStackNavigation/types';
import type {DebugParamList} from '@libs/Navigation/types';
-import {getTransactionViolations} from '@libs/TransactionUtils';
import DebugDetails from '@pages/Debug/DebugDetails';
import DebugJSON from '@pages/Debug/DebugJSON';
import NotFoundPage from '@pages/ErrorPage/NotFoundPage';
@@ -29,7 +29,7 @@ function DebugTransactionViolationPage({
},
}: DebugTransactionViolationPageProps) {
const {translate} = useLocalize();
- const transactionViolations = getTransactionViolations(transactionID);
+ const [transactionViolations] = useOnyx(`${ONYXKEYS.COLLECTION.TRANSACTION_VIOLATIONS}${transactionID}`);
const transactionViolation = useMemo(() => transactionViolations?.[Number(index)], [index, transactionViolations]);
const styles = useThemeStyles();
@@ -84,7 +84,7 @@ function DebugTransactionViolationPage({
{({safeAreaPaddingBottomStyle}) => (
diff --git a/src/pages/TransactionDuplicate/Review.tsx b/src/pages/TransactionDuplicate/Review.tsx
index 883b7e2d8031..93233588e122 100644
--- a/src/pages/TransactionDuplicate/Review.tsx
+++ b/src/pages/TransactionDuplicate/Review.tsx
@@ -10,13 +10,13 @@ import Text from '@components/Text';
import useCurrentUserPersonalDetails from '@hooks/useCurrentUserPersonalDetails';
import useLocalize from '@hooks/useLocalize';
import useThemeStyles from '@hooks/useThemeStyles';
-import {dismissDuplicateTransactionViolation} from '@libs/actions/Transaction';
import Navigation from '@libs/Navigation/Navigation';
import type {PlatformStackRouteProp} from '@libs/Navigation/PlatformStackNavigation/types';
import type {TransactionDuplicateNavigatorParamList} from '@libs/Navigation/types';
-import {getLinkedTransactionID, getReportAction} from '@libs/ReportActionsUtils';
-import {isReportApproved, isSettled} from '@libs/ReportUtils';
-import {getTransaction, getTransactionViolations} from '@libs/TransactionUtils';
+import * as ReportActionsUtils from '@libs/ReportActionsUtils';
+import * as ReportUtils from '@libs/ReportUtils';
+import * as TransactionUtils from '@libs/TransactionUtils';
+import * as Transaction from '@userActions/Transaction';
import CONST from '@src/CONST';
import ONYXKEYS from '@src/ONYXKEYS';
import type SCREENS from '@src/SCREENS';
@@ -28,24 +28,23 @@ function TransactionDuplicateReview() {
const route = useRoute>();
const currentPersonalDetails = useCurrentUserPersonalDetails();
const [report] = useOnyx(`${ONYXKEYS.COLLECTION.REPORT}${route.params.threadReportID}`);
- const reportAction = getReportAction(report?.parentReportID, report?.parentReportActionID);
- const transactionID = getLinkedTransactionID(reportAction, report?.reportID) ?? undefined;
- const transactionViolations = getTransactionViolations(transactionID);
-
+ const reportAction = ReportActionsUtils.getReportAction(report?.parentReportID ?? '-1', report?.parentReportActionID ?? '-1');
+ const transactionID = ReportActionsUtils.getLinkedTransactionID(reportAction, report?.reportID ?? '-1') ?? '-1';
+ const [transactionViolations] = useOnyx(`${ONYXKEYS.COLLECTION.TRANSACTION_VIOLATIONS}${transactionID}`);
const duplicateTransactionIDs = useMemo(
() => transactionViolations?.find((violation) => violation.name === CONST.VIOLATIONS.DUPLICATED_TRANSACTION)?.data?.duplicates ?? [],
[transactionViolations],
);
- const transactionIDs = transactionID ? [transactionID, ...duplicateTransactionIDs] : [...duplicateTransactionIDs];
+ const transactionIDs = [transactionID, ...duplicateTransactionIDs];
- const transactions = transactionIDs.map((item) => getTransaction(item)).sort((a, b) => new Date(a?.created ?? '').getTime() - new Date(b?.created ?? '').getTime());
+ const transactions = transactionIDs.map((item) => TransactionUtils.getTransaction(item)).sort((a, b) => new Date(a?.created ?? '').getTime() - new Date(b?.created ?? '').getTime());
const keepAll = () => {
- dismissDuplicateTransactionViolation(transactionIDs, currentPersonalDetails);
+ Transaction.dismissDuplicateTransactionViolation(transactionIDs, currentPersonalDetails);
Navigation.goBack();
};
- const hasSettledOrApprovedTransaction = transactions.some((transaction) => isSettled(transaction?.reportID) || isReportApproved(transaction?.reportID));
+ const hasSettledOrApprovedTransaction = transactions.some((transaction) => ReportUtils.isSettled(transaction?.reportID) || ReportUtils.isReportIDApproved(transaction?.reportID));
return (
diff --git a/src/pages/iou/request/step/IOURequestStepAttendees.tsx b/src/pages/iou/request/step/IOURequestStepAttendees.tsx
index 2e64e55fb8a1..409ef1cfe02d 100644
--- a/src/pages/iou/request/step/IOURequestStepAttendees.tsx
+++ b/src/pages/iou/request/step/IOURequestStepAttendees.tsx
@@ -4,10 +4,10 @@ import {useOnyx} from 'react-native-onyx';
import type {OnyxEntry} from 'react-native-onyx';
import useLocalize from '@hooks/useLocalize';
import usePrevious from '@hooks/usePrevious';
-import {setMoneyRequestAttendees, updateMoneyRequestAttendees} from '@libs/actions/IOU';
import Navigation from '@libs/Navigation/Navigation';
-import {getAttendees, getTransactionViolations} from '@libs/TransactionUtils';
+import * as TransactionUtils from '@libs/TransactionUtils';
import MoneyRequestAttendeeSelector from '@pages/iou/request/MoneyRequestAttendeeSelector';
+import * as IOU from '@userActions/IOU';
import CONST from '@src/CONST';
import ONYXKEYS from '@src/ONYXKEYS';
import type SCREENS from '@src/SCREENS';
@@ -39,20 +39,20 @@ function IOURequestStepAttendees({
policyCategories,
}: IOURequestStepAttendeesProps) {
const isEditing = action === CONST.IOU.ACTION.EDIT;
- const [transaction] = useOnyx(`${isEditing ? ONYXKEYS.COLLECTION.TRANSACTION : ONYXKEYS.COLLECTION.TRANSACTION_DRAFT}${transactionID || CONST.DEFAULT_NUMBER_ID}`);
- const [attendees, setAttendees] = useState(() => getAttendees(transaction));
+ const [transaction] = useOnyx(`${isEditing ? ONYXKEYS.COLLECTION.TRANSACTION : ONYXKEYS.COLLECTION.TRANSACTION_DRAFT}${transactionID || -1}`);
+ const [attendees, setAttendees] = useState(() => TransactionUtils.getAttendees(transaction));
const previousAttendees = usePrevious(attendees);
const {translate} = useLocalize();
- const violations = getTransactionViolations(transactionID);
+ const [violations] = useOnyx(`${ONYXKEYS.COLLECTION.TRANSACTION_VIOLATIONS}${transactionID}`);
const saveAttendees = useCallback(() => {
if (attendees.length <= 0) {
return;
}
if (!lodashIsEqual(previousAttendees, attendees)) {
- setMoneyRequestAttendees(transactionID, attendees, !isEditing);
+ IOU.setMoneyRequestAttendees(transactionID, attendees, !isEditing);
if (isEditing) {
- updateMoneyRequestAttendees(transactionID, reportID, attendees, policy, policyTags, policyCategories, violations ?? undefined);
+ IOU.updateMoneyRequestAttendees(transactionID, reportID, attendees, policy, policyTags, policyCategories, violations);
}
}
diff --git a/src/types/onyx/Transaction.ts b/src/types/onyx/Transaction.ts
index a573bce74e27..968b9a4dea4b 100644
--- a/src/types/onyx/Transaction.ts
+++ b/src/types/onyx/Transaction.ts
@@ -82,7 +82,7 @@ type Comment = {
splits?: Split[];
/** Violations that were dismissed */
- dismissedViolations?: Partial>>;
+ dismissedViolations?: Record>;
};
/** Model of transaction custom unit */
diff --git a/tests/unit/ViolationUtilsTest.ts b/tests/unit/ViolationUtilsTest.ts
index b161ea8fe40c..659240cc0c30 100644
--- a/tests/unit/ViolationUtilsTest.ts
+++ b/tests/unit/ViolationUtilsTest.ts
@@ -1,12 +1,9 @@
import {beforeEach} from '@jest/globals';
import Onyx from 'react-native-onyx';
-import {getTransactionViolations, hasWarningTypeViolation, isViolationDismissed} from '@libs/TransactionUtils';
import ViolationsUtils from '@libs/Violations/ViolationsUtils';
import CONST from '@src/CONST';
import ONYXKEYS from '@src/ONYXKEYS';
import type {Policy, PolicyCategories, PolicyTagLists, Transaction, TransactionViolation} from '@src/types/onyx';
-import type {TransactionCollectionDataSet} from '@src/types/onyx/Transaction';
-import type {TransactionViolationsCollectionDataSet} from '@src/types/onyx/TransactionViolation';
const categoryOutOfPolicyViolation = {
name: CONST.VIOLATIONS.CATEGORY_OUT_OF_POLICY,
@@ -33,16 +30,6 @@ const tagOutOfPolicyViolation = {
type: CONST.VIOLATION_TYPES.VIOLATION,
};
-const smartScanFailedViolation = {
- name: CONST.VIOLATIONS.SMARTSCAN_FAILED,
- type: CONST.VIOLATION_TYPES.WARNING,
-};
-
-const duplicatedTransactionViolation = {
- name: CONST.VIOLATIONS.DUPLICATED_TRANSACTION,
- type: CONST.VIOLATION_TYPES.WARNING,
-};
-
describe('getViolationsOnyxData', () => {
let transaction: Transaction;
let transactionViolations: TransactionViolation[];
@@ -362,91 +349,3 @@ describe('getViolationsOnyxData', () => {
});
});
});
-
-const getFakeTransaction = (transactionID: string, comment?: Transaction['comment']) => ({
- transactionID,
- attendees: [{email: 'text@expensify.com'}],
- reportID: '1234',
- amount: 100,
- comment: comment ?? {},
- created: '2023-07-24 13:46:20',
- merchant: 'United Airlines',
- currency: 'USD',
-});
-
-const CARLOS_EMAIL = 'cmartins@expensifail.com';
-const CARLOS_ACCOUNT_ID = 1;
-
-describe('getViolations', () => {
- beforeAll(() => {
- Onyx.init({
- keys: ONYXKEYS,
- initialKeyStates: {
- [ONYXKEYS.SESSION]: {
- email: CARLOS_EMAIL,
- accountID: CARLOS_ACCOUNT_ID,
- },
- },
- });
- });
-
- afterEach(() => Onyx.clear());
-
- it('should check if violation is dismissed or not', async () => {
- const transaction = getFakeTransaction('123', {
- dismissedViolations: {smartscanFailed: {[CARLOS_EMAIL]: CARLOS_ACCOUNT_ID.toString()}},
- });
-
- const transactionCollectionDataSet: TransactionCollectionDataSet = {
- [`${ONYXKEYS.COLLECTION.TRANSACTION}${transaction.transactionID}`]: transaction,
- };
-
- await Onyx.multiSet({...transactionCollectionDataSet});
-
- const isSmartScanDismissed = isViolationDismissed(transaction.transactionID, smartScanFailedViolation);
- const isDuplicateViolationDismissed = isViolationDismissed(transaction.transactionID, duplicatedTransactionViolation);
-
- expect(isSmartScanDismissed).toBeTruthy();
- expect(isDuplicateViolationDismissed).toBeFalsy();
- });
-
- it('should return filtered out dismissed violations', async () => {
- const transaction = getFakeTransaction('123', {
- dismissedViolations: {smartscanFailed: {[CARLOS_EMAIL]: CARLOS_ACCOUNT_ID.toString()}},
- });
-
- const transactionCollectionDataSet: TransactionCollectionDataSet = {
- [`${ONYXKEYS.COLLECTION.TRANSACTION}${transaction.transactionID}`]: transaction,
- };
-
- const transactionViolationsCollection: TransactionViolationsCollectionDataSet = {
- [`${ONYXKEYS.COLLECTION.TRANSACTION_VIOLATIONS}${transaction.transactionID}`]: [duplicatedTransactionViolation, smartScanFailedViolation, tagOutOfPolicyViolation],
- };
-
- await Onyx.multiSet({...transactionCollectionDataSet, ...transactionViolationsCollection});
-
- // Should filter out the smartScanFailedViolation
- const filteredViolations = getTransactionViolations(transaction.transactionID);
- expect(filteredViolations).toEqual([duplicatedTransactionViolation, tagOutOfPolicyViolation]);
- });
-
- it('checks if transaction has warning type violation after filtering dismissed violations', async () => {
- const transaction = getFakeTransaction('123', {
- dismissedViolations: {smartscanFailed: {[CARLOS_EMAIL]: CARLOS_ACCOUNT_ID.toString()}},
- });
-
- const transactionCollectionDataSet: TransactionCollectionDataSet = {
- [`${ONYXKEYS.COLLECTION.TRANSACTION}${transaction.transactionID}`]: transaction,
- };
-
- const transactionViolationsCollection = {
- [`${ONYXKEYS.COLLECTION.TRANSACTION_VIOLATIONS}${transaction.transactionID}`]: [duplicatedTransactionViolation, smartScanFailedViolation, tagOutOfPolicyViolation],
- };
-
- await Onyx.multiSet({...transactionCollectionDataSet});
-
- // Should filter out the smartScanFailedViolation and return true, duplicatedTransactionViolation is a warning type violation but it's not considered in hasWarningTypeViolation
- const hasWarningTypeViolationRes = hasWarningTypeViolation(transaction.transactionID, transactionViolationsCollection);
- expect(hasWarningTypeViolationRes).toBeFalsy();
- });
-});