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
1 change: 0 additions & 1 deletion src/CONST/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5768,7 +5768,6 @@ const CONST = {
RECEIPT_GENERATED_WITH_AI: 'receiptGeneratedWithAI',
OVER_TRIP_LIMIT: 'overTripLimit',
COMPANY_CARD_REQUIRED: 'companyCardRequired',
MISSING_ATTENDEES: 'missingAttendees',
},
RTER_VIOLATION_TYPES: {
BROKEN_CARD_CONNECTION: 'brokenCardConnection',
Expand Down
4 changes: 0 additions & 4 deletions src/ROUTES.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1977,10 +1977,6 @@ const ROUTES = {
route: 'workspaces/:policyID/category/:categoryName/require-receipts-over',
getRoute: (policyID: string, categoryName: string) => `workspaces/${policyID}/category/${encodeURIComponent(categoryName)}/require-receipts-over` as const,
},
WORKSPACE_CATEGORY_REQUIRED_FIELDS: {
route: 'workspaces/:policyID/category/:categoryName/required-fields',
getRoute: (policyID: string, categoryName: string) => `workspaces/${policyID}/category/${encodeURIComponent(categoryName)}/required-fields` as const,
},
WORKSPACE_CATEGORY_APPROVER: {
route: 'workspaces/:policyID/category/:categoryName/approver',
getRoute: (policyID: string, categoryName: string) => `workspaces/${policyID}/category/${encodeURIComponent(categoryName)}/approver` as const,
Expand Down
1 change: 0 additions & 1 deletion src/SCREENS.ts
Original file line number Diff line number Diff line change
Expand Up @@ -690,7 +690,6 @@ const SCREENS = {
CATEGORY_DESCRIPTION_HINT: 'Category_Description_Hint',
CATEGORY_APPROVER: 'Category_Approver',
CATEGORY_REQUIRE_RECEIPTS_OVER: 'Category_Require_Receipts_Over',
CATEGORY_REQUIRED_FIELDS: 'Category_Required_Fields',
CATEGORIES_SETTINGS: 'Categories_Settings',
CATEGORIES_IMPORT: 'Categories_Import',
CATEGORIES_IMPORTED: 'Categories_Imported',
Expand Down
13 changes: 0 additions & 13 deletions src/components/MoneyRequestConfirmationList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,6 @@ import {
setMoneyRequestTaxRate,
setSplitShares,
} from '@libs/actions/IOU';
import {getIsMissingAttendeesViolation} from '@libs/AttendeeUtils';
import {isCategoryDescriptionRequired} from '@libs/CategoryUtils';
import {convertToBackendAmount, convertToDisplayString, convertToDisplayStringWithoutCurrency, getCurrencyDecimals} from '@libs/CurrencyUtils';
import DistanceRequestUtils from '@libs/DistanceRequestUtils';
Expand Down Expand Up @@ -921,12 +920,6 @@ function MoneyRequestConfirmationList({
return;
}

const isMissingAttendeesViolation = getIsMissingAttendeesViolation(policyCategories, iouCategory, iouAttendees, currentUserPersonalDetails, policy?.isAttendeeTrackingEnabled);
if (isMissingAttendeesViolation) {
setFormError('violations.missingAttendees');
return;
}

if (isPerDiemRequest && (transaction.comment?.customUnit?.subRates ?? []).length === 0) {
setFormError('iou.error.invalidSubrateLength');
return;
Expand Down Expand Up @@ -1000,8 +993,6 @@ function MoneyRequestConfirmationList({
showDelegateNoAccessModal,
iouCategory,
policyCategories,
iouAttendees,
currentUserPersonalDetails,
],
);

Expand All @@ -1025,10 +1016,6 @@ function MoneyRequestConfirmationList({
if (isTypeSplit && !shouldShowReadOnlySplits) {
return debouncedFormError && translate(debouncedFormError);
}
// Don't show error at the bottom of the form for missing attendees
if (formError === 'violations.missingAttendees') {
return;
}
return formError && translate(formError);
}, [routeError, isTypeSplit, shouldShowReadOnlySplits, debouncedFormError, formError, translate]);

Expand Down
7 changes: 2 additions & 5 deletions src/components/MoneyRequestConfirmationListFooter.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -380,7 +380,6 @@ function MoneyRequestConfirmationListFooter({
const shouldDisplayDistanceRateError = formError === 'iou.error.invalidRate';
const shouldDisplayTagError = formError === 'violations.tagOutOfPolicy';
const shouldDisplayCategoryError = formError === 'violations.categoryOutOfPolicy';
const shouldDisplayAttendeesError = formError === 'violations.missingAttendees';

const showReceiptEmptyState = shouldShowReceiptEmptyState(iouType, action, policy, isPerDiemRequest);
// The per diem custom unit
Expand Down Expand Up @@ -728,7 +727,7 @@ function MoneyRequestConfirmationListFooter({
item: (
<MenuItemWithTopDescription
key="attendees"
shouldShowRightIcon={!isReadOnly}
shouldShowRightIcon
title={iouAttendees?.map((item) => item?.displayName ?? item?.login).join(', ')}
description={`${translate('iou.attendees')} ${
iouAttendees?.length && iouAttendees.length > 1 && formattedAmountPerAttendee ? `\u00B7 ${formattedAmountPerAttendee} ${translate('common.perPerson')}` : ''
Expand All @@ -742,10 +741,8 @@ function MoneyRequestConfirmationListFooter({

Navigation.navigate(ROUTES.MONEY_REQUEST_ATTENDEE.getRoute(action, iouType, transactionID, reportID, Navigation.getActiveRoute()));
}}
interactive={!isReadOnly}
interactive
shouldRenderAsHTML
brickRoadIndicator={shouldDisplayAttendeesError ? CONST.BRICK_ROAD_INDICATOR_STATUS.ERROR : undefined}
errorText={shouldDisplayAttendeesError ? translate(formError) : ''}
/>
),
shouldShow: shouldShowAttendees,
Expand Down
25 changes: 5 additions & 20 deletions src/components/ReportActionItem/MoneyRequestView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,6 @@ import useThemeStyles from '@hooks/useThemeStyles';
import useTransactionViolations from '@hooks/useTransactionViolations';
import type {ViolationField} from '@hooks/useViolations';
import useViolations from '@hooks/useViolations';
import {initSplitExpense, updateMoneyRequestBillable, updateMoneyRequestReimbursable} from '@libs/actions/IOU/index';
import {getIsMissingAttendeesViolation} from '@libs/AttendeeUtils';
import {filterPersonalCards, getCompanyCardDescription} from '@libs/CardUtils';
import {getDecodedCategoryName, isCategoryMissing} from '@libs/CategoryUtils';
import {convertToDisplayString} from '@libs/CurrencyUtils';
Expand All @@ -53,12 +51,13 @@ import {
isTaxTrackingEnabled,
} from '@libs/PolicyUtils';
import {getOriginalMessage, isMoneyRequestAction} from '@libs/ReportActionsUtils';
import {computeReportName} from '@libs/ReportNameUtils';
import {isSplitAction} from '@libs/ReportSecondaryActionUtils';
import {
canEditFieldOfMoneyRequest,
canEditMoneyRequest,
canUserPerformWriteAction as canUserPerformWriteActionReportUtils,
// eslint-disable-next-line @typescript-eslint/no-deprecated
getReportName,
getTransactionDetails,
getTripIDFromTransactionParentReportID,
isExpenseReport,
Expand Down Expand Up @@ -98,6 +97,7 @@ import {
import ViolationsUtils from '@libs/Violations/ViolationsUtils';
import Navigation from '@navigation/Navigation';
import AnimatedEmptyStateBackground from '@pages/home/report/AnimatedEmptyStateBackground';
import {initSplitExpense, updateMoneyRequestBillable, updateMoneyRequestReimbursable} from '@userActions/IOU';
import CONST from '@src/CONST';
import type {TranslationPaths} from '@src/languages/types';
import ONYXKEYS from '@src/ONYXKEYS';
Expand Down Expand Up @@ -167,7 +167,6 @@ function MoneyRequestView({
const {getReportRHPActiveRoute} = useActiveRoute();
const [lastVisitedPath] = useOnyx(ONYXKEYS.LAST_VISITED_PATH, {canBeMissing: true});

const [allPolicies] = useOnyx(ONYXKEYS.COLLECTION.POLICY, {canBeMissing: true});
const [allTransactions] = useOnyx(ONYXKEYS.COLLECTION.TRANSACTION, {canBeMissing: false});

const searchContext = useSearchContext();
Expand Down Expand Up @@ -473,13 +472,6 @@ function MoneyRequestView({
const hasErrors = hasMissingSmartscanFields(transaction);
// Need to return undefined when we have pendingAction to avoid the duplicate pending action
const getPendingFieldAction = (fieldPath: TransactionPendingFieldsKey) => (pendingAction ? undefined : transaction?.pendingFields?.[fieldPath]);
const isMissingAttendeesViolation = getIsMissingAttendeesViolation(
policyCategories,
updatedTransaction?.category ?? categoryForDisplay,
actualAttendees,
currentUserPersonalDetails,
policy?.isAttendeeTrackingEnabled,
);

const getErrorForField = (field: ViolationField, data?: OnyxTypes.TransactionViolation['data'], policyHasDependentTags = false, tagValue?: string) => {
// Checks applied when creating a new expense
Expand Down Expand Up @@ -520,10 +512,6 @@ function MoneyRequestView({
return `${violations.map((violation) => ViolationsUtils.getViolationTranslation(violation, translate, canEdit, undefined, companyCardPageURL)).join('. ')}.`;
}

if (field === 'attendees' && isMissingAttendeesViolation) {
return translate('violations.missingAttendees');
}

return '';
};

Expand Down Expand Up @@ -732,9 +720,8 @@ function MoneyRequestView({
);
});

const reportNameToDisplay = isFromMergeTransaction
? (updatedTransaction?.reportName ?? translate('common.none'))
: (parentReport?.reportName ?? computeReportName(parentReport, allReports, allPolicies, allTransactions));
// eslint-disable-next-line @typescript-eslint/no-deprecated
const reportNameToDisplay = isFromMergeTransaction ? (updatedTransaction?.reportName ?? translate('common.none')) : (parentReport?.reportName ?? getReportName(parentReport));
const shouldShowReport = !!parentReportID || (isFromMergeTransaction && !!reportNameToDisplay);
const reportCopyValue = !canEditReport && reportNameToDisplay !== translate('common.none') ? reportNameToDisplay : undefined;
const shouldShowCategoryAnalyzing = isCategoryBeingAnalyzed(updatedTransaction ?? transaction);
Expand Down Expand Up @@ -1025,8 +1012,6 @@ function MoneyRequestView({
onPress={() => {
Navigation.navigate(ROUTES.MONEY_REQUEST_ATTENDEE.getRoute(CONST.IOU.ACTION.EDIT, iouType, transaction.transactionID, transactionThreadReport?.reportID));
}}
brickRoadIndicator={getErrorForField('attendees') ? CONST.BRICK_ROAD_INDICATOR_STATUS.ERROR : undefined}
errorText={getErrorForField('attendees')}
interactive={canEdit}
shouldShowRightIcon={canEdit}
shouldRenderAsHTML
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@ import useTheme from '@hooks/useTheme';
import useThemeStyles from '@hooks/useThemeStyles';
import type {TransactionPreviewData} from '@libs/actions/Search';
import {handleActionButtonPress as handleActionButtonPressUtil} from '@libs/actions/Search';
import {syncMissingAttendeesViolation} from '@libs/AttendeeUtils';
import getNonEmptyStringOnyxID from '@libs/getNonEmptyStringOnyxID';
import {isViolationDismissed, shouldShowViolation} from '@libs/TransactionUtils';
import variables from '@styles/variables';
Expand Down Expand Up @@ -66,8 +65,6 @@ function TransactionListItem<TItem extends ListItem>({
const snapshotPolicy = useMemo(() => {
return (snapshot?.data?.[`${ONYXKEYS.COLLECTION.POLICY}${transactionItem.policyID}`] ?? {}) as Policy;
}, [snapshot, transactionItem.policyID]);
// Fetch policy categories directly from Onyx since they are not included in the search snapshot
const [policyCategories] = originalUseOnyx(`${ONYXKEYS.COLLECTION.POLICY_CATEGORIES}${transactionItem.policyID}`, {canBeMissing: true});
const [lastPaymentMethod] = useOnyx(`${ONYXKEYS.NVP_LAST_PAYMENT_METHOD}`, {canBeMissing: true});
const [personalPolicyID] = useOnyx(ONYXKEYS.PERSONAL_POLICY_ID, {canBeMissing: true});

Expand Down Expand Up @@ -124,25 +121,12 @@ function TransactionListItem<TItem extends ListItem>({
]);

const transactionViolations = useMemo(() => {
const onyxViolations = (violations?.[`${ONYXKEYS.COLLECTION.TRANSACTION_VIOLATIONS}${transactionItem.transactionID}`] ?? []).filter(
return (violations?.[`${ONYXKEYS.COLLECTION.TRANSACTION_VIOLATIONS}${transactionItem.transactionID}`] ?? []).filter(
(violation: TransactionViolation) =>
!isViolationDismissed(transactionItem, violation, currentUserDetails.email ?? '', currentUserDetails.accountID, snapshotReport, snapshotPolicy) &&
shouldShowViolation(snapshotReport, snapshotPolicy, violation.name, currentUserDetails.email ?? '', false, transactionItem),
);

// Sync missingAttendees violation with current policy category settings (can be removed later when BE handles this)
const attendeeOnyxViolations = syncMissingAttendeesViolation(
onyxViolations,
policyCategories,
transactionItem.category ?? '',
transactionItem.attendees,
currentUserDetails,
snapshotPolicy?.isAttendeeTrackingEnabled ?? false,
snapshotPolicy?.type === CONST.POLICY.TYPE.CORPORATE,
);

return [...onyxViolations, ...attendeeOnyxViolations];
}, [snapshotPolicy, policyCategories, snapshotReport, transactionItem, violations, currentUserDetails.email, currentUserDetails.accountID, currentUserDetails]);
}, [snapshotPolicy, snapshotReport, transactionItem, violations, currentUserDetails.email, currentUserDetails.accountID]);

const {isDelegateAccessRestricted, showDelegateNoAccessModal} = useContext(DelegateNoAccessContext);

Expand Down
3 changes: 1 addition & 2 deletions src/hooks/useViolations.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import type {TransactionViolation, ViolationName} from '@src/types/onyx';
/**
* Names of Fields where violations can occur.
*/
const validationFields = ['amount', 'billable', 'category', 'comment', 'date', 'merchant', 'receipt', 'tag', 'tax', 'attendees', 'customUnitRateID', 'none'] as const;
const validationFields = ['amount', 'billable', 'category', 'comment', 'date', 'merchant', 'receipt', 'tag', 'tax', 'customUnitRateID', 'none'] as const;

type ViolationField = TupleToUnion<typeof validationFields>;

Expand All @@ -28,7 +28,6 @@ const violationNameToField: Record<ViolationName, (violation: TransactionViolati
maxAge: () => 'date',
missingCategory: () => 'category',
missingComment: () => 'comment',
missingAttendees: () => 'attendees',
missingTag: () => 'tag',
modifiedAmount: () => 'amount',
modifiedDate: () => 'date',
Expand Down
5 changes: 0 additions & 5 deletions src/languages/de.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6237,10 +6237,6 @@ Fordere Spesendetails wie Belege und Beschreibungen an, lege Limits und Standard
title: 'Kategorierichtlinien',
approver: 'Genehmiger',
requireDescription: 'Beschreibung erforderlich',
requireFields: 'Felder verpflichtend machen',
requiredFieldsTitle: 'Pflichtfelder',
requiredFieldsDescription: (categoryName: string) => `Dies gilt für alle Ausgaben, die als <strong>${categoryName}</strong> kategorisiert sind.`,
requireAttendees: 'Teilnehmer erforderlich machen',
descriptionHint: 'Hinweis zur Beschreibung',
descriptionHintDescription: (categoryName: string) =>
`Mitarbeitende daran erinnern, zusätzliche Informationen für Ausgaben der Kategorie „${categoryName}“ anzugeben. Dieser Hinweis erscheint im Beschreibungsfeld von Ausgaben.`,
Expand Down Expand Up @@ -7293,7 +7289,6 @@ Fordere Spesendetails wie Belege und Beschreibungen an, lege Limits und Standard
maxAge: ({maxAge}: ViolationsMaxAgeParams) => `Datum älter als ${maxAge} Tage`,
missingCategory: 'Fehlende Kategorie',
missingComment: 'Beschreibung für ausgewählte Kategorie erforderlich',
missingAttendees: 'Für diese Kategorie sind mehrere Teilnehmer erforderlich',
missingTag: ({tagName}: ViolationsMissingTagParams = {}) => `Fehlende ${tagName ?? 'Tag'}`,
modifiedAmount: ({type, displayPercentVariance}: ViolationsModifiedAmountParams) => {
switch (type) {
Expand Down
5 changes: 0 additions & 5 deletions src/languages/en.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6097,10 +6097,6 @@ const translations = {
title: 'Category rules',
approver: 'Approver',
requireDescription: 'Require description',
requireFields: 'Require fields',
requiredFieldsTitle: 'Required fields',
requiredFieldsDescription: (categoryName: string) => `This will apply to all expenses categorized as <strong>${categoryName}</strong>.`,
requireAttendees: 'Require attendees',
descriptionHint: 'Description hint',
descriptionHintDescription: (categoryName: string) =>
`Remind employees to provide additional information for “${categoryName}” spend. This hint appears in the description field on expenses.`,
Expand Down Expand Up @@ -7185,7 +7181,6 @@ const translations = {
maxAge: ({maxAge}: ViolationsMaxAgeParams) => `Date older than ${maxAge} days`,
missingCategory: 'Missing category',
missingComment: 'Description required for selected category',
missingAttendees: 'Multiple attendees required for this category',
missingTag: ({tagName}: ViolationsMissingTagParams = {}) => `Missing ${tagName ?? 'tag'}`,
modifiedAmount: ({type, displayPercentVariance}: ViolationsModifiedAmountParams) => {
switch (type) {
Expand Down
5 changes: 0 additions & 5 deletions src/languages/es.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5834,10 +5834,6 @@ ${amount} para ${merchant} - ${date}`,
title: 'Reglas de categoría',
approver: 'Aprobador',
requireDescription: 'Requerir descripción',
requireFields: 'Requerir campos',
requiredFieldsTitle: 'Campos obligatorios',
requiredFieldsDescription: (categoryName) => `Esto se aplicará a todos los gastos categorizados como <strong>${categoryName}</strong>.`,
requireAttendees: 'Requerir asistentes',
descriptionHint: 'Sugerencia de descripción',
descriptionHintDescription: (categoryName) =>
`Recuerda a los empleados que deben proporcionar información adicional para los gastos de “${categoryName}”. Esta sugerencia aparece en el campo de descripción en los gastos.`,
Expand Down Expand Up @@ -7325,7 +7321,6 @@ ${amount} para ${merchant} - ${date}`,
maxAge: ({maxAge}) => `Fecha de más de ${maxAge} días`,
missingCategory: 'Falta categoría',
missingComment: 'Descripción obligatoria para la categoría seleccionada',
missingAttendees: 'Se requieren múltiples asistentes para esta categoría',
missingTag: ({tagName} = {}) => `Falta ${tagName ?? 'etiqueta'}`,
modifiedAmount: ({type, displayPercentVariance}) => {
switch (type) {
Expand Down
5 changes: 0 additions & 5 deletions src/languages/fr.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6246,10 +6246,6 @@ Exigez des informations de dépense comme les reçus et les descriptions, défin
title: 'Règles de catégorie',
approver: 'Approbateur',
requireDescription: 'Description requise',
requireFields: 'Rendre les champs obligatoires',
requiredFieldsTitle: 'Champs obligatoires',
requiredFieldsDescription: (categoryName: string) => `Cela s’appliquera à toutes les dépenses classées dans la catégorie <strong>${categoryName}</strong>.`,
requireAttendees: 'Exiger des participants',
descriptionHint: 'Indice de description',
descriptionHintDescription: (categoryName: string) =>
`Rappelez aux employés de fournir des informations supplémentaires pour les dépenses « ${categoryName} ». Cet indice apparaît dans le champ de description des dépenses.`,
Expand Down Expand Up @@ -7304,7 +7300,6 @@ Exigez des informations de dépense comme les reçus et les descriptions, défin
maxAge: ({maxAge}: ViolationsMaxAgeParams) => `Date de plus de ${maxAge} jours`,
missingCategory: 'Catégorie manquante',
missingComment: 'Description requise pour la catégorie sélectionnée',
missingAttendees: 'Plusieurs participants sont requis pour cette catégorie',
missingTag: ({tagName}: ViolationsMissingTagParams = {}) => `Manquant ${tagName ?? 'étiquette'}`,
modifiedAmount: ({type, displayPercentVariance}: ViolationsModifiedAmountParams) => {
switch (type) {
Expand Down
Loading
Loading