From 931524f4f64bd67c46ca0abb2bc93598b79fac34 Mon Sep 17 00:00:00 2001
From: Vit Horacek <vit@expensify.com>
Date: Tue, 22 Aug 2023 17:04:34 +0100
Subject: [PATCH 1/5] Implement the edit merchant page

---
 src/libs/ReportUtils.js              |  4 ++
 src/libs/TransactionUtils.js         |  1 +
 src/libs/actions/IOU.js              |  4 +-
 src/pages/EditRequestMerchantPage.js | 61 ++++++++++++++++++++++++++++
 src/pages/EditRequestPage.js         | 19 ++++++++-
 5 files changed, 87 insertions(+), 2 deletions(-)
 create mode 100644 src/pages/EditRequestMerchantPage.js

diff --git a/src/libs/ReportUtils.js b/src/libs/ReportUtils.js
index 99dd31ab99aa..f5e225677d4c 100644
--- a/src/libs/ReportUtils.js
+++ b/src/libs/ReportUtils.js
@@ -1449,6 +1449,10 @@ function getModifiedExpenseOriginalMessage(oldTransaction, transactionChanges, i
         originalMessage.oldCreated = TransactionUtils.getCreated(oldTransaction);
         originalMessage.created = transactionChanges.created;
     }
+    if (_.has(transactionChanges, 'merchant')) {
+        originalMessage.oldMerchant = TransactionUtils.getMerchant(oldTransaction);
+        originalMessage.merchant = transactionChanges.merchant;
+    }
 
     // The amount is always a combination of the currency and the number value so when one changes we need to store both
     // to match how we handle the modified expense action in oldDot
diff --git a/src/libs/TransactionUtils.js b/src/libs/TransactionUtils.js
index f0e3dddd14f3..ceb07d78b469 100644
--- a/src/libs/TransactionUtils.js
+++ b/src/libs/TransactionUtils.js
@@ -128,6 +128,7 @@ function getUpdatedTransaction(transaction, transactionChanges, isFromExpenseRep
         ...(_.has(transactionChanges, 'created') && {created: CONST.RED_BRICK_ROAD_PENDING_ACTION.UPDATE}),
         ...(_.has(transactionChanges, 'amount') && {amount: CONST.RED_BRICK_ROAD_PENDING_ACTION.UPDATE}),
         ...(_.has(transactionChanges, 'currency') && {currency: CONST.RED_BRICK_ROAD_PENDING_ACTION.UPDATE}),
+        ...(_.has(transactionChanges, 'merchant') && {merchant: CONST.RED_BRICK_ROAD_PENDING_ACTION.UPDATE}),
     };
 
     return updatedTransaction;
diff --git a/src/libs/actions/IOU.js b/src/libs/actions/IOU.js
index 267b3eced25f..994898521048 100644
--- a/src/libs/actions/IOU.js
+++ b/src/libs/actions/IOU.js
@@ -1006,6 +1006,7 @@ function editMoneyRequest(transactionID, transactionThreadReportID, transactionC
                     amount: null,
                     created: null,
                     currency: null,
+                    merchant: null,
                 },
             },
         },
@@ -1032,7 +1033,7 @@ function editMoneyRequest(transactionID, transactionThreadReportID, transactionC
     ];
 
     // STEP 6: Call the API endpoint
