Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/languages/en.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9843,6 +9843,7 @@ const translations = {
keepThisOne: 'Keep this one',
confirmDetails: `Confirm the details you're keeping`,
confirmDuplicatesInfo: `The duplicates you don't keep will be held for the submitter to delete.`,
cannotMergeDuplicates: 'You can only merge expenses on reports that are open or pending first approval. You may need to retract the report, merge the expenses, then resubmit.',
hold: 'This expense was put on hold',
resolvedDuplicates: 'resolved the duplicate',
companyCardRequired: 'Company card purchases required',
Expand Down
1 change: 1 addition & 0 deletions src/languages/es.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9885,6 +9885,7 @@ El plan Controlar empieza en 9 $ por miembro activo al mes.`,
keepThisOne: 'Mantener éste',
confirmDetails: 'Confirma los detalles que conservas',
confirmDuplicatesInfo: 'Los duplicados que no conserves se mantendrán para que el remitente los elimine.',
cannotMergeDuplicates: 'Solo puedes combinar gastos en informes que estén abiertos o pendientes de la primera aprobación. Es posible que debas retirar el informe, combinar los gastos y luego volver a enviarlo.',
hold: 'Este gasto está retenido',
resolvedDuplicates: 'resolvió el duplicado',
companyCardRequired: 'Se requieren compras con la tarjeta de la empresa.',
Expand Down
15 changes: 13 additions & 2 deletions src/libs/TransactionUtils/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,8 @@ import {
isCurrentUserSubmitter,
isInvoiceReport,
isOpenExpenseReport,
isOpenReport,
isProcessingReport,
isReportIDApproved,
isSelfDM,
isSettled,
isThread,
Expand Down Expand Up @@ -2589,8 +2589,19 @@ function removeTransactionFromDuplicateTransactionViolation(
}
}

/**
* Keeps only transactions that Auth's MergeTransactions command would accept, i.e. those whose report is still
* open or awaiting first-level approval. Anything approved, closed (Submit & Close), or reimbursed is rejected
* server-side, so filtering here prevents sending a merge request that would fail.
*/
function removeSettledAndApprovedTransactions(transactions: Array<OnyxEntry<Transaction>>): Transaction[] {
return transactions.filter((transaction) => !!transaction && !isSettled(transaction?.reportID) && !isReportIDApproved(transaction?.reportID)) as Transaction[];
return transactions.filter((transaction) => {
if (!transaction) {
return false;
}
const report = getReportOrDraftReport(transaction.reportID);
return isOpenReport(report) || isProcessingReport(report);
}) as Transaction[];
}

/**
Expand Down
22 changes: 20 additions & 2 deletions src/pages/TransactionDuplicate/Confirmation.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import FullPageNotFoundView from '@components/BlockingViews/FullPageNotFoundView';
import Button from '@components/ButtonComposed';
import FixedFooter from '@components/FixedFooter';
import FormHelpMessage from '@components/FormHelpMessage';
import FullScreenLoadingIndicator from '@components/FullscreenLoadingIndicator';
import HeaderWithBackButton from '@components/HeaderWithBackButton';
import MoneyRequestView from '@components/ReportActionItem/MoneyRequestView';
Expand Down Expand Up @@ -44,7 +45,7 @@ import isLoadingOnyxValue from '@src/types/utils/isLoadingOnyxValue';
import type {OnyxEntry} from 'react-native-onyx';

import {useRoute} from '@react-navigation/native';
import React, {useCallback, useMemo, useRef} from 'react';
import React, {useCallback, useMemo, useRef, useState} from 'react';
import {View} from 'react-native';

function Confirmation() {
Expand Down Expand Up @@ -113,6 +114,7 @@ function Confirmation() {
};
}, [reviewDuplicatesTaxCode, reviewDuplicatesTaxAmount, taxRates, duplicatedTransactionTaxCode]);
const isReportOwner = iouReport?.ownerAccountID === currentUserPersonalDetails?.accountID;
const [mergeErrorMessage, setMergeErrorMessage] = useState('');
const currentUserAccountID = currentUserPersonalDetails.accountID;
const currentUserLogin = currentUserPersonalDetails?.login;
const childReportID = reportAction?.childReportID;
Expand Down Expand Up @@ -221,14 +223,30 @@ function Confirmation() {
</ShowContextMenuStateContext.Provider>
</ScrollView>
<FixedFooter style={styles.mtAuto}>
{!!mergeErrorMessage && (
<FormHelpMessage
message={mergeErrorMessage}
style={styles.mb3}
/>
)}
<Button
variant={CONST.BUTTON_VARIANT.SUCCESS}
onPress={() => {
isDismissingRef.current = true;
if (!isReportOwner) {
isDismissingRef.current = true;
handleResolveDuplicates();
return;
}
// Auth's MergeTransactions only accepts a merge when the kept expense's report is still
// editable and there is at least one duplicate to merge, so block it here and explain
// rather than failing server-side.
const isKeptReportMergeable = ReportUtils.isOpenReport(iouReport) || ReportUtils.isProcessingReport(iouReport);
if (!isKeptReportMergeable || transactionsMergeParams.transactionIDList.length === 0) {
setMergeErrorMessage(translate('violations.cannotMergeDuplicates'));
return;
}
setMergeErrorMessage('');
isDismissingRef.current = true;
handleMergeDuplicates();
}}
size={CONST.BUTTON_SIZE.LARGE}
Expand Down
Loading