From b473b78c0134537d940ab546119b2a650d90e805 Mon Sep 17 00:00:00 2001 From: Agata Kosior Date: Sun, 24 Aug 2025 12:30:43 +0200 Subject: [PATCH 01/13] feat: create UnreportedTransaction type and isExpenseUnreported function --- src/libs/TransactionUtils/index.ts | 16 +++++++++++++++- src/types/onyx/Transaction.ts | 7 +++++++ 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/src/libs/TransactionUtils/index.ts b/src/libs/TransactionUtils/index.ts index f09ac210d72d..70c136eae62d 100644 --- a/src/libs/TransactionUtils/index.ts +++ b/src/libs/TransactionUtils/index.ts @@ -64,7 +64,16 @@ import type {Attendee, Participant, SplitExpense} from '@src/types/onyx/IOU'; import type {Errors, PendingAction} from '@src/types/onyx/OnyxCommon'; import type {OnyxData} from '@src/types/onyx/Request'; import type {SearchPolicy, SearchReport, SearchTransaction} from '@src/types/onyx/SearchResults'; -import type {Comment, Receipt, TransactionChanges, TransactionCustomUnit, TransactionPendingFieldsKey, Waypoint, WaypointCollection} from '@src/types/onyx/Transaction'; +import type { + Comment, + Receipt, + TransactionChanges, + TransactionCustomUnit, + TransactionPendingFieldsKey, + UnreportedTransaction, + Waypoint, + WaypointCollection, +} from '@src/types/onyx/Transaction'; import {isEmptyObject} from '@src/types/utils/EmptyObject'; import getDistanceInMeters from './getDistanceInMeters'; @@ -1874,6 +1883,10 @@ function createUnreportedExpenseSections(transactions: Array & AdditionalTransactionChanges; /** Collection of mock transactions, indexed by `transactions_${transactionID}` */ type TransactionCollectionDataSet = CollectionDataSet; +/** Transaction that is not associated with any report */ +type UnreportedTransaction = Omit & { + /** The ID of the report that this transaction is associated with. */ + reportID: "0"; +}; + export default Transaction; export type { WaypointCollection, @@ -609,4 +615,5 @@ export type { TransactionCollectionDataSet, SplitShares, TransactionCustomUnit, + UnreportedTransaction, }; From 09f1d9b798807435dafc911de5fec321555c6a66 Mon Sep 17 00:00:00 2001 From: Agata Kosior Date: Mon, 25 Aug 2025 09:56:04 +0200 Subject: [PATCH 02/13] feat: show report fields in selfDM --- .../ReportActionItem/MoneyRequestView.tsx | 138 ++++++++---------- .../TransactionDuplicate/Confirmation.tsx | 2 +- .../TransactionMerge/ConfirmationPage.tsx | 2 +- .../report/ReportActionItemContentCreated.tsx | 4 +- 4 files changed, 61 insertions(+), 85 deletions(-) diff --git a/src/components/ReportActionItem/MoneyRequestView.tsx b/src/components/ReportActionItem/MoneyRequestView.tsx index b3dd3bab4539..26dbefe49a8b 100644 --- a/src/components/ReportActionItem/MoneyRequestView.tsx +++ b/src/components/ReportActionItem/MoneyRequestView.tsx @@ -1,16 +1,16 @@ -import {Str} from 'expensify-common'; +import { Str } from 'expensify-common'; import mapValues from 'lodash/mapValues'; -import React, {useCallback, useEffect, useMemo, useState} from 'react'; -import {View} from 'react-native'; -import type {OnyxCollection, OnyxEntry} from 'react-native-onyx'; +import React, { useCallback, useEffect, useMemo, useState } from 'react'; +import { View } from 'react-native'; +import type { OnyxCollection, OnyxEntry } from 'react-native-onyx'; import ConfirmModal from '@components/ConfirmModal'; import Icon from '@components/Icon'; import * as Expensicons from '@components/Icon/Expensicons'; import MenuItem from '@components/MenuItem'; import MenuItemWithTopDescription from '@components/MenuItemWithTopDescription'; import OfflineWithFeedback from '@components/OfflineWithFeedback'; -import {usePolicyCategories, usePolicyTags} from '@components/OnyxListItemProvider'; -import ReceiptAudit, {ReceiptAuditMessages} from '@components/ReceiptAudit'; +import { usePolicyCategories, usePolicyTags } from '@components/OnyxListItemProvider'; +import ReceiptAudit, { ReceiptAuditMessages } from '@components/ReceiptAudit'; import ReceiptEmptyState from '@components/ReceiptEmptyState'; import Switch from '@components/Switch'; import Text from '@components/Text'; @@ -27,71 +27,38 @@ import useTheme from '@hooks/useTheme'; import useThemeStyles from '@hooks/useThemeStyles'; import useTransactionViolations from '@hooks/useTransactionViolations'; import useViolations from '@hooks/useViolations'; -import type {ViolationField} from '@hooks/useViolations'; -import {getCompanyCardDescription} from '@libs/CardUtils'; -import {isCategoryMissing} from '@libs/CategoryUtils'; -import {convertToDisplayString} from '@libs/CurrencyUtils'; +import type { ViolationField } from '@hooks/useViolations'; +import { getCompanyCardDescription } from '@libs/CardUtils'; +import { isCategoryMissing } from '@libs/CategoryUtils'; +import { convertToDisplayString } from '@libs/CurrencyUtils'; import DistanceRequestUtils from '@libs/DistanceRequestUtils'; -import {isReceiptError} from '@libs/ErrorUtils'; +import { isReceiptError } from '@libs/ErrorUtils'; import getNonEmptyStringOnyxID from '@libs/getNonEmptyStringOnyxID'; -import {hasEnabledOptions} from '@libs/OptionsListUtils'; -import {getLengthOfTag, getTagLists, hasDependentTags as hasDependentTagsPolicyUtils, isTaxTrackingEnabled} from '@libs/PolicyUtils'; -import {getThumbnailAndImageURIs} from '@libs/ReceiptUtils'; -import {getOriginalMessage, isMoneyRequestAction, isPayAction} from '@libs/ReportActionsUtils'; -import { - canEditFieldOfMoneyRequest, - canEditMoneyRequest, - canUserPerformWriteAction as canUserPerformWriteActionReportUtils, - getCreationReportErrors, - getReportName, - getTransactionDetails, - getTripIDFromTransactionParentReportID, - isInvoiceReport, - isPaidGroupPolicy, - isReportApproved, - isReportInGroupPolicy, - isSettled as isSettledReportUtils, - isTrackExpenseReport, -} from '@libs/ReportUtils'; -import type {TransactionDetails} from '@libs/ReportUtils'; -import {hasEnabledTags} from '@libs/TagsOptionsListUtils'; -import { - didReceiptScanSucceed as didReceiptScanSucceedTransactionUtils, - getAmount, - getBillable, - getCurrency, - getDescription, - getDistanceInMeters, - getReimbursable, - getTagForDisplay, - getTaxName, - hasMissingSmartscanFields, - hasReceipt as hasReceiptTransactionUtils, - hasReservationList, - hasRoute as hasRouteTransactionUtils, - isCardTransaction as isCardTransactionTransactionUtils, - isDistanceRequest as isDistanceRequestTransactionUtils, - isExpenseSplit, - isPerDiemRequest as isPerDiemRequestTransactionUtils, - isScanning, - shouldShowAttendees as shouldShowAttendeesTransactionUtils, -} from '@libs/TransactionUtils'; +import { hasEnabledOptions } from '@libs/OptionsListUtils'; +import { getLengthOfTag, getTagLists, hasDependentTags as hasDependentTagsPolicyUtils, isTaxTrackingEnabled } from '@libs/PolicyUtils'; +import { getThumbnailAndImageURIs } from '@libs/ReceiptUtils'; +import { getOriginalMessage, isMoneyRequestAction, isPayAction } from '@libs/ReportActionsUtils'; +import { canEditFieldOfMoneyRequest, canEditMoneyRequest, canUserPerformWriteAction as canUserPerformWriteActionReportUtils, getCreationReportErrors, getReportName, getTransactionDetails, getTripIDFromTransactionParentReportID, isInvoiceReport, isPaidGroupPolicy, isReportApproved, isReportInGroupPolicy, isSettled as isSettledReportUtils, isTrackExpenseReport } from '@libs/ReportUtils'; +import type { TransactionDetails } from '@libs/ReportUtils'; +import { hasEnabledTags } from '@libs/TagsOptionsListUtils'; +import { didReceiptScanSucceed as didReceiptScanSucceedTransactionUtils, getAmount, getBillable, getCurrency, getDescription, getDistanceInMeters, getReimbursable, getTagForDisplay, getTaxName, hasMissingSmartscanFields, hasReceipt as hasReceiptTransactionUtils, hasReservationList, hasRoute as hasRouteTransactionUtils, isCardTransaction as isCardTransactionTransactionUtils, isDistanceRequest as isDistanceRequestTransactionUtils, isExpenseSplit, isExpenseUnreported as isExpenseUnreportedTransactionUtils, isPerDiemRequest as isPerDiemRequestTransactionUtils, isScanning, shouldShowAttendees as shouldShowAttendeesTransactionUtils } from '@libs/TransactionUtils'; import ViolationsUtils from '@libs/Violations/ViolationsUtils'; import Navigation from '@navigation/Navigation'; import AnimatedEmptyStateBackground from '@pages/home/report/AnimatedEmptyStateBackground'; -import {cleanUpMoneyRequest, updateMoneyRequestBillable, updateMoneyRequestReimbursable} from '@userActions/IOU'; -import {navigateToConciergeChatAndDeleteReport} from '@userActions/Report'; -import {clearAllRelatedReportActionErrors} from '@userActions/ReportActions'; -import {clearError, getLastModifiedExpense, revert} from '@userActions/Transaction'; +import { cleanUpMoneyRequest, updateMoneyRequestBillable, updateMoneyRequestReimbursable } from '@userActions/IOU'; +import { navigateToConciergeChatAndDeleteReport } from '@userActions/Report'; +import { clearAllRelatedReportActionErrors } from '@userActions/ReportActions'; +import { clearError, getLastModifiedExpense, revert } from '@userActions/Transaction'; import CONST from '@src/CONST'; -import type {TranslationPaths} from '@src/languages/types'; +import type { TranslationPaths } from '@src/languages/types'; import ONYXKEYS from '@src/ONYXKEYS'; import ROUTES from '@src/ROUTES'; import type * as OnyxTypes from '@src/types/onyx'; -import type {TransactionPendingFieldsKey} from '@src/types/onyx/Transaction'; -import {isEmptyObject} from '@src/types/utils/EmptyObject'; +import type { TransactionPendingFieldsKey } from '@src/types/onyx/Transaction'; +import { isEmptyObject } from '@src/types/utils/EmptyObject'; import ReportActionItemImage from './ReportActionItemImage'; + type MoneyRequestViewProps = { /** All the data of the report collection */ allReports: OnyxCollection; @@ -100,7 +67,7 @@ type MoneyRequestViewProps = { report: OnyxEntry; /** Policy that the report belongs to */ - policy: OnyxEntry; + expensePolicy: OnyxEntry; /** Whether we should display the animated banner above the component */ shouldShowAnimatedBackground: boolean; @@ -108,7 +75,7 @@ type MoneyRequestViewProps = { /** Whether we should show Money Request with disabled all fields */ readonly?: boolean; - /** whether or not this report is from review duplicates */ + /** whether this report is from review duplicates */ isFromReviewDuplicates?: boolean; /** Updated transaction to show in duplicate & merge transaction flow */ @@ -132,7 +99,7 @@ const receiptFieldViolationNames: OnyxTypes.ViolationName[] = [CONST.VIOLATIONS. function MoneyRequestView({ allReports, report, - policy, + expensePolicy, shouldShowAnimatedBackground, readonly = false, updatedTransaction, @@ -146,25 +113,15 @@ function MoneyRequestView({ const {translate, toLocaleDigit} = useLocalize(); const {shouldUseNarrowLayout} = useResponsiveLayout(); const {getReportRHPActiveRoute} = useActiveRoute(); + const parentReportID = report?.parentReportID; - const policyID = report?.policyID; const parentReport = allReports?.[`${ONYXKEYS.COLLECTION.REPORT}${parentReportID}`]; - const chatReport = allReports?.[`${ONYXKEYS.COLLECTION.REPORT}${parentReport?.parentReportID}`]; - const allPolicyCategories = usePolicyCategories(); - const policyCategories = allPolicyCategories?.[`${ONYXKEYS.COLLECTION.POLICY_CATEGORIES}${policyID}`]; - const transactionReport = allReports?.[`${ONYXKEYS.COLLECTION.REPORT}${updatedTransaction?.reportID}`]; - const targetPolicyID = updatedTransaction?.reportID ? transactionReport?.policyID : policyID; - const allPolicyTags = usePolicyTags(); - const policyTagList = allPolicyTags?.[`${ONYXKEYS.COLLECTION.POLICY_TAGS}${targetPolicyID}`]; - const [cardList] = useOnyx(ONYXKEYS.CARD_LIST, {canBeMissing: true}); const [parentReportActions] = useOnyx(`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${parentReportID}`, { canEvict: false, canBeMissing: true, }); - const parentReportAction = report?.parentReportActionID ? parentReportActions?.[report.parentReportActionID] : undefined; - const isTrackExpense = isTrackExpenseReport(report); - const moneyRequestReport = parentReport; + const linkedTransactionID = useMemo(() => { if (!parentReportAction) { return undefined; @@ -172,8 +129,23 @@ function MoneyRequestView({ const originalMessage = parentReportAction && isMoneyRequestAction(parentReportAction) ? getOriginalMessage(parentReportAction) : undefined; return originalMessage?.IOUTransactionID; }, [parentReportAction]); - const [transaction] = useOnyx(`${ONYXKEYS.COLLECTION.TRANSACTION}${getNonEmptyStringOnyxID(linkedTransactionID)}`, {canBeMissing: true}); + const isExpenseUnreported = isExpenseUnreportedTransactionUtils(updatedTransaction ?? transaction); + + const [activePolicyID] = useOnyx(ONYXKEYS.NVP_ACTIVE_POLICY_ID); + const [activePolicy] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY}${activePolicyID}`, {selector: (policy) => (policy?.type !== CONST.POLICY.TYPE.PERSONAL ? policy : undefined)}); + const policy = isExpenseUnreported ? activePolicy : expensePolicy; + const policyID = isExpenseUnreported ? activePolicy?.id : report?.policyID; + + const chatReport = allReports?.[`${ONYXKEYS.COLLECTION.REPORT}${parentReport?.parentReportID}`]; + const allPolicyCategories = usePolicyCategories(); + const policyCategories = allPolicyCategories?.[`${ONYXKEYS.COLLECTION.POLICY_CATEGORIES}${policyID}`]; + const transactionReport = allReports?.[`${ONYXKEYS.COLLECTION.REPORT}${updatedTransaction?.reportID}`]; + const targetPolicyID = updatedTransaction?.reportID ? transactionReport?.policyID : policyID; + const allPolicyTags = usePolicyTags(); + const policyTagList = allPolicyTags?.[`${ONYXKEYS.COLLECTION.POLICY_TAGS}${targetPolicyID}`]; + const [cardList] = useOnyx(ONYXKEYS.CARD_LIST, {canBeMissing: true}); + const [transactionBackup] = useOnyx(`${ONYXKEYS.COLLECTION.TRANSACTION_BACKUP}${getNonEmptyStringOnyxID(linkedTransactionID)}`, {canBeMissing: true}); const transactionViolations = useTransactionViolations(transaction?.transactionID); const [outstandingReportsByPolicyID] = useOnyx(ONYXKEYS.DERIVED.OUTSTANDING_REPORTS_BY_POLICY_ID, {canBeMissing: true}); @@ -215,8 +187,11 @@ function MoneyRequestView({ const isCardTransaction = isCardTransactionTransactionUtils(transaction); const cardProgramName = getCompanyCardDescription(transaction?.cardName, transaction?.cardID, cardList); const shouldShowCard = isCardTransaction && cardProgramName; + + const moneyRequestReport = parentReport; const isApproved = isReportApproved({report: moneyRequestReport}); const isInvoice = isInvoiceReport(moneyRequestReport); + const isTrackExpense = isTrackExpenseReport(report); const isPaidReport = isPayAction(parentReportAction); const taxRates = policy?.taxRates; const formattedTaxAmount = updatedTransaction?.taxAmount @@ -238,7 +213,6 @@ function MoneyRequestView({ const isReportArchived = useReportIsArchived(report?.reportID); const isEditable = !!canUserPerformWriteActionReportUtils(report, isReportArchived) && !readonly; const canEdit = isMoneyRequestAction(parentReportAction) && canEditMoneyRequest(parentReportAction, transaction, isChatReportArchived) && isEditable; - const canEditTaxFields = canEdit && !isDistanceRequest; const canEditAmount = isEditable && canEditFieldOfMoneyRequest(parentReportAction, CONST.EDIT_REQUEST_FIELD.AMOUNT, undefined, isChatReportArchived); const canEditMerchant = isEditable && canEditFieldOfMoneyRequest(parentReportAction, CONST.EDIT_REQUEST_FIELD.MERCHANT, undefined, isChatReportArchived); @@ -255,6 +229,8 @@ function MoneyRequestView({ // if the policy of the report is either Collect or Control, then this report must be tied to expense chat const isPolicyExpenseChat = isReportInGroupPolicy(report); + const shouldShowPolicySpecificFields = isPolicyExpenseChat || isExpenseUnreported; + const policyTagLists = useMemo(() => getTagLists(policyTagList), [policyTagList]); const iouType = useMemo(() => { @@ -274,11 +250,11 @@ function MoneyRequestView({ // Flags for showing categories and tags // transactionCategory can be an empty string // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing - const shouldShowCategory = isPolicyExpenseChat && (categoryForDisplay || hasEnabledOptions(policyCategories ?? {})); + const shouldShowCategory = shouldShowPolicySpecificFields && (categoryForDisplay || hasEnabledOptions(policyCategories ?? {})); // transactionTag can be an empty string // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing - const shouldShowTag = isPolicyExpenseChat && (transactionTag || hasEnabledTags(policyTagLists)); - const shouldShowBillable = isPolicyExpenseChat && (!!transactionBillable || !(policy?.disabledFields?.defaultBillable ?? true) || !!updatedTransaction?.billable); + const shouldShowTag = shouldShowPolicySpecificFields && (transactionTag || hasEnabledTags(policyTagLists)); + const shouldShowBillable = shouldShowPolicySpecificFields && (!!transactionBillable || !(policy?.disabledFields?.defaultBillable ?? true) || !!updatedTransaction?.billable); const isCurrentTransactionReimbursableDifferentFromPolicyDefault = policy?.defaultReimbursable !== undefined && !!(updatedTransaction?.reimbursable ?? transactionReimbursable) !== policy.defaultReimbursable; const shouldShowReimbursable = @@ -286,7 +262,7 @@ function MoneyRequestView({ const canEditReimbursable = isEditable && canEditFieldOfMoneyRequest(parentReportAction, CONST.EDIT_REQUEST_FIELD.REIMBURSABLE, undefined, isChatReportArchived); const shouldShowAttendees = useMemo(() => shouldShowAttendeesTransactionUtils(iouType, policy), [iouType, policy]); - const shouldShowTax = isTaxTrackingEnabled(isPolicyExpenseChat, policy, isDistanceRequest, isPerDiemRequest); + const shouldShowTax = isTaxTrackingEnabled(shouldShowPolicySpecificFields, policy, isDistanceRequest, isPerDiemRequest); const tripID = getTripIDFromTransactionParentReportID(parentReport?.parentReportID); const shouldShowViewTripDetails = hasReservationList(transaction) && !!tripID; diff --git a/src/pages/TransactionDuplicate/Confirmation.tsx b/src/pages/TransactionDuplicate/Confirmation.tsx index 18f170ed65d1..eda67da2488c 100644 --- a/src/pages/TransactionDuplicate/Confirmation.tsx +++ b/src/pages/TransactionDuplicate/Confirmation.tsx @@ -151,7 +151,7 @@ function Confirmation() { {renderThreadDivider} @@ -184,7 +184,7 @@ function ReportActionItemContentCreated({ {renderThreadDivider} From 86b71bce296cb94f8fbdbb6a52df080d3311f84d Mon Sep 17 00:00:00 2001 From: Agata Kosior Date: Mon, 25 Aug 2025 10:30:51 +0200 Subject: [PATCH 03/13] fix: show categories on the category page --- .../request/step/IOURequestStepCategory.tsx | 30 ++++++++++++------- 1 file changed, 19 insertions(+), 11 deletions(-) diff --git a/src/pages/iou/request/step/IOURequestStepCategory.tsx b/src/pages/iou/request/step/IOURequestStepCategory.tsx index 01ddf0385c3f..d0a8d68ad317 100644 --- a/src/pages/iou/request/step/IOURequestStepCategory.tsx +++ b/src/pages/iou/request/step/IOURequestStepCategory.tsx @@ -23,6 +23,7 @@ import Navigation from '@libs/Navigation/Navigation'; import {hasEnabledOptions} from '@libs/OptionsListUtils'; import {isPolicyAdmin} from '@libs/PolicyUtils'; import {getTransactionDetails, isGroupPolicy, isReportInGroupPolicy} from '@libs/ReportUtils'; +import {isExpenseUnreported as isExpenseUnreportedTransactionUtils} from '@libs/TransactionUtils'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import ROUTES from '@src/ROUTES'; @@ -44,22 +45,29 @@ function IOURequestStepCategory({ }, transaction, }: IOURequestStepCategoryProps) { - const [policyReal] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY}${getIOURequestPolicyID(transaction, reportReal)}`, {canBeMissing: true}); - const [policyDraft] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY_DRAFTS}${getIOURequestPolicyID(transaction, reportDraft)}`, {canBeMissing: true}); + const styles = useThemeStyles(); + const theme = useTheme(); + const {translate} = useLocalize(); + + const policyIdReal = getIOURequestPolicyID(transaction, reportReal); + const policyIdDraft = getIOURequestPolicyID(transaction, reportDraft); + const [policyReal] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY}${policyIdReal}`, {canBeMissing: true}); + const [policyDraft] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY_DRAFTS}${policyIdDraft}`, {canBeMissing: true}); + const [activePolicyID] = useOnyx(ONYXKEYS.NVP_ACTIVE_POLICY_ID); + const [activePolicy] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY}${activePolicyID}`, {selector: (policy) => (policy?.type !== CONST.POLICY.TYPE.PERSONAL ? policy : undefined)}); + const isExpenseUnreported = isExpenseUnreportedTransactionUtils(transaction); + const policy = isExpenseUnreported ? activePolicy : (policyReal ?? policyDraft); + const [splitDraftTransaction] = useOnyx(`${ONYXKEYS.COLLECTION.SPLIT_TRANSACTION_DRAFT}${transactionID}`, {canBeMissing: true}); - const [policyCategoriesReal] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY_CATEGORIES}${getIOURequestPolicyID(transaction, reportReal)}`, {canBeMissing: true}); - const [policyCategoriesDraft] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY_CATEGORIES_DRAFT}${getIOURequestPolicyID(transaction, reportDraft)}`, {canBeMissing: true}); - const [policyTags] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY_TAGS}${getIOURequestPolicyID(transaction, reportReal)}`, {canBeMissing: true}); + const [policyCategoriesReal] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY_CATEGORIES}${policy?.id}`, {canBeMissing: true}); + const [policyCategoriesDraft] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY_CATEGORIES_DRAFT}${policyIdDraft}`, {canBeMissing: true}); + const [policyTags] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY_TAGS}${policy?.id}`, {canBeMissing: true}); const report = reportReal ?? reportDraft; - const policy = policyReal ?? policyDraft; const policyCategories = policyCategoriesReal ?? policyCategoriesDraft; const [allTransactionViolations] = useOnyx(ONYXKEYS.COLLECTION.TRANSACTION_VIOLATIONS, {canBeMissing: true}); const [policyTagLists] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY_TAGS}${policy?.id}`, {canBeMissing: true}); const {currentSearchHash} = useSearchContext(); - const styles = useThemeStyles(); - const theme = useTheme(); - const {translate} = useLocalize(); const isEditing = action === CONST.IOU.ACTION.EDIT; const isEditingSplit = (iouType === CONST.IOU.TYPE.SPLIT || iouType === CONST.IOU.TYPE.SPLIT_EXPENSE) && isEditing; const currentTransaction = isEditingSplit && !lodashIsEmpty(splitDraftTransaction) ? splitDraftTransaction : transaction; @@ -68,7 +76,7 @@ function IOURequestStepCategory({ const categoryForDisplay = isCategoryMissing(transactionCategory) ? '' : transactionCategory; const shouldShowCategory = - (isReportInGroupPolicy(report) || isGroupPolicy(policy?.type ?? '')) && + (isExpenseUnreported || isReportInGroupPolicy(report) || isGroupPolicy(policy?.type ?? '')) && // The transactionCategory can be an empty string, so to maintain the logic we'd like to keep it in this shape until utils refactor // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing (!!categoryForDisplay || hasEnabledOptions(Object.values(policyCategories ?? {}))); @@ -191,7 +199,7 @@ function IOURequestStepCategory({ {translate('iou.categorySelection')} From 050c976e3036ee70fe89e72357dee3d36d267b26 Mon Sep 17 00:00:00 2001 From: Agata Kosior Date: Mon, 25 Aug 2025 13:03:42 +0200 Subject: [PATCH 04/13] fix: show tags and tax rates --- .../ReportActionItem/MoneyRequestView.tsx | 4 ++-- src/pages/iou/request/step/IOURequestStepTag.tsx | 14 +++++++++----- .../iou/request/step/IOURequestStepTaxRatePage.tsx | 14 +++++++++----- 3 files changed, 20 insertions(+), 12 deletions(-) diff --git a/src/components/ReportActionItem/MoneyRequestView.tsx b/src/components/ReportActionItem/MoneyRequestView.tsx index 26dbefe49a8b..8eb5a28c16d3 100644 --- a/src/components/ReportActionItem/MoneyRequestView.tsx +++ b/src/components/ReportActionItem/MoneyRequestView.tsx @@ -301,12 +301,12 @@ function MoneyRequestView({ const saveBillable = useCallback( (newBillable: boolean) => { // If the value hasn't changed, don't request to save changes on the server and just close the modal - if (newBillable === getBillable(transaction) || !transaction?.transactionID || !report?.reportID) { + if (!isExpenseUnreported || newBillable === getBillable(transaction) || !transaction?.transactionID || !report?.reportID) { return; } updateMoneyRequestBillable(transaction.transactionID, report?.reportID, newBillable, policy, policyTagList, policyCategories); }, - [transaction, report, policy, policyTagList, policyCategories], + [isExpenseUnreported, transaction, report?.reportID, policy, policyTagList, policyCategories], ); const saveReimbursable = useCallback( diff --git a/src/pages/iou/request/step/IOURequestStepTag.tsx b/src/pages/iou/request/step/IOURequestStepTag.tsx index 85a31f546810..a22973a6328d 100644 --- a/src/pages/iou/request/step/IOURequestStepTag.tsx +++ b/src/pages/iou/request/step/IOURequestStepTag.tsx @@ -17,7 +17,7 @@ import Navigation from '@libs/Navigation/Navigation'; import {getTagList, getTagListName, getTagLists, hasDependentTags as hasDependentTagsPolicyUtils, isPolicyAdmin} from '@libs/PolicyUtils'; import type {OptionData} from '@libs/ReportUtils'; import {hasEnabledTags} from '@libs/TagsOptionsListUtils'; -import {getTag} from '@libs/TransactionUtils'; +import {getTag, isExpenseUnreported as isExpenseUnreportedTransactionUtils} from '@libs/TransactionUtils'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import ROUTES from '@src/ROUTES'; @@ -39,9 +39,13 @@ function IOURequestStepTag({ transaction, }: IOURequestStepTagProps) { const [splitDraftTransaction] = useOnyx(`${ONYXKEYS.COLLECTION.SPLIT_TRANSACTION_DRAFT}${transactionID}`, {canBeMissing: true}); - const [policy] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY}${report?.policyID}`, {canBeMissing: false}); - const [policyCategories] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY_CATEGORIES}${report?.policyID}`, {canBeMissing: false}); - const [policyTags] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY_TAGS}${report?.policyID}`, {canBeMissing: false}); + const [reportPolicy] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY}${report?.policyID}`, {canBeMissing: false}); + const [activePolicyID] = useOnyx(ONYXKEYS.NVP_ACTIVE_POLICY_ID); + const [activePolicy] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY}${activePolicyID}`, {selector: (policy) => (policy?.type !== CONST.POLICY.TYPE.PERSONAL ? policy : undefined)}); + const isExpenseUnreported = isExpenseUnreportedTransactionUtils(transaction); + const policy = isExpenseUnreported ? activePolicy : reportPolicy; + const [policyCategories] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY_CATEGORIES}${policy?.id}`, {canBeMissing: false}); + const [policyTags] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY_TAGS}${policy?.id}`, {canBeMissing: false}); const styles = useThemeStyles(); const {currentSearchHash} = useSearchContext(); @@ -167,7 +171,7 @@ function IOURequestStepTag({ <> {translate('iou.tagSelection')} (policy?.type !== CONST.POLICY.TYPE.PERSONAL ? policy : undefined)}); + const isExpenseUnreported = isExpenseUnreportedTransactionUtils(transaction); + const policy = isExpenseUnreported ? activePolicy : reportPolicy; + const [policyCategories] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY_CATEGORIES}${policy?.id ?? '-1'}`); + const [policyTags] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY_TAGS}${policy?.id ?? '-1'}`); const [splitDraftTransaction] = useOnyx(`${ONYXKEYS.COLLECTION.SPLIT_TRANSACTION_DRAFT}${transactionID ?? '-1'}`); const isEditing = action === CONST.IOU.ACTION.EDIT; @@ -108,7 +112,7 @@ function IOURequestStepTaxRatePage({ > Date: Mon, 25 Aug 2025 13:41:39 +0200 Subject: [PATCH 05/13] fix: minor fix --- src/libs/actions/IOU.ts | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/libs/actions/IOU.ts b/src/libs/actions/IOU.ts index 34b522dc39ca..ccf63eb5dd71 100644 --- a/src/libs/actions/IOU.ts +++ b/src/libs/actions/IOU.ts @@ -4807,7 +4807,7 @@ function updateMoneyRequestTaxAmount( taxAmount, }; const {params, onyxData} = getUpdateMoneyRequestParams(transactionID, optimisticReportActionID, transactionChanges, policy, policyTagList, policyCategories); - API.write('UpdateMoneyRequestTaxAmount', params, onyxData); + API.write(WRITE_COMMANDS.UPDATE_MONEY_REQUEST_TAX_AMOUNT, params, onyxData); } type UpdateMoneyRequestTaxRateParams = { @@ -4827,7 +4827,9 @@ function updateMoneyRequestTaxRate({transactionID, optimisticReportActionID, tax taxAmount, }; const {params, onyxData} = getUpdateMoneyRequestParams(transactionID, optimisticReportActionID, transactionChanges, policy, policyTagList, policyCategories); - API.write('UpdateMoneyRequestTaxRate', params, onyxData); + + console.log({params}); + API.write(WRITE_COMMANDS.UPDATE_MONEY_REQUEST_TAX_RATE, params, onyxData); } type UpdateMoneyRequestDistanceParams = { @@ -10528,6 +10530,7 @@ function completePaymentOnboarding(paymentSelected: ValueOf, paymentPolicyID?: string, full = true) { if (chatReport.policyID && shouldRestrictUserBillableActions(chatReport.policyID)) { Navigation.navigate(ROUTES.RESTRICTED_ACTION.getRoute(chatReport.policyID)); From a1575635cf0e5c4c2eda8d5303685eda29d93eef Mon Sep 17 00:00:00 2001 From: Agata Kosior Date: Thu, 28 Aug 2025 10:53:50 +0200 Subject: [PATCH 06/13] fix: prettier --- .../ReportActionItem/MoneyRequestView.tsx | 88 +++++++++++++------ src/libs/TransactionUtils/index.ts | 2 +- src/types/onyx/Transaction.ts | 2 +- 3 files changed, 63 insertions(+), 29 deletions(-) diff --git a/src/components/ReportActionItem/MoneyRequestView.tsx b/src/components/ReportActionItem/MoneyRequestView.tsx index 8eb5a28c16d3..7b8c2eab5537 100644 --- a/src/components/ReportActionItem/MoneyRequestView.tsx +++ b/src/components/ReportActionItem/MoneyRequestView.tsx @@ -1,16 +1,16 @@ -import { Str } from 'expensify-common'; +import {Str} from 'expensify-common'; import mapValues from 'lodash/mapValues'; -import React, { useCallback, useEffect, useMemo, useState } from 'react'; -import { View } from 'react-native'; -import type { OnyxCollection, OnyxEntry } from 'react-native-onyx'; +import React, {useCallback, useEffect, useMemo, useState} from 'react'; +import {View} from 'react-native'; +import type {OnyxCollection, OnyxEntry} from 'react-native-onyx'; import ConfirmModal from '@components/ConfirmModal'; import Icon from '@components/Icon'; import * as Expensicons from '@components/Icon/Expensicons'; import MenuItem from '@components/MenuItem'; import MenuItemWithTopDescription from '@components/MenuItemWithTopDescription'; import OfflineWithFeedback from '@components/OfflineWithFeedback'; -import { usePolicyCategories, usePolicyTags } from '@components/OnyxListItemProvider'; -import ReceiptAudit, { ReceiptAuditMessages } from '@components/ReceiptAudit'; +import {usePolicyCategories, usePolicyTags} from '@components/OnyxListItemProvider'; +import ReceiptAudit, {ReceiptAuditMessages} from '@components/ReceiptAudit'; import ReceiptEmptyState from '@components/ReceiptEmptyState'; import Switch from '@components/Switch'; import Text from '@components/Text'; @@ -27,38 +27,72 @@ import useTheme from '@hooks/useTheme'; import useThemeStyles from '@hooks/useThemeStyles'; import useTransactionViolations from '@hooks/useTransactionViolations'; import useViolations from '@hooks/useViolations'; -import type { ViolationField } from '@hooks/useViolations'; -import { getCompanyCardDescription } from '@libs/CardUtils'; -import { isCategoryMissing } from '@libs/CategoryUtils'; -import { convertToDisplayString } from '@libs/CurrencyUtils'; +import type {ViolationField} from '@hooks/useViolations'; +import {getCompanyCardDescription} from '@libs/CardUtils'; +import {isCategoryMissing} from '@libs/CategoryUtils'; +import {convertToDisplayString} from '@libs/CurrencyUtils'; import DistanceRequestUtils from '@libs/DistanceRequestUtils'; -import { isReceiptError } from '@libs/ErrorUtils'; +import {isReceiptError} from '@libs/ErrorUtils'; import getNonEmptyStringOnyxID from '@libs/getNonEmptyStringOnyxID'; -import { hasEnabledOptions } from '@libs/OptionsListUtils'; -import { getLengthOfTag, getTagLists, hasDependentTags as hasDependentTagsPolicyUtils, isTaxTrackingEnabled } from '@libs/PolicyUtils'; -import { getThumbnailAndImageURIs } from '@libs/ReceiptUtils'; -import { getOriginalMessage, isMoneyRequestAction, isPayAction } from '@libs/ReportActionsUtils'; -import { canEditFieldOfMoneyRequest, canEditMoneyRequest, canUserPerformWriteAction as canUserPerformWriteActionReportUtils, getCreationReportErrors, getReportName, getTransactionDetails, getTripIDFromTransactionParentReportID, isInvoiceReport, isPaidGroupPolicy, isReportApproved, isReportInGroupPolicy, isSettled as isSettledReportUtils, isTrackExpenseReport } from '@libs/ReportUtils'; -import type { TransactionDetails } from '@libs/ReportUtils'; -import { hasEnabledTags } from '@libs/TagsOptionsListUtils'; -import { didReceiptScanSucceed as didReceiptScanSucceedTransactionUtils, getAmount, getBillable, getCurrency, getDescription, getDistanceInMeters, getReimbursable, getTagForDisplay, getTaxName, hasMissingSmartscanFields, hasReceipt as hasReceiptTransactionUtils, hasReservationList, hasRoute as hasRouteTransactionUtils, isCardTransaction as isCardTransactionTransactionUtils, isDistanceRequest as isDistanceRequestTransactionUtils, isExpenseSplit, isExpenseUnreported as isExpenseUnreportedTransactionUtils, isPerDiemRequest as isPerDiemRequestTransactionUtils, isScanning, shouldShowAttendees as shouldShowAttendeesTransactionUtils } from '@libs/TransactionUtils'; +import {hasEnabledOptions} from '@libs/OptionsListUtils'; +import {getLengthOfTag, getTagLists, hasDependentTags as hasDependentTagsPolicyUtils, isTaxTrackingEnabled} from '@libs/PolicyUtils'; +import {getThumbnailAndImageURIs} from '@libs/ReceiptUtils'; +import {getOriginalMessage, isMoneyRequestAction, isPayAction} from '@libs/ReportActionsUtils'; +import { + canEditFieldOfMoneyRequest, + canEditMoneyRequest, + canUserPerformWriteAction as canUserPerformWriteActionReportUtils, + getCreationReportErrors, + getReportName, + getTransactionDetails, + getTripIDFromTransactionParentReportID, + isInvoiceReport, + isPaidGroupPolicy, + isReportApproved, + isReportInGroupPolicy, + isSettled as isSettledReportUtils, + isTrackExpenseReport, +} from '@libs/ReportUtils'; +import type {TransactionDetails} from '@libs/ReportUtils'; +import {hasEnabledTags} from '@libs/TagsOptionsListUtils'; +import { + didReceiptScanSucceed as didReceiptScanSucceedTransactionUtils, + getAmount, + getBillable, + getCurrency, + getDescription, + getDistanceInMeters, + getReimbursable, + getTagForDisplay, + getTaxName, + hasMissingSmartscanFields, + hasReceipt as hasReceiptTransactionUtils, + hasReservationList, + hasRoute as hasRouteTransactionUtils, + isCardTransaction as isCardTransactionTransactionUtils, + isDistanceRequest as isDistanceRequestTransactionUtils, + isExpenseSplit, + isExpenseUnreported as isExpenseUnreportedTransactionUtils, + isPerDiemRequest as isPerDiemRequestTransactionUtils, + isScanning, + shouldShowAttendees as shouldShowAttendeesTransactionUtils, +} from '@libs/TransactionUtils'; import ViolationsUtils from '@libs/Violations/ViolationsUtils'; import Navigation from '@navigation/Navigation'; import AnimatedEmptyStateBackground from '@pages/home/report/AnimatedEmptyStateBackground'; -import { cleanUpMoneyRequest, updateMoneyRequestBillable, updateMoneyRequestReimbursable } from '@userActions/IOU'; -import { navigateToConciergeChatAndDeleteReport } from '@userActions/Report'; -import { clearAllRelatedReportActionErrors } from '@userActions/ReportActions'; -import { clearError, getLastModifiedExpense, revert } from '@userActions/Transaction'; +import {cleanUpMoneyRequest, updateMoneyRequestBillable, updateMoneyRequestReimbursable} from '@userActions/IOU'; +import {navigateToConciergeChatAndDeleteReport} from '@userActions/Report'; +import {clearAllRelatedReportActionErrors} from '@userActions/ReportActions'; +import {clearError, getLastModifiedExpense, revert} from '@userActions/Transaction'; import CONST from '@src/CONST'; -import type { TranslationPaths } from '@src/languages/types'; +import type {TranslationPaths} from '@src/languages/types'; import ONYXKEYS from '@src/ONYXKEYS'; import ROUTES from '@src/ROUTES'; import type * as OnyxTypes from '@src/types/onyx'; -import type { TransactionPendingFieldsKey } from '@src/types/onyx/Transaction'; -import { isEmptyObject } from '@src/types/utils/EmptyObject'; +import type {TransactionPendingFieldsKey} from '@src/types/onyx/Transaction'; +import {isEmptyObject} from '@src/types/utils/EmptyObject'; import ReportActionItemImage from './ReportActionItemImage'; - type MoneyRequestViewProps = { /** All the data of the report collection */ allReports: OnyxCollection; diff --git a/src/libs/TransactionUtils/index.ts b/src/libs/TransactionUtils/index.ts index 70c136eae62d..d3e6413d7f00 100644 --- a/src/libs/TransactionUtils/index.ts +++ b/src/libs/TransactionUtils/index.ts @@ -1884,7 +1884,7 @@ function createUnreportedExpenseSections(transactions: Array & { /** The ID of the report that this transaction is associated with. */ - reportID: "0"; + reportID: '0'; }; export default Transaction; From c9dd839298591e7d37f6f9d2bc4e0279a62eef5a Mon Sep 17 00:00:00 2001 From: Agata Kosior Date: Thu, 28 Aug 2025 18:28:39 +0200 Subject: [PATCH 07/13] fix: eslint --- src/libs/actions/IOU.ts | 1 - .../request/step/IOURequestStepCategory.tsx | 4 +-- .../step/IOURequestStepTaxRatePage.tsx | 35 ++++++++++--------- 3 files changed, 20 insertions(+), 20 deletions(-) diff --git a/src/libs/actions/IOU.ts b/src/libs/actions/IOU.ts index 5395431e1171..897c95197ea0 100644 --- a/src/libs/actions/IOU.ts +++ b/src/libs/actions/IOU.ts @@ -4825,7 +4825,6 @@ function updateMoneyRequestTaxRate({transactionID, optimisticReportActionID, tax }; const {params, onyxData} = getUpdateMoneyRequestParams(transactionID, optimisticReportActionID, transactionChanges, policy, policyTagList, policyCategories); - console.log({params}); API.write(WRITE_COMMANDS.UPDATE_MONEY_REQUEST_TAX_RATE, params, onyxData); } diff --git a/src/pages/iou/request/step/IOURequestStepCategory.tsx b/src/pages/iou/request/step/IOURequestStepCategory.tsx index d0a8d68ad317..124d4165aa00 100644 --- a/src/pages/iou/request/step/IOURequestStepCategory.tsx +++ b/src/pages/iou/request/step/IOURequestStepCategory.tsx @@ -53,8 +53,8 @@ function IOURequestStepCategory({ const policyIdDraft = getIOURequestPolicyID(transaction, reportDraft); const [policyReal] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY}${policyIdReal}`, {canBeMissing: true}); const [policyDraft] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY_DRAFTS}${policyIdDraft}`, {canBeMissing: true}); - const [activePolicyID] = useOnyx(ONYXKEYS.NVP_ACTIVE_POLICY_ID); - const [activePolicy] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY}${activePolicyID}`, {selector: (policy) => (policy?.type !== CONST.POLICY.TYPE.PERSONAL ? policy : undefined)}); + const [activePolicyID] = useOnyx(ONYXKEYS.NVP_ACTIVE_POLICY_ID, {canBeMissing: true}); + const [activePolicy] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY}${activePolicyID}`, {canBeMissing: true, selector: (policy) => (policy?.type !== CONST.POLICY.TYPE.PERSONAL ? policy : undefined)}); const isExpenseUnreported = isExpenseUnreportedTransactionUtils(transaction); const policy = isExpenseUnreported ? activePolicy : (policyReal ?? policyDraft); diff --git a/src/pages/iou/request/step/IOURequestStepTaxRatePage.tsx b/src/pages/iou/request/step/IOURequestStepTaxRatePage.tsx index d506724adf51..fbbdfdf046fb 100644 --- a/src/pages/iou/request/step/IOURequestStepTaxRatePage.tsx +++ b/src/pages/iou/request/step/IOURequestStepTaxRatePage.tsx @@ -3,11 +3,10 @@ import type {OnyxEntry} from 'react-native-onyx'; import TaxPicker from '@components/TaxPicker'; import useLocalize from '@hooks/useLocalize'; import useOnyx from '@hooks/useOnyx'; -import * as CurrencyUtils from '@libs/CurrencyUtils'; +import {convertToBackendAmount} from '@libs/CurrencyUtils'; import Navigation from '@libs/Navigation/Navigation'; import type {TaxRatesOption} from '@libs/TaxOptionsListUtils'; -import * as TransactionUtils from '@libs/TransactionUtils'; -import {getCurrency, isExpenseUnreported as isExpenseUnreportedTransactionUtils} from '@libs/TransactionUtils'; +import {calculateTaxAmount, getAmount, getCurrency, getTaxName, getTaxValue, isExpenseUnreported as isExpenseUnreportedTransactionUtils} from '@libs/TransactionUtils'; import * as IOU from '@userActions/IOU'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; @@ -24,10 +23,9 @@ type IOURequestStepTaxRatePageProps = WithWritableReportOrNotFoundProps, transaction: OnyxEntry, selectedTaxCode: string, amount: number): number | undefined { - const getTaxValue = (taxCode: string) => TransactionUtils.getTaxValue(policy, transaction, taxCode); - const taxPercentage = getTaxValue(selectedTaxCode); + const taxPercentage = getTaxValue(policy, transaction, selectedTaxCode); if (taxPercentage) { - return TransactionUtils.calculateTaxAmount(taxPercentage, amount, getCurrency(transaction)); + return calculateTaxAmount(taxPercentage, amount, getCurrency(transaction)); } } @@ -40,14 +38,17 @@ function IOURequestStepTaxRatePage({ }: IOURequestStepTaxRatePageProps) { const {translate} = useLocalize(); - const [reportPolicy] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY}${report?.policyID ?? '-1'}`); - const [activePolicyID] = useOnyx(ONYXKEYS.NVP_ACTIVE_POLICY_ID); - const [activePolicy] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY}${activePolicyID}`, {selector: (policy) => (policy?.type !== CONST.POLICY.TYPE.PERSONAL ? policy : undefined)}); + const [reportPolicy] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY}${report?.policyID}`, {canBeMissing: true}); + const [activePolicyID] = useOnyx(ONYXKEYS.NVP_ACTIVE_POLICY_ID, {canBeMissing: true}); + const [activePolicy] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY}${activePolicyID}`, { + canBeMissing: true, + selector: (policy) => (policy?.type !== CONST.POLICY.TYPE.PERSONAL ? policy : undefined), + }); const isExpenseUnreported = isExpenseUnreportedTransactionUtils(transaction); const policy = isExpenseUnreported ? activePolicy : reportPolicy; - const [policyCategories] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY_CATEGORIES}${policy?.id ?? '-1'}`); - const [policyTags] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY_TAGS}${policy?.id ?? '-1'}`); - const [splitDraftTransaction] = useOnyx(`${ONYXKEYS.COLLECTION.SPLIT_TRANSACTION_DRAFT}${transactionID ?? '-1'}`); + const [policyCategories] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY_CATEGORIES}${policy?.id}`, {canBeMissing: true}); + const [policyTags] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY_TAGS}${policy?.id}`, {canBeMissing: true}); + const [splitDraftTransaction] = useOnyx(`${ONYXKEYS.COLLECTION.SPLIT_TRANSACTION_DRAFT}${transactionID}`, {canBeMissing: true}); const isEditing = action === CONST.IOU.ACTION.EDIT; const isEditingSplitBill = isEditing && iouType === CONST.IOU.TYPE.SPLIT; @@ -58,7 +59,7 @@ function IOURequestStepTaxRatePage({ Navigation.goBack(backTo); }; - const taxRateTitle = TransactionUtils.getTaxName(policy, currentTransaction); + const taxRateTitle = getTaxName(policy, currentTransaction); const updateTaxRates = (taxes: TaxRatesOption) => { if (!currentTransaction || !taxes.code || !taxRates) { @@ -66,11 +67,11 @@ function IOURequestStepTaxRatePage({ return; } - const taxAmount = getTaxAmount(policy, currentTransaction, taxes.code, TransactionUtils.getAmount(currentTransaction, false, true)); + const taxAmount = getTaxAmount(policy, currentTransaction, taxes.code, getAmount(currentTransaction, false, true)); if (isEditingSplitBill) { IOU.setDraftSplitTransaction(currentTransaction.transactionID, { - taxAmount: CurrencyUtils.convertToBackendAmount(taxAmount ?? 0), + taxAmount: convertToBackendAmount(taxAmount ?? 0), taxCode: taxes.code, }); navigateBack(); @@ -83,7 +84,7 @@ function IOURequestStepTaxRatePage({ transactionID: currentTransaction?.transactionID ?? '-1', optimisticReportActionID: report?.reportID ?? '-1', taxCode: newTaxCode, - taxAmount: CurrencyUtils.convertToBackendAmount(taxAmount ?? 0), + taxAmount: convertToBackendAmount(taxAmount ?? 0), policy, policyTagList: policyTags, policyCategories, @@ -96,7 +97,7 @@ function IOURequestStepTaxRatePage({ navigateBack(); return; } - const amountInSmallestCurrencyUnits = CurrencyUtils.convertToBackendAmount(taxAmount); + const amountInSmallestCurrencyUnits = convertToBackendAmount(taxAmount); IOU.setMoneyRequestTaxRate(currentTransaction?.transactionID, taxes?.code ?? ''); IOU.setMoneyRequestTaxAmount(currentTransaction.transactionID, amountInSmallestCurrencyUnits); From f4022d4cc9d7b9bb341fe8636f5c63ac33f124c8 Mon Sep 17 00:00:00 2001 From: Agata Kosior Date: Fri, 29 Aug 2025 09:51:03 +0200 Subject: [PATCH 08/13] fix: prettier --- src/components/ReportActionItem/MoneyRequestView.tsx | 2 +- src/pages/iou/request/step/IOURequestStepCategory.tsx | 5 ++++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/components/ReportActionItem/MoneyRequestView.tsx b/src/components/ReportActionItem/MoneyRequestView.tsx index 72dd20d430e1..ba350bd4dea6 100644 --- a/src/components/ReportActionItem/MoneyRequestView.tsx +++ b/src/components/ReportActionItem/MoneyRequestView.tsx @@ -72,8 +72,8 @@ import { isCardTransaction as isCardTransactionTransactionUtils, isDistanceRequest as isDistanceRequestTransactionUtils, isExpenseSplit, - isManualDistanceRequest as isManualDistanceRequestTransactionUtils, isExpenseUnreported as isExpenseUnreportedTransactionUtils, + isManualDistanceRequest as isManualDistanceRequestTransactionUtils, isPerDiemRequest as isPerDiemRequestTransactionUtils, isScanning, shouldShowAttendees as shouldShowAttendeesTransactionUtils, diff --git a/src/pages/iou/request/step/IOURequestStepCategory.tsx b/src/pages/iou/request/step/IOURequestStepCategory.tsx index 124d4165aa00..b549595aeee1 100644 --- a/src/pages/iou/request/step/IOURequestStepCategory.tsx +++ b/src/pages/iou/request/step/IOURequestStepCategory.tsx @@ -54,7 +54,10 @@ function IOURequestStepCategory({ const [policyReal] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY}${policyIdReal}`, {canBeMissing: true}); const [policyDraft] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY_DRAFTS}${policyIdDraft}`, {canBeMissing: true}); const [activePolicyID] = useOnyx(ONYXKEYS.NVP_ACTIVE_POLICY_ID, {canBeMissing: true}); - const [activePolicy] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY}${activePolicyID}`, {canBeMissing: true, selector: (policy) => (policy?.type !== CONST.POLICY.TYPE.PERSONAL ? policy : undefined)}); + const [activePolicy] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY}${activePolicyID}`, { + canBeMissing: true, + selector: (policy) => (policy?.type !== CONST.POLICY.TYPE.PERSONAL ? policy : undefined), + }); const isExpenseUnreported = isExpenseUnreportedTransactionUtils(transaction); const policy = isExpenseUnreported ? activePolicy : (policyReal ?? policyDraft); From f84605c96658c90cc590f6cc0942db48ff3b261f Mon Sep 17 00:00:00 2001 From: Agata Kosior Date: Fri, 29 Aug 2025 09:53:21 +0200 Subject: [PATCH 09/13] fix: eslint --- src/pages/iou/request/step/IOURequestStepTag.tsx | 7 +++++-- .../iou/request/step/IOURequestStepTaxRatePage.tsx | 10 +++++----- 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/src/pages/iou/request/step/IOURequestStepTag.tsx b/src/pages/iou/request/step/IOURequestStepTag.tsx index cc8b4f599b6a..4a2de05042f8 100644 --- a/src/pages/iou/request/step/IOURequestStepTag.tsx +++ b/src/pages/iou/request/step/IOURequestStepTag.tsx @@ -40,8 +40,11 @@ function IOURequestStepTag({ }: IOURequestStepTagProps) { const [splitDraftTransaction] = useOnyx(`${ONYXKEYS.COLLECTION.SPLIT_TRANSACTION_DRAFT}${transactionID}`, {canBeMissing: true}); const [reportPolicy] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY}${report?.policyID}`, {canBeMissing: false}); - const [activePolicyID] = useOnyx(ONYXKEYS.NVP_ACTIVE_POLICY_ID); - const [activePolicy] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY}${activePolicyID}`, {selector: (policy) => (policy?.type !== CONST.POLICY.TYPE.PERSONAL ? policy : undefined)}); + const [activePolicyID] = useOnyx(ONYXKEYS.NVP_ACTIVE_POLICY_ID, {canBeMissing: true}); + const [activePolicy] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY}${activePolicyID}`, { + canBeMissing: true, + selector: (policy) => (policy?.type !== CONST.POLICY.TYPE.PERSONAL ? policy : undefined), + }); const isExpenseUnreported = isExpenseUnreportedTransactionUtils(transaction); const policy = isExpenseUnreported ? activePolicy : reportPolicy; const [policyCategories] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY_CATEGORIES}${policy?.id}`, {canBeMissing: false}); diff --git a/src/pages/iou/request/step/IOURequestStepTaxRatePage.tsx b/src/pages/iou/request/step/IOURequestStepTaxRatePage.tsx index fbbdfdf046fb..ac1d3ea13ec6 100644 --- a/src/pages/iou/request/step/IOURequestStepTaxRatePage.tsx +++ b/src/pages/iou/request/step/IOURequestStepTaxRatePage.tsx @@ -7,7 +7,7 @@ import {convertToBackendAmount} from '@libs/CurrencyUtils'; import Navigation from '@libs/Navigation/Navigation'; import type {TaxRatesOption} from '@libs/TaxOptionsListUtils'; import {calculateTaxAmount, getAmount, getCurrency, getTaxName, getTaxValue, isExpenseUnreported as isExpenseUnreportedTransactionUtils} from '@libs/TransactionUtils'; -import * as IOU from '@userActions/IOU'; +import {setDraftSplitTransaction, setMoneyRequestTaxAmount, setMoneyRequestTaxRate, updateMoneyRequestTaxRate} from '@userActions/IOU'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import type SCREENS from '@src/SCREENS'; @@ -70,7 +70,7 @@ function IOURequestStepTaxRatePage({ const taxAmount = getTaxAmount(policy, currentTransaction, taxes.code, getAmount(currentTransaction, false, true)); if (isEditingSplitBill) { - IOU.setDraftSplitTransaction(currentTransaction.transactionID, { + setDraftSplitTransaction(currentTransaction.transactionID, { taxAmount: convertToBackendAmount(taxAmount ?? 0), taxCode: taxes.code, }); @@ -80,7 +80,7 @@ function IOURequestStepTaxRatePage({ if (isEditing) { const newTaxCode = taxes.code; - IOU.updateMoneyRequestTaxRate({ + updateMoneyRequestTaxRate({ transactionID: currentTransaction?.transactionID ?? '-1', optimisticReportActionID: report?.reportID ?? '-1', taxCode: newTaxCode, @@ -98,8 +98,8 @@ function IOURequestStepTaxRatePage({ return; } const amountInSmallestCurrencyUnits = convertToBackendAmount(taxAmount); - IOU.setMoneyRequestTaxRate(currentTransaction?.transactionID, taxes?.code ?? ''); - IOU.setMoneyRequestTaxAmount(currentTransaction.transactionID, amountInSmallestCurrencyUnits); + setMoneyRequestTaxRate(currentTransaction?.transactionID, taxes?.code ?? ''); + setMoneyRequestTaxAmount(currentTransaction.transactionID, amountInSmallestCurrencyUnits); navigateBack(); }; From e4f2f256d2d845cde17b7e085517390427d40b62 Mon Sep 17 00:00:00 2001 From: Agata Kosior Date: Fri, 29 Aug 2025 10:59:22 +0200 Subject: [PATCH 10/13] fix: eslint --- src/libs/actions/IOU.ts | 4 ++-- src/pages/iou/request/step/IOURequestStepTaxRatePage.tsx | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/libs/actions/IOU.ts b/src/libs/actions/IOU.ts index 25bcc2a6a0ce..7380dad3ca46 100644 --- a/src/libs/actions/IOU.ts +++ b/src/libs/actions/IOU.ts @@ -4834,8 +4834,8 @@ function updateMoneyRequestTaxAmount( } type UpdateMoneyRequestTaxRateParams = { - transactionID: string; - optimisticReportActionID: string; + transactionID: string | undefined; + optimisticReportActionID: string | undefined; taxCode: string; taxAmount: number; policy: OnyxEntry; diff --git a/src/pages/iou/request/step/IOURequestStepTaxRatePage.tsx b/src/pages/iou/request/step/IOURequestStepTaxRatePage.tsx index ac1d3ea13ec6..4e7c6bbfd0b0 100644 --- a/src/pages/iou/request/step/IOURequestStepTaxRatePage.tsx +++ b/src/pages/iou/request/step/IOURequestStepTaxRatePage.tsx @@ -81,8 +81,8 @@ function IOURequestStepTaxRatePage({ if (isEditing) { const newTaxCode = taxes.code; updateMoneyRequestTaxRate({ - transactionID: currentTransaction?.transactionID ?? '-1', - optimisticReportActionID: report?.reportID ?? '-1', + transactionID: currentTransaction?.transactionID, + optimisticReportActionID: report?.reportID, taxCode: newTaxCode, taxAmount: convertToBackendAmount(taxAmount ?? 0), policy, From cae23db4e2633b7a22ef0d9ef82c3fe0a34f188b Mon Sep 17 00:00:00 2001 From: Agata Kosior Date: Tue, 2 Sep 2025 12:50:44 +0200 Subject: [PATCH 11/13] fix: minor fix --- src/libs/TransactionUtils/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libs/TransactionUtils/index.ts b/src/libs/TransactionUtils/index.ts index 97c811eeec06..7b1c87183ee3 100644 --- a/src/libs/TransactionUtils/index.ts +++ b/src/libs/TransactionUtils/index.ts @@ -1920,7 +1920,7 @@ function createUnreportedExpenseSections(transactions: Array Date: Tue, 2 Sep 2025 16:00:13 +0200 Subject: [PATCH 12/13] fix: add comment and fix lint --- src/components/ReportActionItem/MoneyRequestView.tsx | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/components/ReportActionItem/MoneyRequestView.tsx b/src/components/ReportActionItem/MoneyRequestView.tsx index ba350bd4dea6..239c9db2f306 100644 --- a/src/components/ReportActionItem/MoneyRequestView.tsx +++ b/src/components/ReportActionItem/MoneyRequestView.tsx @@ -167,8 +167,9 @@ function MoneyRequestView({ const [transaction] = useOnyx(`${ONYXKEYS.COLLECTION.TRANSACTION}${getNonEmptyStringOnyxID(linkedTransactionID)}`, {canBeMissing: true}); const isExpenseUnreported = isExpenseUnreportedTransactionUtils(updatedTransaction ?? transaction); - const [activePolicyID] = useOnyx(ONYXKEYS.NVP_ACTIVE_POLICY_ID); - const [activePolicy] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY}${activePolicyID}`, {selector: (policy) => (policy?.type !== CONST.POLICY.TYPE.PERSONAL ? policy : undefined)}); + const [activePolicyID] = useOnyx(ONYXKEYS.NVP_ACTIVE_POLICY_ID, {canBeMissing: true}); + const [activePolicy] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY}${activePolicyID}`, {canBeMissing: true, selector: (policy) => (policy?.type !== CONST.POLICY.TYPE.PERSONAL ? policy : undefined)}); + // If the expense is unreported the policy should be the user's default policy, otherwise it should be the policy the expense was made for const policy = isExpenseUnreported ? activePolicy : expensePolicy; const policyID = isExpenseUnreported ? activePolicy?.id : report?.policyID; From 59be151fb139d7490eb7f250fc0998ac94658e30 Mon Sep 17 00:00:00 2001 From: Agata Kosior Date: Tue, 2 Sep 2025 17:15:09 +0200 Subject: [PATCH 13/13] fix: prettier --- src/components/ReportActionItem/MoneyRequestView.tsx | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/components/ReportActionItem/MoneyRequestView.tsx b/src/components/ReportActionItem/MoneyRequestView.tsx index c4adce9357b1..d31161071164 100644 --- a/src/components/ReportActionItem/MoneyRequestView.tsx +++ b/src/components/ReportActionItem/MoneyRequestView.tsx @@ -142,7 +142,10 @@ function MoneyRequestView({ const isExpenseUnreported = isExpenseUnreportedTransactionUtils(updatedTransaction ?? transaction); const [activePolicyID] = useOnyx(ONYXKEYS.NVP_ACTIVE_POLICY_ID, {canBeMissing: true}); - const [activePolicy] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY}${activePolicyID}`, {canBeMissing: true, selector: (policy) => (policy?.type !== CONST.POLICY.TYPE.PERSONAL ? policy : undefined)}); + const [activePolicy] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY}${activePolicyID}`, { + canBeMissing: true, + selector: (policy) => (policy?.type !== CONST.POLICY.TYPE.PERSONAL ? policy : undefined), + }); // If the expense is unreported the policy should be the user's default policy, otherwise it should be the policy the expense was made for const policy = isExpenseUnreported ? activePolicy : expensePolicy; const policyID = isExpenseUnreported ? activePolicy?.id : report?.policyID;