diff --git a/__mocks__/reportData/transactions.ts b/__mocks__/reportData/transactions.ts index 4dc0cfdd1902..dfc621ed90a7 100644 --- a/__mocks__/reportData/transactions.ts +++ b/__mocks__/reportData/transactions.ts @@ -30,7 +30,7 @@ const transactionR14932: Transaction = { reimbursable: true, hasEReceipt: true, cardID: 0, - modifiedAmount: 0, + modifiedAmount: '', originalAmount: 0, comment: {}, bank: '', @@ -59,7 +59,7 @@ const transactionR98765: Transaction = { hasEReceipt: true, managedCard: false, billable: false, - modifiedAmount: 0, + modifiedAmount: '', cardID: 0, originalAmount: 0, comment: {}, diff --git a/src/components/ReportActionItem/MoneyRequestReportPreview/index.tsx b/src/components/ReportActionItem/MoneyRequestReportPreview/index.tsx index d9cceea897a7..f4a80b467390 100644 --- a/src/components/ReportActionItem/MoneyRequestReportPreview/index.tsx +++ b/src/components/ReportActionItem/MoneyRequestReportPreview/index.tsx @@ -96,7 +96,7 @@ function MoneyRequestReportPreview({ } // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing - return transactions.some((transaction) => (transaction?.modifiedAmount || transaction?.amount) < 0); + return transactions.some((transaction) => (Number(transaction?.modifiedAmount) || transaction?.amount) < 0); }, [transactions, action.childType, iouReport]); const openReportFromPreview = useCallback(() => { diff --git a/src/components/ReportActionItem/MoneyRequestView.tsx b/src/components/ReportActionItem/MoneyRequestView.tsx index f7c51c627df1..d0054e8e8595 100644 --- a/src/components/ReportActionItem/MoneyRequestView.tsx +++ b/src/components/ReportActionItem/MoneyRequestView.tsx @@ -205,7 +205,8 @@ function MoneyRequestView({ originalCurrency: transactionOriginalCurrency, postedDate: transactionPostedDate, } = useMemo>(() => getTransactionDetails(transaction, undefined, undefined, allowNegativeAmount) ?? {}, [allowNegativeAmount, transaction]); - const isEmptyMerchant = transactionMerchant === '' || transactionMerchant === CONST.TRANSACTION.PARTIAL_TRANSACTION_MERCHANT; + const isEmptyMerchant = + transactionMerchant === '' || transactionMerchant === CONST.TRANSACTION.PARTIAL_TRANSACTION_MERCHANT || transactionMerchant === CONST.TRANSACTION.DEFAULT_MERCHANT; const isDistanceRequest = isDistanceRequestTransactionUtils(transaction); const isManualDistanceRequest = isManualDistanceRequestTransactionUtils(transaction); const isMapDistanceRequest = isDistanceRequest && !isManualDistanceRequest; @@ -218,9 +219,10 @@ function MoneyRequestView({ // Use the updated transaction amount in merge flow to have correct positive/negative sign const actualAmount = isFromMergeTransaction && updatedTransaction ? updatedTransaction.amount : transactionAmount; const actualCurrency = updatedTransaction ? getCurrency(updatedTransaction) : transactionCurrency; - const shouldDisplayTransactionAmount = ((isDistanceRequest && hasRoute) || !!actualAmount) && actualAmount !== undefined; + const shouldDisplayTransactionAmount = (isDistanceRequest && hasRoute) || !isDistanceRequest; const formattedTransactionAmount = shouldDisplayTransactionAmount ? convertToDisplayString(actualAmount, actualCurrency) : ''; - const formattedPerAttendeeAmount = shouldDisplayTransactionAmount ? convertToDisplayString(actualAmount / (actualAttendees?.length ?? 1), actualCurrency) : ''; + const formattedPerAttendeeAmount = + shouldDisplayTransactionAmount && actualAmount !== undefined ? convertToDisplayString(actualAmount / (transactionAttendees?.length ?? 1), actualCurrency) : ''; const formattedOriginalAmount = transactionOriginalAmount && transactionOriginalCurrency && convertToDisplayString(transactionOriginalAmount, transactionOriginalCurrency); const isCardTransaction = isCardTransactionTransactionUtils(transaction); @@ -311,7 +313,7 @@ function MoneyRequestView({ const rateToDisplay = isCustomUnitOutOfPolicy ? translate('common.rateOutOfPolicy') : DistanceRequestUtils.getRateForDisplay(unit, rate, currency, translate, toLocaleDigit, isOffline); const distanceToDisplay = DistanceRequestUtils.getDistanceForDisplay(hasRoute, distance, unit, rate, translate); let merchantTitle = isEmptyMerchant ? '' : transactionMerchant; - let amountTitle = formattedTransactionAmount ? formattedTransactionAmount.toString() : ''; + let amountTitle = formattedTransactionAmount?.toString() || ''; if (isTransactionScanning) { merchantTitle = translate('iou.receiptStatusTitle'); amountTitle = translate('iou.receiptStatusTitle'); @@ -325,7 +327,10 @@ function MoneyRequestView({ } return getDescription(updatedTransaction ?? null); }, [updatedTransaction]); - const isEmptyUpdatedMerchant = updatedTransaction?.modifiedMerchant === '' || updatedTransaction?.modifiedMerchant === CONST.TRANSACTION.PARTIAL_TRANSACTION_MERCHANT; + const isEmptyUpdatedMerchant = + updatedTransaction?.modifiedMerchant === '' || + updatedTransaction?.modifiedMerchant === CONST.TRANSACTION.PARTIAL_TRANSACTION_MERCHANT || + updatedTransaction?.modifiedMerchant === CONST.TRANSACTION.DEFAULT_MERCHANT; const updatedMerchantTitle = isEmptyUpdatedMerchant ? '' : (updatedTransaction?.modifiedMerchant ?? merchantTitle); const saveBillable = useCallback( @@ -386,10 +391,6 @@ function MoneyRequestView({ // Checks applied when creating a new expense // NOTE: receipt field can return multiple violations, so we need to handle it separately const fieldChecks: Partial> = { - amount: { - isError: transactionAmount === 0, - translationPath: canEditAmount ? 'common.error.enterAmount' : 'common.error.missingAmount', - }, merchant: { isError: !isSettled && !isCancelled && isPolicyExpenseChat && isEmptyMerchant, translationPath: canEditMerchant ? 'common.error.enterMerchant' : 'common.error.missingMerchantName', @@ -424,7 +425,6 @@ function MoneyRequestView({ return ''; }, [ - transactionAmount, isSettled, isCancelled, isPolicyExpenseChat, @@ -435,7 +435,6 @@ function MoneyRequestView({ hasViolations, translate, getViolationsForField, - canEditAmount, canEditDate, canEditMerchant, canEdit, diff --git a/src/components/ReportActionItem/TransactionPreview/index.tsx b/src/components/ReportActionItem/TransactionPreview/index.tsx index 5685d336c89c..f208962b84c7 100644 --- a/src/components/ReportActionItem/TransactionPreview/index.tsx +++ b/src/components/ReportActionItem/TransactionPreview/index.tsx @@ -92,7 +92,7 @@ function TransactionPreview(props: TransactionPreviewProps) { // See description of `transactionRawAmount` prop for more context // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing - const transactionRawAmount = (transaction?.modifiedAmount || transaction?.amount) ?? 0; + const transactionRawAmount = (Number(transaction?.modifiedAmount) || transaction?.amount) ?? 0; const shouldDisableOnPress = isBillSplit && isEmptyObject(transaction); const isTransactionMadeWithCard = isManagedCardTransaction(transaction); diff --git a/src/components/Search/index.tsx b/src/components/Search/index.tsx index 6198a8f6430b..8f1b3594379b 100644 --- a/src/components/Search/index.tsx +++ b/src/components/Search/index.tsx @@ -55,7 +55,7 @@ import { shouldShowEmptyState, shouldShowYear as shouldShowYearUtil, } from '@libs/SearchUIUtils'; -import {isOnHold, isTransactionPendingDelete, mergeProhibitedViolations, shouldShowViolation} from '@libs/TransactionUtils'; +import {hasValidModifiedAmount, isOnHold, isTransactionPendingDelete, mergeProhibitedViolations, shouldShowViolation} from '@libs/TransactionUtils'; import Navigation, {navigationRef} from '@navigation/Navigation'; import type {SearchFullscreenNavigatorParamList} from '@navigation/types'; import EmptySearchView from '@pages/Search/EmptySearchView'; @@ -115,7 +115,7 @@ function mapTransactionItemToSelectedEntry(item: TransactionListItemType, outsta convertedCurrency: item.convertedCurrency, reportID: item.reportID, policyID: item.report?.policyID, - amount: item.modifiedAmount ?? item.amount, + amount: hasValidModifiedAmount(item) ? Number(item.modifiedAmount) : item.amount, convertedAmount: item.convertedAmount, currency: item.currency, isFromOneTransactionReport: item.isFromOneTransactionReport, @@ -194,7 +194,7 @@ function prepareTransactionsList(item: TransactionListItemType, selectedTransact action: item.action, reportID: item.reportID, policyID: item.policyID, - amount: Math.abs(item.modifiedAmount || item.amount), + amount: hasValidModifiedAmount(item) ? Number(item.modifiedAmount) : item.amount, convertedAmount: item.convertedAmount, convertedCurrency: item.convertedCurrency, currency: item.currency, @@ -473,7 +473,7 @@ function Search({ canDelete: transactionItem.canDelete, reportID: transactionItem.reportID, policyID: transactionItem.report?.policyID, - amount: transactionItem.modifiedAmount ?? transactionItem.amount, + amount: hasValidModifiedAmount(transactionItem) ? Number(transactionItem.modifiedAmount) : transactionItem.amount, convertedAmount: transactionItem.convertedAmount, convertedCurrency: transactionItem.convertedCurrency, currency: transactionItem.currency, @@ -510,7 +510,7 @@ function Search({ canDelete: transactionItem.canDelete, reportID: transactionItem.reportID, policyID: transactionItem.report?.policyID, - amount: transactionItem.modifiedAmount ?? transactionItem.amount, + amount: hasValidModifiedAmount(transactionItem) ? Number(transactionItem.modifiedAmount) : transactionItem.amount, convertedAmount: transactionItem.convertedAmount, convertedCurrency: transactionItem.convertedCurrency, currency: transactionItem.currency, diff --git a/src/components/TransactionItemRow/index.tsx b/src/components/TransactionItemRow/index.tsx index 36196083bf24..e902a5519eb2 100644 --- a/src/components/TransactionItemRow/index.tsx +++ b/src/components/TransactionItemRow/index.tsx @@ -126,7 +126,7 @@ function getMerchantName(transactionItem: TransactionWithOptionalSearchFields, t } const merchantName = StringUtils.getFirstLine(merchant); - return merchantName !== CONST.TRANSACTION.PARTIAL_TRANSACTION_MERCHANT ? merchantName : ''; + return merchantName !== CONST.TRANSACTION.PARTIAL_TRANSACTION_MERCHANT && merchantName !== CONST.TRANSACTION.DEFAULT_MERCHANT ? merchantName : ''; } function TransactionItemRow({ diff --git a/src/libs/API/parameters/TrackExpenseParams.ts b/src/libs/API/parameters/TrackExpenseParams.ts index 7cb8fb86a9ec..7da368e0eeb9 100644 --- a/src/libs/API/parameters/TrackExpenseParams.ts +++ b/src/libs/API/parameters/TrackExpenseParams.ts @@ -32,6 +32,7 @@ type TrackExpenseParams = { customUnitRateID?: string; description?: string; distance?: number; + isDistance?: boolean; }; export default TrackExpenseParams; diff --git a/src/libs/DistanceRequestUtils.ts b/src/libs/DistanceRequestUtils.ts index 0d363d599be5..11e51e0d5395 100644 --- a/src/libs/DistanceRequestUtils.ts +++ b/src/libs/DistanceRequestUtils.ts @@ -168,7 +168,7 @@ function getDistanceForDisplay( translate: LocaleContextProps['translate'], useShortFormUnit?: boolean, ): string { - if (!hasRoute || !unit || !distanceInMeters) { + if (!hasRoute || !unit) { return translate('iou.fieldPending'); } diff --git a/src/libs/ReportUtils.ts b/src/libs/ReportUtils.ts index 043f3cc4313a..8a36059d10d1 100644 --- a/src/libs/ReportUtils.ts +++ b/src/libs/ReportUtils.ts @@ -5273,7 +5273,7 @@ function getModifiedExpenseOriginalMessage( originalMessage.oldMerchant = getMerchant(oldTransaction); // For the originalMessage, we should use the non-negative amount, similar to what getAmount does for oldAmount - originalMessage.amount = Math.abs(updatedTransaction?.modifiedAmount ?? 0); + originalMessage.amount = Math.abs(Number(updatedTransaction?.modifiedAmount ?? 0)); originalMessage.currency = updatedTransaction?.modifiedCurrency ?? CONST.CURRENCY.USD; originalMessage.merchant = updatedTransaction?.modifiedMerchant; } @@ -11898,7 +11898,7 @@ function hasExportError(reportActions: OnyxEntry | ReportAction[] function doesReportContainRequestsFromMultipleUsers(iouReport: OnyxEntry): boolean { const transactions = getReportTransactions(iouReport?.reportID); // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing - return isIOUReport(iouReport) && transactions.some((transaction) => (transaction?.modifiedAmount || transaction?.amount) < 0); + return isIOUReport(iouReport) && transactions.some((transaction) => (Number(transaction?.modifiedAmount) || transaction?.amount) <= 0); } /** diff --git a/src/libs/SearchUIUtils.ts b/src/libs/SearchUIUtils.ts index cc56686a0fa3..8697e0f238c4 100644 --- a/src/libs/SearchUIUtils.ts +++ b/src/libs/SearchUIUtils.ts @@ -626,7 +626,7 @@ function getTransactionItemCommonFormattedProperties( const formattedTotal = getTransactionAmount(transactionItem, isExpenseReport); const date = transactionItem?.modifiedCreated ? transactionItem.modifiedCreated : transactionItem?.created; const merchant = getTransactionMerchant(transactionItem, policy); - const formattedMerchant = merchant === CONST.TRANSACTION.PARTIAL_TRANSACTION_MERCHANT ? '' : merchant; + const formattedMerchant = merchant === CONST.TRANSACTION.PARTIAL_TRANSACTION_MERCHANT || merchant === CONST.TRANSACTION.DEFAULT_MERCHANT ? '' : merchant; return { formattedFrom, @@ -684,7 +684,7 @@ function getShouldShowMerchant(data: OnyxTypes.SearchResults['data']): boolean { if (isTransactionEntry(key)) { const item = data[key]; const merchant = item.modifiedMerchant ? item.modifiedMerchant : (item.merchant ?? ''); - return merchant !== '' && merchant !== CONST.TRANSACTION.PARTIAL_TRANSACTION_MERCHANT; + return merchant !== '' && merchant !== CONST.TRANSACTION.PARTIAL_TRANSACTION_MERCHANT && merchant !== CONST.TRANSACTION.DEFAULT_MERCHANT; } return false; }); @@ -754,7 +754,7 @@ function isAmountTooLong(amount: number, maxLength = 8): boolean { function isTransactionAmountTooLong(transactionItem: TransactionListItemType | SearchTransaction | OnyxTypes.Transaction) { // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing - const amount = Math.abs(transactionItem.modifiedAmount || transactionItem.amount); + const amount = Math.abs(Number(transactionItem.modifiedAmount) || transactionItem.amount); return isAmountTooLong(amount); } @@ -2389,7 +2389,7 @@ function getColumnsToShow( const reportActionsByTransactionIDMap = Array.isArray(data) ? undefined : createReportActionsByTransactionIDMap(data); const updateColumns = (transaction: OnyxTypes.Transaction | SearchTransaction) => { const merchant = transaction.modifiedMerchant ? transaction.modifiedMerchant : (transaction.merchant ?? ''); - if ((merchant !== '' && merchant !== CONST.TRANSACTION.PARTIAL_TRANSACTION_MERCHANT) || isScanning(transaction)) { + if ((merchant !== '' && merchant !== CONST.TRANSACTION.PARTIAL_TRANSACTION_MERCHANT && merchant !== CONST.TRANSACTION.DEFAULT_MERCHANT) || isScanning(transaction)) { columns[CONST.REPORT.TRANSACTION_LIST.COLUMNS.MERCHANT] = true; } diff --git a/src/libs/TransactionPreviewUtils.ts b/src/libs/TransactionPreviewUtils.ts index cdd98a05ab43..c0d0cbcb327f 100644 --- a/src/libs/TransactionPreviewUtils.ts +++ b/src/libs/TransactionPreviewUtils.ts @@ -33,7 +33,6 @@ import { hasPendingRTERViolation, hasViolation, hasWarningTypeViolation, - isAmountMissing, isCreatedMissing, isDistanceRequest, isFetchingWaypointsFromServer, @@ -247,12 +246,7 @@ function getTransactionPreviewTextAndTranslationPaths({ if (hasFieldErrors && RBRMessage === undefined) { const merchantMissing = isMerchantMissing(transaction); - const amountMissing = isAmountMissing(transaction); - if (amountMissing && merchantMissing) { - RBRMessage = {translationPath: 'violations.reviewRequired'}; - } else if (amountMissing) { - RBRMessage = {translationPath: 'iou.missingAmount'}; - } else if (merchantMissing) { + if (merchantMissing) { RBRMessage = {translationPath: 'iou.missingMerchant'}; } } diff --git a/src/libs/TransactionUtils/index.ts b/src/libs/TransactionUtils/index.ts index be870d4f32b5..900f18b1540e 100644 --- a/src/libs/TransactionUtils/index.ts +++ b/src/libs/TransactionUtils/index.ts @@ -155,7 +155,7 @@ Onyx.connect({ }, }); -function hasDistanceCustomUnit(transaction: OnyxEntry): boolean { +function hasDistanceCustomUnit(transaction: OnyxEntry | Partial): boolean { const type = transaction?.comment?.type; const customUnitName = transaction?.comment?.customUnit?.name; return type === CONST.TRANSACTION.TYPE.CUSTOM_UNIT && customUnitName === CONST.CUSTOM_UNITS.NAME_DISTANCE; @@ -211,6 +211,11 @@ function isScanRequest(transaction: OnyxEntry | Partial): boolean function isMerchantMissing(transaction: OnyxEntry) { if (transaction?.modifiedMerchant && transaction.modifiedMerchant !== '') { - return transaction.modifiedMerchant === CONST.TRANSACTION.PARTIAL_TRANSACTION_MERCHANT; + return transaction.modifiedMerchant === CONST.TRANSACTION.PARTIAL_TRANSACTION_MERCHANT || transaction.modifiedMerchant === CONST.TRANSACTION.DEFAULT_MERCHANT; } - const isMerchantEmpty = transaction?.merchant === CONST.TRANSACTION.PARTIAL_TRANSACTION_MERCHANT || transaction?.merchant === ''; + const isMerchantEmpty = + transaction?.merchant === CONST.TRANSACTION.PARTIAL_TRANSACTION_MERCHANT || transaction?.merchant === CONST.TRANSACTION.DEFAULT_MERCHANT || transaction?.merchant === ''; return isMerchantEmpty; } @@ -449,6 +457,13 @@ function isAmountMissing(transaction: OnyxEntry) { return transaction?.amount === 0 && (!transaction.modifiedAmount || transaction.modifiedAmount === 0); } +function hasValidModifiedAmount(transaction: OnyxEntry | null): boolean { + if (!transaction) { + return false; + } + return transaction?.modifiedAmount !== undefined && transaction?.modifiedAmount !== null && transaction?.modifiedAmount !== ''; +} + function isPartial(transaction: OnyxEntry): boolean { return isPartialMerchant(getMerchant(transaction)) && isAmountMissing(transaction); } @@ -465,7 +480,7 @@ function areRequiredFieldsEmpty(transaction: OnyxEntry, reportTrans const isFromExpenseReport = parentReport?.type === CONST.REPORT.TYPE.EXPENSE; const isSplitPolicyExpenseChat = !!transaction?.comment?.splits?.some((participant) => allReports?.[`${ONYXKEYS.COLLECTION.REPORT}${participant.chatReportID}`]?.isOwnPolicyExpenseChat); const isMerchantRequired = isFromExpenseReport || isSplitPolicyExpenseChat; - return (isMerchantRequired && isMerchantMissing(transaction)) || isAmountMissing(transaction) || isCreatedMissing(transaction); + return (isMerchantRequired && isMerchantMissing(transaction)) || isCreatedMissing(transaction); } function getClearedPendingFields(transactionChanges: TransactionChanges) { @@ -717,8 +732,8 @@ function getDescription(transaction: OnyxInputOrEntry): string { function getAmount(transaction: OnyxInputOrEntry, isFromExpenseReport = false, isFromTrackedExpense = false, allowNegative = false, disableOppositeConversion = false): number { // IOU requests cannot have negative values, but they can be stored as negative values, let's return absolute value if (!isFromExpenseReport && !isFromTrackedExpense && !allowNegative) { - const amount = transaction?.modifiedAmount ?? 0; - if (amount) { + const amount = Number(transaction?.modifiedAmount) ?? 0; + if (hasValidModifiedAmount(transaction)) { return Math.abs(amount); } return Math.abs(transaction?.amount ?? 0); @@ -731,8 +746,8 @@ function getAmount(transaction: OnyxInputOrEntry, isFromExpenseRepo // Expense report case: // The amounts are stored using an opposite sign and negative values can be set, // we need to return an opposite sign than is saved in the transaction object - let amount = transaction?.modifiedAmount ?? 0; - if (amount) { + let amount = Number(transaction?.modifiedAmount) ?? 0; + if (hasValidModifiedAmount(transaction)) { return -amount; } @@ -1263,7 +1278,7 @@ function hasPendingUI(transaction: OnyxEntry, transactionViolations * Check if the transaction has a defined route */ function hasRoute(transaction: OnyxEntry, isDistanceRequestType?: boolean): boolean { - return !!transaction?.routes?.route0?.geometry?.coordinates || (!!isDistanceRequestType && !!transaction?.comment?.customUnit?.quantity); + return !!transaction?.routes?.route0?.geometry?.coordinates || (!!isDistanceRequestType && transaction?.comment?.customUnit?.name === 'Distance'); } function waypointHasValidAddress(waypoint: RecentWaypoint | Waypoint): boolean { @@ -2124,6 +2139,7 @@ export { areRequiredFieldsEmpty, hasMissingSmartscanFields, hasPendingRTERViolation, + hasValidModifiedAmount, allHavePendingRTERViolation, hasPendingUI, getWaypointIndex, diff --git a/src/libs/Violations/ViolationsUtils.ts b/src/libs/Violations/ViolationsUtils.ts index ace1cb060ef5..8fd2e99e412b 100644 --- a/src/libs/Violations/ViolationsUtils.ts +++ b/src/libs/Violations/ViolationsUtils.ts @@ -11,7 +11,7 @@ import {isReceiptError} from '@libs/ErrorUtils'; import Parser from '@libs/Parser'; import {getDistanceRateCustomUnitRate, getPerDiemRateCustomUnitRate, getSortedTagKeys, isTaxTrackingEnabled} from '@libs/PolicyUtils'; import * as TransactionUtils from '@libs/TransactionUtils'; -import {shouldShowViolation} from '@libs/TransactionUtils'; +import {hasValidModifiedAmount, shouldShowViolation} from '@libs/TransactionUtils'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import type {Policy, PolicyCategories, PolicyTagLists, Report, ReportAction, Transaction, TransactionViolation, ViolationName} from '@src/types/onyx'; @@ -325,7 +325,7 @@ const ViolationsUtils = { const isTaxInPolicy = Object.keys(policy.taxRates?.taxes ?? {}).some((key) => key === updatedTransaction.taxCode); // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing - const amount = updatedTransaction.modifiedAmount || updatedTransaction.amount; + const amount = hasValidModifiedAmount(updatedTransaction) ? Number(updatedTransaction.modifiedAmount) : updatedTransaction.amount; // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing const currency = updatedTransaction.modifiedCurrency || updatedTransaction.currency; const canCalculateAmountViolations = policy.outputCurrency === currency; diff --git a/src/libs/actions/IOU.ts b/src/libs/actions/IOU.ts index 6d293bcd01ec..80519a51d419 100644 --- a/src/libs/actions/IOU.ts +++ b/src/libs/actions/IOU.ts @@ -1079,6 +1079,8 @@ function initMoneyRequest({ } } + const defaultMerchant = newIouRequestType === CONST.IOU.REQUEST_TYPE.MANUAL ? CONST.TRANSACTION.DEFAULT_MERCHANT : CONST.TRANSACTION.PARTIAL_TRANSACTION_MERCHANT; + const newTransaction = { amount: 0, comment, @@ -1089,7 +1091,7 @@ function initMoneyRequest({ reportID, transactionID: newTransactionID, isFromGlobalCreate, - merchant: CONST.TRANSACTION.PARTIAL_TRANSACTION_MERCHANT, + merchant: defaultMerchant, }; // Store the transaction in Onyx and mark it as not saved so it can be cleaned up later @@ -6566,6 +6568,7 @@ function trackExpense(params: CreateTrackExpenseParams) { waypoints: sanitizedWaypoints, customUnitRateID, description: parsedComment, + isDistance: isMapDistanceRequest(transaction) || isManualDistanceRequestTransactionUtils(transaction), }; if (actionableWhisperReportActionIDParam) { parameters.actionableWhisperReportActionID = actionableWhisperReportActionIDParam; @@ -7753,7 +7756,7 @@ function completeSplitBill( ]; const splitParticipants: Split[] = updatedTransaction?.comment?.splits ?? []; - const amount = updatedTransaction?.modifiedAmount; + const amount = Number(updatedTransaction?.modifiedAmount); const currency = updatedTransaction?.modifiedCurrency; // Exclude the current user when calculating the split amount, `calculateAmount` takes it into account @@ -14224,7 +14227,7 @@ function updateSplitTransactions({ failureData.push({ onyxMethod: Onyx.METHOD.MERGE, key: `${ONYXKEYS.COLLECTION.REPORT}${firstIOU?.childReportID}`, - value: transactionThread, + value: transactionThread ?? null, }); } diff --git a/src/libs/actions/Policy/Member.ts b/src/libs/actions/Policy/Member.ts index f836fe71a1c6..435a363ac3de 100644 --- a/src/libs/actions/Policy/Member.ts +++ b/src/libs/actions/Policy/Member.ts @@ -901,6 +901,7 @@ function buildAddMembersToWorkspaceOnyxData( }; successMembersState[email] = {pendingAction: null}; failureMembersState[email] = { + pendingAction: null, errors: ErrorUtils.getMicroSecondOnyxErrorWithTranslationKey('workspace.people.error.genericAdd'), }; }); diff --git a/src/libs/actions/Policy/Policy.ts b/src/libs/actions/Policy/Policy.ts index 1327f3526110..2f715fabe745 100644 --- a/src/libs/actions/Policy/Policy.ts +++ b/src/libs/actions/Policy/Policy.ts @@ -96,6 +96,7 @@ import { navigateToReceiptPartnersPage, } from '@libs/PolicyUtils'; import * as ReportUtils from '@libs/ReportUtils'; +import {hasValidModifiedAmount} from '@libs/TransactionUtils'; import type {PolicySelector} from '@pages/home/sidebar/FloatingActionButtonAndPopover'; import type {Feature} from '@pages/OnboardingInterestedFeatures/types'; import * as PaymentMethods from '@userActions/PaymentMethods'; @@ -3705,7 +3706,7 @@ function createWorkspaceFromIOUPayment(iouReport: OnyxEntry): WorkspaceF transactionsOptimisticData[`${ONYXKEYS.COLLECTION.TRANSACTION}${transaction.transactionID}`] = { ...transaction, amount: -transaction.amount, - modifiedAmount: transaction.modifiedAmount ? -transaction.modifiedAmount : 0, + modifiedAmount: hasValidModifiedAmount(transaction) ? -Number(transaction.modifiedAmount) : '', }; transactionFailureData[`${ONYXKEYS.COLLECTION.TRANSACTION}${transaction.transactionID}`] = transaction; diff --git a/src/libs/actions/Report.ts b/src/libs/actions/Report.ts index 45ac20a30438..ffa1babf1708 100644 --- a/src/libs/actions/Report.ts +++ b/src/libs/actions/Report.ts @@ -162,7 +162,7 @@ import { import {getCurrentSearchQueryJSON} from '@libs/SearchQueryUtils'; import type {ArchivedReportsIDSet} from '@libs/SearchUIUtils'; import playSound, {SOUNDS} from '@libs/Sound'; -import {isOnHold} from '@libs/TransactionUtils'; +import {hasValidModifiedAmount, isOnHold} from '@libs/TransactionUtils'; import addTrailingForwardSlash from '@libs/UrlUtils'; import Visibility from '@libs/Visibility'; import CONFIG from '@src/CONFIG'; @@ -5360,7 +5360,7 @@ function convertIOUReportToExpenseReport(iouReport: Report, policy: Policy, poli transactionsOptimisticData[`${ONYXKEYS.COLLECTION.TRANSACTION}${transaction.transactionID}`] = { ...transaction, amount: -transaction.amount, - modifiedAmount: transaction.modifiedAmount ? -transaction.modifiedAmount : 0, + modifiedAmount: hasValidModifiedAmount(transaction) ? -Number(transaction.modifiedAmount) : '', }; transactionFailureData[`${ONYXKEYS.COLLECTION.TRANSACTION}${transaction.transactionID}`] = transaction; diff --git a/src/pages/AddUnreportedExpense.tsx b/src/pages/AddUnreportedExpense.tsx index a6013b59faa8..f5e307008034 100644 --- a/src/pages/AddUnreportedExpense.tsx +++ b/src/pages/AddUnreportedExpense.tsx @@ -130,7 +130,7 @@ function AddUnreportedExpense({route}: AddUnreportedExpensePageType) { const searchableFields: string[] = []; const merchant = getMerchant(transaction); - if (merchant !== CONST.TRANSACTION.PARTIAL_TRANSACTION_MERCHANT) { + if (merchant !== CONST.TRANSACTION.PARTIAL_TRANSACTION_MERCHANT && merchant !== CONST.TRANSACTION.DEFAULT_MERCHANT) { searchableFields.push(merchant); } diff --git a/src/pages/iou/MoneyRequestAmountForm.tsx b/src/pages/iou/MoneyRequestAmountForm.tsx index 1a50af10a360..95d688e3e413 100644 --- a/src/pages/iou/MoneyRequestAmountForm.tsx +++ b/src/pages/iou/MoneyRequestAmountForm.tsx @@ -54,7 +54,8 @@ type MoneyRequestAmountFormProps = Omit !amount.length || parseFloat(amount) < 0.01; +const nonZeroExpenses = new Set>([CONST.IOU.TYPE.PAY, CONST.IOU.TYPE.INVOICE, CONST.IOU.TYPE.SPLIT]); +const isAmountInvalid = (amount: string, iouType: ValueOf) => !amount.length || parseFloat(amount) < 0 || (parseFloat(amount) < 0.01 && nonZeroExpenses.has(iouType)); const isTaxAmountInvalid = (currentAmount: string, taxAmount: number, isTaxAmountForm: boolean, currency: string) => isTaxAmountForm && Number.parseFloat(currentAmount) > convertToFrontendAmountAsInteger(Math.abs(taxAmount), currency); @@ -143,7 +144,7 @@ function MoneyRequestAmountForm({ // Skip the check for tax amount form as 0 is a valid input const currentAmount = moneyRequestAmountInputRef.current?.getNumber() ?? ''; - if (!currentAmount.length || (!isTaxAmountForm && isAmountInvalid(currentAmount))) { + if (!currentAmount.length || (!isTaxAmountForm && isAmountInvalid(currentAmount, iouType))) { setFormError(translate('iou.error.invalidAmount')); return; } diff --git a/src/pages/iou/request/step/IOURequestStepConfirmation.tsx b/src/pages/iou/request/step/IOURequestStepConfirmation.tsx index 76907eac4931..528e28161358 100644 --- a/src/pages/iou/request/step/IOURequestStepConfirmation.tsx +++ b/src/pages/iou/request/step/IOURequestStepConfirmation.tsx @@ -1213,8 +1213,7 @@ function IOURequestStepConfirmation({ const showReceiptEmptyState = shouldShowReceiptEmptyState(iouType, action, policy, isPerDiemRequest); - const shouldShowSmartScanFields = - !!transaction?.receipt?.isTestDriveReceipt || (isMovingTransactionFromTrackExpense ? transaction?.amount !== 0 : requestType !== CONST.IOU.REQUEST_TYPE.SCAN); + const shouldShowSmartScanFields = !!transaction?.receipt?.isTestDriveReceipt || isMovingTransactionFromTrackExpense || requestType !== CONST.IOU.REQUEST_TYPE.SCAN; return ( { const value = numberFormRef.current?.getNumber() ?? ''; - if (!value.length || parseFloat(value) < 0.01) { + if (!value.length || parseFloat(value) < 0) { setFormError(translate('iou.error.invalidDistance')); return; } diff --git a/src/pages/iou/request/step/IOURequestStepMerchant.tsx b/src/pages/iou/request/step/IOURequestStepMerchant.tsx index 5b478dc50dad..f1141b8a60b4 100644 --- a/src/pages/iou/request/step/IOURequestStepMerchant.tsx +++ b/src/pages/iou/request/step/IOURequestStepMerchant.tsx @@ -52,7 +52,7 @@ function IOURequestStepMerchant({ // In the split flow, when editing we use SPLIT_TRANSACTION_DRAFT to save draft value const isEditingSplitBill = iouType === CONST.IOU.TYPE.SPLIT && isEditing; const merchant = getTransactionDetails(isEditingSplitBill && !isEmptyObject(splitDraftTransaction) ? splitDraftTransaction : transaction)?.merchant; - const isEmptyMerchant = merchant === '' || merchant === CONST.TRANSACTION.PARTIAL_TRANSACTION_MERCHANT; + const isEmptyMerchant = merchant === '' || merchant === CONST.TRANSACTION.PARTIAL_TRANSACTION_MERCHANT || merchant === CONST.TRANSACTION.DEFAULT_MERCHANT; const initialMerchant = isEmptyMerchant ? '' : merchant; const merchantRef = useRef(initialMerchant); const isSavedRef = useRef(false); @@ -70,7 +70,10 @@ function IOURequestStepMerchant({ if (isMerchantRequired && !value.moneyRequestMerchant) { errors.moneyRequestMerchant = translate('common.error.fieldRequired'); - } else if (isMerchantRequired && value.moneyRequestMerchant === CONST.TRANSACTION.PARTIAL_TRANSACTION_MERCHANT) { + } else if ( + isMerchantRequired && + (value.moneyRequestMerchant === CONST.TRANSACTION.PARTIAL_TRANSACTION_MERCHANT || value.moneyRequestMerchant === CONST.TRANSACTION.DEFAULT_MERCHANT) + ) { errors.moneyRequestMerchant = translate('iou.error.invalidMerchant'); } else if (!isValid) { errors.moneyRequestMerchant = translate('common.error.characterLimitExceedCounter', { diff --git a/src/stories/objects/Transaction.ts b/src/stories/objects/Transaction.ts index ffc3d71a4f5f..22551325bbd7 100644 --- a/src/stories/objects/Transaction.ts +++ b/src/stories/objects/Transaction.ts @@ -21,7 +21,7 @@ const transaction: Transaction & {mcc: string; modifiedMCC: string} = { managedCard: false, mcc: '', merchant: "Mario's", - modifiedAmount: 0, + modifiedAmount: '', modifiedCreated: '', modifiedCurrency: '', modifiedMCC: '', diff --git a/src/types/onyx/SearchResults.ts b/src/types/onyx/SearchResults.ts index b92423550a84..00255111691a 100644 --- a/src/types/onyx/SearchResults.ts +++ b/src/types/onyx/SearchResults.ts @@ -183,7 +183,7 @@ type SearchTransaction = { canUnhold: boolean; /** The edited transaction amount */ - modifiedAmount: number; + modifiedAmount: number | string; /** The transaction currency */ currency: string; diff --git a/src/types/onyx/Transaction.ts b/src/types/onyx/Transaction.ts index f0cb54f1d373..d0b56e711ddf 100644 --- a/src/types/onyx/Transaction.ts +++ b/src/types/onyx/Transaction.ts @@ -449,7 +449,7 @@ type Transaction = OnyxCommon.OnyxValueWithOfflineFeedback< merchant: string; /** The edited transaction amount */ - modifiedAmount?: number; + modifiedAmount?: number | string; /** The edited attendees list */ modifiedAttendees?: Attendee[]; diff --git a/tests/actions/IOUTest.ts b/tests/actions/IOUTest.ts index 87e505a34a18..7b07fc593af6 100644 --- a/tests/actions/IOUTest.ts +++ b/tests/actions/IOUTest.ts @@ -1112,7 +1112,7 @@ describe('actions/IOU', () => { attendees: [], currency: CONST.CURRENCY.USD, created: '', - merchant: '', + merchant: '(none)', comment, }, shouldGenerateTransactionThreadReport: true, @@ -1421,7 +1421,7 @@ describe('actions/IOU', () => { expect(newTransaction?.reportID).toBe(iouReportID); expect(newTransaction?.amount).toBe(amount); expect(newTransaction?.comment?.comment).toBe(comment); - expect(newTransaction?.merchant).toBe(CONST.TRANSACTION.PARTIAL_TRANSACTION_MERCHANT); + expect(newTransaction?.merchant).toBe(CONST.TRANSACTION.DEFAULT_MERCHANT); expect(newTransaction?.pendingAction).toBe(CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD); // The transactionID on the iou action should match the one from the transactions collection @@ -1592,7 +1592,7 @@ describe('actions/IOU', () => { expect(transaction?.reportID).toBe(iouReportID); expect(transaction?.amount).toBe(amount); expect(transaction?.comment?.comment).toBe(comment); - expect(transaction?.merchant).toBe(CONST.TRANSACTION.PARTIAL_TRANSACTION_MERCHANT); + expect(transaction?.merchant).toBe(CONST.TRANSACTION.DEFAULT_MERCHANT); expect(transaction?.pendingAction).toBe(CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD); // The transactionID on the iou action should match the one from the transactions collection @@ -6333,7 +6333,7 @@ describe('actions/IOU', () => { ...createRandomTransaction(0), reportID, amount: 0, - modifiedAmount: 0, + modifiedAmount: '', receipt: { source: 'test', state: CONST.IOU.RECEIPT_STATE.SCANNING, @@ -6345,7 +6345,7 @@ describe('actions/IOU', () => { ...createRandomTransaction(1), reportID, amount: 0, - modifiedAmount: 0, + modifiedAmount: '', receipt: { source: 'test', state: CONST.IOU.RECEIPT_STATE.SCANNING, @@ -6395,7 +6395,7 @@ describe('actions/IOU', () => { ...createRandomTransaction(1), reportID, amount: 0, - modifiedAmount: 0, + modifiedAmount: '', receipt: { source: 'test', state: CONST.IOU.RECEIPT_STATE.SCANNING, @@ -6687,7 +6687,7 @@ describe('actions/IOU', () => { reportID: fakeReport.reportID, transactionID: CONST.IOU.OPTIMISTIC_TRANSACTION_ID, isFromGlobalCreate: true, - merchant: '(none)', + merchant: 'Expense', }; const currentDate = '2025-04-01'; @@ -6737,6 +6737,7 @@ describe('actions/IOU', () => { .then(async () => { expect(await getOnyxValue(`${ONYXKEYS.COLLECTION.TRANSACTION_DRAFT}${CONST.IOU.OPTIMISTIC_TRANSACTION_ID}`)).toStrictEqual({ ...transactionResult, + merchant: CONST.TRANSACTION.PARTIAL_TRANSACTION_MERCHANT, iouRequestType: CONST.IOU.REQUEST_TYPE.SCAN, }); }); @@ -6881,7 +6882,7 @@ describe('actions/IOU', () => { }, }); }); - expect(updatedTransaction?.modifiedAmount).toBe(0); + expect(updatedTransaction?.modifiedAmount).toBe(''); }); }); diff --git a/tests/unit/AddUnreportedExpenseSearchTest.ts b/tests/unit/AddUnreportedExpenseSearchTest.ts index 6c7e90dce970..5eccc644c0ef 100644 --- a/tests/unit/AddUnreportedExpenseSearchTest.ts +++ b/tests/unit/AddUnreportedExpenseSearchTest.ts @@ -107,7 +107,7 @@ describe('AddUnreportedExpense Search Functionality', () => { // Add merchant to searchable fields const merchant = getMerchant(transaction); - if (merchant !== CONST.TRANSACTION.PARTIAL_TRANSACTION_MERCHANT) { + if (merchant !== CONST.TRANSACTION.PARTIAL_TRANSACTION_MERCHANT && merchant !== CONST.TRANSACTION.DEFAULT_MERCHANT) { searchableFields.push(merchant); } diff --git a/tests/unit/DebugUtilsTest.ts b/tests/unit/DebugUtilsTest.ts index a4f5e7328dd5..130a66bcc76f 100644 --- a/tests/unit/DebugUtilsTest.ts +++ b/tests/unit/DebugUtilsTest.ts @@ -1233,8 +1233,9 @@ describe('DebugUtils', () => { accountID: 12345, }, [`${ONYXKEYS.COLLECTION.TRANSACTION}1` as const]: { - amount: 0, - modifiedAmount: 0, + amount: 100, + created: '', + modifiedCreated: '', }, }); const {reportAction} = @@ -1293,8 +1294,9 @@ describe('DebugUtils', () => { }; await Onyx.multiSet({ [`${ONYXKEYS.COLLECTION.TRANSACTION}1` as const]: { - amount: 0, - modifiedAmount: 0, + amount: 100, + created: '', + modifiedCreated: '', }, [`${ONYXKEYS.COLLECTION.REPORT}1` as const]: MOCK_CHAT_REPORT, [`${ONYXKEYS.COLLECTION.REPORT}2` as const]: MOCK_IOU_REPORT, @@ -1358,8 +1360,9 @@ describe('DebugUtils', () => { }; await Onyx.multiSet({ [`${ONYXKEYS.COLLECTION.TRANSACTION}1` as const]: { - amount: 0, - modifiedAmount: 0, + amount: 100, + created: '', + modifiedCreated: '', }, [`${ONYXKEYS.COLLECTION.REPORT}1` as const]: MOCK_CHAT_REPORT, [`${ONYXKEYS.COLLECTION.REPORT}2` as const]: MOCK_IOU_REPORT, diff --git a/tests/unit/ReportUtilsTest.ts b/tests/unit/ReportUtilsTest.ts index 577d1a294f5a..9efcad421768 100644 --- a/tests/unit/ReportUtilsTest.ts +++ b/tests/unit/ReportUtilsTest.ts @@ -124,7 +124,7 @@ import type {ErrorFields, Errors} from '@src/types/onyx/OnyxCommon'; import type {JoinWorkspaceResolution} from '@src/types/onyx/OriginalMessage'; import type {ACHAccount} from '@src/types/onyx/Policy'; import type {Participant, Participants} from '@src/types/onyx/Report'; -import type {SearchReport, SearchTransaction} from '@src/types/onyx/SearchResults'; +import type {SearchTransaction} from '@src/types/onyx/SearchResults'; import {toCollectionDataSet} from '@src/types/utils/CollectionDataSet'; import {chatReportR14932 as mockedChatReport} from '../../__mocks__/reportData/reports'; import * as NumberUtils from '../../src/libs/NumberUtils'; @@ -7386,7 +7386,8 @@ describe('ReportUtils', () => { const transaction: Transaction = { ...createRandomTransaction(Number(transactionID)), reportID: parentReport.reportID, - amount: 0, + created: '', + modifiedCreated: '', }; await Onyx.merge(`${ONYXKEYS.COLLECTION.TRANSACTION}${transaction.transactionID}`, transaction); await waitForBatchedUpdates(); @@ -7411,7 +7412,8 @@ describe('ReportUtils', () => { const transaction: Transaction = { ...createRandomTransaction(12345), reportID: parentReport.reportID, - amount: 0, + created: '', + modifiedCreated: '', }; await Onyx.merge(`${ONYXKEYS.COLLECTION.TRANSACTION}${transaction.transactionID}`, transaction); await waitForBatchedUpdates(); @@ -8479,8 +8481,7 @@ describe('ReportUtils', () => { describe('getReportOrDraftReport', () => { const mockReportIDIndex = 1; const mockReportID = mockReportIDIndex.toString(); - // eslint-disable-next-line @typescript-eslint/no-deprecated - const mockSearchReport: SearchReport = { + const mockSearchReport: Report = { ...createRandomReport(mockReportIDIndex, undefined), reportName: 'Search Report', type: CONST.REPORT.TYPE.CHAT, @@ -8509,31 +8510,27 @@ describe('ReportUtils', () => { }); test('returns onyx report when search report is not found but onyx report exists', async () => { - // eslint-disable-next-line @typescript-eslint/no-deprecated - const searchReports: SearchReport[] = []; + const searchReports: Report[] = []; await Onyx.set(`${ONYXKEYS.COLLECTION.REPORT}${mockReportID}`, mockOnyxReport); const result = getReportOrDraftReport(mockReportID, searchReports); expect(result).toEqual(mockOnyxReport); }); test('returns draft report when neither search nor onyx report exists but draft exists', async () => { - // eslint-disable-next-line @typescript-eslint/no-deprecated - const searchReports: SearchReport[] = []; + const searchReports: Report[] = []; await Onyx.set(`${ONYXKEYS.COLLECTION.REPORT_DRAFT}${mockReportID}`, mockDraftReport); const result = getReportOrDraftReport(mockReportID, searchReports); expect(result).toEqual(mockDraftReport); }); test('returns fallback report when no other reports exist', () => { - // eslint-disable-next-line @typescript-eslint/no-deprecated - const searchReports: SearchReport[] = []; + const searchReports: Report[] = []; const result = getReportOrDraftReport('unknownReportID', searchReports, mockFallbackReport); expect(result).toEqual(mockFallbackReport); }); test('returns undefined when no reports exist and no fallback provided', () => { - // eslint-disable-next-line @typescript-eslint/no-deprecated - const searchReports: SearchReport[] = []; + const searchReports: Report[] = []; const result = getReportOrDraftReport(mockReportID, searchReports); expect(result).toBeUndefined(); }); @@ -8564,8 +8561,7 @@ describe('ReportUtils', () => { }); test('prioritizes onyx report over draft report when both exist', async () => { - // eslint-disable-next-line @typescript-eslint/no-deprecated - const searchReports: SearchReport[] = []; + const searchReports: Report[] = []; await Onyx.set(`${ONYXKEYS.COLLECTION.REPORT}${mockReportID}`, mockOnyxReport); await Onyx.set(`${ONYXKEYS.COLLECTION.REPORT_DRAFT}${mockReportID}`, mockDraftReport); const result = getReportOrDraftReport(mockReportID, searchReports); @@ -8574,8 +8570,7 @@ describe('ReportUtils', () => { }); test('prioritizes draft report over fallback when both exist', async () => { - // eslint-disable-next-line @typescript-eslint/no-deprecated - const searchReports: SearchReport[] = []; + const searchReports: Report[] = []; await Onyx.set(`${ONYXKEYS.COLLECTION.REPORT_DRAFT}${mockReportID}`, mockDraftReport); const result = getReportOrDraftReport(mockReportID, searchReports, mockFallbackReport); expect(result).toEqual(mockDraftReport); diff --git a/tests/unit/Search/SearchUIUtilsTest.ts b/tests/unit/Search/SearchUIUtilsTest.ts index 3334f784147c..0dd6124b1cc6 100644 --- a/tests/unit/Search/SearchUIUtilsTest.ts +++ b/tests/unit/Search/SearchUIUtilsTest.ts @@ -384,7 +384,7 @@ const searchResults: OnyxTypes.SearchResults = { hasEReceipt: false, isFromOneTransactionReport: true, merchant: 'Expense', - modifiedAmount: 0, + modifiedAmount: '', modifiedCreated: '', modifiedCurrency: '', modifiedMerchant: 'Expense', @@ -422,7 +422,7 @@ const searchResults: OnyxTypes.SearchResults = { hasEReceipt: false, isFromOneTransactionReport: true, merchant: 'Expense', - modifiedAmount: 0, + modifiedAmount: '', modifiedCreated: '', modifiedCurrency: '', modifiedMerchant: 'Expense', @@ -461,7 +461,7 @@ const searchResults: OnyxTypes.SearchResults = { hasEReceipt: false, isFromOneTransactionReport: false, merchant: '(none)', - modifiedAmount: 0, + modifiedAmount: '', modifiedCreated: '', modifiedCurrency: '', modifiedMerchant: '', @@ -499,7 +499,7 @@ const searchResults: OnyxTypes.SearchResults = { hasEReceipt: false, isFromOneTransactionReport: false, merchant: '(none)', - modifiedAmount: 0, + modifiedAmount: '', modifiedCreated: '', modifiedCurrency: '', modifiedMerchant: '', @@ -787,7 +787,7 @@ const transactionsListItems = [ currency: 'USD', date: '2024-12-21', formattedFrom: 'Admin', - formattedMerchant: 'Expense', + formattedMerchant: '', formattedTo: '', formattedTotal: 5000, from: { @@ -800,14 +800,14 @@ const transactionsListItems = [ isFromOneTransactionReport: true, keyForList: '1', merchant: 'Expense', - modifiedAmount: 0, + modifiedAmount: '', modifiedCreated: '', modifiedCurrency: '', modifiedMerchant: 'Expense', parentTransactionID: '', pendingAction: CONST.RED_BRICK_ROAD_PENDING_ACTION.DELETE, reportID: '123456789', - shouldShowMerchant: true, + shouldShowMerchant: false, shouldShowYear: true, isAmountColumnWide: false, isTaxAmountColumnWide: false, @@ -851,7 +851,7 @@ const transactionsListItems = [ currency: 'USD', date: '2024-12-21', formattedFrom: 'Admin', - formattedMerchant: 'Expense', + formattedMerchant: '', formattedTo: 'Admin', formattedTotal: 5000, from: { @@ -864,13 +864,13 @@ const transactionsListItems = [ isFromOneTransactionReport: true, keyForList: '2', merchant: 'Expense', - modifiedAmount: 0, + modifiedAmount: '', modifiedCreated: '', modifiedCurrency: '', modifiedMerchant: 'Expense', parentTransactionID: '', reportID: '11111', - shouldShowMerchant: true, + shouldShowMerchant: false, shouldShowYear: true, isAmountColumnWide: false, isTaxAmountColumnWide: false, @@ -921,7 +921,7 @@ const transactionsListItems = [ hasEReceipt: false, isFromOneTransactionReport: false, merchant: '(none)', - modifiedAmount: 0, + modifiedAmount: '', modifiedCreated: '', modifiedCurrency: '', modifiedMerchant: '', @@ -948,7 +948,7 @@ const transactionsListItems = [ formattedTotal: 1200, formattedMerchant: '', date: '2025-03-05', - shouldShowMerchant: true, + shouldShowMerchant: false, shouldShowYear: true, keyForList: '3', isAmountColumnWide: false, @@ -985,7 +985,7 @@ const transactionsListItems = [ hasEReceipt: false, isFromOneTransactionReport: false, merchant: '(none)', - modifiedAmount: 0, + modifiedAmount: '', modifiedCreated: '', modifiedCurrency: '', modifiedMerchant: '', @@ -1012,7 +1012,7 @@ const transactionsListItems = [ formattedTotal: 3200, formattedMerchant: '', date: '2025-03-05', - shouldShowMerchant: true, + shouldShowMerchant: false, shouldShowYear: true, keyForList: '4', isAmountColumnWide: false, @@ -1084,7 +1084,7 @@ const transactionReportGroupListItems = [ currency: 'USD', date: '2024-12-21', formattedFrom: 'Admin', - formattedMerchant: 'Expense', + formattedMerchant: '', formattedTo: '', formattedTotal: 5000, from: { @@ -1097,14 +1097,14 @@ const transactionReportGroupListItems = [ isFromOneTransactionReport: true, keyForList: '1', merchant: 'Expense', - modifiedAmount: 0, + modifiedAmount: '', modifiedCreated: '', modifiedCurrency: '', modifiedMerchant: 'Expense', parentTransactionID: '', pendingAction: CONST.RED_BRICK_ROAD_PENDING_ACTION.DELETE, reportID: '123456789', - shouldShowMerchant: true, + shouldShowMerchant: false, shouldShowYear: true, isAmountColumnWide: false, isTaxAmountColumnWide: false, @@ -1185,7 +1185,7 @@ const transactionReportGroupListItems = [ currency: 'USD', date: '2024-12-21', formattedFrom: 'Admin', - formattedMerchant: 'Expense', + formattedMerchant: '', formattedTo: 'Admin', formattedTotal: 5000, from: { @@ -1204,13 +1204,13 @@ const transactionReportGroupListItems = [ isFromOneTransactionReport: true, keyForList: '2', merchant: 'Expense', - modifiedAmount: 0, + modifiedAmount: '', modifiedCreated: '', modifiedCurrency: '', modifiedMerchant: 'Expense', parentTransactionID: '', reportID: '11111', - shouldShowMerchant: true, + shouldShowMerchant: false, shouldShowYear: true, isAmountColumnWide: false, isTaxAmountColumnWide: false, diff --git a/tests/unit/Search/handleActionButtonPressTest.ts b/tests/unit/Search/handleActionButtonPressTest.ts index e595bb796f56..e8ed28963d8c 100644 --- a/tests/unit/Search/handleActionButtonPressTest.ts +++ b/tests/unit/Search/handleActionButtonPressTest.ts @@ -100,7 +100,7 @@ const mockReportItemWithHold = { isFromOneTransactionReport: false, managerID: 1206, merchant: 'Qatar', - modifiedAmount: 0, + modifiedAmount: '', modifiedCreated: '', modifiedCurrency: '', modifiedMerchant: '', @@ -190,7 +190,7 @@ const mockReportItemWithHold = { hasEReceipt: false, isFromOneTransactionReport: false, merchant: 'Forbes', - modifiedAmount: 0, + modifiedAmount: '', modifiedCreated: '', modifiedCurrency: '', modifiedMerchant: '', diff --git a/tests/unit/TransactionPreviewUtils.test.ts b/tests/unit/TransactionPreviewUtils.test.ts index 4331f657be60..608bd8a0bcf9 100644 --- a/tests/unit/TransactionPreviewUtils.test.ts +++ b/tests/unit/TransactionPreviewUtils.test.ts @@ -104,15 +104,15 @@ describe('TransactionPreviewUtils', () => { expect(result.displayAmountText.text).toEqual('$0.00'); }); - it('returns merchant missing and amount missing message when appropriate', () => { + it('returns missing field message when appropriate', () => { const functionArgs = { ...basicProps, - transaction: {...basicProps.transaction, merchant: '', amount: 0}, + transaction: {...basicProps.transaction, created: '', amount: 100}, originalTransaction: undefined, shouldShowRBR: true, }; const result = getTransactionPreviewTextAndTranslationPaths(functionArgs); - expect(result.RBRMessage.translationPath).toEqual('violations.reviewRequired'); + expect(result.RBRMessage.translationPath).toEqual('iou.missingMerchant'); }); it('should display showCashOrCard in previewHeaderText', () => { @@ -138,7 +138,12 @@ describe('TransactionPreviewUtils', () => { }); it('displays description when receipt is being scanned', () => { - const functionArgs = {...basicProps, transaction: {...basicProps.transaction, receipt: {state: CONST.IOU.RECEIPT_STATE.SCANNING}}, originalTransaction: undefined}; + const functionArgs = { + ...basicProps, + transaction: {...basicProps.transaction, merchant: '(none)', receipt: {state: CONST.IOU.RECEIPT_STATE.SCANNING}}, + originalTransaction: undefined, + merchant: 'Expense', + }; const result = getTransactionPreviewTextAndTranslationPaths(functionArgs); expect(result.previewHeaderText).toEqual(expect.arrayContaining([{translationPath: 'common.receipt'}])); }); @@ -153,7 +158,7 @@ describe('TransactionPreviewUtils', () => { const functionArgs = { ...basicProps, transactionDetails: {amount: 300, currency: 'EUR'}, - transaction: {...basicProps.transaction, receipt: {state: CONST.IOU.RECEIPT_STATE.SCANNING}}, + transaction: {...basicProps.transaction, merchant: '(none)', receipt: {state: CONST.IOU.RECEIPT_STATE.SCANNING}}, originalTransaction: undefined, }; const result = getTransactionPreviewTextAndTranslationPaths(functionArgs); diff --git a/tests/unit/TransactionUtilsTest.ts b/tests/unit/TransactionUtilsTest.ts index 0eb538d2ea26..a42c1f567a26 100644 --- a/tests/unit/TransactionUtilsTest.ts +++ b/tests/unit/TransactionUtilsTest.ts @@ -405,6 +405,7 @@ describe('TransactionUtils', () => { receipt: { state: CONST.IOU.RECEIPT_STATE.SCAN_READY, }, + merchant: '(none)', }); expect(TransactionUtils.shouldShowRTERViolationMessage([transaction])).toBe(true); }); @@ -521,7 +522,7 @@ describe('TransactionUtils', () => { it('should return (none) if transaction has no merchant', () => { const transaction = generateTransaction(); const merchant = TransactionUtils.getMerchant(transaction); - expect(merchant).toBe('(none)'); + expect(merchant).toBe('Expense'); }); it('should return modified merchant if transaction has modified merchant', () => { diff --git a/tests/utils/collections/transaction.ts b/tests/utils/collections/transaction.ts index 3f9fdf7ca1e3..c4c3e69c0834 100644 --- a/tests/utils/collections/transaction.ts +++ b/tests/utils/collections/transaction.ts @@ -42,6 +42,6 @@ export default function createRandomTransaction(index: number): Transaction { receipt: {}, reimbursable: randBoolean(), hasEReceipt: randBoolean(), - modifiedAmount: 0, + modifiedAmount: '', }; }