Skip to content
Merged
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
24 changes: 18 additions & 6 deletions src/libs/ReportUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3473,7 +3473,7 @@ function getMoneyRequestSpendBreakdown(report: OnyxInputOrEntry<Report>, searchR
if (nonReimbursableSpend + totalSpend !== 0) {
// There is a possibility that if the Expense report has a negative total.
// This is because there are instances where you can get a credit back on your card,
// or you enter a negative expense to offset future expenses
// or you enter a negative expense to "offset" future expenses
nonReimbursableSpend = isExpenseReport(moneyRequestReport) ? nonReimbursableSpend * -1 : Math.abs(nonReimbursableSpend);
totalSpend = isExpenseReport(moneyRequestReport) ? totalSpend * -1 : Math.abs(totalSpend);

Expand Down Expand Up @@ -5652,7 +5652,7 @@ function buildOptimisticInvoiceReport(
ownerAccountID: currentUserAccountID,
managerID: receiverAccountID,
currency,
// We dont translate reportName because the server response is always in English
// We don't translate reportName because the server response is always in English
reportName: `${receiverName} owes ${formattedTotal}`,
stateNum: CONST.REPORT.STATE_NUM.SUBMITTED,
statusNum: CONST.REPORT.STATUS_NUM.OPEN,
Expand Down Expand Up @@ -8328,6 +8328,9 @@ function isGroupChatAdmin(report: OnyxEntry<Report>, accountID: number) {
* as a participant of the report.
*/
function getMoneyRequestOptions(report: OnyxEntry<Report>, policy: OnyxEntry<Policy>, reportParticipants: number[], filterDeprecatedTypes = false): IOUType[] {
const teacherUnitePolicyID = environment === CONST.ENVIRONMENT.PRODUCTION ? CONST.TEACHERS_UNITE.PROD_POLICY_ID : CONST.TEACHERS_UNITE.TEST_POLICY_ID;
const isTeachersUniteReport = report?.policyID === teacherUnitePolicyID;

// This will get removed as part of https://github.com/Expensify/App/issues/59961
// eslint-disable-next-line deprecation/deprecation
const reportNameValuePairs = getReportNameValuePairs(report?.reportID);
Expand Down Expand Up @@ -8367,9 +8370,12 @@ function getMoneyRequestOptions(report: OnyxEntry<Report>, policy: OnyxEntry<Pol
}

if (canRequestMoney(report, policy, otherParticipants)) {
options = [...options, CONST.IOU.TYPE.SUBMIT];
if (!filterDeprecatedTypes) {
options = [...options, CONST.IOU.TYPE.REQUEST];
// For Teachers Unite policy, don't show Create Expense option
if (!isTeachersUniteReport) {
options = [...options, CONST.IOU.TYPE.SUBMIT];
if (!filterDeprecatedTypes) {
options = [...options, CONST.IOU.TYPE.REQUEST];
}
}

// If the user can request money from the workspace report, they can also track expenses
Expand All @@ -8378,15 +8384,21 @@ function getMoneyRequestOptions(report: OnyxEntry<Report>, policy: OnyxEntry<Pol
}
}

// For expense reports on Teachers Unite workspace, disable "Create report" option
if (isExpenseReport(report) && report?.policyID === teacherUnitePolicyID) {
options = options.filter((option) => option !== CONST.IOU.TYPE.SUBMIT);
}

// User created policy rooms and default rooms like #admins or #announce will always have the Split Expense option
// unless there are no other participants at all (e.g. #admins room for a policy with only 1 admin)
// DM chats will have the Split Expense option.
// Your own expense chats will have the split expense option.
// Only show Split Expense for TU policy
if (
(isChatRoom(report) && !isAnnounceRoom(report) && otherParticipants.length > 0) ||
(isDM(report) && otherParticipants.length > 0) ||
(isGroupChat(report) && otherParticipants.length > 0) ||
(isPolicyExpenseChat(report) && report?.isOwnPolicyExpenseChat)
(isPolicyExpenseChat(report) && report?.isOwnPolicyExpenseChat && isTeachersUniteReport)
) {
options = [...options, CONST.IOU.TYPE.SPLIT];
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import type {PopoverMenuItem} from '@components/PopoverMenu';
import PopoverMenu from '@components/PopoverMenu';
import PressableWithFeedback from '@components/Pressable/PressableWithFeedback';
import Tooltip from '@components/Tooltip/PopoverAnchorTooltip';
import useEnvironment from '@hooks/useEnvironment';
import useLocalize from '@hooks/useLocalize';
import usePrevious from '@hooks/usePrevious';
import useResponsiveLayout from '@hooks/useResponsiveLayout';
Expand Down Expand Up @@ -131,6 +132,7 @@ function AttachmentPickerWithMenuItems({
const {isDelegateAccessRestricted} = useDelegateUserDetails();
const [isNoDelegateAccessMenuVisible, setIsNoDelegateAccessMenuVisible] = useState(false);
const [policy] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY}${report?.policyID}`, {canBeMissing: true});
const {isProduction} = useEnvironment();

const selectOption = useCallback(
(onSelected: () => void, shouldRestrictAction: boolean) => {
Expand All @@ -143,6 +145,10 @@ function AttachmentPickerWithMenuItems({
},
[policy],
);

const teacherUnitePolicyID = isProduction ? CONST.TEACHERS_UNITE.PROD_POLICY_ID : CONST.TEACHERS_UNITE.TEST_POLICY_ID;
const isTeachersUniteReport = report?.policyID === teacherUnitePolicyID;

/**
* Returns the list of IOU Options
*/
Expand Down Expand Up @@ -285,7 +291,7 @@ function AttachmentPickerWithMenuItems({
};
const menuItems = [
...moneyRequestOptions,
...createReportOption,
...(!isTeachersUniteReport ? createReportOption : []),
...taskOption,
{
icon: Expensicons.Paperclip,
Expand Down
60 changes: 58 additions & 2 deletions tests/unit/ReportUtilsTest.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1174,13 +1174,69 @@ describe('ReportUtils', () => {
managerID: currentUserAccountID,
};
const moneyRequestOptions = temporary_getMoneyRequestOptions(report, undefined, [currentUserAccountID, ...participantsAccountIDs]);
expect(moneyRequestOptions.length).toBe(3);
expect(moneyRequestOptions.length).toBe(2);
expect(moneyRequestOptions.includes(CONST.IOU.TYPE.SUBMIT)).toBe(true);
expect(moneyRequestOptions.includes(CONST.IOU.TYPE.SPLIT)).toBe(true);
expect(moneyRequestOptions.includes(CONST.IOU.TYPE.TRACK)).toBe(true);
expect(moneyRequestOptions.indexOf(CONST.IOU.TYPE.SUBMIT)).toBe(0);
});
});

describe('Teachers Unite policy logic', () => {
const teachersUniteTestPolicyID = CONST.TEACHERS_UNITE.TEST_POLICY_ID;
const otherPolicyID = 'normal-policy-id';

it('should hide Create Expense option and show Split Expense for Teachers Unite policy', () => {
const report = {
...LHNTestUtils.getFakeReport(),
policyID: teachersUniteTestPolicyID,
chatType: CONST.REPORT.CHAT_TYPE.POLICY_EXPENSE_CHAT,
isOwnPolicyExpenseChat: true,
};

const moneyRequestOptions = temporary_getMoneyRequestOptions(report, undefined, [currentUserAccountID, participantsAccountIDs.at(0) ?? CONST.DEFAULT_NUMBER_ID]);

// Should not include SUBMIT (Create Expense)
expect(moneyRequestOptions.includes(CONST.IOU.TYPE.SUBMIT)).toBe(false);

// Should include SPLIT (Split Expense)
expect(moneyRequestOptions.includes(CONST.IOU.TYPE.SPLIT)).toBe(true);
});

it('should show Create Expense option and hide Split Expense for non-Teachers Unite policy', () => {
const report = {
...LHNTestUtils.getFakeReport(),
policyID: otherPolicyID,
chatType: CONST.REPORT.CHAT_TYPE.POLICY_EXPENSE_CHAT,
isOwnPolicyExpenseChat: true,
};

const moneyRequestOptions = temporary_getMoneyRequestOptions(report, undefined, [currentUserAccountID, participantsAccountIDs.at(0) ?? CONST.DEFAULT_NUMBER_ID]);

// Should include SUBMIT (Create Expense)
expect(moneyRequestOptions.includes(CONST.IOU.TYPE.SUBMIT)).toBe(true);

// Should not include SPLIT (Split Expense)
expect(moneyRequestOptions.includes(CONST.IOU.TYPE.SPLIT)).toBe(false);

// Should include other options like TRACK
expect(moneyRequestOptions.includes(CONST.IOU.TYPE.TRACK)).toBe(true);
});

it('should disable Create report option for expense chats on Teachers Unite workspace', () => {
const expenseReport = {
...LHNTestUtils.getFakeReport(),
policyID: teachersUniteTestPolicyID,
type: CONST.REPORT.TYPE.EXPENSE,
chatType: CONST.REPORT.CHAT_TYPE.POLICY_EXPENSE_CHAT,
isOwnPolicyExpenseChat: true,
};

const moneyRequestOptions = temporary_getMoneyRequestOptions(expenseReport, undefined, [currentUserAccountID, participantsAccountIDs.at(0) ?? CONST.DEFAULT_NUMBER_ID]);

// Should not include SUBMIT
expect(moneyRequestOptions.includes(CONST.IOU.TYPE.SUBMIT)).toBe(false);
});
});
});

describe('getReportIDFromLink', () => {
Expand Down