Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,23 +1,18 @@
import React, {useCallback} from 'react';
import React from 'react';
import type {ViewStyle} from 'react-native';
import {View} from 'react-native';
import Icon from '@components/Icon';
import {DotIndicator} from '@components/Icon/Expensicons';
import type {LocaleContextProps} from '@components/LocaleContextProvider';
import RenderHTML from '@components/RenderHTML';
import useLocalize from '@hooks/useLocalize';
import usePaginatedReportActions from '@hooks/usePaginatedReportActions';
import useTheme from '@hooks/useTheme';
import useThemeStyles from '@hooks/useThemeStyles';
import useTransactionViolations from '@hooks/useTransactionViolations';
import {isReceiptError} from '@libs/ErrorUtils';
import {getIOUActionForTransactionID} from '@libs/ReportActionsUtils';
import ViolationsUtils from '@libs/Violations/ViolationsUtils';
import variables from '@styles/variables';
import type {Errors} from '@src/types/onyx/OnyxCommon';
import type ReportAction from '@src/types/onyx/ReportAction';
import type Transaction from '@src/types/onyx/Transaction';
import type {ReceiptError, ReceiptErrors} from '@src/types/onyx/Transaction';

type TransactionItemRowRBRProps = {
/** Transaction item */
Expand All @@ -30,43 +25,6 @@ type TransactionItemRowRBRProps = {
missingFieldError?: string;
};

/**
* Extracts unique error messages from errors and actions
*/
const extractErrorMessages = (errors: Errors | ReceiptErrors, errorActions: ReportAction[], translate: LocaleContextProps['translate']): string[] => {
const uniqueMessages = new Set<string>();

// Combine transaction and action errors
let allErrors: Record<string, string | Errors | ReceiptError | null | undefined> = {...errors};
errorActions.forEach((action) => {
if (!action.errors) {
return;
}
allErrors = {...allErrors, ...action.errors};
});

// Extract error messages
Object.values(allErrors).forEach((errorValue) => {
if (!errorValue) {
return;
}
if (typeof errorValue === 'string') {
uniqueMessages.add(errorValue);
} else if (isReceiptError(errorValue)) {
uniqueMessages.add(translate('iou.error.receiptFailureMessageShort'));
} else {
Object.values(errorValue).forEach((nestedErrorValue) => {
if (!nestedErrorValue) {
return;
}
uniqueMessages.add(nestedErrorValue);
});
}
});

return Array.from(uniqueMessages);
};

function TransactionItemRowRBRWithOnyx({transaction, containerStyles, missingFieldError}: TransactionItemRowRBRProps) {
const styles = useThemeStyles();
const transactionViolations = useTransactionViolations(transaction?.transactionID);
Expand All @@ -76,27 +34,9 @@ function TransactionItemRowRBRWithOnyx({transaction, containerStyles, missingFie
const {sortedAllReportActions: transactionActions} = usePaginatedReportActions(transaction.reportID);
const transactionThreadId = transactionActions ? getIOUActionForTransactionID(transactionActions, transaction.transactionID)?.childReportID : undefined;
const {sortedAllReportActions: transactionThreadActions} = usePaginatedReportActions(transactionThreadId);
const getErrorMessages = useCallback(
(errors: Errors | ReceiptErrors | undefined = {}, errorActions: ReportAction[] | undefined = []) => extractErrorMessages(errors, errorActions, translate),
[translate],
);

const RBRMessages = [
...getErrorMessages(
transaction?.errors,
transactionThreadActions?.filter((e) => !!e.errors),
),
...(missingFieldError ? [`${missingFieldError}.`] : []),
// Some violations end with a period already so lets make sure the connected messages have only single period between them
// and end with a single dot.
...transactionViolations.map((violation) => {
const message = ViolationsUtils.getViolationTranslation(violation, translate);
if (!message.length) {
return [];
}
return message.endsWith('.') ? message : `${message}.`;
}),
].join(' ');
const RBRMessages = ViolationsUtils.getRBRMessages(transaction, transactionViolations, translate, missingFieldError, transactionThreadActions);

return (
RBRMessages.length > 0 && (
<View
Expand Down
6 changes: 3 additions & 3 deletions src/languages/de.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6240,10 +6240,10 @@ const translations = {
customRules: ({message}: ViolationsCustomRulesParams) => message,
reviewRequired: 'Überprüfung erforderlich',
rter: ({brokenBankConnection, email, isAdmin, isTransactionOlderThan7Days, member, rterType}: ViolationsRterParams) => {
if (rterType === CONST.RTER_VIOLATION_TYPES.BROKEN_CARD_CONNECTION_530 || rterType === CONST.RTER_VIOLATION_TYPES.BROKEN_CARD_CONNECTION) {
return '';
if (rterType === CONST.RTER_VIOLATION_TYPES.BROKEN_CARD_CONNECTION_530) {
return 'Kassenbon kann aufgrund einer unterbrochenen Bankverbindung nicht automatisch zugeordnet werden.';
}
if (brokenBankConnection) {
if (brokenBankConnection || rterType === CONST.RTER_VIOLATION_TYPES.BROKEN_CARD_CONNECTION) {
return isAdmin
? `Kassenbon kann aufgrund einer unterbrochenen Bankverbindung, die ${email} beheben muss, nicht automatisch zugeordnet werden.`
: 'Konnte Beleg aufgrund einer defekten Bankverbindung, die Sie beheben müssen, nicht automatisch zuordnen.';
Expand Down
6 changes: 3 additions & 3 deletions src/languages/en.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6173,10 +6173,10 @@ const translations = {
customRules: ({message}: ViolationsCustomRulesParams) => message,
reviewRequired: 'Review required',
rter: ({brokenBankConnection, email, isAdmin, isTransactionOlderThan7Days, member, rterType}: ViolationsRterParams) => {
if (rterType === CONST.RTER_VIOLATION_TYPES.BROKEN_CARD_CONNECTION_530 || rterType === CONST.RTER_VIOLATION_TYPES.BROKEN_CARD_CONNECTION) {
return '';
if (rterType === CONST.RTER_VIOLATION_TYPES.BROKEN_CARD_CONNECTION_530) {
return "Can't auto-match receipt due to broken bank connection";
}
if (brokenBankConnection) {
if (brokenBankConnection || rterType === CONST.RTER_VIOLATION_TYPES.BROKEN_CARD_CONNECTION) {
return isAdmin
? `Can't auto-match receipt due to broken bank connection which ${email} needs to fix`
: "Can't auto-match receipt due to broken bank connection which you need to fix";
Expand Down
6 changes: 3 additions & 3 deletions src/languages/es.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6691,10 +6691,10 @@ const translations = {
customRules: ({message}: ViolationsCustomRulesParams) => message,
reviewRequired: 'Revisión requerida',
rter: ({brokenBankConnection, isAdmin, email, isTransactionOlderThan7Days, member, rterType}: ViolationsRterParams) => {
if (rterType === CONST.RTER_VIOLATION_TYPES.BROKEN_CARD_CONNECTION_530 || rterType === CONST.RTER_VIOLATION_TYPES.BROKEN_CARD_CONNECTION) {
return '';
if (rterType === CONST.RTER_VIOLATION_TYPES.BROKEN_CARD_CONNECTION_530) {
return 'No se puede emparejar automáticamente el recibo debido a una conexión bancaria interrumpida.';
}
if (brokenBankConnection) {
if (brokenBankConnection || rterType === CONST.RTER_VIOLATION_TYPES.BROKEN_CARD_CONNECTION) {
return isAdmin
? `No se puede adjuntar recibo debido a un problema con la conexión a tu banco que ${email} necesita arreglar`
: 'No se puede adjuntar recibo debido a un problema con la conexión a tu banco que necesitas arreglar';
Expand Down
6 changes: 3 additions & 3 deletions src/languages/fr.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6250,10 +6250,10 @@ const translations = {
customRules: ({message}: ViolationsCustomRulesParams) => message,
reviewRequired: 'Examen requis',
rter: ({brokenBankConnection, email, isAdmin, isTransactionOlderThan7Days, member, rterType}: ViolationsRterParams) => {
if (rterType === CONST.RTER_VIOLATION_TYPES.BROKEN_CARD_CONNECTION_530 || rterType === CONST.RTER_VIOLATION_TYPES.BROKEN_CARD_CONNECTION) {
return '';
if (rterType === CONST.RTER_VIOLATION_TYPES.BROKEN_CARD_CONNECTION_530) {
return "Impossible de faire correspondre automatiquement le reçu en raison d'une connexion bancaire défectueuse.";
}
if (brokenBankConnection) {
if (brokenBankConnection || rterType === CONST.RTER_VIOLATION_TYPES.BROKEN_CARD_CONNECTION) {
return isAdmin
? `Impossible de faire correspondre automatiquement le reçu en raison d'une connexion bancaire défectueuse que ${email} doit corriger.`
: "Impossible de faire correspondre automatiquement le reçu en raison d'une connexion bancaire défectueuse que vous devez réparer.";
Expand Down
6 changes: 3 additions & 3 deletions src/languages/it.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6225,10 +6225,10 @@ const translations = {
customRules: ({message}: ViolationsCustomRulesParams) => message,
reviewRequired: 'Revisione richiesta',
rter: ({brokenBankConnection, email, isAdmin, isTransactionOlderThan7Days, member, rterType}: ViolationsRterParams) => {
if (rterType === CONST.RTER_VIOLATION_TYPES.BROKEN_CARD_CONNECTION_530 || rterType === CONST.RTER_VIOLATION_TYPES.BROKEN_CARD_CONNECTION) {
return '';
if (rterType === CONST.RTER_VIOLATION_TYPES.BROKEN_CARD_CONNECTION_530) {
return 'Impossibile associare automaticamente la ricevuta a causa di una connessione bancaria interrotta.';
}
if (brokenBankConnection) {
if (brokenBankConnection || rterType === CONST.RTER_VIOLATION_TYPES.BROKEN_CARD_CONNECTION) {
return isAdmin
? `Impossibile abbinare automaticamente la ricevuta a causa di una connessione bancaria interrotta che ${email} deve risolvere.`
: 'Impossibile abbinare automaticamente la ricevuta a causa di una connessione bancaria interrotta che devi risolvere.';
Expand Down
6 changes: 3 additions & 3 deletions src/languages/ja.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6168,10 +6168,10 @@ const translations = {
customRules: ({message}: ViolationsCustomRulesParams) => message,
reviewRequired: 'レビューが必要です',
rter: ({brokenBankConnection, email, isAdmin, isTransactionOlderThan7Days, member, rterType}: ViolationsRterParams) => {
if (rterType === CONST.RTER_VIOLATION_TYPES.BROKEN_CARD_CONNECTION_530 || rterType === CONST.RTER_VIOLATION_TYPES.BROKEN_CARD_CONNECTION) {
return '';
if (rterType === CONST.RTER_VIOLATION_TYPES.BROKEN_CARD_CONNECTION_530) {
return '銀行接続が切れているため、領収書を自動照合できません。';
}
if (brokenBankConnection) {
if (brokenBankConnection || rterType === CONST.RTER_VIOLATION_TYPES.BROKEN_CARD_CONNECTION) {
return isAdmin
? `${email}が修正する必要がある銀行接続の問題のため、領収書を自動マッチングできません。`
: '壊れた銀行接続のため、領収書を自動マッチングできません。修正が必要です。';
Expand Down
6 changes: 3 additions & 3 deletions src/languages/nl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6213,10 +6213,10 @@ const translations = {
customRules: ({message}: ViolationsCustomRulesParams) => message,
reviewRequired: 'Beoordeling vereist',
rter: ({brokenBankConnection, email, isAdmin, isTransactionOlderThan7Days, member, rterType}: ViolationsRterParams) => {
if (rterType === CONST.RTER_VIOLATION_TYPES.BROKEN_CARD_CONNECTION_530 || rterType === CONST.RTER_VIOLATION_TYPES.BROKEN_CARD_CONNECTION) {
return '';
if (rterType === CONST.RTER_VIOLATION_TYPES.BROKEN_CARD_CONNECTION_530) {
return 'Kan bon niet automatisch koppelen vanwege verbroken bankverbinding.';
}
if (brokenBankConnection) {
if (brokenBankConnection || rterType === CONST.RTER_VIOLATION_TYPES.BROKEN_CARD_CONNECTION) {
return isAdmin
? `Kan ontvangst niet automatisch koppelen vanwege een verbroken bankverbinding die ${email} moet herstellen.`
: 'Kan bon niet automatisch koppelen vanwege een verbroken bankverbinding die je moet herstellen.';
Expand Down
6 changes: 3 additions & 3 deletions src/languages/pl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6196,10 +6196,10 @@ const translations = {
customRules: ({message}: ViolationsCustomRulesParams) => message,
reviewRequired: 'Wymagana recenzja',
rter: ({brokenBankConnection, email, isAdmin, isTransactionOlderThan7Days, member, rterType}: ViolationsRterParams) => {
if (rterType === CONST.RTER_VIOLATION_TYPES.BROKEN_CARD_CONNECTION_530 || rterType === CONST.RTER_VIOLATION_TYPES.BROKEN_CARD_CONNECTION) {
return '';
if (rterType === CONST.RTER_VIOLATION_TYPES.BROKEN_CARD_CONNECTION_530) {
return 'Nie można automatycznie dopasować paragonu z powodu przerwanego połączenia z bankiem.';
}
if (brokenBankConnection) {
if (brokenBankConnection || rterType === CONST.RTER_VIOLATION_TYPES.BROKEN_CARD_CONNECTION) {
return isAdmin
? `Nie można automatycznie dopasować paragonu z powodu zerwanego połączenia z bankiem, które ${email} musi naprawić.`
: 'Nie można automatycznie dopasować paragonu z powodu przerwanego połączenia z bankiem, które musisz naprawić.';
Expand Down
6 changes: 3 additions & 3 deletions src/languages/pt-BR.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6209,10 +6209,10 @@ const translations = {
customRules: ({message}: ViolationsCustomRulesParams) => message,
reviewRequired: 'Revisão necessária',
rter: ({brokenBankConnection, email, isAdmin, isTransactionOlderThan7Days, member, rterType}: ViolationsRterParams) => {
if (rterType === CONST.RTER_VIOLATION_TYPES.BROKEN_CARD_CONNECTION_530 || rterType === CONST.RTER_VIOLATION_TYPES.BROKEN_CARD_CONNECTION) {
return '';
if (rterType === CONST.RTER_VIOLATION_TYPES.BROKEN_CARD_CONNECTION_530) {
return 'Não é possível associar automaticamente o recibo devido a uma conexão bancária interrompida.';
}
if (brokenBankConnection) {
if (brokenBankConnection || rterType === CONST.RTER_VIOLATION_TYPES.BROKEN_CARD_CONNECTION) {
return isAdmin
? `Não é possível associar automaticamente o recibo devido a uma conexão bancária interrompida que ${email} precisa corrigir.`
: 'Não é possível associar automaticamente o recibo devido a uma conexão bancária interrompida que você precisa corrigir.';
Expand Down
6 changes: 3 additions & 3 deletions src/languages/zh-hans.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6098,10 +6098,10 @@ const translations = {
customRules: ({message}: ViolationsCustomRulesParams) => message,
reviewRequired: '需要审核',
rter: ({brokenBankConnection, email, isAdmin, isTransactionOlderThan7Days, member, rterType}: ViolationsRterParams) => {
if (rterType === CONST.RTER_VIOLATION_TYPES.BROKEN_CARD_CONNECTION_530 || rterType === CONST.RTER_VIOLATION_TYPES.BROKEN_CARD_CONNECTION) {
return '';
if (rterType === CONST.RTER_VIOLATION_TYPES.BROKEN_CARD_CONNECTION_530) {
return '由于银行连接中断,无法自动匹配收据。';
}
if (brokenBankConnection) {
if (brokenBankConnection || rterType === CONST.RTER_VIOLATION_TYPES.BROKEN_CARD_CONNECTION) {
return isAdmin ? `由于银行连接中断,无法自动匹配收据,需要${email}进行修复。` : '由于需要修复的银行连接中断,无法自动匹配收据。';
}
if (!isTransactionOlderThan7Days) {
Expand Down
68 changes: 67 additions & 1 deletion src/libs/Violations/ViolationsUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,14 @@ import type {OnyxUpdate} from 'react-native-onyx';
import type {LocaleContextProps} from '@components/LocaleContextProvider';
import * as CurrencyUtils from '@libs/CurrencyUtils';
import DateUtils from '@libs/DateUtils';
import {isReceiptError} from '@libs/ErrorUtils';
import {getDistanceRateCustomUnitRate, getSortedTagKeys} from '@libs/PolicyUtils';
import * as TransactionUtils from '@libs/TransactionUtils';
import CONST from '@src/CONST';
import ONYXKEYS from '@src/ONYXKEYS';
import type {Policy, PolicyCategories, PolicyTagLists, Transaction, TransactionViolation, ViolationName} from '@src/types/onyx';
import type {Policy, PolicyCategories, PolicyTagLists, ReportAction, Transaction, TransactionViolation, ViolationName} from '@src/types/onyx';
import type {Errors} from '@src/types/onyx/OnyxCommon';
import type {ReceiptError, ReceiptErrors} from '@src/types/onyx/Transaction';

/**
* Calculates tag out of policy and missing tag violations for the given transaction
Expand Down Expand Up @@ -158,6 +161,43 @@ function getTagViolationsForMultiLevelTags(
return getTagViolationForIndependentTags(policyTagList, filteredTransactionViolations, updatedTransaction);
}

/**
* Extracts unique error messages from errors and actions
*/
function extractErrorMessages(errors: Errors | ReceiptErrors, errorActions: ReportAction[], translate: LocaleContextProps['translate']): string[] {
const uniqueMessages = new Set<string>();

// Combine transaction and action errors
let allErrors: Record<string, string | Errors | ReceiptError | null | undefined> = {...errors};
errorActions.forEach((action) => {
if (!action.errors) {
return;
}
allErrors = {...allErrors, ...action.errors};
});

// Extract error messages
Object.values(allErrors).forEach((errorValue) => {
if (!errorValue) {
return;
}
if (typeof errorValue === 'string') {
uniqueMessages.add(errorValue);
} else if (isReceiptError(errorValue)) {
uniqueMessages.add(translate('iou.error.receiptFailureMessageShort'));
} else {
Object.values(errorValue).forEach((nestedErrorValue) => {
if (!nestedErrorValue) {
return;
}
uniqueMessages.add(nestedErrorValue);
});
}
});

return Array.from(uniqueMessages);
}

const ViolationsUtils = {
/**
* Checks a transaction for policy violations and returns an object with Onyx method, key and updated transaction
Expand Down Expand Up @@ -472,6 +512,32 @@ const ViolationsUtils = {
getViolationAmountLimit(violation: TransactionViolation): number {
return Number(violation.data?.formattedLimit?.replace(CONST.VIOLATION_LIMIT_REGEX, ''));
},

getRBRMessages(
transaction: Transaction,
transactionViolations: TransactionViolation[],
translate: LocaleContextProps['translate'],
missingFieldError?: string,
transactionThreadActions?: ReportAction[],
): string {
const errorMessages = extractErrorMessages(transaction?.errors ?? {}, transactionThreadActions?.filter((e) => !!e.errors) ?? [], translate);

return [
...errorMessages,
...(missingFieldError ? [`${missingFieldError}.`] : []),
// Some violations end with a period already so lets make sure the connected messages have only single period between them
// and end with a single dot.
...transactionViolations.map((violation) => {
const message = ViolationsUtils.getViolationTranslation(violation, translate);
if (!message) {
return;
}
return message.endsWith('.') ? message : `${message}.`;
}),
]
.filter(Boolean)
.join(' ');
},
};

export default ViolationsUtils;
Loading