diff --git a/src/libs/ReportUtils.ts b/src/libs/ReportUtils.ts index 585693e07a4e..4a68949b9466 100644 --- a/src/libs/ReportUtils.ts +++ b/src/libs/ReportUtils.ts @@ -2145,15 +2145,15 @@ function pushTransactionViolationsOnyxData( for (const {transactions, violations} of nonInvoiceReportTransactionsAndViolations) { for (const transaction of Object.values(transactions)) { const existingViolations = violations[`${ONYXKEYS.COLLECTION.TRANSACTION_VIOLATIONS}${transaction.transactionID}`]; - const optimisticViolations = ViolationsUtils.getViolationsOnyxData( - transaction, - existingViolations ?? [], - optimisticPolicy, - optimisticTagLists, - optimisticCategories, + const optimisticViolations = ViolationsUtils.getViolationsOnyxData({ + updatedTransaction: transaction, + transactionViolations: existingViolations ?? [], + policy: optimisticPolicy, + policyTagList: optimisticTagLists, + policyCategories: optimisticCategories, hasDependentTags, - false, - ); + isInvoiceTransaction: false, + }); if (!isEmptyObject(optimisticViolations)) { onyxData.optimisticData?.push(optimisticViolations); diff --git a/src/libs/Violations/ViolationsUtils.ts b/src/libs/Violations/ViolationsUtils.ts index 9d279e329c1a..e99ba60f3a09 100644 --- a/src/libs/Violations/ViolationsUtils.ts +++ b/src/libs/Violations/ViolationsUtils.ts @@ -339,18 +339,31 @@ const ViolationsUtils = { * Checks a transaction for policy violations and returns an object with Onyx method, key and updated transaction * violations. */ - getViolationsOnyxData( - updatedTransaction: Transaction, - transactionViolations: TransactionViolation[], - policy: Policy, - policyTagList: PolicyTagLists, - policyCategories: PolicyCategories, - hasDependentTags: boolean, - isInvoiceTransaction: boolean, - isSelfDM?: boolean, - iouReport?: OnyxEntry, - isFromExpenseReport?: boolean, - ): OnyxUpdate { + getViolationsOnyxData({ + updatedTransaction, + transactionViolations, + policy, + policyTagList, + policyCategories, + hasDependentTags, + isInvoiceTransaction, + isSelfDM, + iouReport, + isFromExpenseReport, + shouldRemoveRejectedExpenseViolation, + }: { + updatedTransaction: Transaction; + transactionViolations: TransactionViolation[]; + policy: Policy; + policyTagList: PolicyTagLists; + policyCategories: PolicyCategories; + hasDependentTags: boolean; + isInvoiceTransaction: boolean; + isSelfDM?: boolean; + iouReport?: OnyxEntry; + isFromExpenseReport?: boolean; + shouldRemoveRejectedExpenseViolation?: boolean; + }): OnyxUpdate { const isScanning = TransactionUtils.isScanning(updatedTransaction); const isScanRequest = TransactionUtils.isScanRequest(updatedTransaction); const isPartialTransaction = TransactionUtils.isPartialTransaction(updatedTransaction); @@ -364,8 +377,9 @@ const ViolationsUtils = { let newTransactionViolations = [...transactionViolations]; - // Remove AUTO_REPORTED_REJECTED_EXPENSE violation when the submitter edits the expense - if (iouReport && isFromExpenseReport && isCurrentUserSubmitter(iouReport)) { + // Remove AUTO_REPORTED_REJECTED_EXPENSE violation when the submitter edits the expense, when the transaction is moved to a different report, + // or when explicitly requested (e.g. from changeTransactionsReport) + if (shouldRemoveRejectedExpenseViolation || (iouReport && isFromExpenseReport && isCurrentUserSubmitter(iouReport))) { const hasRejectedExpenseViolation = newTransactionViolations.some((violation) => violation.name === CONST.VIOLATIONS.AUTO_REPORTED_REJECTED_EXPENSE); if (hasRejectedExpenseViolation) { newTransactionViolations = newTransactionViolations.filter((violation) => violation.name !== CONST.VIOLATIONS.AUTO_REPORTED_REJECTED_EXPENSE); diff --git a/src/libs/actions/IOU/BulkEdit.ts b/src/libs/actions/IOU/BulkEdit.ts index 102d8be1eeab..67319eba3f16 100644 --- a/src/libs/actions/IOU/BulkEdit.ts +++ b/src/libs/actions/IOU/BulkEdit.ts @@ -328,18 +328,18 @@ function updateMultipleMoneyRequests({ : optimisticViolations; const transactionPolicyTagList = policyTags?.[`${ONYXKEYS.COLLECTION.POLICY_TAGS}${transactionPolicy?.id}`] ?? {}; const transactionPolicyCategories = policyCategories?.[`${ONYXKEYS.COLLECTION.POLICY_CATEGORIES}${transactionPolicy?.id}`] ?? {}; - optimisticViolationsData = ViolationsUtils.getViolationsOnyxData( + optimisticViolationsData = ViolationsUtils.getViolationsOnyxData({ updatedTransaction, - optimisticViolations, - transactionPolicy, - transactionPolicyTagList, - transactionPolicyCategories, - hasDependentTags(transactionPolicy, transactionPolicyTagList), - isInvoiceReportReportUtils(iouReport), - isSelfDM(iouReport), + transactionViolations: optimisticViolations, + policy: transactionPolicy, + policyTagList: transactionPolicyTagList, + policyCategories: transactionPolicyCategories, + hasDependentTags: hasDependentTags(transactionPolicy, transactionPolicyTagList), + isInvoiceTransaction: isInvoiceReportReportUtils(iouReport), + isSelfDM: isSelfDM(iouReport), iouReport, isFromExpenseReport, - ); + }); optimisticData.push(optimisticViolationsData); failureData.push({ onyxMethod: Onyx.METHOD.MERGE, diff --git a/src/libs/actions/IOU/MoneyRequestBuilder.ts b/src/libs/actions/IOU/MoneyRequestBuilder.ts index 6033d2c4a747..b9a945eaf4b4 100644 --- a/src/libs/actions/IOU/MoneyRequestBuilder.ts +++ b/src/libs/actions/IOU/MoneyRequestBuilder.ts @@ -996,15 +996,15 @@ function buildOnyxDataForMoneyRequest(moneyRequestParams: BuildOnyxDataForMoneyR if (!policy || !isPaidGroupPolicy(policy) || transaction.reportID === CONST.REPORT.UNREPORTED_REPORT_ID) { return onyxData; } - const violationsOnyxData = ViolationsUtils.getViolationsOnyxData( - transaction, - [], + const violationsOnyxData = ViolationsUtils.getViolationsOnyxData({ + updatedTransaction: transaction, + transactionViolations: [], policy, - policyTagList ?? {}, - policyCategories ?? {}, - hasDependentTags(policy, policyTagList ?? {}), - false, - ); + policyTagList: policyTagList ?? {}, + policyCategories: policyCategories ?? {}, + hasDependentTags: hasDependentTags(policy, policyTagList ?? {}), + isInvoiceTransaction: false, + }); if (violationsOnyxData) { const reportTransactions = [...getReportTransactions(iou.report.reportID).filter((reportTransaction) => reportTransaction.transactionID !== transaction.transactionID), transaction]; diff --git a/src/libs/actions/IOU/Receipt.ts b/src/libs/actions/IOU/Receipt.ts index 27b3196315da..7f5ec6f61989 100644 --- a/src/libs/actions/IOU/Receipt.ts +++ b/src/libs/actions/IOU/Receipt.ts @@ -101,15 +101,15 @@ function detachReceipt( if (transactionPolicy && isPaidGroupPolicy(transactionPolicy) && newTransaction) { const currentTransactionViolations = allTransactionViolations[`${ONYXKEYS.COLLECTION.TRANSACTION_VIOLATIONS}${transactionID}`] ?? []; - const violationsOnyxData = ViolationsUtils.getViolationsOnyxData( - newTransaction, - currentTransactionViolations, - transactionPolicy, - transactionPolicyTagList ?? {}, - transactionPolicyCategories ?? {}, - hasDependentTags(transactionPolicy, transactionPolicyTagList ?? {}), - isInvoiceReportReportUtils(expenseReport), - ); + const violationsOnyxData = ViolationsUtils.getViolationsOnyxData({ + updatedTransaction: newTransaction, + transactionViolations: currentTransactionViolations, + policy: transactionPolicy, + policyTagList: transactionPolicyTagList ?? {}, + policyCategories: transactionPolicyCategories ?? {}, + hasDependentTags: hasDependentTags(transactionPolicy, transactionPolicyTagList ?? {}), + isInvoiceTransaction: isInvoiceReportReportUtils(expenseReport), + }); optimisticData.push(violationsOnyxData); failureData.push({ onyxMethod: Onyx.METHOD.MERGE, @@ -237,15 +237,15 @@ function replaceReceipt({transactionID, file, source, state, transactionPolicy, if (transactionPolicy && isPaidGroupPolicy(transactionPolicy) && newTransaction) { const currentTransactionViolations = allTransactionViolations[`${ONYXKEYS.COLLECTION.TRANSACTION_VIOLATIONS}${transactionID}`] ?? []; - const violationsOnyxData = ViolationsUtils.getViolationsOnyxData( - newTransaction, - currentTransactionViolations, - transactionPolicy, - transactionPolicyTagList ?? {}, - transactionPolicyCategories ?? {}, - hasDependentTags(transactionPolicy, transactionPolicyTagList ?? {}), - isInvoiceReportReportUtils(expenseReport), - ); + const violationsOnyxData = ViolationsUtils.getViolationsOnyxData({ + updatedTransaction: newTransaction, + transactionViolations: currentTransactionViolations, + policy: transactionPolicy, + policyTagList: transactionPolicyTagList ?? {}, + policyCategories: transactionPolicyCategories ?? {}, + hasDependentTags: hasDependentTags(transactionPolicy, transactionPolicyTagList ?? {}), + isInvoiceTransaction: isInvoiceReportReportUtils(expenseReport), + }); optimisticData.push(violationsOnyxData); failureData.push({ onyxMethod: Onyx.METHOD.MERGE, diff --git a/src/libs/actions/IOU/UpdateMoneyRequest.ts b/src/libs/actions/IOU/UpdateMoneyRequest.ts index c7f94fb7fbd5..f628f3a1bdf5 100644 --- a/src/libs/actions/IOU/UpdateMoneyRequest.ts +++ b/src/libs/actions/IOU/UpdateMoneyRequest.ts @@ -1540,18 +1540,18 @@ function getUpdateMoneyRequestParams(params: GetUpdateMoneyRequestParamsType): U ); } - const violationsOnyxData = ViolationsUtils.getViolationsOnyxData( + const violationsOnyxData = ViolationsUtils.getViolationsOnyxData({ updatedTransaction, - optimisticViolations, + transactionViolations: optimisticViolations, policy, - policyTagList ?? {}, - policyCategories ?? {}, - hasDependentTags(policy, policyTagList ?? {}), - isInvoice, - isSelfDM(iouReport), + policyTagList: policyTagList ?? {}, + policyCategories: policyCategories ?? {}, + hasDependentTags: hasDependentTags(policy, policyTagList ?? {}), + isInvoiceTransaction: isInvoice, + isSelfDM: isSelfDM(iouReport), iouReport, isFromExpenseReport, - ); + }); optimisticData.push(violationsOnyxData); failureData.push({ onyxMethod: Onyx.METHOD.MERGE, diff --git a/src/libs/actions/Transaction.ts b/src/libs/actions/Transaction.ts index 95629e1e9536..91825cda8dec 100644 --- a/src/libs/actions/Transaction.ts +++ b/src/libs/actions/Transaction.ts @@ -1270,15 +1270,16 @@ function changeTransactionsReport({ let transactionReimbursable = transaction.reimbursable; // 2. Calculate transaction violations if moving transaction to a workspace if (isPaidGroupPolicy(policy) && policy?.id) { - const violationData = ViolationsUtils.getViolationsOnyxData( - transactionForViolations, - currentTransactionViolations[transaction.transactionID] ?? [], + const violationData = ViolationsUtils.getViolationsOnyxData({ + updatedTransaction: transactionForViolations, + transactionViolations: currentTransactionViolations[transaction.transactionID] ?? [], policy, - policyTagList ?? {}, - policyCategories ?? {}, - policyHasDependentTags, - false, - ); + policyTagList: policyTagList ?? {}, + policyCategories: policyCategories ?? {}, + hasDependentTags: policyHasDependentTags, + isInvoiceTransaction: false, + shouldRemoveRejectedExpenseViolation: true, + }); optimisticData.push(violationData); failureData.push({ onyxMethod: Onyx.METHOD.MERGE, @@ -1668,15 +1669,15 @@ function changeTransactionsReport({ if (!isPaidGroupPolicy(policy) || !policy?.id) { continue; } - const violationData = ViolationsUtils.getViolationsOnyxData( - transaction, - currentTransactionViolations[transaction.transactionID] ?? [], + const violationData = ViolationsUtils.getViolationsOnyxData({ + updatedTransaction: transaction, + transactionViolations: currentTransactionViolations[transaction.transactionID] ?? [], policy, - policyTagList ?? {}, - policyCategories ?? {}, - policyHasDependentTags, - false, - ); + policyTagList: policyTagList ?? {}, + policyCategories: policyCategories ?? {}, + hasDependentTags: policyHasDependentTags, + isInvoiceTransaction: false, + }); if (Array.isArray(violationData.value) && hasSubmissionBlockingViolationInList(violationData.value)) { shouldFixViolations = true; } diff --git a/tests/unit/TransactionTest.ts b/tests/unit/TransactionTest.ts index 29a2e0249ab9..0603ce8f1855 100644 --- a/tests/unit/TransactionTest.ts +++ b/tests/unit/TransactionTest.ts @@ -18,7 +18,7 @@ import type {ReportCollectionDataSet} from '@src/types/onyx/Report'; import type {OnyxData} from '@src/types/onyx/Request'; import type {UpdateMoneyRequestDataKeys} from '../../src/libs/actions/IOU/UpdateMoneyRequest'; import * as TransactionUtils from '../../src/libs/TransactionUtils'; -import type {PersonalDetails, PolicyTagLists, RecentWaypoint, Report, ReportAction, ReportActions, Transaction} from '../../src/types/onyx'; +import type {PersonalDetails, Policy, PolicyTagLists, RecentWaypoint, Report, ReportAction, ReportActions, Transaction} from '../../src/types/onyx'; import createRandomPolicy from '../utils/collections/policies'; import createRandomPolicyCategories from '../utils/collections/policyCategory'; import {createExpenseReport, createRandomReport} from '../utils/collections/reports'; @@ -1336,6 +1336,50 @@ describe('Transaction', () => { expect(missingTagViolations.some((violation) => violation.data?.tagName === 'City')).toBe(true); }); + it('removes AUTO_REPORTED_REJECTED_EXPENSE from transaction violations when moving to a paid group policy', async () => { + const policyID = '1001'; + const transaction = generateTransaction({reportID: FAKE_OLD_REPORT_ID}); + const oldIOUAction = createIOUAction(transaction); + const newExpenseReport = { + ...createExpenseReport(Number(FAKE_NEW_REPORT_ID)), + policyID, + stateNum: CONST.REPORT.STATE_NUM.OPEN, + statusNum: CONST.REPORT.STATUS_NUM.OPEN, + ownerAccountID: CURRENT_USER_ID, + }; + const policy: Policy = { + ...createRandomPolicy(Number(policyID), CONST.POLICY.TYPE.TEAM), + requiresTag: false, + requiresCategory: false, + }; + + await Onyx.merge(`${ONYXKEYS.COLLECTION.TRANSACTION}${transaction.transactionID}`, transaction); + await Onyx.merge(`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${FAKE_OLD_REPORT_ID}`, {[oldIOUAction.reportActionID]: oldIOUAction}); + await Onyx.merge(`${ONYXKEYS.COLLECTION.TRANSACTION_VIOLATIONS}${transaction.transactionID}`, [ + {name: CONST.VIOLATIONS.AUTO_REPORTED_REJECTED_EXPENSE, type: CONST.VIOLATION_TYPES.VIOLATION, showInReview: true}, + ]); + await waitForBatchedUpdates(); + + const allTransactions = { + [`${ONYXKEYS.COLLECTION.TRANSACTION}${transaction.transactionID}`]: transaction, + }; + + changeTransactionsReport({ + transactionIDs: [transaction.transactionID], + isASAPSubmitBetaEnabled: false, + accountID: CURRENT_USER_ID, + email: 'test@example.com', + newReport: newExpenseReport, + policy, + allTransactions, + policyTagList: {}, + }); + await waitForBatchedUpdates(); + + const updatedViolations = await getOnyxValue(`${ONYXKEYS.COLLECTION.TRANSACTION_VIOLATIONS}${transaction.transactionID}`); + expect(updatedViolations?.some((violation) => violation.name === CONST.VIOLATIONS.AUTO_REPORTED_REJECTED_EXPENSE)).toBe(false); + }); + it('should auto-select a valid distance rate when moving a distance expense with an invalid P2P rate to a workspace', async () => { const policyID = '100'; const validRateID = 'valid_rate_1'; diff --git a/tests/unit/ViolationUtilsTest.ts b/tests/unit/ViolationUtilsTest.ts index 3e7004653e96..a88fc98354e5 100644 --- a/tests/unit/ViolationUtilsTest.ts +++ b/tests/unit/ViolationUtilsTest.ts @@ -134,7 +134,15 @@ describe('getViolationsOnyxData', () => { }); it('should return an object with correct shape and with empty transactionViolations array', () => { - const result = ViolationsUtils.getViolationsOnyxData(transaction, transactionViolations, policy, policyTags, policyCategories, false, false); + const result = ViolationsUtils.getViolationsOnyxData({ + updatedTransaction: transaction, + transactionViolations, + policy, + policyTagList: policyTags, + policyCategories, + hasDependentTags: false, + isInvoiceTransaction: false, + }); expect(result).toEqual({ onyxMethod: Onyx.METHOD.SET, @@ -151,7 +159,15 @@ describe('getViolationsOnyxData', () => { {name: 'duplicatedTransaction', type: CONST.VIOLATION_TYPES.VIOLATION}, {name: 'receiptRequired', type: CONST.VIOLATION_TYPES.VIOLATION}, ]; - const result = ViolationsUtils.getViolationsOnyxData(transaction, transactionViolations, policy, policyTags, policyCategories, false, false); + const result = ViolationsUtils.getViolationsOnyxData({ + updatedTransaction: transaction, + transactionViolations, + policy, + policyTagList: policyTags, + policyCategories, + hasDependentTags: false, + isInvoiceTransaction: false, + }); expect(result.value).toEqual(expect.arrayContaining(transactionViolations)); }); @@ -188,7 +204,15 @@ describe('getViolationsOnyxData', () => { }); it('should remove the customUnitOutOfPolicy violation if the modified one belongs to the policy', () => { - const result = ViolationsUtils.getViolationsOnyxData(transaction, transactionViolations, policy, policyTags, policyCategories, false, false); + const result = ViolationsUtils.getViolationsOnyxData({ + updatedTransaction: transaction, + transactionViolations, + policy, + policyTagList: policyTags, + policyCategories, + hasDependentTags: false, + isInvoiceTransaction: false, + }); expect(result.value).not.toContainEqual(customUnitOutOfPolicyViolation); }); @@ -213,7 +237,15 @@ describe('getViolationsOnyxData', () => { }, }, }; - const result = ViolationsUtils.getViolationsOnyxData(transaction, transactionViolations, policy, policyTags, policyCategories, false, false); + const result = ViolationsUtils.getViolationsOnyxData({ + updatedTransaction: transaction, + transactionViolations, + policy, + policyTagList: policyTags, + policyCategories, + hasDependentTags: false, + isInvoiceTransaction: false, + }); expect(result.value).toContainEqual(expect.objectContaining({name: CONST.VIOLATIONS.CUSTOM_UNIT_OUT_OF_POLICY})); }); @@ -252,7 +284,15 @@ describe('getViolationsOnyxData', () => { }); it('should remove the customUnitOutOfPolicy violation if the per diem rate is valid for the policy', () => { - const result = ViolationsUtils.getViolationsOnyxData(transaction, transactionViolations, policy, policyTags, policyCategories, false, false); + const result = ViolationsUtils.getViolationsOnyxData({ + updatedTransaction: transaction, + transactionViolations, + policy, + policyTagList: policyTags, + policyCategories, + hasDependentTags: false, + isInvoiceTransaction: false, + }); expect(result.value).not.toContainEqual(customUnitOutOfPolicyViolation); }); @@ -267,13 +307,29 @@ describe('getViolationsOnyxData', () => { it('should not add futureDate violation if the policy is not corporate', () => { transaction.created = '9999-12-31T23:59:59Z'; policy.type = 'personal'; - const result = ViolationsUtils.getViolationsOnyxData(transaction, transactionViolations, policy, policyTags, policyCategories, false, false); + const result = ViolationsUtils.getViolationsOnyxData({ + updatedTransaction: transaction, + transactionViolations, + policy, + policyTagList: policyTags, + policyCategories, + hasDependentTags: false, + isInvoiceTransaction: false, + }); expect(result.value).toEqual(transactionViolations); }); it('should add futureDate violation if the transaction has a future date and policy is corporate', () => { transaction.created = '9999-12-31T23:59:59Z'; - const result = ViolationsUtils.getViolationsOnyxData(transaction, transactionViolations, policy, policyTags, policyCategories, false, false); + const result = ViolationsUtils.getViolationsOnyxData({ + updatedTransaction: transaction, + transactionViolations, + policy, + policyTagList: policyTags, + policyCategories, + hasDependentTags: false, + isInvoiceTransaction: false, + }); expect(result.value).toEqual(expect.arrayContaining([futureDateViolation, ...transactionViolations])); }); @@ -281,14 +337,30 @@ describe('getViolationsOnyxData', () => { transaction.created = '9999-12-31T23:59:59Z'; policy.type = 'personal'; transactionViolations = [futureDateViolation]; - const result = ViolationsUtils.getViolationsOnyxData(transaction, transactionViolations, policy, policyTags, policyCategories, false, false); + const result = ViolationsUtils.getViolationsOnyxData({ + updatedTransaction: transaction, + transactionViolations, + policy, + policyTagList: policyTags, + policyCategories, + hasDependentTags: false, + isInvoiceTransaction: false, + }); expect(result.value).not.toContainEqual(futureDateViolation); }); it('should add receiptRequired violation if the transaction has no receipt', () => { transaction.amount = -1000000; policy.maxExpenseAmountNoReceipt = 2500; - const result = ViolationsUtils.getViolationsOnyxData(transaction, transactionViolations, policy, policyTags, policyCategories, false, false); + const result = ViolationsUtils.getViolationsOnyxData({ + updatedTransaction: transaction, + transactionViolations, + policy, + policyTagList: policyTags, + policyCategories, + hasDependentTags: false, + isInvoiceTransaction: false, + }); expect(result.value).toEqual(expect.arrayContaining([receiptRequiredViolation, ...transactionViolations])); }); @@ -296,14 +368,30 @@ describe('getViolationsOnyxData', () => { transaction.amount = -1000000; transaction.modifiedCurrency = CONST.CURRENCY.CAD; policy.maxExpenseAmountNoReceipt = 2500; - const result = ViolationsUtils.getViolationsOnyxData(transaction, transactionViolations, policy, policyTags, policyCategories, false, false); + const result = ViolationsUtils.getViolationsOnyxData({ + updatedTransaction: transaction, + transactionViolations, + policy, + policyTagList: policyTags, + policyCategories, + hasDependentTags: false, + isInvoiceTransaction: false, + }); expect(result.value).toEqual([]); }); it('should add overLimit violation if the transaction amount is over the policy limit', () => { transaction.amount = -1000000; policy.maxExpenseAmount = 200000; - const result = ViolationsUtils.getViolationsOnyxData(transaction, transactionViolations, policy, policyTags, policyCategories, false, false); + const result = ViolationsUtils.getViolationsOnyxData({ + updatedTransaction: transaction, + transactionViolations, + policy, + policyTagList: policyTags, + policyCategories, + hasDependentTags: false, + isInvoiceTransaction: false, + }); expect(result.value).toEqual(expect.arrayContaining([overLimitViolation, ...transactionViolations])); }); @@ -311,7 +399,15 @@ describe('getViolationsOnyxData', () => { transaction.amount = -1000000; transaction.modifiedCurrency = CONST.CURRENCY.NZD; policy.maxExpenseAmount = 200000; - const result = ViolationsUtils.getViolationsOnyxData(transaction, transactionViolations, policy, policyTags, policyCategories, false, false); + const result = ViolationsUtils.getViolationsOnyxData({ + updatedTransaction: transaction, + transactionViolations, + policy, + policyTagList: policyTags, + policyCategories, + hasDependentTags: false, + isInvoiceTransaction: false, + }); expect(result.value).toEqual([]); }); @@ -320,7 +416,15 @@ describe('getViolationsOnyxData', () => { policy.outputCurrency = CONST.CURRENCY.USD; transaction.amount = -10000; policy.maxExpenseAmountNoItemizedReceipt = 7500; - const result = ViolationsUtils.getViolationsOnyxData(transaction, transactionViolations, policy, policyTags, policyCategories, false, false); + const result = ViolationsUtils.getViolationsOnyxData({ + updatedTransaction: transaction, + transactionViolations, + policy, + policyTagList: policyTags, + policyCategories, + hasDependentTags: false, + isInvoiceTransaction: false, + }); const violations = result.value as TransactionViolation[]; const itemizedReceiptViolation = violations.find((v: TransactionViolation) => v.name === CONST.VIOLATIONS.ITEMIZED_RECEIPT_REQUIRED); expect(itemizedReceiptViolation).toBeDefined(); @@ -333,7 +437,15 @@ describe('getViolationsOnyxData', () => { transaction.amount = -10000; transaction.receipt = {state: CONST.IOU.RECEIPT_STATE.SCAN_READY, source: 'https://example.com/receipt.jpg'}; policy.maxExpenseAmountNoReceipt = 2500; - const result = ViolationsUtils.getViolationsOnyxData(transaction, transactionViolations, policy, policyTags, policyCategories, false, false); + const result = ViolationsUtils.getViolationsOnyxData({ + updatedTransaction: transaction, + transactionViolations, + policy, + policyTagList: policyTags, + policyCategories, + hasDependentTags: false, + isInvoiceTransaction: false, + }); const violations = result.value as TransactionViolation[]; const foundReceiptRequiredViolation = violations.find((v: TransactionViolation) => v.name === CONST.VIOLATIONS.RECEIPT_REQUIRED); expect(foundReceiptRequiredViolation).toBeUndefined(); @@ -345,7 +457,15 @@ describe('getViolationsOnyxData', () => { transaction.amount = -10000; policy.maxExpenseAmountNoReceipt = 2500; // Regular receipt required over $25 policy.maxExpenseAmountNoItemizedReceipt = 7500; // Itemized receipt required over $75 - const result = ViolationsUtils.getViolationsOnyxData(transaction, transactionViolations, policy, policyTags, policyCategories, false, false); + const result = ViolationsUtils.getViolationsOnyxData({ + updatedTransaction: transaction, + transactionViolations, + policy, + policyTagList: policyTags, + policyCategories, + hasDependentTags: false, + isInvoiceTransaction: false, + }); const violations = result.value as TransactionViolation[]; const receiptViolation = violations.find((v: TransactionViolation) => v.name === CONST.VIOLATIONS.RECEIPT_REQUIRED); const itemizedReceiptViolation = violations.find((v: TransactionViolation) => v.name === CONST.VIOLATIONS.ITEMIZED_RECEIPT_REQUIRED); @@ -360,7 +480,15 @@ describe('getViolationsOnyxData', () => { transaction.amount = -5000; transaction.receipt = {state: CONST.IOU.RECEIPT_STATE.SCAN_READY, source: 'https://example.com/receipt.jpg'}; policy.maxExpenseAmountNoItemizedReceipt = 7500; - const result = ViolationsUtils.getViolationsOnyxData(transaction, transactionViolations, policy, policyTags, policyCategories, false, false); + const result = ViolationsUtils.getViolationsOnyxData({ + updatedTransaction: transaction, + transactionViolations, + policy, + policyTagList: policyTags, + policyCategories, + hasDependentTags: false, + isInvoiceTransaction: false, + }); const violations = result.value as TransactionViolation[]; const itemizedReceiptViolation = violations.find((v: TransactionViolation) => v.name === CONST.VIOLATIONS.ITEMIZED_RECEIPT_REQUIRED); expect(itemizedReceiptViolation).toBeUndefined(); @@ -372,7 +500,15 @@ describe('getViolationsOnyxData', () => { transaction.amount = -10000; transaction.modifiedCurrency = CONST.CURRENCY.CAD; policy.maxExpenseAmountNoItemizedReceipt = 7500; - const result = ViolationsUtils.getViolationsOnyxData(transaction, transactionViolations, policy, policyTags, policyCategories, false, false); + const result = ViolationsUtils.getViolationsOnyxData({ + updatedTransaction: transaction, + transactionViolations, + policy, + policyTagList: policyTags, + policyCategories, + hasDependentTags: false, + isInvoiceTransaction: false, + }); const violations = result.value as TransactionViolation[]; const itemizedReceiptViolation = violations.find((v: TransactionViolation) => v.name === CONST.VIOLATIONS.ITEMIZED_RECEIPT_REQUIRED); expect(itemizedReceiptViolation).toBeUndefined(); @@ -399,14 +535,30 @@ describe('getViolationsOnyxData', () => { it('should add category specific violations', () => { policy.areRulesEnabled = true; - const result = ViolationsUtils.getViolationsOnyxData(transaction, transactionViolations, policy, policyTags, policyCategories, false, false); + const result = ViolationsUtils.getViolationsOnyxData({ + updatedTransaction: transaction, + transactionViolations, + policy, + policyTagList: policyTags, + policyCategories, + hasDependentTags: false, + isInvoiceTransaction: false, + }); expect(result.value).toEqual(expect.arrayContaining([categoryOverLimitViolation, categoryReceiptRequiredViolation, categoryMissingCommentViolation, ...transactionViolations])); }); it('should add category-level itemizedReceiptRequired violation when category is set to always', () => { policyCategories.Food.maxAmountNoItemizedReceipt = 0; // Category set to "Always" transaction.amount = -10000; - const result = ViolationsUtils.getViolationsOnyxData(transaction, transactionViolations, policy, policyTags, policyCategories, false, false); + const result = ViolationsUtils.getViolationsOnyxData({ + updatedTransaction: transaction, + transactionViolations, + policy, + policyTagList: policyTags, + policyCategories, + hasDependentTags: false, + isInvoiceTransaction: false, + }); const violations = result.value as TransactionViolation[]; const itemizedReceiptViolation = violations.find((v: TransactionViolation) => v.name === CONST.VIOLATIONS.ITEMIZED_RECEIPT_REQUIRED); expect(itemizedReceiptViolation).toBeDefined(); @@ -417,7 +569,15 @@ describe('getViolationsOnyxData', () => { policy.maxExpenseAmountNoItemizedReceipt = 7500; // Policy requires itemized receipt over $75 policyCategories.Food.maxAmountNoItemizedReceipt = CONST.DISABLED_MAX_EXPENSE_VALUE; // Category set to "Never" transaction.amount = -10000; // $100 expense - would trigger policy-level but category overrides - const result = ViolationsUtils.getViolationsOnyxData(transaction, transactionViolations, policy, policyTags, policyCategories, false, false); + const result = ViolationsUtils.getViolationsOnyxData({ + updatedTransaction: transaction, + transactionViolations, + policy, + policyTagList: policyTags, + policyCategories, + hasDependentTags: false, + isInvoiceTransaction: false, + }); const violations = result.value as TransactionViolation[]; const itemizedReceiptViolation = violations.find((v: TransactionViolation) => v.name === CONST.VIOLATIONS.ITEMIZED_RECEIPT_REQUIRED); expect(itemizedReceiptViolation).toBeUndefined(); // Category "Never" should override policy @@ -427,7 +587,15 @@ describe('getViolationsOnyxData', () => { policy.maxExpenseAmountNoItemizedReceipt = 7500; // Policy requires itemized receipt over $75 // policyCategories.Food.maxAmountNoItemizedReceipt is undefined (Default - follow policy) transaction.amount = -10000; // $100 expense - exceeds policy threshold - const result = ViolationsUtils.getViolationsOnyxData(transaction, transactionViolations, policy, policyTags, policyCategories, false, false); + const result = ViolationsUtils.getViolationsOnyxData({ + updatedTransaction: transaction, + transactionViolations, + policy, + policyTagList: policyTags, + policyCategories, + hasDependentTags: false, + isInvoiceTransaction: false, + }); const violations = result.value as TransactionViolation[]; const itemizedReceiptViolation = violations.find((v: TransactionViolation) => v.name === CONST.VIOLATIONS.ITEMIZED_RECEIPT_REQUIRED); expect(itemizedReceiptViolation).toBeDefined(); // Should follow policy threshold @@ -443,7 +611,15 @@ describe('getViolationsOnyxData', () => { const existingViolations: TransactionViolation[] = [{name: CONST.VIOLATIONS.ITEMIZED_RECEIPT_REQUIRED, type: CONST.VIOLATION_TYPES.VIOLATION, showInReview: true}]; // When the category is changed to "never require itemized receipt" - const result = ViolationsUtils.getViolationsOnyxData(transaction, existingViolations, policy, policyTags, policyCategories, false, false); + const result = ViolationsUtils.getViolationsOnyxData({ + updatedTransaction: transaction, + transactionViolations: existingViolations, + policy, + policyTagList: policyTags, + policyCategories, + hasDependentTags: false, + isInvoiceTransaction: false, + }); const violations = result.value as TransactionViolation[]; // Then the itemized violation should be removed and replaced with receiptRequired because the policy still requires receipts @@ -462,7 +638,15 @@ describe('getViolationsOnyxData', () => { ]; // When violations are recalculated after the policy threshold changed - const result = ViolationsUtils.getViolationsOnyxData(transaction, existingViolations, policy, policyTags, policyCategories, false, false); + const result = ViolationsUtils.getViolationsOnyxData({ + updatedTransaction: transaction, + transactionViolations: existingViolations, + policy, + policyTagList: policyTags, + policyCategories, + hasDependentTags: false, + isInvoiceTransaction: false, + }); const violations = result.value as TransactionViolation[]; // Then the violation should have updated threshold data to reflect the current policy settings @@ -480,7 +664,15 @@ describe('getViolationsOnyxData', () => { const existingViolations: TransactionViolation[] = [{name: CONST.VIOLATIONS.RECEIPT_REQUIRED, type: CONST.VIOLATION_TYPES.VIOLATION, showInReview: true}]; // When the category is changed to "always require itemized receipts" - const result = ViolationsUtils.getViolationsOnyxData(transaction, existingViolations, policy, policyTags, policyCategories, false, false); + const result = ViolationsUtils.getViolationsOnyxData({ + updatedTransaction: transaction, + transactionViolations: existingViolations, + policy, + policyTagList: policyTags, + policyCategories, + hasDependentTags: false, + isInvoiceTransaction: false, + }); const violations = result.value as TransactionViolation[]; // Then itemized should supersede receipt because itemized is more restrictive @@ -500,7 +692,15 @@ describe('getViolationsOnyxData', () => { const existingViolations: TransactionViolation[] = [{name: CONST.VIOLATIONS.ITEMIZED_RECEIPT_REQUIRED, type: CONST.VIOLATION_TYPES.VIOLATION, showInReview: true}]; // When the category is set to "never" for both receipt types - const result = ViolationsUtils.getViolationsOnyxData(transaction, existingViolations, policy, policyTags, policyCategories, false, false); + const result = ViolationsUtils.getViolationsOnyxData({ + updatedTransaction: transaction, + transactionViolations: existingViolations, + policy, + policyTagList: policyTags, + policyCategories, + hasDependentTags: false, + isInvoiceTransaction: false, + }); const violations = result.value as TransactionViolation[]; // Then no receipt violations should exist because category overrides take precedence over policy settings @@ -521,18 +721,42 @@ describe('getViolationsOnyxData', () => { it('should add missingCategory violation if no category is included', () => { transaction.category = undefined; - const result = ViolationsUtils.getViolationsOnyxData(transaction, transactionViolations, policy, policyTags, policyCategories, false, false); + const result = ViolationsUtils.getViolationsOnyxData({ + updatedTransaction: transaction, + transactionViolations, + policy, + policyTagList: policyTags, + policyCategories, + hasDependentTags: false, + isInvoiceTransaction: false, + }); expect(result.value).toEqual(expect.arrayContaining([missingCategoryViolation, ...transactionViolations])); }); it('should add categoryOutOfPolicy violation when category is not in policy', () => { transaction.category = 'Bananas'; - const result = ViolationsUtils.getViolationsOnyxData(transaction, transactionViolations, policy, policyTags, policyCategories, false, false); + const result = ViolationsUtils.getViolationsOnyxData({ + updatedTransaction: transaction, + transactionViolations, + policy, + policyTagList: policyTags, + policyCategories, + hasDependentTags: false, + isInvoiceTransaction: false, + }); expect(result.value).toEqual(expect.arrayContaining([categoryOutOfPolicyViolation, ...transactionViolations])); }); it('should not include a categoryOutOfPolicy violation when category is in policy', () => { - const result = ViolationsUtils.getViolationsOnyxData(transaction, transactionViolations, policy, policyTags, policyCategories, false, false); + const result = ViolationsUtils.getViolationsOnyxData({ + updatedTransaction: transaction, + transactionViolations, + policy, + policyTagList: policyTags, + policyCategories, + hasDependentTags: false, + isInvoiceTransaction: false, + }); expect(result.value).not.toContainEqual(categoryOutOfPolicyViolation); }); @@ -544,19 +768,43 @@ describe('getViolationsOnyxData', () => { category: undefined, receipt: {state: CONST.IOU.RECEIPT_STATE.SCANNING}, }; - const result = ViolationsUtils.getViolationsOnyxData(partialTransaction, transactionViolations, policy, policyTags, policyCategories, false, false); + const result = ViolationsUtils.getViolationsOnyxData({ + updatedTransaction: partialTransaction, + transactionViolations, + policy, + policyTagList: policyTags, + policyCategories, + hasDependentTags: false, + isInvoiceTransaction: false, + }); expect(result.value).not.toContainEqual(missingCategoryViolation); }); it('should not add categoryOutOfPolicy violation when category is Uncategorized', () => { transaction.category = 'Uncategorized'; - const result = ViolationsUtils.getViolationsOnyxData(transaction, transactionViolations, policy, policyTags, policyCategories, false, false); + const result = ViolationsUtils.getViolationsOnyxData({ + updatedTransaction: transaction, + transactionViolations, + policy, + policyTagList: policyTags, + policyCategories, + hasDependentTags: false, + isInvoiceTransaction: false, + }); expect(result.value).not.toContainEqual(categoryOutOfPolicyViolation); }); it('should not add categoryOutOfPolicy violation when category is none', () => { transaction.category = 'none'; - const result = ViolationsUtils.getViolationsOnyxData(transaction, transactionViolations, policy, policyTags, policyCategories, false, false); + const result = ViolationsUtils.getViolationsOnyxData({ + updatedTransaction: transaction, + transactionViolations, + policy, + policyTagList: policyTags, + policyCategories, + hasDependentTags: false, + isInvoiceTransaction: false, + }); expect(result.value).not.toContainEqual(categoryOutOfPolicyViolation); }); @@ -565,7 +813,15 @@ describe('getViolationsOnyxData', () => { transaction.amount = 1000000; transactionViolations = [{name: 'duplicatedTransaction', type: CONST.VIOLATION_TYPES.VIOLATION}]; - const result = ViolationsUtils.getViolationsOnyxData(transaction, transactionViolations, policy, policyTags, policyCategories, false, false); + const result = ViolationsUtils.getViolationsOnyxData({ + updatedTransaction: transaction, + transactionViolations, + policy, + policyTagList: policyTags, + policyCategories, + hasDependentTags: false, + isInvoiceTransaction: false, + }); expect(result.value).toEqual(expect.arrayContaining([categoryOutOfPolicyViolation, ...transactionViolations])); }); @@ -575,7 +831,15 @@ describe('getViolationsOnyxData', () => { transaction.amount = 1000000; transactionViolations = [{name: 'duplicatedTransaction', type: CONST.VIOLATION_TYPES.VIOLATION}]; - const result = ViolationsUtils.getViolationsOnyxData(transaction, transactionViolations, policy, policyTags, policyCategories, false, false); + const result = ViolationsUtils.getViolationsOnyxData({ + updatedTransaction: transaction, + transactionViolations, + policy, + policyTagList: policyTags, + policyCategories, + hasDependentTags: false, + isInvoiceTransaction: false, + }); expect(result.value).toEqual(expect.arrayContaining([missingCategoryViolation, ...transactionViolations])); }); @@ -590,7 +854,17 @@ describe('getViolationsOnyxData', () => { receipt: {state: CONST.IOU.RECEIPT_STATE.SCAN_FAILED}, }; const iouReport = {reportID: '1234', type: CONST.REPORT.TYPE.EXPENSE} as Report; - const result = ViolationsUtils.getViolationsOnyxData(partialTransaction, transactionViolations, policy, policyTags, policyCategories, false, false, false, iouReport); + const result = ViolationsUtils.getViolationsOnyxData({ + updatedTransaction: partialTransaction, + transactionViolations, + policy, + policyTagList: policyTags, + policyCategories, + hasDependentTags: false, + isInvoiceTransaction: false, + isSelfDM: false, + iouReport, + }); expect(result.value).toEqual( expect.arrayContaining([{name: CONST.VIOLATIONS.SMARTSCAN_FAILED, type: CONST.VIOLATION_TYPES.WARNING, showInReview: true}, missingCategoryViolation]), ); @@ -604,7 +878,15 @@ describe('getViolationsOnyxData', () => { iouRequestType: CONST.IOU.REQUEST_TYPE.SCAN, receipt: {state: CONST.IOU.RECEIPT_STATE.SCAN_FAILED}, }; - const result = ViolationsUtils.getViolationsOnyxData(transactionWithEnteredDetails, transactionViolations, policy, policyTags, policyCategories, false, false); + const result = ViolationsUtils.getViolationsOnyxData({ + updatedTransaction: transactionWithEnteredDetails, + transactionViolations, + policy, + policyTagList: policyTags, + policyCategories, + hasDependentTags: false, + isInvoiceTransaction: false, + }); expect(result.value).not.toContainEqual(expect.objectContaining({name: CONST.VIOLATIONS.SMARTSCAN_FAILED})); }); @@ -618,15 +900,15 @@ describe('getViolationsOnyxData', () => { iouRequestType: CONST.IOU.REQUEST_TYPE.SCAN, receipt: {state: CONST.IOU.RECEIPT_STATE.SCAN_FAILED}, }; - const result = ViolationsUtils.getViolationsOnyxData( - transactionWithModifiedDetails as unknown as Transaction, + const result = ViolationsUtils.getViolationsOnyxData({ + updatedTransaction: transactionWithModifiedDetails as unknown as Transaction, transactionViolations, policy, - policyTags, + policyTagList: policyTags, policyCategories, - false, - false, - ); + hasDependentTags: false, + isInvoiceTransaction: false, + }); expect(result.value).not.toContainEqual(expect.objectContaining({name: CONST.VIOLATIONS.SMARTSCAN_FAILED})); }); }); @@ -637,7 +919,15 @@ describe('getViolationsOnyxData', () => { }); it('should not add any violations when categories are not required', () => { - const result = ViolationsUtils.getViolationsOnyxData(transaction, transactionViolations, policy, policyTags, policyCategories, false, false); + const result = ViolationsUtils.getViolationsOnyxData({ + updatedTransaction: transaction, + transactionViolations, + policy, + policyTagList: policyTags, + policyCategories, + hasDependentTags: false, + isInvoiceTransaction: false, + }); expect(result.value).not.toContainEqual(categoryOutOfPolicyViolation); expect(result.value).not.toContainEqual(missingCategoryViolation); @@ -662,7 +952,15 @@ describe('getViolationsOnyxData', () => { }); it("shouldn't update the transactionViolations if the policy requires tags and the transaction has a tag from the policy", () => { - const result = ViolationsUtils.getViolationsOnyxData(transaction, transactionViolations, policy, policyTags, policyCategories, false, false); + const result = ViolationsUtils.getViolationsOnyxData({ + updatedTransaction: transaction, + transactionViolations, + policy, + policyTagList: policyTags, + policyCategories, + hasDependentTags: false, + isInvoiceTransaction: false, + }); expect(result.value).toEqual(transactionViolations); }); @@ -670,7 +968,15 @@ describe('getViolationsOnyxData', () => { it('should add a missingTag violation if none is provided and policy requires tags', () => { transaction.tag = undefined; - const result = ViolationsUtils.getViolationsOnyxData(transaction, transactionViolations, policy, policyTags, policyCategories, false, false); + const result = ViolationsUtils.getViolationsOnyxData({ + updatedTransaction: transaction, + transactionViolations, + policy, + policyTagList: policyTags, + policyCategories, + hasDependentTags: false, + isInvoiceTransaction: false, + }); expect(result.value).toEqual(expect.arrayContaining([{...missingTagViolation, showInReview: true, data: {tagName: 'Meals'}}])); }); @@ -679,7 +985,15 @@ describe('getViolationsOnyxData', () => { policyTags = {}; transaction.tag = undefined; - const result = ViolationsUtils.getViolationsOnyxData(transaction, transactionViolations, policy, policyTags, policyCategories, false, false); + const result = ViolationsUtils.getViolationsOnyxData({ + updatedTransaction: transaction, + transactionViolations, + policy, + policyTagList: policyTags, + policyCategories, + hasDependentTags: false, + isInvoiceTransaction: false, + }); expect(result.value).toEqual([]); }); @@ -689,7 +1003,15 @@ describe('getViolationsOnyxData', () => { transaction.tag = undefined; transactionViolations = [missingTagViolation, {name: 'duplicatedTransaction', type: CONST.VIOLATION_TYPES.VIOLATION}]; - const result = ViolationsUtils.getViolationsOnyxData(transaction, transactionViolations, policy, policyTags, policyCategories, false, false); + const result = ViolationsUtils.getViolationsOnyxData({ + updatedTransaction: transaction, + transactionViolations, + policy, + policyTagList: policyTags, + policyCategories, + hasDependentTags: false, + isInvoiceTransaction: false, + }); expect(result.value).toEqual([{name: 'duplicatedTransaction', type: CONST.VIOLATION_TYPES.VIOLATION}]); }); @@ -698,7 +1020,15 @@ describe('getViolationsOnyxData', () => { transaction.tag = ''; transactionViolations = [tagOutOfPolicyViolation, duplicatedTransactionViolation]; - const result = ViolationsUtils.getViolationsOnyxData(transaction, transactionViolations, policy, policyTags, policyCategories, false, false); + const result = ViolationsUtils.getViolationsOnyxData({ + updatedTransaction: transaction, + transactionViolations, + policy, + policyTagList: policyTags, + policyCategories, + hasDependentTags: false, + isInvoiceTransaction: false, + }); expect(result.value).not.toContainEqual(tagOutOfPolicyViolation); expect(result.value).toContainEqual(duplicatedTransactionViolation); @@ -710,7 +1040,15 @@ describe('getViolationsOnyxData', () => { transaction.tag = ''; transactionViolations = [tagOutOfPolicyViolation, duplicatedTransactionViolation]; - const result = ViolationsUtils.getViolationsOnyxData(transaction, transactionViolations, policy, policyTags, policyCategories, false, false); + const result = ViolationsUtils.getViolationsOnyxData({ + updatedTransaction: transaction, + transactionViolations, + policy, + policyTagList: policyTags, + policyCategories, + hasDependentTags: false, + isInvoiceTransaction: false, + }); expect(result.value).toEqual([duplicatedTransactionViolation]); }); @@ -723,7 +1061,15 @@ describe('getViolationsOnyxData', () => { tag: undefined, receipt: {state: CONST.IOU.RECEIPT_STATE.SCANNING}, }; - const result = ViolationsUtils.getViolationsOnyxData(partialTransaction, transactionViolations, policy, policyTags, policyCategories, false, false); + const result = ViolationsUtils.getViolationsOnyxData({ + updatedTransaction: partialTransaction, + transactionViolations, + policy, + policyTagList: policyTags, + policyCategories, + hasDependentTags: false, + isInvoiceTransaction: false, + }); expect(result.value).not.toContainEqual(missingTagViolation); }); @@ -731,7 +1077,15 @@ describe('getViolationsOnyxData', () => { transaction.tag = 'Bananas'; transactionViolations = [{name: 'duplicatedTransaction', type: CONST.VIOLATION_TYPES.VIOLATION}]; - const result = ViolationsUtils.getViolationsOnyxData(transaction, transactionViolations, policy, policyTags, policyCategories, false, false); + const result = ViolationsUtils.getViolationsOnyxData({ + updatedTransaction: transaction, + transactionViolations, + policy, + policyTagList: policyTags, + policyCategories, + hasDependentTags: false, + isInvoiceTransaction: false, + }); expect(result.value).toEqual(expect.arrayContaining([{...tagOutOfPolicyViolation, data: {tagName: 'Meals'}}, ...transactionViolations])); }); @@ -740,7 +1094,15 @@ describe('getViolationsOnyxData', () => { transaction.tag = undefined; transactionViolations = [{name: 'duplicatedTransaction', type: CONST.VIOLATION_TYPES.VIOLATION}]; - const result = ViolationsUtils.getViolationsOnyxData(transaction, transactionViolations, policy, policyTags, policyCategories, false, false); + const result = ViolationsUtils.getViolationsOnyxData({ + updatedTransaction: transaction, + transactionViolations, + policy, + policyTagList: policyTags, + policyCategories, + hasDependentTags: false, + isInvoiceTransaction: false, + }); expect(result.value).toEqual(expect.arrayContaining([{...missingTagViolation, showInReview: true, data: {tagName: 'Meals'}}, ...transactionViolations])); }); @@ -752,7 +1114,15 @@ describe('getViolationsOnyxData', () => { }); it('should not add any violations when tags are not required', () => { - const result = ViolationsUtils.getViolationsOnyxData(transaction, transactionViolations, policy, policyTags, policyCategories, false, false); + const result = ViolationsUtils.getViolationsOnyxData({ + updatedTransaction: transaction, + transactionViolations, + policy, + policyTagList: policyTags, + policyCategories, + hasDependentTags: false, + isInvoiceTransaction: false, + }); expect(result.value).not.toContainEqual(tagOutOfPolicyViolation); expect(result.value).not.toContainEqual(missingTagViolation); @@ -772,7 +1142,15 @@ describe('getViolationsOnyxData', () => { }; transaction.tag = 'Lunch'; - const result = ViolationsUtils.getViolationsOnyxData(transaction, transactionViolations, policy, policyTags, policyCategories, false, false); + const result = ViolationsUtils.getViolationsOnyxData({ + updatedTransaction: transaction, + transactionViolations, + policy, + policyTagList: policyTags, + policyCategories, + hasDependentTags: false, + isInvoiceTransaction: false, + }); expect(result.value).not.toContainEqual(tagOutOfPolicyViolation); }); @@ -792,7 +1170,15 @@ describe('getViolationsOnyxData', () => { transaction.tag = 'Lunch'; transactionViolations = [tagOutOfPolicyViolation, duplicatedTransactionViolation]; - const result = ViolationsUtils.getViolationsOnyxData(transaction, transactionViolations, policy, policyTags, policyCategories, false, false); + const result = ViolationsUtils.getViolationsOnyxData({ + updatedTransaction: transaction, + transactionViolations, + policy, + policyTagList: policyTags, + policyCategories, + hasDependentTags: false, + isInvoiceTransaction: false, + }); expect(result.value).not.toContainEqual(tagOutOfPolicyViolation); expect(result.value).toContainEqual(duplicatedTransactionViolation); @@ -849,31 +1235,71 @@ describe('getViolationsOnyxData', () => { }; // Test case where transaction has no tags - let result = ViolationsUtils.getViolationsOnyxData(transaction, transactionViolations, policy, policyTags, policyCategories, false, false); + let result = ViolationsUtils.getViolationsOnyxData({ + updatedTransaction: transaction, + transactionViolations, + policy, + policyTagList: policyTags, + policyCategories, + hasDependentTags: false, + isInvoiceTransaction: false, + }); expect(result.value).toEqual([someTagLevelsRequiredViolation]); // Test case where transaction has 1 tag transaction.tag = 'Africa'; someTagLevelsRequiredViolation.data = {errorIndexes: [1, 2]}; - result = ViolationsUtils.getViolationsOnyxData(transaction, transactionViolations, policy, policyTags, policyCategories, false, false); + result = ViolationsUtils.getViolationsOnyxData({ + updatedTransaction: transaction, + transactionViolations, + policy, + policyTagList: policyTags, + policyCategories, + hasDependentTags: false, + isInvoiceTransaction: false, + }); expect(result.value).toEqual([someTagLevelsRequiredViolation]); // Test case where transaction has 2 tags transaction.tag = 'Africa::Project1'; someTagLevelsRequiredViolation.data = {errorIndexes: [1]}; - result = ViolationsUtils.getViolationsOnyxData(transaction, transactionViolations, policy, policyTags, policyCategories, false, false); + result = ViolationsUtils.getViolationsOnyxData({ + updatedTransaction: transaction, + transactionViolations, + policy, + policyTagList: policyTags, + policyCategories, + hasDependentTags: false, + isInvoiceTransaction: false, + }); expect(result.value).toEqual([someTagLevelsRequiredViolation]); // Test case where transaction has all tags transaction.tag = 'Africa:Accounting:Project1'; - result = ViolationsUtils.getViolationsOnyxData(transaction, transactionViolations, policy, policyTags, policyCategories, false, false); + result = ViolationsUtils.getViolationsOnyxData({ + updatedTransaction: transaction, + transactionViolations, + policy, + policyTagList: policyTags, + policyCategories, + hasDependentTags: false, + isInvoiceTransaction: false, + }); expect(result.value).toEqual([]); }); it('should not return tagOutOfPolicy when the selected tag level has no enabled tags', () => { policyTags.Department.tags.Accounting.enabled = false; transaction.tag = 'Africa:Accounting:Project1'; - const result = ViolationsUtils.getViolationsOnyxData(transaction, transactionViolations, policy, policyTags, policyCategories, false, false); + const result = ViolationsUtils.getViolationsOnyxData({ + updatedTransaction: transaction, + transactionViolations, + policy, + policyTagList: policyTags, + policyCategories, + hasDependentTags: false, + isInvoiceTransaction: false, + }); expect(result.value).toEqual([]); }); @@ -886,7 +1312,15 @@ describe('getViolationsOnyxData', () => { policyTags.Department.tags.Accounting.enabled = false; transaction.tag = 'Africa:Accounting:Project1'; - const result = ViolationsUtils.getViolationsOnyxData(transaction, transactionViolations, policy, policyTags, policyCategories, false, false); + const result = ViolationsUtils.getViolationsOnyxData({ + updatedTransaction: transaction, + transactionViolations, + policy, + policyTagList: policyTags, + policyCategories, + hasDependentTags: false, + isInvoiceTransaction: false, + }); const violation = {...tagOutOfPolicyViolation, data: {tagName: 'Department'}}; expect(result.value).toEqual([violation]); @@ -897,7 +1331,15 @@ describe('getViolationsOnyxData', () => { policyTags.Project.tags.Project1.enabled = false; transaction.tag = 'Africa:Accounting:Project1'; - const result = ViolationsUtils.getViolationsOnyxData(transaction, transactionViolations, policy, policyTags, policyCategories, false, false); + const result = ViolationsUtils.getViolationsOnyxData({ + updatedTransaction: transaction, + transactionViolations, + policy, + policyTagList: policyTags, + policyCategories, + hasDependentTags: false, + isInvoiceTransaction: false, + }); expect(result.value).toEqual([]); }); @@ -908,7 +1350,15 @@ describe('getViolationsOnyxData', () => { transaction.tag = 'Africa::Project1'; // hasDependentTags = true to exercise getTagViolationsForDependentTags - const result = ViolationsUtils.getViolationsOnyxData(transaction, transactionViolations, policy, policyTags, policyCategories, true, false); + const result = ViolationsUtils.getViolationsOnyxData({ + updatedTransaction: transaction, + transactionViolations, + policy, + policyTagList: policyTags, + policyCategories, + hasDependentTags: true, + isInvoiceTransaction: false, + }); expect(result.value).not.toContainEqual(expect.objectContaining({name: CONST.VIOLATIONS.ALL_TAG_LEVELS_REQUIRED})); }); @@ -920,7 +1370,15 @@ describe('getViolationsOnyxData', () => { transaction.tag = 'Africa'; // hasDependentTags = true to exercise getTagViolationsForDependentTags - const result = ViolationsUtils.getViolationsOnyxData(transaction, transactionViolations, policy, policyTags, policyCategories, true, false); + const result = ViolationsUtils.getViolationsOnyxData({ + updatedTransaction: transaction, + transactionViolations, + policy, + policyTagList: policyTags, + policyCategories, + hasDependentTags: true, + isInvoiceTransaction: false, + }); expect(result.value).toContainEqual(expect.objectContaining({name: CONST.VIOLATIONS.ALL_TAG_LEVELS_REQUIRED})); }); @@ -930,7 +1388,15 @@ describe('getViolationsOnyxData', () => { const missingRegionTag = {...missingTagViolation, data: {tagName: 'Region'}}; const missingProjectTag = {...missingTagViolation, data: {tagName: 'Project'}}; transaction.tag = undefined; - const result = ViolationsUtils.getViolationsOnyxData(transaction, transactionViolations, policy, policyTags, policyCategories, true, false); + const result = ViolationsUtils.getViolationsOnyxData({ + updatedTransaction: transaction, + transactionViolations, + policy, + policyTagList: policyTags, + policyCategories, + hasDependentTags: true, + isInvoiceTransaction: false, + }); expect(result.value).toEqual(expect.arrayContaining([missingDepartmentTag, missingRegionTag, missingProjectTag])); }); }); @@ -966,7 +1432,17 @@ describe('getViolationsOnyxData', () => { it('should add missingAttendees violation when no attendees are present', () => { transaction.comment = {attendees: []}; - const result = ViolationsUtils.getViolationsOnyxData(transaction, transactionViolations, policy, policyTags, policyCategories, false, false, false, iouReport); + const result = ViolationsUtils.getViolationsOnyxData({ + updatedTransaction: transaction, + transactionViolations, + policy, + policyTagList: policyTags, + policyCategories, + hasDependentTags: false, + isInvoiceTransaction: false, + isSelfDM: false, + iouReport, + }); expect(result.value).toEqual(expect.arrayContaining([missingAttendeesViolation])); }); @@ -974,7 +1450,17 @@ describe('getViolationsOnyxData', () => { transaction.comment = { attendees: [{email: 'owner@example.com', displayName: 'Owner', avatarUrl: '', accountID: ownerAccountID}], }; - const result = ViolationsUtils.getViolationsOnyxData(transaction, transactionViolations, policy, policyTags, policyCategories, false, false, false, iouReport); + const result = ViolationsUtils.getViolationsOnyxData({ + updatedTransaction: transaction, + transactionViolations, + policy, + policyTagList: policyTags, + policyCategories, + hasDependentTags: false, + isInvoiceTransaction: false, + isSelfDM: false, + iouReport, + }); expect(result.value).toEqual(expect.arrayContaining([missingAttendeesViolation])); }); @@ -985,7 +1471,17 @@ describe('getViolationsOnyxData', () => { {email: 'other@example.com', displayName: 'Other', avatarUrl: '', accountID: otherAccountID}, ], }; - const result = ViolationsUtils.getViolationsOnyxData(transaction, transactionViolations, policy, policyTags, policyCategories, false, false, false, iouReport); + const result = ViolationsUtils.getViolationsOnyxData({ + updatedTransaction: transaction, + transactionViolations, + policy, + policyTagList: policyTags, + policyCategories, + hasDependentTags: false, + isInvoiceTransaction: false, + isSelfDM: false, + iouReport, + }); expect(result.value).not.toEqual(expect.arrayContaining([missingAttendeesViolation])); }); @@ -997,21 +1493,51 @@ describe('getViolationsOnyxData', () => { {email: 'other@example.com', displayName: 'Other', avatarUrl: '', accountID: otherAccountID}, ], }; - const result = ViolationsUtils.getViolationsOnyxData(transaction, transactionViolations, policy, policyTags, policyCategories, false, false, false, iouReport); + const result = ViolationsUtils.getViolationsOnyxData({ + updatedTransaction: transaction, + transactionViolations, + policy, + policyTagList: policyTags, + policyCategories, + hasDependentTags: false, + isInvoiceTransaction: false, + isSelfDM: false, + iouReport, + }); expect(result.value).not.toEqual(expect.arrayContaining([missingAttendeesViolation])); }); it('should not add missingAttendees violation when attendee tracking is disabled', () => { policy.isAttendeeTrackingEnabled = false; transaction.comment = {attendees: []}; - const result = ViolationsUtils.getViolationsOnyxData(transaction, transactionViolations, policy, policyTags, policyCategories, false, false, false, iouReport); + const result = ViolationsUtils.getViolationsOnyxData({ + updatedTransaction: transaction, + transactionViolations, + policy, + policyTagList: policyTags, + policyCategories, + hasDependentTags: false, + isInvoiceTransaction: false, + isSelfDM: false, + iouReport, + }); expect(result.value).not.toEqual(expect.arrayContaining([missingAttendeesViolation])); }); it('should not add missingAttendees violation when category does not require attendees', () => { policyCategories.Meals.areAttendeesRequired = false; transaction.comment = {attendees: []}; - const result = ViolationsUtils.getViolationsOnyxData(transaction, transactionViolations, policy, policyTags, policyCategories, false, false, false, iouReport); + const result = ViolationsUtils.getViolationsOnyxData({ + updatedTransaction: transaction, + transactionViolations, + policy, + policyTagList: policyTags, + policyCategories, + hasDependentTags: false, + isInvoiceTransaction: false, + isSelfDM: false, + iouReport, + }); expect(result.value).not.toEqual(expect.arrayContaining([missingAttendeesViolation])); }); @@ -1025,7 +1551,16 @@ describe('getViolationsOnyxData', () => { transaction.comment = { attendees: [{email: MOCK_CURRENT_USER_EMAIL, displayName: 'Test User', avatarUrl: ''}], }; - const result = ViolationsUtils.getViolationsOnyxData(transaction, transactionViolations, policy, policyTags, policyCategories, false, false, false, undefined); + const result = ViolationsUtils.getViolationsOnyxData({ + updatedTransaction: transaction, + transactionViolations, + policy, + policyTagList: policyTags, + policyCategories, + hasDependentTags: false, + isInvoiceTransaction: false, + isSelfDM: false, + }); // Violation should be added since the only attendee is the current user (owner) expect(result.value).toEqual(expect.arrayContaining([missingAttendeesViolation])); }); @@ -1039,7 +1574,16 @@ describe('getViolationsOnyxData', () => { {email: 'other@example.com', displayName: 'Other User', avatarUrl: ''}, ], }; - const result = ViolationsUtils.getViolationsOnyxData(transaction, transactionViolations, policy, policyTags, policyCategories, false, false, false, undefined); + const result = ViolationsUtils.getViolationsOnyxData({ + updatedTransaction: transaction, + transactionViolations, + policy, + policyTagList: policyTags, + policyCategories, + hasDependentTags: false, + isInvoiceTransaction: false, + isSelfDM: false, + }); // Violation should NOT be added since there's a non-owner attendee expect(result.value).not.toEqual(expect.arrayContaining([missingAttendeesViolation])); }); @@ -1053,7 +1597,16 @@ describe('getViolationsOnyxData', () => { {email: 'other@example.com', displayName: 'Other User', avatarUrl: ''}, ], }; - const result = ViolationsUtils.getViolationsOnyxData(transaction, transactionViolations, policy, policyTags, policyCategories, false, false, false, undefined); + const result = ViolationsUtils.getViolationsOnyxData({ + updatedTransaction: transaction, + transactionViolations, + policy, + policyTagList: policyTags, + policyCategories, + hasDependentTags: false, + isInvoiceTransaction: false, + isSelfDM: false, + }); // Violation should be removed expect(result.value).not.toEqual(expect.arrayContaining([missingAttendeesViolation])); }); @@ -1064,7 +1617,16 @@ describe('getViolationsOnyxData', () => { transaction.comment = { attendees: [{email: MOCK_CURRENT_USER_EMAIL, displayName: 'Test User', avatarUrl: ''}], }; - const result = ViolationsUtils.getViolationsOnyxData(transaction, transactionViolations, policy, policyTags, policyCategories, false, false, false, undefined); + const result = ViolationsUtils.getViolationsOnyxData({ + updatedTransaction: transaction, + transactionViolations, + policy, + policyTagList: policyTags, + policyCategories, + hasDependentTags: false, + isInvoiceTransaction: false, + isSelfDM: false, + }); // Violation should be preserved expect(result.value).toEqual(expect.arrayContaining([missingAttendeesViolation])); }); @@ -1089,7 +1651,16 @@ describe('getViolationsOnyxData', () => { it("should add missingAttendees violation when no attendees are present (can't identify owner)", () => { transactionViolations = []; transaction.comment = {attendees: []}; - const result = ViolationsUtils.getViolationsOnyxData(transaction, transactionViolations, policy, policyTags, policyCategories, false, false, false, undefined); + const result = ViolationsUtils.getViolationsOnyxData({ + updatedTransaction: transaction, + transactionViolations, + policy, + policyTagList: policyTags, + policyCategories, + hasDependentTags: false, + isInvoiceTransaction: false, + isSelfDM: false, + }); // With 0 attendees, attendeesMinusOwnerCount = Math.max(0, 0 - 1) = 0, violation should be added expect(result.value).toEqual(expect.arrayContaining([missingAttendeesViolation])); }); @@ -1099,7 +1670,16 @@ describe('getViolationsOnyxData', () => { transaction.comment = { attendees: [{email: 'anyone@example.com', displayName: 'Someone', avatarUrl: ''}], }; - const result = ViolationsUtils.getViolationsOnyxData(transaction, transactionViolations, policy, policyTags, policyCategories, false, false, false, undefined); + const result = ViolationsUtils.getViolationsOnyxData({ + updatedTransaction: transaction, + transactionViolations, + policy, + policyTagList: policyTags, + policyCategories, + hasDependentTags: false, + isInvoiceTransaction: false, + isSelfDM: false, + }); // With 1 attendee, attendeesMinusOwnerCount = Math.max(0, 1 - 1) = 0, violation should be added expect(result.value).toEqual(expect.arrayContaining([missingAttendeesViolation])); }); @@ -1112,7 +1692,16 @@ describe('getViolationsOnyxData', () => { {email: 'person2@example.com', displayName: 'Person 2', avatarUrl: ''}, ], }; - const result = ViolationsUtils.getViolationsOnyxData(transaction, transactionViolations, policy, policyTags, policyCategories, false, false, false, undefined); + const result = ViolationsUtils.getViolationsOnyxData({ + updatedTransaction: transaction, + transactionViolations, + policy, + policyTagList: policyTags, + policyCategories, + hasDependentTags: false, + isInvoiceTransaction: false, + isSelfDM: false, + }); // With 2 attendees, attendeesMinusOwnerCount = Math.max(0, 2 - 1) = 1, no violation expect(result.value).not.toEqual(expect.arrayContaining([missingAttendeesViolation])); }); @@ -1125,7 +1714,16 @@ describe('getViolationsOnyxData', () => { {email: 'person2@example.com', displayName: 'Person 2', avatarUrl: ''}, ], }; - const result = ViolationsUtils.getViolationsOnyxData(transaction, transactionViolations, policy, policyTags, policyCategories, false, false, false, undefined); + const result = ViolationsUtils.getViolationsOnyxData({ + updatedTransaction: transaction, + transactionViolations, + policy, + policyTagList: policyTags, + policyCategories, + hasDependentTags: false, + isInvoiceTransaction: false, + isSelfDM: false, + }); // Violation should be removed since we now have 2 attendees expect(result.value).not.toEqual(expect.arrayContaining([missingAttendeesViolation])); }); @@ -1147,14 +1745,30 @@ describe('getViolationsOnyxData', () => { it('should add taxOutOfPolicy violation when taxCode is not in policy tax rates', () => { transaction.taxCode = 'UNKNOWN_TAX'; policy.taxRates = {name: 'Taxes', defaultExternalID: 'TAX_10', defaultValue: '10%', foreignTaxDefault: 'TAX_10', taxes: {TAX_10: {name: '10%', value: '10%'}}}; - const result = ViolationsUtils.getViolationsOnyxData(transaction, transactionViolations, policy, policyTags, policyCategories, false, false); + const result = ViolationsUtils.getViolationsOnyxData({ + updatedTransaction: transaction, + transactionViolations, + policy, + policyTagList: policyTags, + policyCategories, + hasDependentTags: false, + isInvoiceTransaction: false, + }); expect(result.value).toContainEqual(taxOutOfPolicyViolation); }); it('should not add taxOutOfPolicy violation when taxCode is in policy tax rates', () => { transaction.taxCode = 'TAX_10'; policy.taxRates = {name: 'Taxes', defaultExternalID: 'TAX_10', defaultValue: '10%', foreignTaxDefault: 'TAX_10', taxes: {TAX_10: {name: '10%', value: '10%'}}}; - const result = ViolationsUtils.getViolationsOnyxData(transaction, transactionViolations, policy, policyTags, policyCategories, false, false); + const result = ViolationsUtils.getViolationsOnyxData({ + updatedTransaction: transaction, + transactionViolations, + policy, + policyTagList: policyTags, + policyCategories, + hasDependentTags: false, + isInvoiceTransaction: false, + }); expect(result.value).not.toContainEqual(taxOutOfPolicyViolation); }); @@ -1162,7 +1776,15 @@ describe('getViolationsOnyxData', () => { transaction.taxCode = 'TAX_10'; policy.taxRates = {name: 'Taxes', defaultExternalID: 'TAX_10', defaultValue: '10%', foreignTaxDefault: 'TAX_10', taxes: {TAX_10: {name: '10%', value: '10%'}}}; transactionViolations = [taxOutOfPolicyViolation]; - const result = ViolationsUtils.getViolationsOnyxData(transaction, transactionViolations, policy, policyTags, policyCategories, false, false); + const result = ViolationsUtils.getViolationsOnyxData({ + updatedTransaction: transaction, + transactionViolations, + policy, + policyTagList: policyTags, + policyCategories, + hasDependentTags: false, + isInvoiceTransaction: false, + }); expect(result.value).not.toContainEqual(taxOutOfPolicyViolation); }); }); @@ -1174,19 +1796,43 @@ describe('getViolationsOnyxData', () => { it('should add taxOutOfPolicy violation when transaction has taxCode', () => { transaction.taxCode = 'SOME_TAX'; - const result = ViolationsUtils.getViolationsOnyxData(transaction, transactionViolations, policy, policyTags, policyCategories, false, false); + const result = ViolationsUtils.getViolationsOnyxData({ + updatedTransaction: transaction, + transactionViolations, + policy, + policyTagList: policyTags, + policyCategories, + hasDependentTags: false, + isInvoiceTransaction: false, + }); expect(result.value).toContainEqual(taxOutOfPolicyViolation); }); it('should add taxOutOfPolicy violation when transaction has taxAmount', () => { transaction.taxAmount = 500; - const result = ViolationsUtils.getViolationsOnyxData(transaction, transactionViolations, policy, policyTags, policyCategories, false, false); + const result = ViolationsUtils.getViolationsOnyxData({ + updatedTransaction: transaction, + transactionViolations, + policy, + policyTagList: policyTags, + policyCategories, + hasDependentTags: false, + isInvoiceTransaction: false, + }); expect(result.value).toContainEqual(taxOutOfPolicyViolation); }); it('should add taxOutOfPolicy violation when transaction has taxValue', () => { transaction.taxValue = '10%'; - const result = ViolationsUtils.getViolationsOnyxData(transaction, transactionViolations, policy, policyTags, policyCategories, false, false); + const result = ViolationsUtils.getViolationsOnyxData({ + updatedTransaction: transaction, + transactionViolations, + policy, + policyTagList: policyTags, + policyCategories, + hasDependentTags: false, + isInvoiceTransaction: false, + }); expect(result.value).toContainEqual(taxOutOfPolicyViolation); }); @@ -1194,7 +1840,15 @@ describe('getViolationsOnyxData', () => { transaction.taxCode = undefined; transaction.taxAmount = undefined; transaction.taxValue = undefined; - const result = ViolationsUtils.getViolationsOnyxData(transaction, transactionViolations, policy, policyTags, policyCategories, false, false); + const result = ViolationsUtils.getViolationsOnyxData({ + updatedTransaction: transaction, + transactionViolations, + policy, + policyTagList: policyTags, + policyCategories, + hasDependentTags: false, + isInvoiceTransaction: false, + }); expect(result.value).not.toContainEqual(taxOutOfPolicyViolation); }); @@ -1202,7 +1856,15 @@ describe('getViolationsOnyxData', () => { transaction.taxCode = ''; transaction.taxAmount = 0; transaction.taxValue = ''; - const result = ViolationsUtils.getViolationsOnyxData(transaction, transactionViolations, policy, policyTags, policyCategories, false, false); + const result = ViolationsUtils.getViolationsOnyxData({ + updatedTransaction: transaction, + transactionViolations, + policy, + policyTagList: policyTags, + policyCategories, + hasDependentTags: false, + isInvoiceTransaction: false, + }); expect(result.value).not.toContainEqual(taxOutOfPolicyViolation); }); @@ -1211,7 +1873,15 @@ describe('getViolationsOnyxData', () => { transaction.taxAmount = undefined; transaction.taxValue = undefined; transactionViolations = [taxOutOfPolicyViolation]; - const result = ViolationsUtils.getViolationsOnyxData(transaction, transactionViolations, policy, policyTags, policyCategories, false, false); + const result = ViolationsUtils.getViolationsOnyxData({ + updatedTransaction: transaction, + transactionViolations, + policy, + policyTagList: policyTags, + policyCategories, + hasDependentTags: false, + isInvoiceTransaction: false, + }); expect(result.value).not.toContainEqual(taxOutOfPolicyViolation); }); }); @@ -1221,7 +1891,15 @@ describe('getViolationsOnyxData', () => { policy.tax = {trackingEnabled: false}; transaction.taxCode = 'SOME_TAX'; transaction.comment = {...transaction.comment, type: CONST.TRANSACTION.TYPE.TIME}; - const result = ViolationsUtils.getViolationsOnyxData(transaction, transactionViolations, policy, policyTags, policyCategories, false, false); + const result = ViolationsUtils.getViolationsOnyxData({ + updatedTransaction: transaction, + transactionViolations, + policy, + policyTagList: policyTags, + policyCategories, + hasDependentTags: false, + isInvoiceTransaction: false, + }); expect(result.value).not.toContainEqual(taxOutOfPolicyViolation); }); @@ -1229,7 +1907,15 @@ describe('getViolationsOnyxData', () => { policy.tax = {trackingEnabled: false}; transaction.taxCode = 'SOME_TAX'; transaction.comment = {...transaction.comment, type: CONST.TRANSACTION.TYPE.CUSTOM_UNIT, customUnit: {name: CONST.CUSTOM_UNITS.NAME_PER_DIEM_INTERNATIONAL}}; - const result = ViolationsUtils.getViolationsOnyxData(transaction, transactionViolations, policy, policyTags, policyCategories, false, false); + const result = ViolationsUtils.getViolationsOnyxData({ + updatedTransaction: transaction, + transactionViolations, + policy, + policyTagList: policyTags, + policyCategories, + hasDependentTags: false, + isInvoiceTransaction: false, + }); expect(result.value).not.toContainEqual(taxOutOfPolicyViolation); }); @@ -1238,7 +1924,15 @@ describe('getViolationsOnyxData', () => { transaction.taxCode = 'UNKNOWN_TAX'; transaction.comment = {...transaction.comment, type: CONST.TRANSACTION.TYPE.TIME}; policy.taxRates = {name: 'Taxes', defaultExternalID: 'TAX_10', defaultValue: '10%', foreignTaxDefault: 'TAX_10', taxes: {TAX_10: {name: '10%', value: '10%'}}}; - const result = ViolationsUtils.getViolationsOnyxData(transaction, transactionViolations, policy, policyTags, policyCategories, false, false); + const result = ViolationsUtils.getViolationsOnyxData({ + updatedTransaction: transaction, + transactionViolations, + policy, + policyTagList: policyTags, + policyCategories, + hasDependentTags: false, + isInvoiceTransaction: false, + }); expect(result.value).not.toContainEqual(taxOutOfPolicyViolation); }); }); @@ -1258,7 +1952,15 @@ describe('getViolationsOnyxData', () => { }, ], }; - const result = ViolationsUtils.getViolationsOnyxData(transaction, transactionViolations, policy, policyTags, policyCategories, false, false); + const result = ViolationsUtils.getViolationsOnyxData({ + updatedTransaction: transaction, + transactionViolations, + policy, + policyTagList: policyTags, + policyCategories, + hasDependentTags: false, + isInvoiceTransaction: false, + }); expect(result.value).toEqual(expect.arrayContaining([overTripLimitViolation, ...transactionViolations])); }); @@ -1277,7 +1979,15 @@ describe('getViolationsOnyxData', () => { }, ], }; - const result = ViolationsUtils.getViolationsOnyxData(transaction, transactionViolations, policy, policyTags, policyCategories, false, false); + const result = ViolationsUtils.getViolationsOnyxData({ + updatedTransaction: transaction, + transactionViolations, + policy, + policyTagList: policyTags, + policyCategories, + hasDependentTags: false, + isInvoiceTransaction: false, + }); expect(result.value).toEqual([]); }); @@ -1295,10 +2005,55 @@ describe('getViolationsOnyxData', () => { ], }; const modifiedTransactionViolations = [overTripLimitViolation, ...transactionViolations]; - const result = ViolationsUtils.getViolationsOnyxData(transaction, modifiedTransactionViolations, policy, policyTags, policyCategories, false, false); + const result = ViolationsUtils.getViolationsOnyxData({ + updatedTransaction: transaction, + transactionViolations: modifiedTransactionViolations, + policy, + policyTagList: policyTags, + policyCategories, + hasDependentTags: false, + isInvoiceTransaction: false, + }); expect(result.value).toEqual([]); }); }); + + describe('shouldRemoveRejectedExpenseViolation (move transaction / explicit removal)', () => { + const autoRejectedViolation: TransactionViolation = { + name: CONST.VIOLATIONS.AUTO_REPORTED_REJECTED_EXPENSE, + type: CONST.VIOLATION_TYPES.VIOLATION, + showInReview: true, + }; + + it('removes AUTO_REPORTED_REJECTED_EXPENSE from output when shouldRemoveRejectedExpenseViolation is true', () => { + const result = ViolationsUtils.getViolationsOnyxData({ + updatedTransaction: transaction, + transactionViolations: [autoRejectedViolation], + policy, + policyTagList: policyTags, + policyCategories, + hasDependentTags: false, + isInvoiceTransaction: false, + shouldRemoveRejectedExpenseViolation: true, + }); + const violations = (result.value ?? []) as TransactionViolation[]; + expect(violations.some((v) => v.name === CONST.VIOLATIONS.AUTO_REPORTED_REJECTED_EXPENSE)).toBe(false); + }); + + it('keeps AUTO_REPORTED_REJECTED_EXPENSE when the 11th param is omitted and submitter-edit branch does not apply', () => { + const result = ViolationsUtils.getViolationsOnyxData({ + updatedTransaction: transaction, + transactionViolations: [autoRejectedViolation], + policy, + policyTagList: policyTags, + policyCategories, + hasDependentTags: false, + isInvoiceTransaction: false, + }); + const violations = (result.value ?? []) as TransactionViolation[]; + expect(violations.some((v) => v.name === CONST.VIOLATIONS.AUTO_REPORTED_REJECTED_EXPENSE)).toBe(true); + }); + }); }); const getFakeTransaction = (transactionID: string, comment?: Transaction['comment']) => ({