Skip to content

Commit 60f3604

Browse files
authored
Merge pull request Expensify#80079 from nkdengineer/fix/78927
feat: Add Billable and Tax subtotals to the report view
2 parents dedd11d + dc3d15b commit 60f3604

16 files changed

Lines changed: 285 additions & 85 deletions

File tree

src/components/MoneyRequestReportView/MoneyRequestReportTransactionList.tsx

Lines changed: 43 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ import {groupTransactionsByCategory, groupTransactionsByTag} from '@libs/ReportL
3838
import {
3939
canAddTransaction,
4040
getAddExpenseDropdownOptions,
41+
getBillableAndTaxTotal,
4142
getMoneyRequestSpendBreakdown,
4243
getReportOfflinePendingActionAndErrors,
4344
isCurrentUserSubmitter,
@@ -178,9 +179,13 @@ function MoneyRequestReportTransactionList({
178179
const {reportPendingAction} = getReportOfflinePendingActionAndErrors(report);
179180

180181
const {totalDisplaySpend, nonReimbursableSpend, reimbursableSpend} = getMoneyRequestSpendBreakdown(report);
182+
const {billableTotal, taxTotal} = getBillableAndTaxTotal(report, transactions);
181183
const formattedOutOfPocketAmount = convertToDisplayString(reimbursableSpend, report?.currency);
182184
const formattedCompanySpendAmount = convertToDisplayString(nonReimbursableSpend, report?.currency);
183-
const shouldShowBreakdown = useMemo(() => shouldShowExpenseBreakdown(transactions), [transactions]);
185+
const formattedBillableAmount = convertToDisplayString(billableTotal, report?.currency);
186+
const formattedTaxAmount = convertToDisplayString(taxTotal, report?.currency);
187+
const shouldShowExpenseReportBreakDown = shouldShowExpenseBreakdown(transactions);
188+
const shouldShowBreakdown = shouldShowExpenseReportBreakDown || !!billableTotal || !!taxTotal;
184189
const transactionsWithoutPendingDelete = useMemo(() => transactions.filter((t) => !isTransactionPendingDelete(t)), [transactions]);
185190
const currentUserDetails = useCurrentUserPersonalDetails();
186191
const isReportArchived = useReportIsArchived(report?.reportID);
@@ -623,34 +628,44 @@ function MoneyRequestReportTransactionList({
623628
{shouldShowBreakdown && (
624629
<View style={[styles.dFlex, styles.alignItemsEnd, styles.gap2, styles.mb2, styles.flex1]}>
625630
{[
626-
{text: 'cardTransactions.outOfPocket', value: formattedOutOfPocketAmount},
627-
{text: 'cardTransactions.companySpend', value: formattedCompanySpendAmount},
628-
].map(({text, value}) => (
629-
<View
630-
key={text}
631-
style={[
632-
styles.dFlex,
633-
styles.flexRow,
634-
styles.alignItemsCenter,
635-
styles.pr3,
636-
styles.mw100,
637-
shouldUseNarrowLayout && [styles.justifyContentBetween, styles.w100],
638-
]}
639-
>
640-
<Text
641-
style={[styles.textLabelSupporting, styles.mr3]}
642-
numberOfLines={1}
631+
{text: 'cardTransactions.outOfPocket', value: formattedOutOfPocketAmount, shouldShow: shouldShowExpenseReportBreakDown},
632+
{text: 'cardTransactions.companySpend', value: formattedCompanySpendAmount, shouldShow: shouldShowExpenseReportBreakDown},
633+
{text: 'common.billable', value: formattedBillableAmount, shouldShow: !!billableTotal},
634+
{text: 'common.tax', value: formattedTaxAmount, shouldShow: !!taxTotal},
635+
]
636+
.filter(({shouldShow}) => shouldShow)
637+
.map(({text, value}) => (
638+
<View
639+
key={text}
640+
style={[
641+
styles.dFlex,
642+
styles.flexRow,
643+
styles.alignItemsCenter,
644+
styles.pr3,
645+
styles.mw100,
646+
shouldUseNarrowLayout && [styles.justifyContentBetween, styles.w100],
647+
]}
643648
>
644-
{translate(text as TranslationPaths)}
645-
</Text>
646-
<Text
647-
numberOfLines={1}
648-
style={[styles.textLabelSupporting, styles.textNormal, shouldUseNarrowLayout ? styles.mnw64p : styles.mnw100p, styles.textAlignRight]}
649-
>
650-
{value}
651-
</Text>
652-
</View>
653-
))}
649+
<Text
650+
style={[styles.textLabelSupporting, styles.mr3, hasPendingAction && styles.opacitySemiTransparent]}
651+
numberOfLines={1}
652+
>
653+
{translate(text as TranslationPaths)}
654+
</Text>
655+
<Text
656+
numberOfLines={1}
657+
style={[
658+
styles.textLabelSupporting,
659+
styles.textNormal,
660+
shouldUseNarrowLayout ? styles.mnw64p : styles.mnw100p,
661+
styles.textAlignRight,
662+
hasPendingAction && styles.opacitySemiTransparent,
663+
]}
664+
>
665+
{value}
666+
</Text>
667+
</View>
668+
))}
654669
</View>
655670
)}
656671

src/components/ReportActionItem/MoneyReportView.tsx

Lines changed: 40 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -14,13 +14,15 @@ import UnreadActionIndicator from '@components/UnreadActionIndicator';
1414
import useLocalize from '@hooks/useLocalize';
1515
import useNetwork from '@hooks/useNetwork';
1616
import useOnyx from '@hooks/useOnyx';
17+
import useReportTransactions from '@hooks/useReportTransactions';
1718
import useStyleUtils from '@hooks/useStyleUtils';
1819
import useTheme from '@hooks/useTheme';
1920
import useThemeStyles from '@hooks/useThemeStyles';
2021
import {convertToDisplayString} from '@libs/CurrencyUtils';
2122
import {resolveReportFieldValue} from '@libs/Formula';
2223
import Navigation from '@libs/Navigation/Navigation';
2324
import {
25+
getBillableAndTaxTotal,
2426
getFieldViolation,
2527
getFieldViolationTranslation,
2628
getMoneyRequestSpendBreakdown,
@@ -36,9 +38,11 @@ import {
3638
isSettled as isSettledReportUtils,
3739
shouldHideSingleReportField,
3840
} from '@libs/ReportUtils';
41+
import {getTransactionPendingAction} from '@libs/TransactionUtils';
3942
import AnimatedEmptyStateBackground from '@pages/inbox/report/AnimatedEmptyStateBackground';
4043
import variables from '@styles/variables';
4144
import CONST from '@src/CONST';
45+
import type {TranslationPaths} from '@src/languages/types';
4246
import {clearReportFieldKeyErrors} from '@src/libs/actions/Report';
4347
import ONYXKEYS from '@src/ONYXKEYS';
4448
import ROUTES from '@src/ROUTES';
@@ -74,11 +78,15 @@ function MoneyReportView({report, policy, isCombinedReport = false, shouldShowTo
7478
const isTotalUpdated = hasUpdatedTotal(report, policy);
7579

7680
const {totalDisplaySpend, nonReimbursableSpend, reimbursableSpend} = getMoneyRequestSpendBreakdown(report);
81+
const transactions = useReportTransactions(report?.reportID);
82+
const {billableTotal, taxTotal} = getBillableAndTaxTotal(report, transactions);
7783

78-
const shouldShowBreakdown = nonReimbursableSpend && reimbursableSpend && shouldShowTotal;
84+
const shouldShowBreakdown = (nonReimbursableSpend && reimbursableSpend) || !!billableTotal || !!taxTotal;
7985
const formattedTotalAmount = convertToDisplayString(totalDisplaySpend, report?.currency);
8086
const formattedOutOfPocketAmount = convertToDisplayString(reimbursableSpend, report?.currency);
8187
const formattedCompanySpendAmount = convertToDisplayString(nonReimbursableSpend, report?.currency);
88+
const formattedBillableAmount = convertToDisplayString(billableTotal, report?.currency);
89+
const formattedTaxAmount = convertToDisplayString(taxTotal, report?.currency);
8290
const isPartiallyPaid = !!report?.pendingFields?.partial;
8391

8492
const subAmountTextStyles: StyleProp<TextStyle> = [
@@ -112,6 +120,8 @@ function MoneyReportView({report, policy, isCombinedReport = false, shouldShowTo
112120
(!isCombinedReport || !isOnlyTitleFieldEnabled) &&
113121
!sortedPolicyReportFields.every(shouldHideSingleReportField);
114122

123+
const hasPendingAction = transactions.some(getTransactionPendingAction);
124+
115125
const renderThreadDivider = useMemo(
116126
() =>
117127
shouldHideThreadDividerLine ? (
@@ -218,42 +228,36 @@ function MoneyReportView({report, policy, isCombinedReport = false, shouldShowTo
218228

219229
{!!shouldShowBreakdown && (
220230
<>
221-
<View style={[styles.flexRow, styles.pointerEventsNone, styles.containerWithSpaceBetween, styles.ph5, styles.pv1]}>
222-
<View style={[styles.flex1, styles.justifyContentCenter]}>
223-
<Text
224-
style={[styles.textLabelSupporting]}
225-
numberOfLines={1}
226-
>
227-
{translate('cardTransactions.outOfPocket')}
228-
</Text>
229-
</View>
230-
<View style={[styles.flexRow, styles.justifyContentCenter]}>
231-
<Text
232-
numberOfLines={1}
233-
style={subAmountTextStyles}
231+
{[
232+
{label: 'cardTransactions.outOfPocket', value: formattedOutOfPocketAmount, show: !!nonReimbursableSpend && !!reimbursableSpend},
233+
{label: 'cardTransactions.companySpend', value: formattedCompanySpendAmount, show: !!nonReimbursableSpend && !!reimbursableSpend},
234+
{label: 'common.billable', value: formattedBillableAmount, show: !!billableTotal},
235+
{label: 'common.tax', value: formattedTaxAmount, show: !!taxTotal},
236+
]
237+
.filter(({show}) => show)
238+
.map(({label, value}) => (
239+
<View
240+
key={label}
241+
style={[styles.flexRow, styles.pointerEventsNone, styles.containerWithSpaceBetween, styles.ph5, styles.pv1]}
234242
>
235-
{formattedOutOfPocketAmount}
236-
</Text>
237-
</View>
238-
</View>
239-
<View style={[styles.flexRow, styles.pointerEventsNone, styles.containerWithSpaceBetween, styles.ph5, styles.pv1]}>
240-
<View style={[styles.flex1, styles.justifyContentCenter]}>
241-
<Text
242-
style={[styles.textLabelSupporting]}
243-
numberOfLines={1}
244-
>
245-
{translate('cardTransactions.companySpend')}
246-
</Text>
247-
</View>
248-
<View style={[styles.flexRow, styles.justifyContentCenter]}>
249-
<Text
250-
numberOfLines={1}
251-
style={subAmountTextStyles}
252-
>
253-
{formattedCompanySpendAmount}
254-
</Text>
255-
</View>
256-
</View>
243+
<View style={[styles.flex1, styles.justifyContentCenter]}>
244+
<Text
245+
style={[styles.textLabelSupporting, hasPendingAction && styles.opacitySemiTransparent]}
246+
numberOfLines={1}
247+
>
248+
{translate(label as TranslationPaths)}
249+
</Text>
250+
</View>
251+
<View style={[styles.flexRow, styles.justifyContentCenter]}>
252+
<Text
253+
numberOfLines={1}
254+
style={[subAmountTextStyles, hasPendingAction && styles.opacitySemiTransparent]}
255+
>
256+
{value}
257+
</Text>
258+
</View>
259+
</View>
260+
))}
257261
</>
258262
)}
259263
</>

src/languages/de.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7547,8 +7547,8 @@ Fordern Sie Spesendetails wie Belege und Beschreibungen an, legen Sie Limits und
75477547
},
75487548
cardTransactions: {
75497549
notActivated: 'Nicht aktiviert',
7550-
outOfPocket: 'Auslagen-Spend',
7551-
companySpend: 'Unternehmensausgaben',
7550+
outOfPocket: 'Erstattungsfähig',
7551+
companySpend: 'Nicht erstattungsfähig',
75527552
},
75537553
distance: {
75547554
addStop: 'Stopp hinzufügen',

src/languages/en.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7485,8 +7485,8 @@ const translations = {
74857485
},
74867486
cardTransactions: {
74877487
notActivated: 'Not activated',
7488-
outOfPocket: 'Out-of-pocket spend',
7489-
companySpend: 'Company spend',
7488+
outOfPocket: 'Reimbursable',
7489+
companySpend: 'Non-reimbursable',
74907490
},
74917491
distance: {
74927492
addStop: 'Add stop',

src/languages/es.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7707,8 +7707,8 @@ ${amount} para ${merchant} - ${date}`,
77077707
},
77087708
cardTransactions: {
77097709
notActivated: 'No activado',
7710-
outOfPocket: 'Gastos por cuenta propia',
7711-
companySpend: 'Gastos de empresa',
7710+
outOfPocket: 'Reembolsable',
7711+
companySpend: 'No reembolsable',
77127712
},
77137713
distance: {
77147714
addStop: 'Añadir parada',

src/languages/fr.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7560,8 +7560,8 @@ Rendez obligatoires des informations de dépense comme les reçus et les descrip
75607560
},
75617561
cardTransactions: {
75627562
notActivated: 'Non activé',
7563-
outOfPocket: 'Dépenses personnelles',
7564-
companySpend: 'Dépenses de l’entreprise',
7563+
outOfPocket: 'Remboursable',
7564+
companySpend: 'Non remboursable',
75657565
},
75667566
distance: {
75677567
addStop: 'Ajouter un arrêt',

src/languages/it.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7527,8 +7527,8 @@ Richiedi dettagli sulle spese come ricevute e descrizioni, imposta limiti e valo
75277527
},
75287528
cardTransactions: {
75297529
notActivated: 'Non attivato',
7530-
outOfPocket: 'Spesa personale',
7531-
companySpend: 'Spese aziendali',
7530+
outOfPocket: 'Rimborsabile',
7531+
companySpend: 'Non rimborsabile',
75327532
},
75337533
distance: {
75347534
addStop: 'Aggiungi fermata',

src/languages/ja.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7466,8 +7466,8 @@ ${reportName}
74667466
},
74677467
cardTransactions: {
74687468
notActivated: '未有効化',
7469-
outOfPocket: '立替経費支出',
7470-
companySpend: '会社の支出',
7469+
outOfPocket: '返金可能',
7470+
companySpend: '返金不可',
74717471
},
74727472
distance: {
74737473
addStop: '経由地を追加',

src/languages/nl.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7515,8 +7515,8 @@ Vereis onkostendetails zoals bonnen en beschrijvingen, stel limieten en standaar
75157515
},
75167516
cardTransactions: {
75177517
notActivated: 'Niet geactiveerd',
7518-
outOfPocket: 'Uitgaven uit eigen zak',
7519-
companySpend: 'Uitgaven van het bedrijf',
7518+
outOfPocket: 'Vergoedbaar',
7519+
companySpend: 'Niet vergoedbaar',
75207520
},
75217521
distance: {
75227522
addStop: 'Stop toevoegen',

src/languages/pl.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7496,8 +7496,8 @@ Wymagaj szczegółów wydatków, takich jak paragony i opisy, ustawiaj limity i
74967496
},
74977497
cardTransactions: {
74987498
notActivated: 'Nieaktywne',
7499-
outOfPocket: 'Wydatki z własnej kieszeni',
7500-
companySpend: 'Wydatki firmowe',
7499+
outOfPocket: 'Zwrotne',
7500+
companySpend: 'Niezgodne z refundacją',
75017501
},
75027502
distance: {
75037503
addStop: 'Dodaj przystanek',

0 commit comments

Comments
 (0)