Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
40 commits
Select commit Hold shift + click to select a range
198a10f
feat: enable duplicating distance expenses
jjcoffee Dec 16, 2025
9cb8ed8
Merge branch 'main' into feat/duplicate-distance-expenses
jjcoffee Dec 18, 2025
7befa67
fix: ts error
jjcoffee Dec 18, 2025
a17546b
fix: ts and jest
jjcoffee Dec 18, 2025
c2f67f3
fix: failing jest test
jjcoffee Dec 18, 2025
243d4ad
Merge branch 'main' into feat/duplicate-distance-expenses
jjcoffee Jan 2, 2026
e6eaf45
fix: prettier
jjcoffee Jan 2, 2026
760e502
fix: add support for customUnitPolicyID
jjcoffee Jan 2, 2026
6a62904
fix: ts checks
jjcoffee Jan 5, 2026
1606796
fix: lint errors
jjcoffee Jan 5, 2026
bd0e090
fix: ts and lint errors
jjcoffee Jan 5, 2026
b92de78
fix: check for custom unit out of policy violation
jjcoffee Jan 5, 2026
09dbda5
Merge branch 'main' into feat/duplicate-distance-expenses
jjcoffee Jan 5, 2026
c045aa6
fix: errors
jjcoffee Jan 5, 2026
5ea4081
fix: prevent navigation when duplicating distance expenses
jjcoffee Jan 6, 2026
eb5d456
Merge branch 'main' into feat/duplicate-distance-expenses
jjcoffee Jan 6, 2026
ac07c4f
fix: after merge changes
jjcoffee Jan 6, 2026
7c8480e
fix: ts errors
jjcoffee Jan 6, 2026
78445cc
Merge branch 'main' into feat/duplicate-distance-expenses
jjcoffee Jan 7, 2026
64e9fea
feat: add modal error when duplicating distance expense with out of r…
jjcoffee Jan 8, 2026
06033f6
fix: cleanup check custom unit out of policy violation
jjcoffee Jan 8, 2026
c118eda
feat: add Spanish translation
jjcoffee Jan 8, 2026
c223bae
fix: errors
jjcoffee Jan 8, 2026
7e33f59
feat: add translations
jjcoffee Jan 8, 2026
be74284
Merge branch 'main' into feat/duplicate-distance-expenses
jjcoffee Jan 8, 2026
5e60b78
fix: ts error
jjcoffee Jan 8, 2026
e47e857
Merge branch 'main' into feat/duplicate-distance-expenses
jjcoffee Jan 9, 2026
7675dbf
Merge branch 'main' into feat/duplicate-distance-expenses
jjcoffee Jan 20, 2026
512f9c2
fix: errors after merge
jjcoffee Jan 20, 2026
0364456
fix: incorrect request type for manual distance expense
jjcoffee Jan 20, 2026
bcb3369
fix: ts error
jjcoffee Jan 20, 2026
dba48cc
fix: remove unnecessary guard
jjcoffee Jan 20, 2026
4946874
fix: lint errors
jjcoffee Jan 20, 2026
1518b4c
fix: jest test
jjcoffee Jan 22, 2026
c1d2f2c
Merge branch 'main' into feat/duplicate-distance-expenses
jjcoffee Jan 22, 2026
d07ca33
fix: ts checks
jjcoffee Jan 22, 2026
9af40b2
fix: add fallback iouRequestType
jjcoffee Jan 22, 2026
ed56dca
fix: fallback to specific value
jjcoffee Jan 22, 2026
ee3fb9e
Merge branch 'main' into feat/duplicate-distance-expenses
jjcoffee Jan 22, 2026
0354799
fix: use getRequestType for iouRequestType
jjcoffee Jan 22, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 21 additions & 2 deletions src/components/MoneyReportHeader.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@ import {shouldRestrictUserBillableActions} from '@libs/SubscriptionUtils';
import {
allHavePendingRTERViolation,
getOriginalTransactionWithSplitInfo,
hasCustomUnitOutOfPolicyViolation as hasCustomUnitOutOfPolicyViolationTransactionUtils,
hasDuplicateTransactions,
isDuplicate,
isExpensifyCardTransaction,
Expand Down Expand Up @@ -132,6 +133,7 @@ import BrokenConnectionDescription from './BrokenConnectionDescription';
import Button from './Button';
import ButtonWithDropdownMenu from './ButtonWithDropdownMenu';
import type {DropdownOption} from './ButtonWithDropdownMenu/types';
import ConfirmModal from './ConfirmModal';
import DecisionModal from './DecisionModal';
import {DelegateNoAccessContext} from './DelegateNoAccessModalProvider';
import Header from './Header';
Expand Down Expand Up @@ -326,6 +328,7 @@ function MoneyReportHeader({
const isASAPSubmitBetaEnabled = isBetaEnabled(CONST.BETAS.ASAP_SUBMIT);
const isDEWBetaEnabled = isBetaEnabled(CONST.BETAS.NEW_DOT_DEW);
const hasViolations = hasViolationsReportUtils(moneyRequestReport?.reportID, allTransactionViolations, accountID, email ?? '');
const hasCustomUnitOutOfPolicyViolation = hasCustomUnitOutOfPolicyViolationTransactionUtils(transactionViolations);

const [exportModalStatus, setExportModalStatus] = useState<ExportType | null>(null);
const {showConfirmModal} = useConfirmModal();
Expand Down Expand Up @@ -395,6 +398,7 @@ function MoneyReportHeader({

const [isDownloadErrorModalVisible, setIsDownloadErrorModalVisible] = useState(false);
const [isHoldEducationalModalVisible, setIsHoldEducationalModalVisible] = useState(false);
const [duplicateDistanceErrorModalVisible, setDuplicateDistanceErrorModalVisible] = useState(false);
const [rejectModalAction, setRejectModalAction] = useState<ValueOf<
typeof CONST.REPORT.TRANSACTION_SECONDARY_ACTIONS.HOLD | typeof CONST.REPORT.TRANSACTION_SECONDARY_ACTIONS.REJECT | typeof CONST.REPORT.TRANSACTION_SECONDARY_ACTIONS.REJECT_BULK
> | null>(null);
Expand Down Expand Up @@ -649,13 +653,14 @@ function MoneyReportHeader({
activePolicyID,
quickAction,
policyRecentlyUsedCurrencies: policyRecentlyUsedCurrencies ?? [],
customUnitPolicyID: policy?.id,
targetPolicy: defaultExpensePolicy ?? undefined,
targetPolicyCategories: activePolicyCategories,
targetReport: activePolicyExpenseChat,
});
}
},
[activePolicyExpenseChat, activePolicyID, allPolicyCategories, defaultExpensePolicy, introSelected, isASAPSubmitBetaEnabled, quickAction, policyRecentlyUsedCurrencies],
[activePolicyExpenseChat, activePolicyID, allPolicyCategories, defaultExpensePolicy, introSelected, isASAPSubmitBetaEnabled, quickAction, policyRecentlyUsedCurrencies, policy?.id],
);

const getStatusIcon: (src: IconAsset) => React.ReactNode = (src) => (
Expand Down Expand Up @@ -1319,6 +1324,11 @@ function MoneyReportHeader({
icon: isDuplicateActive ? expensifyIcons.ReceiptMultiple : expensifyIcons.CheckmarkCircle,
value: CONST.REPORT.SECONDARY_ACTIONS.DUPLICATE,
onSelected: () => {
if (hasCustomUnitOutOfPolicyViolation) {
setDuplicateDistanceErrorModalVisible(true);
return;
}

if (!isDuplicateActive || !transaction) {
return;
}
Expand All @@ -1327,7 +1337,7 @@ function MoneyReportHeader({

duplicateExpenseTransaction([transaction]);
},
shouldCloseModalOnSelect: activePolicyExpenseChat?.iouReportID === moneyRequestReport?.reportID,
shouldCloseModalOnSelect: hasCustomUnitOutOfPolicyViolation || activePolicyExpenseChat?.iouReportID === moneyRequestReport?.reportID,
},
[CONST.REPORT.SECONDARY_ACTIONS.CHANGE_WORKSPACE]: {
text: translate('iou.changeWorkspace'),
Expand Down Expand Up @@ -1791,6 +1801,15 @@ function MoneyReportHeader({
isVisible={isDownloadErrorModalVisible}
onClose={() => setIsDownloadErrorModalVisible(false)}
/>
<ConfirmModal
title={translate('common.duplicateExpense')}
isVisible={duplicateDistanceErrorModalVisible}
onConfirm={() => setDuplicateDistanceErrorModalVisible(false)}
onCancel={() => setDuplicateDistanceErrorModalVisible(false)}
confirmText={translate('common.buttonConfirm')}
prompt={translate('iou.correctDistanceRateError')}
shouldShowCancelButton={false}
/>
{!!rejectModalAction && (
<HoldOrRejectEducationalModal
onClose={dismissRejectModalBasedOnAction}
Expand Down
22 changes: 20 additions & 2 deletions src/components/MoneyRequestHeader.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ import {
import {getReviewNavigationRoute} from '@libs/TransactionPreviewUtils';
import {
getOriginalTransactionWithSplitInfo,
hasCustomUnitOutOfPolicyViolation as hasCustomUnitOutOfPolicyViolationTransactionUtils,
hasPendingRTERViolation as hasPendingRTERViolationTransactionUtils,
isDuplicate as isDuplicateTransactionUtils,
isExpensifyCardTransaction,
Expand Down Expand Up @@ -127,6 +128,7 @@ function MoneyRequestHeader({report, parentReportAction, policy, onBackButtonPre
const [rejectModalAction, setRejectModalAction] = useState<ValueOf<
typeof CONST.REPORT.TRANSACTION_SECONDARY_ACTIONS.HOLD | typeof CONST.REPORT.TRANSACTION_SECONDARY_ACTIONS.REJECT
> | null>(null);
const [duplicateDistanceErrorModalVisible, setDuplicateDistanceErrorModalVisible] = useState(false);
const [isDuplicateActive, temporarilyDisableDuplicateAction] = useThrottledButtonState();
const [dismissedRejectUseExplanation] = useOnyx(ONYXKEYS.NVP_DISMISSED_REJECT_USE_EXPLANATION, {canBeMissing: true});
const [dismissedHoldUseExplanation] = useOnyx(ONYXKEYS.NVP_DISMISSED_HOLD_USE_EXPLANATION, {canBeMissing: true});
Expand Down Expand Up @@ -159,6 +161,7 @@ function MoneyRequestHeader({report, parentReportAction, policy, onBackButtonPre
const {iouReport, chatReport: chatIOUReport, isChatIOUReportArchived} = useGetIOUReportFromReportAction(parentReportAction);

const hasPendingRTERViolation = hasPendingRTERViolationTransactionUtils(transactionViolations);
const hasCustomUnitOutOfPolicyViolation = hasCustomUnitOutOfPolicyViolationTransactionUtils(transactionViolations);

const shouldShowBrokenConnectionViolation = shouldShowBrokenConnectionViolationTransactionUtils(parentReport, policy, transactionViolations);
const isReportSubmitter = isCurrentUserSubmitter(chatIOUReport);
Expand Down Expand Up @@ -196,13 +199,14 @@ function MoneyRequestHeader({report, parentReportAction, policy, onBackButtonPre
activePolicyID,
quickAction,
policyRecentlyUsedCurrencies: policyRecentlyUsedCurrencies ?? [],
customUnitPolicyID: policy?.id,
targetPolicy: defaultExpensePolicy ?? undefined,
targetPolicyCategories: activePolicyCategories,
targetReport: activePolicyExpenseChat,
});
}
},
[activePolicyExpenseChat, allPolicyCategories, defaultExpensePolicy, isASAPSubmitBetaEnabled, introSelected, activePolicyID, quickAction, policyRecentlyUsedCurrencies],
[activePolicyExpenseChat, allPolicyCategories, defaultExpensePolicy, isASAPSubmitBetaEnabled, introSelected, activePolicyID, quickAction, policyRecentlyUsedCurrencies, policy?.id],
);

const getStatusIcon: (src: IconAsset) => ReactNode = (src) => (
Expand Down Expand Up @@ -427,6 +431,11 @@ function MoneyRequestHeader({report, parentReportAction, policy, onBackButtonPre
icon: isDuplicateActive ? Expensicons.ReceiptMultiple : Expensicons.CheckmarkCircle,
value: CONST.REPORT.SECONDARY_ACTIONS.DUPLICATE,
onSelected: () => {
if (hasCustomUnitOutOfPolicyViolation) {
setDuplicateDistanceErrorModalVisible(true);
return;
}

if (!isDuplicateActive || !transaction) {
return;
}
Expand All @@ -435,7 +444,7 @@ function MoneyRequestHeader({report, parentReportAction, policy, onBackButtonPre

duplicateTransaction([transaction]);
},
shouldCloseModalOnSelect: false,
shouldCloseModalOnSelect: hasCustomUnitOutOfPolicyViolation,
},
[CONST.REPORT.TRANSACTION_SECONDARY_ACTIONS.VIEW_DETAILS]: {
value: CONST.REPORT.SECONDARY_ACTIONS.VIEW_DETAILS,
Expand Down Expand Up @@ -596,6 +605,15 @@ function MoneyRequestHeader({report, parentReportAction, policy, onBackButtonPre
danger
shouldEnableNewFocusManagement
/>
<ConfirmModal
title={translate('common.duplicateExpense')}
isVisible={duplicateDistanceErrorModalVisible}
onConfirm={() => setDuplicateDistanceErrorModalVisible(false)}
onCancel={() => setDuplicateDistanceErrorModalVisible(false)}
confirmText={translate('common.buttonConfirm')}
prompt={translate('iou.correctDistanceRateError')}
shouldShowCancelButton={false}
/>
{!!rejectModalAction && (
<HoldOrRejectEducationalModal
onClose={dismissRejectModalBasedOnAction}
Expand Down
2 changes: 2 additions & 0 deletions src/languages/de.ts
Original file line number Diff line number Diff line change
Expand Up @@ -634,6 +634,7 @@ const translations: TranslationDeepObject<typeof en> = {
nonReimbursableTotal: 'Nicht erstattungsfähiger Gesamtbetrag',
originalAmount: 'Ursprünglicher Betrag',
insights: 'Einblicke',
duplicateExpense: 'Doppelte Ausgabe',
},
supportalNoAccess: {
title: 'Nicht so schnell',
Expand Down Expand Up @@ -1476,6 +1477,7 @@ const translations: TranslationDeepObject<typeof en> = {
ratePreview: (rate: string) => `${rate} / Stunde`,
amountTooLargeError: 'Der Gesamtbetrag ist zu hoch. Verringere die Stunden oder reduziere den Satz.',
},
correctDistanceRateError: 'Beheben Sie den Fehler beim Entfernungssatz und versuchen Sie es erneut.',
},
transactionMerge: {
listPage: {
Expand Down
2 changes: 2 additions & 0 deletions src/languages/en.ts
Original file line number Diff line number Diff line change
Expand Up @@ -623,6 +623,7 @@ const translations = {
actionRequired: 'Action required',
duplicate: 'Duplicate',
duplicated: 'Duplicated',
duplicateExpense: 'Duplicate expense',
exchangeRate: 'Exchange rate',
reimbursableTotal: 'Reimbursable total',
nonReimbursableTotal: 'Non-reimbursable total',
Expand Down Expand Up @@ -1460,6 +1461,7 @@ const translations = {
ratePreview: (rate: string) => `${rate} / hour`,
amountTooLargeError: 'The total amount is too large. Lower the hours or reduce the rate.',
},
correctDistanceRateError: 'Fix the distance rate error and try again.',
},
transactionMerge: {
listPage: {
Expand Down
2 changes: 2 additions & 0 deletions src/languages/es.ts
Original file line number Diff line number Diff line change
Expand Up @@ -382,6 +382,7 @@ const translations: TranslationDeepObject<typeof en> = {
actionRequired: 'Acción requerida',
duplicate: 'Duplicar',
duplicated: 'Duplicado',
duplicateExpense: 'Duplicar gasto',
exchangeRate: 'Tipo de cambio',
reimbursableTotal: 'Total reembolsable',
nonReimbursableTotal: 'Total no reembolsable',
Expand Down Expand Up @@ -1205,6 +1206,7 @@ const translations: TranslationDeepObject<typeof en> = {
ratePreview: (rate: string) => `${rate} / hora`,
amountTooLargeError: 'El importe total es demasiado alto. Reduce las horas o disminuye la tasa.',
},
correctDistanceRateError: 'Corrige el error de la tasa de distancia y vuelve a intentarlo.',
},
transactionMerge: {
listPage: {
Expand Down
2 changes: 2 additions & 0 deletions src/languages/fr.ts
Original file line number Diff line number Diff line change
Expand Up @@ -636,6 +636,7 @@ const translations: TranslationDeepObject<typeof en> = {
nonReimbursableTotal: 'Total non remboursable',
originalAmount: 'Montant d’origine',
insights: 'Analyses',
duplicateExpense: 'Note de frais en double',
},
supportalNoAccess: {
title: 'Pas si vite',
Expand Down Expand Up @@ -1479,6 +1480,7 @@ const translations: TranslationDeepObject<typeof en> = {
ratePreview: (rate: string) => `${rate} / heure`,
amountTooLargeError: 'Le montant total est trop élevé. Réduisez le nombre d’heures ou diminuez le tarif.',
},
correctDistanceRateError: 'Corrigez l’erreur de taux de distance et réessayez.',
},
transactionMerge: {
listPage: {
Expand Down
2 changes: 2 additions & 0 deletions src/languages/it.ts
Original file line number Diff line number Diff line change
Expand Up @@ -635,6 +635,7 @@ const translations: TranslationDeepObject<typeof en> = {
nonReimbursableTotal: 'Totale non rimborsabile',
originalAmount: 'Importo originale',
insights: 'Analisi',
duplicateExpense: 'Spesa duplicata',
},
supportalNoAccess: {
title: 'Non così in fretta',
Expand Down Expand Up @@ -1473,6 +1474,7 @@ const translations: TranslationDeepObject<typeof en> = {
ratePreview: (rate: string) => `${rate} / ora`,
amountTooLargeError: 'L’importo totale è troppo elevato. Riduci le ore o diminuisci la tariffa.',
},
correctDistanceRateError: "Correggi l'errore nella tariffa della distanza e riprova.",
},
transactionMerge: {
listPage: {
Expand Down
2 changes: 2 additions & 0 deletions src/languages/ja.ts
Original file line number Diff line number Diff line change
Expand Up @@ -634,6 +634,7 @@ const translations: TranslationDeepObject<typeof en> = {
nonReimbursableTotal: '非払い戻し合計',
originalAmount: '元の金額',
insights: 'インサイト',
duplicateExpense: '重複した経費',
},
supportalNoAccess: {
title: 'ちょっと待ってください',
Expand Down Expand Up @@ -1471,6 +1472,7 @@ const translations: TranslationDeepObject<typeof en> = {
ratePreview: (rate: string) => `${rate} / 時間`,
amountTooLargeError: '合計金額が大きすぎます。時間を減らすか、レートを下げてください。',
},
correctDistanceRateError: '距離レートのエラーを修正して、もう一度お試しください。',
},
transactionMerge: {
listPage: {
Expand Down
2 changes: 2 additions & 0 deletions src/languages/nl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -635,6 +635,7 @@ const translations: TranslationDeepObject<typeof en> = {
nonReimbursableTotal: 'Niet-vergoedbaar totaal',
originalAmount: 'Oorspronkelijk bedrag',
insights: 'Inzichten',
duplicateExpense: 'Dubbele uitgave',
},
supportalNoAccess: {
title: 'Niet zo snel',
Expand Down Expand Up @@ -1472,6 +1473,7 @@ const translations: TranslationDeepObject<typeof en> = {
ratePreview: (rate: string) => `${rate} / uur`,
amountTooLargeError: 'Het totale bedrag is te hoog. Verlaag het aantal uren of verlaag het tarief.',
},
correctDistanceRateError: 'Los het foutieve kilometertarief op en probeer het opnieuw.',
},
transactionMerge: {
listPage: {
Expand Down
2 changes: 2 additions & 0 deletions src/languages/pl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -635,6 +635,7 @@ const translations: TranslationDeepObject<typeof en> = {
nonReimbursableTotal: 'Suma niepodlegająca zwrotowi',
originalAmount: 'Kwota pierwotna',
insights: 'Analizy',
duplicateExpense: 'Zduplikowany wydatek',
},
supportalNoAccess: {
title: 'Nie tak szybko',
Expand Down Expand Up @@ -1471,6 +1472,7 @@ const translations: TranslationDeepObject<typeof en> = {
ratePreview: (rate: string) => `${rate} / godzina`,
amountTooLargeError: 'Całkowita kwota jest zbyt wysoka. Zmniejsz liczbę godzin lub obniż stawkę.',
},
correctDistanceRateError: 'Napraw błąd stawki za dystans i spróbuj ponownie.',
},
transactionMerge: {
listPage: {
Expand Down
2 changes: 2 additions & 0 deletions src/languages/pt-BR.ts
Original file line number Diff line number Diff line change
Expand Up @@ -634,6 +634,7 @@ const translations: TranslationDeepObject<typeof en> = {
nonReimbursableTotal: 'Total não reembolsável',
originalAmount: 'Valor original',
insights: 'Insights',
duplicateExpense: 'Despesa duplicada',
},
supportalNoAccess: {
title: 'Não tão rápido',
Expand Down Expand Up @@ -1469,6 +1470,7 @@ const translations: TranslationDeepObject<typeof en> = {
ratePreview: (rate: string) => `${rate} / hora`,
amountTooLargeError: 'O valor total é muito alto. Reduza as horas ou diminua a tarifa.',
},
correctDistanceRateError: 'Corrija o erro na taxa de distância e tente novamente.',
},
transactionMerge: {
listPage: {
Expand Down
2 changes: 2 additions & 0 deletions src/languages/zh-hans.ts
Original file line number Diff line number Diff line change
Expand Up @@ -631,6 +631,7 @@ const translations: TranslationDeepObject<typeof en> = {
nonReimbursableTotal: '不可报销总额',
originalAmount: '原始金额',
insights: '洞察',
duplicateExpense: '重复报销',
},
supportalNoAccess: {
title: '先别急',
Expand Down Expand Up @@ -1448,6 +1449,7 @@ const translations: TranslationDeepObject<typeof en> = {
ratePreview: (rate: string) => `${rate} / 小时`,
amountTooLargeError: '总金额过大。请减少工时或降低费率。',
},
correctDistanceRateError: '修复里程费率错误后请重试。',
},
transactionMerge: {
listPage: {
Expand Down
1 change: 1 addition & 0 deletions src/libs/API/parameters/CreateDistanceRequestParams.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ type CreateDistanceRequestParams = {
distance?: number;
odometerStart?: number;
odometerEnd?: number;
customUnitPolicyID?: string;
};

export default CreateDistanceRequestParams;
3 changes: 1 addition & 2 deletions src/libs/ReportSecondaryActionUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,6 @@ import {
getOriginalTransactionWithSplitInfo,
hasReceipt as hasReceiptTransactionUtils,
hasSmartScanFailedOrNoRouteViolation,
isDistanceRequest as isDistanceRequestTransactionUtils,
isDuplicate,
isManagedCardTransaction as isManagedCardTransactionTransactionUtils,
isOnHold as isOnHoldTransactionUtils,
Expand Down Expand Up @@ -758,7 +757,7 @@ function isDuplicateAction(report: Report, reportTransactions: Transaction[]): b
const reportTransaction = reportTransactions.at(0);

// Per diem and distance requests will be handled separately in a follow-up
if (isPerDiemRequestTransactionUtils(reportTransaction) || isDistanceRequestTransactionUtils(reportTransaction)) {
if (isPerDiemRequestTransactionUtils(reportTransaction)) {
return false;
}

Expand Down
8 changes: 8 additions & 0 deletions src/libs/TransactionUtils/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1476,6 +1476,13 @@ function hasPendingRTERViolation(transactionViolations?: TransactionViolations |
);
}

/**
* Check if there is a custom unit out of policy violation in transactionViolations.
*/
function hasCustomUnitOutOfPolicyViolation(transactionViolations?: TransactionViolations | null): boolean {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

NAB: it should be great if we can add unit tests for this util

return !!transactionViolations?.some((violation) => violation.name === CONST.VIOLATIONS.CUSTOM_UNIT_OUT_OF_POLICY);
}

/**
* Check if there is broken connection violation.
*/
Expand Down Expand Up @@ -2716,6 +2723,7 @@ export {
hasDuplicateTransactions,
hasBrokenConnectionViolation,
hasSmartScanFailedOrNoRouteViolation,
hasCustomUnitOutOfPolicyViolation,
shouldShowBrokenConnectionViolation,
shouldShowBrokenConnectionViolationForMultipleTransactions,
hasNoticeTypeViolation,
Expand Down
Loading
Loading