Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: Use new ResolveDuplicates when approver is resolving duplicates #48522

Merged
merged 25 commits into from
Sep 25, 2024
Merged
Show file tree
Hide file tree
Changes from 12 commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
36b7e06
fix: Use new ResolveDuplicates when approver is resolving duplicates
nkdengineer Sep 4, 2024
2d1d4ca
add new api params
nkdengineer Sep 4, 2024
6325f73
Merge branch 'main' into fix/48416
nkdengineer Sep 9, 2024
8086b11
complete parameter for API
nkdengineer Sep 9, 2024
06bdd10
Merge branch 'main' into fix/48416
nkdengineer Sep 11, 2024
107be8e
fix the order issue
nkdengineer Sep 11, 2024
c5023dc
fix lint
nkdengineer Sep 11, 2024
e881a3b
Merge branch 'main' into fix/48416
nkdengineer Sep 11, 2024
b549c50
merge main
nkdengineer Sep 12, 2024
96d0da4
create a util to get iou action
nkdengineer Sep 12, 2024
754932d
rename variable
nkdengineer Sep 12, 2024
b7a27c3
fix lint
nkdengineer Sep 12, 2024
b331032
use getIOUActionForTransactions
nkdengineer Sep 12, 2024
85cc2e9
merge main
nkdengineer Sep 12, 2024
5fcf063
remove unuse variable
nkdengineer Sep 12, 2024
f56ffab
Update src/libs/API/parameters/ResolveDuplicatesParams.ts
nkdengineer Sep 12, 2024
c076bdc
Merge branch 'main' into fix/48416
nkdengineer Sep 13, 2024
aee9154
fix lint
nkdengineer Sep 13, 2024
0ba5ac8
Merge branch 'main' into fix/48416
nkdengineer Sep 17, 2024
c776014
update param
nkdengineer Sep 17, 2024
46c75e1
Merge branch 'main' into fix/48416
nkdengineer Sep 19, 2024
e32ed93
Merge branch 'main' into fix/48416
nkdengineer Sep 24, 2024
98287b6
fix native bug
nkdengineer Sep 24, 2024
23e2313
Update src/libs/actions/IOU.ts
nkdengineer Sep 25, 2024
b3cce2d
Merge branch 'main' into fix/48416
nkdengineer Sep 25, 2024
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
21 changes: 21 additions & 0 deletions src/libs/API/parameters/TransactionResolveParams.ts
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Rename this file too.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same as below.

Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
type ResolveDuplicatesParams = {
/** The ID of the transaction that we want to keep */
transactionID: string;
/** The list of other duplicated transactions */
transactionIDList: string[];
created: string;
merchant: string;
amount: number;
currency: string;
category: string;
comment: string;
billable: boolean;
reimbursable: boolean;
tag: string;
/** The reportActionID of the dismiss violation action of the kept transaction thread report */
optimisticReportActionID: string;
/** The list ID of hold report action corresponds to transactionIDList */
reportActionIDList: string[];
};

export default ResolveDuplicatesParams;
1 change: 1 addition & 0 deletions src/libs/API/parameters/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -240,6 +240,7 @@
export type {default as PayInvoiceParams} from './PayInvoiceParams';
export type {default as MarkAsCashParams} from './MarkAsCashParams';
export type {default as TransactionMergeParams} from './TransactionMergeParams';
export type {default as ResolveDuplicatesParams} from './ResolveDuplicatesParams';

Check failure on line 243 in src/libs/API/parameters/index.ts

View workflow job for this annotation

GitHub Actions / typecheck