-    const {created, amount, currency, comment} = ReportUtils.getTransactionDetails(updatedTransaction);
+    const {created, amount, currency, comment, merchant} = ReportUtils.getTransactionDetails(updatedTransaction);
     API.write(
         'EditMoneyRequest',
         {
@@ -1042,6 +1043,7 @@ function editMoneyRequest(transactionID, transactionThreadReportID, transactionC
             amount,
             currency,
             comment,
+            merchant,
         },
         {optimisticData, successData, failureData},
     );
diff --git a/src/pages/EditRequestMerchantPage.js b/src/pages/EditRequestMerchantPage.js
new file mode 100644
index 000000000000..104e3ae1f596
--- /dev/null
+++ b/src/pages/EditRequestMerchantPage.js
@@ -0,0 +1,61 @@
+import React, {useRef} from 'react';
+import {View} from 'react-native';
+import PropTypes from 'prop-types';
+import TextInput from '../components/TextInput';
+import ScreenWrapper from '../components/ScreenWrapper';
+import HeaderWithBackButton from '../components/HeaderWithBackButton';
+import Form from '../components/Form';
+import ONYXKEYS from '../ONYXKEYS';
+import styles from '../styles/styles';
+import Navigation from '../libs/Navigation/Navigation';
+import CONST from '../CONST';
+import useLocalize from '../hooks/useLocalize';
+
+const propTypes = {
+    /** Transaction default merchant value */
+    defaultMerchant: PropTypes.string.isRequired,
+
+    /** Callback to fire when the Save button is pressed  */
+    onSubmit: PropTypes.func.isRequired,
+};
+
+function EditRequestMerchantPage({defaultMerchant, onSubmit}) {
+    const {translate} = useLocalize();
+    const merchantInputRef = useRef(null);
+    return (
+        <ScreenWrapper
+            includeSafeAreaPaddingBottom={false}
+            shouldEnableMaxHeight
+            onEntryTransitionEnd={() => merchantInputRef.current && merchantInputRef.current.focus()}
+        >
+            <HeaderWithBackButton
+                title={translate('common.merchant')}
+                onBackButtonPress={() => Navigation.goBack()}
+            />
+            <Form
+                style={[styles.flexGrow1, styles.ph5]}
+                formID={ONYXKEYS.FORMS.MONEY_REQUEST_MERCHANT_FORM}
+                onSubmit={onSubmit}
+                submitButtonText={translate('common.save')}
+                enabledWhenOffline
+            >
+                <View style={styles.mb4}>
+                    <TextInput
+                        inputID="merchant"
+                        name="merchant"
+                        defaultValue={defaultMerchant}
+                        label={translate('moneyRequestConfirmationList.merchant')}
+                        accessibilityLabel={translate('moneyRequestConfirmationList.merchant')}
+                        accessibilityRole={CONST.ACCESSIBILITY_ROLE.TEXT}
+                        ref={(e) => (merchantInputRef.current = e)}
+                    />
+                </View>
+            </Form>
+        </ScreenWrapper>
+    );
+}
+
+EditRequestMerchantPage.propTypes = propTypes;
+EditRequestMerchantPage.displayName = 'EditRequestMerchantPage';
+
+export default EditRequestMerchantPage;
diff --git a/src/pages/EditRequestPage.js b/src/pages/EditRequestPage.js
index 8133acb0994e..83b0019315e4 100644
--- a/src/pages/EditRequestPage.js
+++ b/src/pages/EditRequestPage.js
@@ -12,6 +12,7 @@ import * as TransactionUtils from '../libs/TransactionUtils';
 import * as Policy from '../libs/actions/Policy';
 import withCurrentUserPersonalDetails, {withCurrentUserPersonalDetailsPropTypes} from '../components/withCurrentUserPersonalDetails';
 import EditRequestDescriptionPage from './EditRequestDescriptionPage';
+import EditRequestMerchantPage from './EditRequestMerchantPage';
 import EditRequestCreatedPage from './EditRequestCreatedPage';
 import EditRequestAmountPage from './EditRequestAmountPage';
 import reportPropTypes from './reportPropTypes';
@@ -67,7 +68,7 @@ const defaultProps = {
 function EditRequestPage({report, route, parentReport, policy, session}) {
     const parentReportAction = ReportActionsUtils.getParentReportAction(report);
     const transaction = TransactionUtils.getLinkedTransaction(parentReportAction);
-    const {amount: transactionAmount, currency: transactionCurrency, comment: transactionDescription} = ReportUtils.getTransactionDetails(transaction);
+    const {amount: transactionAmount, currency: transactionCurrency, comment: transactionDescription, merchant: transactionMerchant} = ReportUtils.getTransactionDetails(transaction);
 
     const defaultCurrency = lodashGet(route, 'params.currency', '') || transactionCurrency;
 
@@ -151,6 +152,22 @@ function EditRequestPage({report, route, parentReport, policy, session}) {
         );
     }
 
+    if (fieldToEdit === CONST.EDIT_REQUEST_FIELD.MERCHANT) {
+        return (
+            <EditRequestMerchantPage
+                defaultMerchant={transactionMerchant}
+                onSubmit={(transactionChanges) => {
+                    // In case the merchant hasn't been changed, do not make the API request.
+                    if (transactionChanges.merchant.trim() === transactionMerchant) {
+                        Navigation.dismissModal();
+                        return;
+                    }
+                    editMoneyRequest({merchant: transactionChanges.merchant.trim()});
+                }}
+            />
+        );
+    }
+
     return null;
 }
 

From 880ba045a6c50cc1bb1517b5a34c5a463210df5f Mon Sep 17 00:00:00 2001
From: Vit Horacek <vit@expensify.com>
Date: Tue, 22 Aug 2023 17:06:16 +0100
Subject: [PATCH 2/5] Remove disabled prop from the edit merchant row

---
 src/components/ReportActionItem/MoneyRequestView.js | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/src/components/ReportActionItem/MoneyRequestView.js b/src/components/ReportActionItem/MoneyRequestView.js
index 5d09c99d3533..b9bc405504df 100644
--- a/src/components/ReportActionItem/MoneyRequestView.js
+++ b/src/components/ReportActionItem/MoneyRequestView.js
@@ -166,8 +166,7 @@ function MoneyRequestView({report, parentReport, shouldShowHorizontalRule, polic
                 <MenuItemWithTopDescription
                     description={translate('common.merchant')}
                     title={transactionMerchant}
-                    shouldShowRightIcon={false}
-                    disabled
+                    shouldShowRightIcon={canEdit}
                 />
             </OfflineWithFeedback>
             {shouldShowHorizontalRule && <View style={styles.reportHorizontalRule} />}

From 1afa76898aec4992ce6cf651ef0c88106e79089a Mon Sep 17 00:00:00 2001
From: Vit Horacek <vit@expensify.com>
Date: Tue, 22 Aug 2023 17:11:23 +0100
Subject: [PATCH 3/5] Update tests

---
 src/CONST.js                                        |  3 +++
 src/components/ReportActionItem/MoneyRequestView.js |  3 +++
 src/libs/TransactionUtils.js                        |  4 ++--
 tests/actions/IOUTest.js                            | 12 ++++++------
 4 files changed, 14 insertions(+), 8 deletions(-)

diff --git a/src/CONST.js b/src/CONST.js
index 70fe2c3f1c18..5fbc24710eec 100755
--- a/src/CONST.js
+++ b/src/CONST.js
@@ -661,6 +661,9 @@ const CONST = {
         DARK: 'dark',
         SYSTEM: 'system',
     },
+    TRANSACTION: {
+        DEFAULT_MERCHANT: 'Request',
+    },
     JSON_CODE: {
         SUCCESS: 200,
         BAD_REQUEST: 400,
diff --git a/src/components/ReportActionItem/MoneyRequestView.js b/src/components/ReportActionItem/MoneyRequestView.js
index b9bc405504df..d31048e4a77e 100644
--- a/src/components/ReportActionItem/MoneyRequestView.js
+++ b/src/components/ReportActionItem/MoneyRequestView.js
@@ -166,7 +166,10 @@ function MoneyRequestView({report, parentReport, shouldShowHorizontalRule, polic
                 <MenuItemWithTopDescription
                     description={translate('common.merchant')}
                     title={transactionMerchant}
+                    disabled={isSettled || !canEdit}
                     shouldShowRightIcon={canEdit}
+                    titleStyle={styles.flex1}
+                    onPress={() => Navigation.navigate(ROUTES.getEditRequestRoute(report.reportID, CONST.EDIT_REQUEST_FIELD.MERCHANT))}
                 />
             </OfflineWithFeedback>
             {shouldShowHorizontalRule && <View style={styles.reportHorizontalRule} />}
diff --git a/src/libs/TransactionUtils.js b/src/libs/TransactionUtils.js
index ceb07d78b469..c348c4d77dc7 100644
--- a/src/libs/TransactionUtils.js
+++ b/src/libs/TransactionUtils.js
@@ -43,7 +43,7 @@ function buildOptimisticTransaction(
     created = '',
     source = '',
     originalTransactionID = '',
-    merchant = CONST.REPORT.TYPE.IOU,
+    merchant = CONST.TRANSACTION.DEFAULT_MERCHANT,
     receipt = {},
     filename = '',
     existingTransactionID = null,
@@ -66,7 +66,7 @@ function buildOptimisticTransaction(
         currency,
         reportID,
         comment: commentJSON,
-        merchant: merchant || CONST.REPORT.TYPE.IOU,
+        merchant: merchant || CONST.TRANSACTION.DEFAULT_MERCHANT,
         created: created || DateUtils.getDBTime(),
         pendingAction: CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD,
         receipt,
diff --git a/tests/actions/IOUTest.js b/tests/actions/IOUTest.js
index bf32c2ef8f9a..6fbbe19cec8e 100644
--- a/tests/actions/IOUTest.js
+++ b/tests/actions/IOUTest.js
@@ -293,7 +293,7 @@ describe('actions/IOU', () => {
                                     // The comment should be correct
                                     expect(transaction.comment.comment).toBe(comment);
 
-                                    expect(transaction.merchant).toBe(CONST.REPORT.TYPE.IOU);
+                                    expect(transaction.merchant).toBe(CONST.TRANSACTION.DEFAULT_MERCHANT);
 
                                     // It should be pending
                                     expect(transaction.pendingAction).toBe(CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD);
@@ -477,7 +477,7 @@ describe('actions/IOU', () => {
                                     expect(newTransaction.reportID).toBe(iouReportID);
                                     expect(newTransaction.amount).toBe(amount);
                                     expect(newTransaction.comment.comment).toBe(comment);
-                                    expect(newTransaction.merchant).toBe(CONST.REPORT.TYPE.IOU);
+                                    expect(newTransaction.merchant).toBe(CONST.TRANSACTION.DEFAULT_MERCHANT);
                                     expect(newTransaction.pendingAction).toBe(CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD);
 
                                     // The transactionID on the iou action should match the one from the transactions collection
@@ -620,7 +620,7 @@ describe('actions/IOU', () => {
                                         expect(transaction.reportID).toBe(iouReportID);
                                         expect(transaction.amount).toBe(amount);
                                         expect(transaction.comment.comment).toBe(comment);
-                                        expect(transaction.merchant).toBe(CONST.REPORT.TYPE.IOU);
+                                        expect(transaction.merchant).toBe(CONST.TRANSACTION.DEFAULT_MERCHANT);
                                         expect(transaction.pendingAction).toBe(CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD);
 
                                         // The transactionID on the iou action should match the one from the transactions collection
@@ -1079,9 +1079,9 @@ describe('actions/IOU', () => {
                                     expect(vitTransaction.comment.comment).toBe(comment);
                                     expect(groupTransaction.comment.comment).toBe(comment);
 
-                                    expect(carlosTransaction.merchant).toBe(CONST.REPORT.TYPE.IOU);
-                                    expect(julesTransaction.merchant).toBe(CONST.REPORT.TYPE.IOU);
-                                    expect(vitTransaction.merchant).toBe(CONST.REPORT.TYPE.IOU);
+                                    expect(carlosTransaction.merchant).toBe(CONST.TRANSACTION.DEFAULT_MERCHANT);
+                                    expect(julesTransaction.merchant).toBe(CONST.TRANSACTION.DEFAULT_MERCHANT);
+                                    expect(vitTransaction.merchant).toBe(CONST.TRANSACTION.DEFAULT_MERCHANT);
                                     expect(groupTransaction.merchant).toBe(
                                         `Split bill with ${RORY_EMAIL}, ${CARLOS_EMAIL}, ${JULES_EMAIL}, and ${VIT_EMAIL} [${DateUtils.getDBTime().slice(0, 10)}]`,
                                     );

From 4fd293e7f5d3e2244e0f499234cc5ea0ff448cc0 Mon Sep 17 00:00:00 2001
From: Vit Horacek <vit@expensify.com>
Date: Tue, 22 Aug 2023 17:13:19 +0100
Subject: [PATCH 4/5] Swap the created and merchant order for the modified
 expense messahe

---
 src/libs/ReportUtils.js | 10 +++++-----
 1 file changed, 5 insertions(+), 5 deletions(-)

diff --git a/src/libs/ReportUtils.js b/src/libs/ReportUtils.js
index f5e225677d4c..83b1bca9a13e 100644
--- a/src/libs/ReportUtils.js
+++ b/src/libs/ReportUtils.js
@@ -1411,11 +1411,6 @@ function getModifiedExpenseMessage(reportAction) {
         return getProperSchemaForModifiedExpenseMessage(reportActionOriginalMessage.newComment, reportActionOriginalMessage.oldComment, 'description', true);
     }
 
-    const hasModifiedMerchant = _.has(reportActionOriginalMessage, 'oldMerchant') && _.has(reportActionOriginalMessage, 'merchant');
-    if (hasModifiedMerchant) {
-        return getProperSchemaForModifiedExpenseMessage(reportActionOriginalMessage.merchant, reportActionOriginalMessage.oldMerchant, 'merchant', true);
-    }
-
     const hasModifiedCreated = _.has(reportActionOriginalMessage, 'oldCreated') && _.has(reportActionOriginalMessage, 'created');
     if (hasModifiedCreated) {
         // Take only the YYYY-MM-DD value as the original date includes timestamp
@@ -1423,6 +1418,11 @@ function getModifiedExpenseMessage(reportAction) {
         formattedOldCreated = format(formattedOldCreated, CONST.DATE.FNS_FORMAT_STRING);
         return getProperSchemaForModifiedExpenseMessage(reportActionOriginalMessage.created, formattedOldCreated, 'date', false);
     }
+
+    const hasModifiedMerchant = _.has(reportActionOriginalMessage, 'oldMerchant') && _.has(reportActionOriginalMessage, 'merchant');
+    if (hasModifiedMerchant) {
+        return getProperSchemaForModifiedExpenseMessage(reportActionOriginalMessage.merchant, reportActionOriginalMessage.oldMerchant, 'merchant', true);
+    }
 }
 
 /**

From 8d17b2c53edd0c09b4732a22a21f0357b05165fe Mon Sep 17 00:00:00 2001
From: Vit Horacek <vit@expensify.com>
Date: Tue, 22 Aug 2023 17:35:59 +0100
Subject: [PATCH 5/5] Polish

---
 package-lock.json                              | 2 +-
 src/components/MoneyRequestConfirmationList.js | 2 +-
 src/pages/EditRequestMerchantPage.js           | 4 ++--
 3 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/package-lock.json b/package-lock.json
index e0f6c8ab897b..36f7380189d8 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -107,7 +107,7 @@
         "react-native-web-linear-gradient": "^1.1.2",
         "react-native-web-lottie": "^1.4.4",
         "react-native-webview": "^11.17.2",
-        "react-native-x-maps": "1.0.9",
+        "react-native-x-maps": "^1.0.9",
         "react-pdf": "^6.2.2",
         "react-plaid-link": "3.3.2",
         "react-web-config": "^1.0.0",
diff --git a/src/components/MoneyRequestConfirmationList.js b/src/components/MoneyRequestConfirmationList.js
index ffd65cfb8f74..50ba4aba95c1 100755
--- a/src/components/MoneyRequestConfirmationList.js
+++ b/src/components/MoneyRequestConfirmationList.js
@@ -386,7 +386,7 @@ function MoneyRequestConfirmationList(props) {
                     />
                     <MenuItemWithTopDescription
                         shouldShowRightIcon={!props.isReadOnly && isTypeRequest}
-                        title={props.iouMerchant}
+                        title={props.iouMerchant || CONST.TRANSACTION.DEFAULT_MERCHANT}
                         description={translate('common.merchant')}
                         style={[styles.moneyRequestMenuItem, styles.mb2]}
                         titleStyle={styles.flex1}
diff --git a/src/pages/EditRequestMerchantPage.js b/src/pages/EditRequestMerchantPage.js
index 104e3ae1f596..c9c4cfbdbfaf 100644
--- a/src/pages/EditRequestMerchantPage.js
+++ b/src/pages/EditRequestMerchantPage.js
@@ -44,8 +44,8 @@ function EditRequestMerchantPage({defaultMerchant, onSubmit}) {
                         inputID="merchant"
                         name="merchant"
                         defaultValue={defaultMerchant}
-                        label={translate('moneyRequestConfirmationList.merchant')}
-                        accessibilityLabel={translate('moneyRequestConfirmationList.merchant')}
+                        label={translate('common.merchant')}
+                        accessibilityLabel={translate('common.merchant')}
                         accessibilityRole={CONST.ACCESSIBILITY_ROLE.TEXT}
                         ref={(e) => (merchantInputRef.current = e)}
                     />
