From 800788663d447e6bd9bea174cdd2700dbb435345 Mon Sep 17 00:00:00 2001 From: Carlos Martins Date: Wed, 29 Mar 2023 12:21:12 +0000 Subject: [PATCH 1/9] create canRequestMoney --- src/libs/ReportUtils.js | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/libs/ReportUtils.js b/src/libs/ReportUtils.js index 43ba811e914d..4d8407e0a682 100644 --- a/src/libs/ReportUtils.js +++ b/src/libs/ReportUtils.js @@ -1648,6 +1648,14 @@ function canLeaveRoom(report, isPolicyMember) { return true; } +/** + * @param {Object} report + * @returns {Boolean} + */ +function canRequestMoney(report) { + return (!isPolicyExpenseChat(report) || report.isOwnPolicyExpenseChat); +} + export { getReportParticipantsTitle, isReportMessageAttachment, @@ -1713,4 +1721,5 @@ export { getFullSizeAvatar, getSmallSizeAvatar, getIOUOptions, + canRequestMoney, }; From 0a3adb8bc77b022a4951465b60b135da5d345411 Mon Sep 17 00:00:00 2001 From: Carlos Martins Date: Wed, 29 Mar 2023 12:26:55 +0000 Subject: [PATCH 2/9] disable split bill in workspace chats --- src/libs/ReportUtils.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/libs/ReportUtils.js b/src/libs/ReportUtils.js index 4d8407e0a682..c74b9bf94f21 100644 --- a/src/libs/ReportUtils.js +++ b/src/libs/ReportUtils.js @@ -1604,8 +1604,9 @@ function getIOUOptions(report, reportParticipants, betas) { // User created policy rooms and default rooms like #admins or #announce will always have the Split Bill option // unless there are no participants at all (e.g. #admins room for a policy with only 1 admin) - // DM chats and workspace chats will have the Split Bill option only when there are at least 3 people in the chat. - if (isChatRoom(report) || hasMultipleParticipants) { + // DM chats will have the Split Bill option only when there are at least 3 people in the chat. + // There is no Split Bill option for Workspace chats + if (isChatRoom(report) || (hasMultipleParticipants && !isPolicyExpenseChat(this.props.report))) { return [CONST.IOU.IOU_TYPE.SPLIT]; } From c4febfd67f46838500d98d54b03ba80c8aa23037 Mon Sep 17 00:00:00 2001 From: Carlos Martins Date: Wed, 29 Mar 2023 12:29:55 +0000 Subject: [PATCH 3/9] enable request money in workspace chat --- src/libs/ReportUtils.js | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/libs/ReportUtils.js b/src/libs/ReportUtils.js index c74b9bf94f21..563e1ce8caf4 100644 --- a/src/libs/ReportUtils.js +++ b/src/libs/ReportUtils.js @@ -1587,6 +1587,14 @@ function getReportIDFromLink(url) { return reportID; } +/** + * @param {Object} report + * @returns {Boolean} + */ +function canRequestMoney(report) { + return (!isPolicyExpenseChat(report) || report.isOwnPolicyExpenseChat); +} + /** * @param {Object} report * @param {Array} reportParticipants @@ -1613,7 +1621,7 @@ function getIOUOptions(report, reportParticipants, betas) { // DM chats that only have 2 people will see the Send / Request money options. // Workspace chats should only see the Request money option, as "easy overages" is not available. return [ - CONST.IOU.IOU_TYPE.REQUEST, + ...(canRequestMoney(report) ? [CONST.IOU.IOU_TYPE.REQUEST] : []), ...(Permissions.canUseIOUSend(betas) && !isPolicyExpenseChat(report) ? [CONST.IOU.IOU_TYPE.SEND] : []), ]; } @@ -1649,14 +1657,6 @@ function canLeaveRoom(report, isPolicyMember) { return true; } -/** - * @param {Object} report - * @returns {Boolean} - */ -function canRequestMoney(report) { - return (!isPolicyExpenseChat(report) || report.isOwnPolicyExpenseChat); -} - export { getReportParticipantsTitle, isReportMessageAttachment, From 0eaf78f0bf5b4d6895408c68643db21e60209817 Mon Sep 17 00:00:00 2001 From: Carlos Martins Date: Wed, 29 Mar 2023 12:32:37 +0000 Subject: [PATCH 4/9] rename getIOUOptions to getMoneyRequest options --- src/components/ReportWelcomeText.js | 2 +- src/libs/ReportUtils.js | 4 ++-- src/pages/home/report/ReportActionCompose.js | 8 ++++---- tests/unit/ReportUtilsTest.js | 18 +++++++++--------- 4 files changed, 16 insertions(+), 16 deletions(-) diff --git a/src/components/ReportWelcomeText.js b/src/components/ReportWelcomeText.js index 560c93813819..92c0dc4113b6 100644 --- a/src/components/ReportWelcomeText.js +++ b/src/components/ReportWelcomeText.js @@ -68,7 +68,7 @@ const ReportWelcomeText = (props) => { isMultipleParticipant, ); const roomWelcomeMessage = ReportUtils.getRoomWelcomeMessage(props.report, props.policies); - const iouOptions = ReportUtils.getIOUOptions(props.report, participants, props.betas); + const iouOptions = ReportUtils.getMoneyRequestOptions(props.report, participants, props.betas); return ( <> diff --git a/src/libs/ReportUtils.js b/src/libs/ReportUtils.js index 563e1ce8caf4..40e3103f4b4b 100644 --- a/src/libs/ReportUtils.js +++ b/src/libs/ReportUtils.js @@ -1601,7 +1601,7 @@ function canRequestMoney(report) { * @param {Array} betas * @returns {Array} */ -function getIOUOptions(report, reportParticipants, betas) { +function getMoneyRequestOptions(report, reportParticipants, betas) { const participants = _.filter(reportParticipants, email => currentUserPersonalDetails.login !== email); const hasExcludedIOUEmails = lodashIntersection(reportParticipants, CONST.EXPENSIFY_EMAILS).length > 0; const hasMultipleParticipants = participants.length > 1; @@ -1721,6 +1721,6 @@ export { getParsedComment, getFullSizeAvatar, getSmallSizeAvatar, - getIOUOptions, + getMoneyRequestOptions, canRequestMoney, }; diff --git a/src/pages/home/report/ReportActionCompose.js b/src/pages/home/report/ReportActionCompose.js index 4e57dba3b159..c8352a6fa69b 100644 --- a/src/pages/home/report/ReportActionCompose.js +++ b/src/pages/home/report/ReportActionCompose.js @@ -163,7 +163,7 @@ class ReportActionCompose extends React.Component { this.isEmojiCode = this.isEmojiCode.bind(this); this.setTextInputRef = this.setTextInputRef.bind(this); this.getInputPlaceholder = this.getInputPlaceholder.bind(this); - this.getIOUOptions = this.getIOUOptions.bind(this); + this.getMoneyRequestOptions = this.getMoneyRequestOptions.bind(this); this.addAttachment = this.addAttachment.bind(this); this.insertSelectedEmoji = this.insertSelectedEmoji.bind(this); this.setExceededMaxCommentLength = this.setExceededMaxCommentLength.bind(this); @@ -332,7 +332,7 @@ class ReportActionCompose extends React.Component { * @param {Array} reportParticipants * @returns {Array} */ - getIOUOptions(reportParticipants) { + getMoneyRequestOptions(reportParticipants) { const options = { [CONST.IOU.IOU_TYPE.SPLIT]: { icon: Expensicons.Receipt, @@ -350,7 +350,7 @@ class ReportActionCompose extends React.Component { onSelected: () => Navigation.navigate(ROUTES.getIOUSendRoute(this.props.reportID)), }, }; - return _.map(ReportUtils.getIOUOptions(this.props.report, reportParticipants, this.props.betas), option => options[option]); + return _.map(ReportUtils.getMoneyRequestOptions(this.props.report, reportParticipants, this.props.betas), option => options[option]); } /** @@ -780,7 +780,7 @@ class ReportActionCompose extends React.Component { onClose={() => this.setMenuVisibility(false)} onItemSelected={() => this.setMenuVisibility(false)} anchorPosition={styles.createMenuPositionReportActionCompose} - menuItems={[...this.getIOUOptions(reportParticipants), + menuItems={[...this.getMoneyRequestOptions(reportParticipants), { icon: Expensicons.Paperclip, text: this.props.translate('reportActionCompose.addAttachment'), diff --git a/tests/unit/ReportUtilsTest.js b/tests/unit/ReportUtilsTest.js index b4383b3c0fd4..acebdea08e1a 100644 --- a/tests/unit/ReportUtilsTest.js +++ b/tests/unit/ReportUtilsTest.js @@ -308,7 +308,7 @@ describe('ReportUtils', () => { }); }); - describe('getIOUOptions', () => { + describe('getMoneyRequestOptions', () => { const participants = _.keys(participantsPersonalDetails); beforeAll(() => { @@ -324,19 +324,19 @@ describe('ReportUtils', () => { describe('return empty iou options if', () => { it('participants contains excluded iou emails', () => { const allEmpty = _.every(CONST.EXPENSIFY_EMAILS, (email) => { - const iouOptions = ReportUtils.getIOUOptions({}, [currentUserEmail, email], [CONST.BETAS.IOU]); + const iouOptions = ReportUtils.getMoneyRequestOptions({}, [currentUserEmail, email], [CONST.BETAS.IOU]); return iouOptions.length === 0; }); expect(allEmpty).toBe(true); }); it('no participants except self', () => { - const iouOptions = ReportUtils.getIOUOptions({}, [currentUserEmail], [CONST.BETAS.IOU]); + const iouOptions = ReportUtils.getMoneyRequestOptions({}, [currentUserEmail], [CONST.BETAS.IOU]); expect(iouOptions.length).toBe(0); }); it('no iou permission', () => { - const iouOptions = ReportUtils.getIOUOptions({}, [currentUserEmail, participants], []); + const iouOptions = ReportUtils.getMoneyRequestOptions({}, [currentUserEmail, participants], []); expect(iouOptions.length).toBe(0); }); }); @@ -353,14 +353,14 @@ describe('ReportUtils', () => { ...LHNTestUtils.getFakeReport(), chatType, }; - const iouOptions = ReportUtils.getIOUOptions(report, [currentUserEmail, participants[0]], [CONST.BETAS.IOU]); + const iouOptions = ReportUtils.getMoneyRequestOptions(report, [currentUserEmail, participants[0]], [CONST.BETAS.IOU]); return iouOptions.length === 1 && iouOptions.includes(CONST.IOU.IOU_TYPE.SPLIT); }); expect(onlyHaveSplitOption).toBe(true); }); it('has multiple participants exclude self', () => { - const iouOptions = ReportUtils.getIOUOptions({}, [currentUserEmail, ...participants], [CONST.BETAS.IOU]); + const iouOptions = ReportUtils.getMoneyRequestOptions({}, [currentUserEmail, ...participants], [CONST.BETAS.IOU]); expect(iouOptions.length).toBe(1); expect(iouOptions.includes(CONST.IOU.IOU_TYPE.SPLIT)).toBe(true); }); @@ -368,7 +368,7 @@ describe('ReportUtils', () => { describe('return only iou request option if', () => { it(' does not have iou send permission', () => { - const iouOptions = ReportUtils.getIOUOptions({}, [currentUserEmail, participants], [CONST.BETAS.IOU]); + const iouOptions = ReportUtils.getMoneyRequestOptions({}, [currentUserEmail, participants], [CONST.BETAS.IOU]); expect(iouOptions.length).toBe(1); expect(iouOptions.includes(CONST.IOU.IOU_TYPE.REQUEST)).toBe(true); }); @@ -378,14 +378,14 @@ describe('ReportUtils', () => { ...LHNTestUtils.getFakeReport(), chatType: CONST.REPORT.CHAT_TYPE.POLICY_EXPENSE_CHAT, }; - const iouOptions = ReportUtils.getIOUOptions(report, [currentUserEmail, participants], [CONST.BETAS.IOU, CONST.BETAS.IOU_SEND]); + const iouOptions = ReportUtils.getMoneyRequestOptions(report, [currentUserEmail, participants], [CONST.BETAS.IOU, CONST.BETAS.IOU_SEND]); expect(iouOptions.length).toBe(1); expect(iouOptions.includes(CONST.IOU.IOU_TYPE.REQUEST)).toBe(true); }); }); it('return both iou send and request money', () => { - const iouOptions = ReportUtils.getIOUOptions({}, [currentUserEmail, participants], [CONST.BETAS.IOU, CONST.BETAS.IOU_SEND]); + const iouOptions = ReportUtils.getMoneyRequestOptions({}, [currentUserEmail, participants], [CONST.BETAS.IOU, CONST.BETAS.IOU_SEND]); expect(iouOptions.length).toBe(2); expect(iouOptions.includes(CONST.IOU.IOU_TYPE.REQUEST)).toBe(true); expect(iouOptions.includes(CONST.IOU.IOU_TYPE.SEND)).toBe(true); From 52fb05efba8c412e50f6f9db9854cde15d3f614e Mon Sep 17 00:00:00 2001 From: Carlos Martins Date: Wed, 29 Mar 2023 12:34:12 +0000 Subject: [PATCH 5/9] rename iouOptions to moneyRequestOptions --- src/components/ReportWelcomeText.js | 4 +-- tests/unit/ReportUtilsTest.js | 42 ++++++++++++++--------------- 2 files changed, 23 insertions(+), 23 deletions(-) diff --git a/src/components/ReportWelcomeText.js b/src/components/ReportWelcomeText.js index 92c0dc4113b6..3c6dc7a763af 100644 --- a/src/components/ReportWelcomeText.js +++ b/src/components/ReportWelcomeText.js @@ -68,7 +68,7 @@ const ReportWelcomeText = (props) => { isMultipleParticipant, ); const roomWelcomeMessage = ReportUtils.getRoomWelcomeMessage(props.report, props.policies); - const iouOptions = ReportUtils.getMoneyRequestOptions(props.report, participants, props.betas); + const moneyRequestOptions = ReportUtils.getMoneyRequestOptions(props.report, participants, props.betas); return ( <> @@ -132,7 +132,7 @@ const ReportWelcomeText = (props) => { ))} )} - {(iouOptions.includes(CONST.IOU.IOU_TYPE.SEND) || iouOptions.includes(CONST.IOU.IOU_TYPE.REQUEST)) && ( + {(moneyRequestOptions.includes(CONST.IOU.IOU_TYPE.SEND) || moneyRequestOptions.includes(CONST.IOU.IOU_TYPE.REQUEST)) && ( {/* Need to confirm copy for the below with marketing, and then add to translations. */} {props.translate('reportActionsView.usePlusButton')} diff --git a/tests/unit/ReportUtilsTest.js b/tests/unit/ReportUtilsTest.js index acebdea08e1a..bd14c86f2d89 100644 --- a/tests/unit/ReportUtilsTest.js +++ b/tests/unit/ReportUtilsTest.js @@ -324,20 +324,20 @@ describe('ReportUtils', () => { describe('return empty iou options if', () => { it('participants contains excluded iou emails', () => { const allEmpty = _.every(CONST.EXPENSIFY_EMAILS, (email) => { - const iouOptions = ReportUtils.getMoneyRequestOptions({}, [currentUserEmail, email], [CONST.BETAS.IOU]); - return iouOptions.length === 0; + const moneyRequestOptions = ReportUtils.getMoneyRequestOptions({}, [currentUserEmail, email], [CONST.BETAS.IOU]); + return moneyRequestOptions.length === 0; }); expect(allEmpty).toBe(true); }); it('no participants except self', () => { - const iouOptions = ReportUtils.getMoneyRequestOptions({}, [currentUserEmail], [CONST.BETAS.IOU]); - expect(iouOptions.length).toBe(0); + const moneyRequestOptions = ReportUtils.getMoneyRequestOptions({}, [currentUserEmail], [CONST.BETAS.IOU]); + expect(moneyRequestOptions.length).toBe(0); }); it('no iou permission', () => { - const iouOptions = ReportUtils.getMoneyRequestOptions({}, [currentUserEmail, participants], []); - expect(iouOptions.length).toBe(0); + const moneyRequestOptions = ReportUtils.getMoneyRequestOptions({}, [currentUserEmail, participants], []); + expect(moneyRequestOptions.length).toBe(0); }); }); @@ -353,24 +353,24 @@ describe('ReportUtils', () => { ...LHNTestUtils.getFakeReport(), chatType, }; - const iouOptions = ReportUtils.getMoneyRequestOptions(report, [currentUserEmail, participants[0]], [CONST.BETAS.IOU]); - return iouOptions.length === 1 && iouOptions.includes(CONST.IOU.IOU_TYPE.SPLIT); + const moneyRequestOptions = ReportUtils.getMoneyRequestOptions(report, [currentUserEmail, participants[0]], [CONST.BETAS.IOU]); + return moneyRequestOptions.length === 1 && moneyRequestOptions.includes(CONST.IOU.IOU_TYPE.SPLIT); }); expect(onlyHaveSplitOption).toBe(true); }); it('has multiple participants exclude self', () => { - const iouOptions = ReportUtils.getMoneyRequestOptions({}, [currentUserEmail, ...participants], [CONST.BETAS.IOU]); - expect(iouOptions.length).toBe(1); - expect(iouOptions.includes(CONST.IOU.IOU_TYPE.SPLIT)).toBe(true); + const moneyRequestOptions = ReportUtils.getMoneyRequestOptions({}, [currentUserEmail, ...participants], [CONST.BETAS.IOU]); + expect(moneyRequestOptions.length).toBe(1); + expect(moneyRequestOptions.includes(CONST.IOU.IOU_TYPE.SPLIT)).toBe(true); }); }); describe('return only iou request option if', () => { it(' does not have iou send permission', () => { - const iouOptions = ReportUtils.getMoneyRequestOptions({}, [currentUserEmail, participants], [CONST.BETAS.IOU]); - expect(iouOptions.length).toBe(1); - expect(iouOptions.includes(CONST.IOU.IOU_TYPE.REQUEST)).toBe(true); + const moneyRequestOptions = ReportUtils.getMoneyRequestOptions({}, [currentUserEmail, participants], [CONST.BETAS.IOU]); + expect(moneyRequestOptions.length).toBe(1); + expect(moneyRequestOptions.includes(CONST.IOU.IOU_TYPE.REQUEST)).toBe(true); }); it('a policy expense chat', () => { @@ -378,17 +378,17 @@ describe('ReportUtils', () => { ...LHNTestUtils.getFakeReport(), chatType: CONST.REPORT.CHAT_TYPE.POLICY_EXPENSE_CHAT, }; - const iouOptions = ReportUtils.getMoneyRequestOptions(report, [currentUserEmail, participants], [CONST.BETAS.IOU, CONST.BETAS.IOU_SEND]); - expect(iouOptions.length).toBe(1); - expect(iouOptions.includes(CONST.IOU.IOU_TYPE.REQUEST)).toBe(true); + const moneyRequestOptions = ReportUtils.getMoneyRequestOptions(report, [currentUserEmail, participants], [CONST.BETAS.IOU, CONST.BETAS.IOU_SEND]); + expect(moneyRequestOptions.length).toBe(1); + expect(moneyRequestOptions.includes(CONST.IOU.IOU_TYPE.REQUEST)).toBe(true); }); }); it('return both iou send and request money', () => { - const iouOptions = ReportUtils.getMoneyRequestOptions({}, [currentUserEmail, participants], [CONST.BETAS.IOU, CONST.BETAS.IOU_SEND]); - expect(iouOptions.length).toBe(2); - expect(iouOptions.includes(CONST.IOU.IOU_TYPE.REQUEST)).toBe(true); - expect(iouOptions.includes(CONST.IOU.IOU_TYPE.SEND)).toBe(true); + const moneyRequestOptions = ReportUtils.getMoneyRequestOptions({}, [currentUserEmail, participants], [CONST.BETAS.IOU, CONST.BETAS.IOU_SEND]); + expect(moneyRequestOptions.length).toBe(2); + expect(moneyRequestOptions.includes(CONST.IOU.IOU_TYPE.REQUEST)).toBe(true); + expect(moneyRequestOptions.includes(CONST.IOU.IOU_TYPE.SEND)).toBe(true); }); }); From a6e88802ec62ad787f9f504d4542c29aa486ce6a Mon Sep 17 00:00:00 2001 From: Carlos Martins Date: Wed, 29 Mar 2023 12:41:59 +0000 Subject: [PATCH 6/9] replace this.props.report with report --- src/libs/ReportUtils.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libs/ReportUtils.js b/src/libs/ReportUtils.js index 40e3103f4b4b..8ecb847f1ab2 100644 --- a/src/libs/ReportUtils.js +++ b/src/libs/ReportUtils.js @@ -1614,7 +1614,7 @@ function getMoneyRequestOptions(report, reportParticipants, betas) { // unless there are no participants at all (e.g. #admins room for a policy with only 1 admin) // DM chats will have the Split Bill option only when there are at least 3 people in the chat. // There is no Split Bill option for Workspace chats - if (isChatRoom(report) || (hasMultipleParticipants && !isPolicyExpenseChat(this.props.report))) { + if (isChatRoom(report) || (hasMultipleParticipants && !isPolicyExpenseChat(report))) { return [CONST.IOU.IOU_TYPE.SPLIT]; } From 1b123a799cd677e12c4785b2f0f0acb695d943c4 Mon Sep 17 00:00:00 2001 From: Carlos Martins Date: Wed, 29 Mar 2023 12:48:31 +0000 Subject: [PATCH 7/9] fix test --- tests/unit/ReportUtilsTest.js | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/unit/ReportUtilsTest.js b/tests/unit/ReportUtilsTest.js index bd14c86f2d89..1701793edfd1 100644 --- a/tests/unit/ReportUtilsTest.js +++ b/tests/unit/ReportUtilsTest.js @@ -377,6 +377,7 @@ describe('ReportUtils', () => { const report = { ...LHNTestUtils.getFakeReport(), chatType: CONST.REPORT.CHAT_TYPE.POLICY_EXPENSE_CHAT, + isOwnPolicyExpenseChat: true, }; const moneyRequestOptions = ReportUtils.getMoneyRequestOptions(report, [currentUserEmail, participants], [CONST.BETAS.IOU, CONST.BETAS.IOU_SEND]); expect(moneyRequestOptions.length).toBe(1); From d5f475925869f5ae69bf725122451cfda0eb9fac Mon Sep 17 00:00:00 2001 From: Carlos Martins Date: Wed, 29 Mar 2023 14:05:58 +0000 Subject: [PATCH 8/9] do not filter ownExpenseChats --- src/libs/ReportUtils.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libs/ReportUtils.js b/src/libs/ReportUtils.js index 8ecb847f1ab2..b6004362ccc7 100644 --- a/src/libs/ReportUtils.js +++ b/src/libs/ReportUtils.js @@ -1606,7 +1606,7 @@ function getMoneyRequestOptions(report, reportParticipants, betas) { const hasExcludedIOUEmails = lodashIntersection(reportParticipants, CONST.EXPENSIFY_EMAILS).length > 0; const hasMultipleParticipants = participants.length > 1; - if (hasExcludedIOUEmails || participants.length === 0 || !Permissions.canUseIOU(betas)) { + if (hasExcludedIOUEmails || (participants.length === 0 && !report.isOwnPolicyExpenseChat) || !Permissions.canUseIOU(betas)) { return []; } From 154ba074818ebfe2c5e58fd9a8d48e5d64b1c581 Mon Sep 17 00:00:00 2001 From: Carlos Martins Date: Thu, 30 Mar 2023 10:17:35 +0000 Subject: [PATCH 9/9] add comment --- src/libs/ReportUtils.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/libs/ReportUtils.js b/src/libs/ReportUtils.js index b6004362ccc7..752ceddd79f8 100644 --- a/src/libs/ReportUtils.js +++ b/src/libs/ReportUtils.js @@ -1588,6 +1588,8 @@ function getReportIDFromLink(url) { } /** + * Users can request money in policy expense chats only if they are in a role of a member in the chat (in other words, if it's their policy expense chat) + * * @param {Object} report * @returns {Boolean} */