Cannot find module './ResolveDuplicatesParams' or its corresponding type declarations.
export type {default as UpdateSubscriptionTypeParams} from './UpdateSubscriptionTypeParams';
export type {default as SignUpUserParams} from './SignUpUserParams';
export type {default as UpdateSubscriptionAutoRenewParams} from './UpdateSubscriptionAutoRenewParams';
Expand Down
2 changes: 2 additions & 0 deletions src/libs/API/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -274,6 +274,7 @@ const WRITE_COMMANDS = {
PAY_INVOICE: 'PayInvoice',
MARK_AS_CASH: 'MarkAsCash',
TRANSACTION_MERGE: 'Transaction_Merge',
RESOLVE_DUPLICATES: 'ResolveDuplicates',
UPDATE_SUBSCRIPTION_TYPE: 'UpdateSubscriptionType',
SIGN_UP_USER: 'SignUpUser',
UPDATE_SUBSCRIPTION_AUTO_RENEW: 'UpdateSubscriptionAutoRenew',
Expand Down Expand Up @@ -659,6 +660,7 @@ type WriteCommandParameters = {
[WRITE_COMMANDS.PAY_INVOICE]: Parameters.PayInvoiceParams;
[WRITE_COMMANDS.MARK_AS_CASH]: Parameters.MarkAsCashParams;
[WRITE_COMMANDS.TRANSACTION_MERGE]: Parameters.TransactionMergeParams;
[WRITE_COMMANDS.RESOLVE_DUPLICATES]: Parameters.ResolveDuplicatesParams;
[WRITE_COMMANDS.UPDATE_SUBSCRIPTION_TYPE]: Parameters.UpdateSubscriptionTypeParams;
[WRITE_COMMANDS.SIGN_UP_USER]: Parameters.SignUpUserParams;
[WRITE_COMMANDS.UPDATE_SUBSCRIPTION_AUTO_RENEW]: Parameters.UpdateSubscriptionAutoRenewParams;
Expand Down
160 changes: 148 additions & 12 deletions src/libs/actions/IOU.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
PayMoneyRequestParams,
ReplaceReceiptParams,
RequestMoneyParams,
ResolveDuplicatesParams,
SendInvoiceParams,
SendMoneyParams,
SetNameValuePairParams,
Expand Down Expand Up @@ -7954,6 +7955,21 @@
return workspaceSender?.policyID ?? report?.policyID ?? '-1';
}

function getIOUActionForTransactions(transactionIDList: string[], iouReportID: string): ReportAction<typeof CONST.REPORT.ACTIONS.TYPE.IOU>[] {

Check failure on line 7958 in src/libs/actions/IOU.ts

View workflow job for this annotation

GitHub Actions / Run ESLint

Array type using 'T[]' is forbidden for non-simple types. Use 'Array<T>' instead
return Object.values(allReportActions?.[`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${iouReportID}`] ?? {})?.filter(
(reportAction): reportAction is ReportAction<typeof CONST.REPORT.ACTIONS.TYPE.IOU> => {
if (!ReportActionsUtils.isMoneyRequestAction(reportAction)) {
return false;
}
const message = ReportActionsUtils.getOriginalMessage(reportAction);
if (!message?.IOUTransactionID) {
return false;
}
return transactionIDList.includes(message.IOUTransactionID);
},
);
}

/** Merge several transactions into one by updating the fields of the one we want to keep and deleting the rest */
function mergeDuplicates(params: TransactionMergeParams) {
const originalSelectedTransaction = allTransactions[`${ONYXKEYS.COLLECTION.TRANSACTION}${params.transactionID}`];
Expand Down Expand Up @@ -8038,18 +8054,7 @@
},
};

const iouActionsToDelete = Object.values(allReportActions?.[`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${params.reportID}`] ?? {})?.filter(
(reportAction): reportAction is ReportAction<typeof CONST.REPORT.ACTIONS.TYPE.IOU> => {
if (!ReportActionsUtils.isMoneyRequestAction(reportAction)) {
return false;
}
const message = ReportActionsUtils.getOriginalMessage(reportAction);
if (!message?.IOUTransactionID) {
return false;
}
return params.transactionIDList.includes(message.IOUTransactionID);
},
);
const iouActionsToDelete = getIOUActionForTransactions(params.transactionIDList, params.reportID);

const deletedTime = DateUtils.getDBTime();
const expenseReportActionsOptimisticData: OnyxUpdate = {
Expand Down Expand Up @@ -8110,6 +8115,136 @@
API.write(WRITE_COMMANDS.TRANSACTION_MERGE, params, {optimisticData, failureData});
}

