Skip to content

Commit b5d7a95

Browse files
committed
fixed negative values as Total
1 parent dcf8ca5 commit b5d7a95

3 files changed

Lines changed: 30 additions & 9 deletions

File tree

src/components/TransactionItemRow/index.tsx

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ import StringUtils from '@libs/StringUtils';
3333
import {
3434
getAmount,
3535
getAttendees,
36+
getConvertedAmount,
3637
getCurrency,
3738
getDescription,
3839
getExchangeRate,
@@ -585,15 +586,20 @@ function TransactionItemRow({
585586
</View>
586587
);
587588
case CONST.SEARCH.TABLE_COLUMNS.TOTAL: {
588-
const convertedAmount = transactionItem.convertedAmount ?? 0;
589+
// getConvertedAmount flips the stored opposite-sign value to the display convention, so an expense
590+
// with a negative Amount renders Total as negative too (matching Classic).
591+
const convertedAmount = getConvertedAmount(transactionItem, isExpenseReport(transactionItem.report ?? report), false, true);
592+
// convertedAmount is expressed in the report's output currency. Prefer the report currency, then the
593+
// policy output currency. Fall back to the transaction's own currency only when neither is available
594+
// (e.g. self-DM or unreported contexts) — in that case no conversion happened so the currencies match.
589595
const convertedCurrency = report?.currency ?? policy?.outputCurrency ?? getCurrency(transactionItem);
590596
return (
591597
<View
592598
key={column}
593599
style={[StyleUtils.getReportTableColumnStyles(CONST.SEARCH.TABLE_COLUMNS.TOTAL_AMOUNT, {isAmountColumnWide})]}
594600
>
595601
<AmountCell
596-
total={Math.abs(convertedAmount)}
602+
total={convertedAmount}
597603
currency={convertedCurrency}
598604
/>
599605
</View>

src/libs/TransactionUtils/index.ts

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1318,8 +1318,11 @@ function getExchangeRate(transaction: TransactionWithOptionalSearchFields, repor
13181318
}
13191319

13201320
// currencyConversionRate: report-layout rate (fromCurrency → reportCurrency).
1321-
const conversionToCurrency = reportCurrency ?? (transaction.currency !== fromCurrency ? transaction.currency : (transaction.groupCurrency ?? fromCurrency));
1322-
if (transaction.currencyConversionRate != null && fromCurrency !== conversionToCurrency) {
1321+
// When no reportCurrency is provided (e.g. search sort), fall back to groupCurrency so we can still
1322+
// surface a meaningful rate. We intentionally do not use transaction.currency here, since it reflects
1323+
// the pre-modification currency and is almost never the correct conversion target.
1324+
const conversionToCurrency = reportCurrency ?? transaction.groupCurrency;
1325+
if (conversionToCurrency && transaction.currencyConversionRate != null && fromCurrency !== conversionToCurrency) {
13231326
const conversionRate = Number(transaction.currencyConversionRate);
13241327
if (conversionRate !== 1) {
13251328
return `${transaction.currencyConversionRate} ${fromCurrency}/${conversionToCurrency}`;

src/pages/settings/Report/ReportDetailsColumnsPage.tsx

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import {useRoute} from '@react-navigation/native';
2-
import React, {useMemo} from 'react';
2+
import React, {useCallback, useMemo} from 'react';
3+
import type {OnyxCollection} from 'react-native-onyx';
34
import ColumnsSettingsList from '@components/ColumnsSettingsList';
45
import type {SearchCustomColumnIds} from '@components/Search/types';
56
import useCurrentUserPersonalDetails from '@hooks/useCurrentUserPersonalDetails';
@@ -14,6 +15,7 @@ import type {ReportSettingsNavigatorParamList} from '@navigation/types';
1415
import CONST from '@src/CONST';
1516
import ONYXKEYS from '@src/ONYXKEYS';
1617
import type SCREENS from '@src/SCREENS';
18+
import type {Transaction} from '@src/types/onyx';
1719
import arraysEqual from '@src/utils/arraysEqual';
1820

1921
/**
@@ -36,16 +38,26 @@ function ReportDetailsColumnsPage() {
3638
const [reportDetailsColumns] = useOnyx(ONYXKEYS.NVP_REPORT_DETAILS_COLUMNS);
3739
const [report] = useOnyx(`${ONYXKEYS.COLLECTION.REPORT}${reportID}`);
3840
const [policy] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY}${report?.policyID}`);
39-
const [allTransactions] = useOnyx(ONYXKEYS.COLLECTION.TRANSACTION);
40-
const reportTransactions = Object.values(allTransactions ?? {}).filter((t): t is NonNullable<typeof t> => t != null && t.reportID === reportID);
41+
// Selector keeps re-renders scoped to this report's transactions. We intentionally return undefined
42+
// while the collection is loading so the caller can distinguish "loading" from "no transactions".
43+
const reportTransactionsSelector = useCallback(
44+
(transactions: OnyxCollection<Transaction>): Transaction[] | undefined => {
45+
if (!transactions) {
46+
return undefined;
47+
}
48+
return Object.values(transactions).filter((transaction): transaction is Transaction => !!transaction && transaction.reportID === reportID);
49+
},
50+
[reportID],
51+
);
52+
const [reportTransactions] = useOnyx(ONYXKEYS.COLLECTION.TRANSACTION, {selector: reportTransactionsSelector}, [reportTransactionsSelector]);
4153
const currentUserDetails = useCurrentUserPersonalDetails();
4254

4355
const allTypeCustomColumns = Object.values(CONST.SEARCH.REPORT_DETAILS_CUSTOM_COLUMNS) as SearchCustomColumnIds[];
4456

4557
// Wait for transactions to load before rendering. ColumnsSettingsList snapshots
4658
// currentColumns in useState on mount and does not sync prop updates, so we must
4759
// pass the final value on first render.
48-
const isLoading = !allTransactions;
60+
const isLoading = !reportTransactions;
4961

5062
// When no custom columns are saved, compute which columns getColumnsToShow would
5163
// return for this report so data-driven columns (e.g. Exchange rate, Original amount,
@@ -56,7 +68,7 @@ function ReportDetailsColumnsPage() {
5668
return savedColumns;
5769
}
5870

59-
if (!reportTransactions.length) {
71+
if (!reportTransactions?.length) {
6072
return REPORT_DETAILS_DEFAULT_COLUMNS;
6173
}
6274

0 commit comments

Comments
 (0)