function resolveDuplicates(params: TransactionMergeParams) {
nkdengineer marked this conversation as resolved.
Show resolved Hide resolved
const originalSelectedTransaction = allTransactions[`${ONYXKEYS.COLLECTION.TRANSACTION}${params.transactionID}`];

const optimisticTransactionData: OnyxUpdate = {
onyxMethod: Onyx.METHOD.MERGE,
key: `${ONYXKEYS.COLLECTION.TRANSACTION}${params.transactionID}`,
value: {
...originalSelectedTransaction,
billable: params.billable,
comment: {
comment: params.comment,
},
category: params.category,
created: params.created,
currency: params.currency,
modifiedMerchant: params.merchant,
reimbursable: params.reimbursable,
tag: params.tag,
},
};

const failureTransactionData: OnyxUpdate = {
onyxMethod: Onyx.METHOD.MERGE,
key: `${ONYXKEYS.COLLECTION.TRANSACTION}${params.transactionID}`,
// eslint-disable-next-line @typescript-eslint/non-nullable-type-assertion-style
value: originalSelectedTransaction as OnyxTypes.Transaction,
};

const optimisticTransactionViolations: OnyxUpdate[] = [...params.transactionIDList, params.transactionID].map((id) => {
const violations = allTransactionViolations[`${ONYXKEYS.COLLECTION.TRANSACTION_VIOLATIONS}${id}`] ?? [];
const newViolation = {name: CONST.VIOLATIONS.HOLD, type: CONST.VIOLATION_TYPES.VIOLATION};
const updatedViolations = id === params.transactionID ? violations : [...violations, newViolation];
return {
onyxMethod: Onyx.METHOD.MERGE,
key: `${ONYXKEYS.COLLECTION.TRANSACTION_VIOLATIONS}${id}`,
value: updatedViolations.filter((violation) => violation.name !== CONST.VIOLATIONS.DUPLICATED_TRANSACTION),
};
});

const failureTransactionViolations: OnyxUpdate[] = [...params.transactionIDList, params.transactionID].map((id) => {
const violations = allTransactionViolations[`${ONYXKEYS.COLLECTION.TRANSACTION_VIOLATIONS}${id}`] ?? [];
return {
onyxMethod: Onyx.METHOD.MERGE,
key: `${ONYXKEYS.COLLECTION.TRANSACTION_VIOLATIONS}${id}`,
value: violations,
};
});

const iouActionList = getIOUActionForTransactions(params.transactionIDList, params.reportID);
const transactionThreadReportIDList = iouActionList.map((action) => action?.childReportID);
const orderedTransactionIDList = iouActionList.map((action) => {
const message = ReportActionsUtils.getOriginalMessage(action);
return message?.IOUTransactionID ?? '';
});

const optimisticHoldActions: OnyxUpdate[] = [];
const failureHoldActions: OnyxUpdate[] = [];
const reportActionIDList: string[] = [];
transactionThreadReportIDList.forEach((transactionThreadReportID) => {
const createdReportAction = ReportUtils.buildOptimisticHoldReportAction();
reportActionIDList.push(createdReportAction.reportActionID);
optimisticHoldActions.push({
onyxMethod: Onyx.METHOD.MERGE,
key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${transactionThreadReportID}`,
value: {
[createdReportAction.reportActionID]: createdReportAction,
},
});
failureHoldActions.push({
onyxMethod: Onyx.METHOD.MERGE,
key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${transactionThreadReportID}`,
value: {
[createdReportAction.reportActionID]: {
errors: ErrorUtils.getMicroSecondOnyxErrorWithTranslationKey('iou.error.genericHoldExpenseFailureMessage'),
},
},
});
});

const transactionThreadReportID = Object.values(allReportActions?.[`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${params.reportID}`] ?? {})?.find(
(reportAction): reportAction is ReportAction<typeof CONST.REPORT.ACTIONS.TYPE.IOU> => {
if (!ReportActionsUtils.isMoneyRequestAction(reportAction)) {
return false;
}
const message = ReportActionsUtils.getOriginalMessage(reportAction);
if (!message?.IOUTransactionID) {
return false;
}
return params.transactionID === message.IOUTransactionID;
},
)?.childReportID;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This can also be replaced with that new function getIOUActionForTransactions

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I updated.


const optimisticReportAction = ReportUtils.buildOptimisticDismissedViolationReportAction({
reason: 'manual',
violationName: CONST.VIOLATIONS.DUPLICATED_TRANSACTION,
});

const optimisticReportActionData: OnyxUpdate = {
onyxMethod: Onyx.METHOD.MERGE,
key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${transactionThreadReportID}`,
value: {
[optimisticReportAction.reportActionID]: optimisticReportAction,
},
};

const failureReportActionData: OnyxUpdate = {
onyxMethod: Onyx.METHOD.MERGE,
key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${transactionThreadReportID}`,
value: {
[optimisticReportAction.reportActionID]: null,
},
};

const optimisticData: OnyxUpdate[] = [];
const failureData: OnyxUpdate[] = [];

optimisticData.push(optimisticTransactionData, ...optimisticTransactionViolations, ...optimisticHoldActions, optimisticReportActionData);
failureData.push(failureTransactionData, ...failureTransactionViolations, ...failureHoldActions, failureReportActionData);
const {reportID, transactionIDList, receiptID, ...otherParams} = params;

const parameters: ResolveDuplicatesParams = {
...otherParams,
reportActionIDList,
transactionIDList: orderedTransactionIDList,
optimisticReportActionID: optimisticReportAction.reportActionID,
};

API.write(WRITE_COMMANDS.RESOLVE_DUPLICATES, parameters, {optimisticData, failureData});
}

export {
adjustRemainingSplitShares,
approveMoneyRequest,
Expand Down Expand Up @@ -8180,6 +8315,7 @@
updateMoneyRequestTaxAmount,
updateMoneyRequestTaxRate,
mergeDuplicates,
resolveDuplicates,
prepareToCleanUpMoneyRequest,
};
export type {GPSPoint as GpsPoint, IOURequestType};
21 changes: 20 additions & 1 deletion src/pages/TransactionDuplicate/Confirmation.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import ScreenWrapper from '@components/ScreenWrapper';
import ScrollView from '@components/ScrollView';
import {ShowContextMenuContext} from '@components/ShowContextMenuContext';
import Text from '@components/Text';
import useCurrentUserPersonalDetails from '@hooks/useCurrentUserPersonalDetails';
import useLocalize from '@hooks/useLocalize';
import useThemeStyles from '@hooks/useThemeStyles';
import Navigation from '@libs/Navigation/Navigation';
Expand All @@ -33,6 +34,8 @@ import isLoadingOnyxValue from '@src/types/utils/isLoadingOnyxValue';
function Confirmation() {
const styles = useThemeStyles();
const {translate} = useLocalize();
const currentUserPersonalDetails = useCurrentUserPersonalDetails();
const [allPolicies] = useOnyx(ONYXKEYS.COLLECTION.POLICY);
const route = useRoute<RouteProp<TransactionDuplicateNavigatorParamList, typeof SCREENS.TRANSACTION_DUPLICATE.REVIEW>>();
const [reviewDuplicates, reviewDuplicatesResult] = useOnyx(ONYXKEYS.REVIEW_DUPLICATES);
const transaction = useMemo(() => TransactionUtils.buildNewTransactionAfterReviewingDuplicates(reviewDuplicates), [reviewDuplicates]);
Expand All @@ -42,12 +45,22 @@ function Confirmation() {
(action) => ReportActionsUtils.isMoneyRequestAction(action) && ReportActionsUtils.getOriginalMessage(action)?.IOUTransactionID === reviewDuplicates?.transactionID,
);

const isActionOwner = report?.ownerAccountID === currentUserPersonalDetails?.accountID;
pecanoro marked this conversation as resolved.
Show resolved Hide resolved
const isApprover = ReportUtils.isMoneyRequestReport(report) && report?.managerID !== null && currentUserPersonalDetails?.accountID === report?.managerID;
const isAdmin = ReportUtils.isPolicyAdmin(report?.policyID ?? '-1', allPolicies);

const transactionsMergeParams = useMemo(() => TransactionUtils.buildTransactionsMergeParams(reviewDuplicates, transaction), [reviewDuplicates, transaction]);

const mergeDuplicates = useCallback(() => {
IOU.mergeDuplicates(transactionsMergeParams);
Navigation.navigate(ROUTES.REPORT_WITH_ID.getRoute(reportAction?.childReportID ?? '-1'));
}, [reportAction?.childReportID, transactionsMergeParams]);

const resolveDuplicates = useCallback(() => {
IOU.resolveDuplicates(transactionsMergeParams);
Navigation.navigate(ROUTES.REPORT_WITH_ID.getRoute(reportAction?.childReportID ?? '-1'));
}, [transactionsMergeParams, reportAction?.childReportID]);

const contextValue = useMemo(
() => ({
transactionThreadReport: report,
Expand Down Expand Up @@ -109,7 +122,13 @@ function Confirmation() {
<Button
text={translate('common.confirm')}
success
onPress={mergeDuplicates}
onPress={() => {
if ((isAdmin || isApprover) && !isActionOwner) {
pecanoro marked this conversation as resolved.
Show resolved Hide resolved
resolveDuplicates();
return;
}
mergeDuplicates();
}}
large
/>
</FixedFooter>
Expand Down
Loading