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

Send an invoice from an invoice room #41902

Merged
merged 8 commits into from
May 15, 2024
4 changes: 2 additions & 2 deletions src/components/MoneyRequestConfirmationList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -599,7 +599,7 @@ function MoneyRequestConfirmationList({
const formattedSelectedParticipants = selectedParticipants.map((participant) => ({
...participant,
isSelected: false,
isDisabled: !participant.isPolicyExpenseChat && !participant.isSelfDM && ReportUtils.isOptimisticPersonalDetail(participant.accountID ?? -1),
isDisabled: !participant.isInvoiceRoom && !participant.isPolicyExpenseChat && !participant.isSelfDM && ReportUtils.isOptimisticPersonalDetail(participant.accountID ?? -1),
}));
options.push({
title: translate('common.to'),
Expand Down Expand Up @@ -1148,7 +1148,7 @@ function MoneyRequestConfirmationList({
style={styles.moneyRequestMenuItem}
labelStyle={styles.mt2}
titleStyle={styles.flex1}
disabled={didConfirm || !canUpdateSenderWorkspace}
disabled={didConfirm}
/>
)}
{isDistanceRequest && (
Expand Down
4 changes: 4 additions & 0 deletions src/libs/OptionsListUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -694,6 +694,7 @@ function createOption(
result.isDefaultRoom = ReportUtils.isDefaultRoom(report);
result.isArchivedRoom = ReportUtils.isArchivedRoom(report);
result.isExpenseReport = ReportUtils.isExpenseReport(report);
result.isInvoiceRoom = ReportUtils.isInvoiceRoom(report);
result.isMoneyRequestReport = ReportUtils.isMoneyRequestReport(report);
result.isThread = ReportUtils.isChatThread(report);
result.isTaskReport = ReportUtils.isTaskReport(report);
Expand Down Expand Up @@ -806,6 +807,9 @@ function getReportOption(participant: Participant): ReportUtils.OptionData {
// Update text & alternateText because createOption returns workspace name only if report is owned by the user
if (option.isSelfDM) {
option.alternateText = Localize.translateLocal('reportActionsView.yourSpace');
} else if (option.isInvoiceRoom) {
option.text = ReportUtils.getReportName(report);
option.alternateText = Localize.translateLocal('workspace.common.invoices');
} else {
option.text = ReportUtils.getPolicyName(report);
option.alternateText = Localize.translateLocal('workspace.common.workspace');
Expand Down
13 changes: 11 additions & 2 deletions src/libs/ReportUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -432,6 +432,7 @@ type OptionData = {
parentReportAction?: OnyxEntry<ReportAction>;
displayNamesWithTooltips?: DisplayNameWithTooltips | null;
isDefaultRoom?: boolean;
isInvoiceRoom?: boolean;
isExpenseReport?: boolean;
isOptimisticPersonalDetail?: boolean;
selected?: boolean;
Expand Down Expand Up @@ -5506,13 +5507,21 @@ function isGroupChatAdmin(report: OnyxEntry<Report>, accountID: number) {
* - Self DMs
* - own policy expense chats
* - open and processing expense reports tied to own policy expense chat
*
* - Send invoice option should show for:
* - invoice rooms if the user is an admin of the sender workspace
* None of the options should show in chat threads or if there is some special Expensify account
* as a participant of the report.
*/
function getMoneyRequestOptions(report: OnyxEntry<Report>, policy: OnyxEntry<Policy>, reportParticipants: number[], filterDeprecatedTypes = false): IOUType[] {
// In any thread or task report, we do not allow any new expenses yet
if (isChatThread(report) || isTaskReport(report) || isInvoiceRoom(report) || isInvoiceReport(report)) {
if (isChatThread(report) || isTaskReport(report) || isInvoiceReport(report)) {
return [];
}

if (isInvoiceRoom(report)) {
if (isPolicyAdmin(report?.policyID ?? '', allPolicies)) {
return [CONST.IOU.TYPE.INVOICE];
}
return [];
}

Expand Down
29 changes: 14 additions & 15 deletions src/libs/actions/IOU.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1650,8 +1650,8 @@ function getSendInvoiceInformation(
const {amount = 0, currency = '', created = '', merchant = '', category = '', tag = '', taxCode = '', taxAmount = 0, billable, comment, participants} = transaction ?? {};
const trimmedComment = (comment?.comment ?? '').trim();
const senderWorkspaceID = participants?.find((participant) => participant?.isSender)?.policyID ?? '';
const receiverParticipant = participants?.find((participant) => participant?.accountID);
const receiverAccountID = receiverParticipant?.accountID ?? -1;
const receiverParticipant = participants?.find((participant) => participant?.accountID) ?? invoiceChatReport?.invoiceReceiver;
const receiverAccountID = receiverParticipant && 'accountID' in receiverParticipant && receiverParticipant.accountID ? receiverParticipant.accountID : -1;
let receiver = ReportUtils.getPersonalDetailsForAccountID(receiverAccountID);
let optimisticPersonalDetailListAction = {};

Expand Down Expand Up @@ -1704,11 +1704,12 @@ function getSendInvoiceInformation(
// STEP 4: Add optimistic personal details for participant
const shouldCreateOptimisticPersonalDetails = isNewChatReport && !allPersonalDetails[receiverAccountID];
if (shouldCreateOptimisticPersonalDetails) {
const receiverLogin = receiverParticipant && 'login' in receiverParticipant && receiverParticipant.login ? receiverParticipant.login : '';
receiver = {
accountID: receiverAccountID,
avatar: UserUtils.getDefaultAvatarURL(receiverAccountID),
displayName: LocalePhoneNumber.formatPhoneNumber(receiverParticipant?.login ?? ''),
login: receiverParticipant?.login,
displayName: LocalePhoneNumber.formatPhoneNumber(receiverLogin),
login: receiverLogin,
isOptimisticPersonalDetail: true,
};

Expand Down Expand Up @@ -6494,22 +6495,20 @@ function setMoneyRequestParticipantsFromReport(transactionID: string, report: On

if (ReportUtils.isPolicyExpenseChat(chatReport) || shouldAddAsReport) {
participants = [{accountID: 0, reportID: chatReport?.reportID, isPolicyExpenseChat: ReportUtils.isPolicyExpenseChat(chatReport), selected: true}];
} else if (ReportUtils.isInvoiceRoom(chatReport)) {
participants = [
{reportID: chatReport?.reportID, selected: true},
{
policyID: chatReport?.policyID,
isSender: true,
selected: false,
},
];
} else {
const chatReportOtherParticipants = Object.keys(chatReport?.participants ?? {})
.map(Number)
.filter((accountID) => accountID !== currentUserAccountID);
participants = chatReportOtherParticipants.map((accountID) => ({accountID, selected: true}));

if (ReportUtils.isInvoiceRoom(chatReport)) {
participants = [
...participants,
{
policyID: chatReport?.policyID,
isSender: true,
selected: false,
},
];
}
}

Onyx.merge(`${ONYXKEYS.COLLECTION.TRANSACTION_DRAFT}${transactionID}`, {participants, participantsAutoAssigned: true});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,7 @@ function AttachmentPickerWithMenuItems({
onSelected: () => IOU.startMoneyRequest(CONST.IOU.TYPE.TRACK, report?.reportID ?? ''),
},
[CONST.IOU.TYPE.INVOICE]: {
icon: Expensicons.Invoice,
icon: Expensicons.InvoiceGeneric,
text: translate('workspace.invoices.sendInvoice'),
onSelected: () => IOU.startMoneyRequest(CONST.IOU.TYPE.INVOICE, report?.reportID ?? ''),
},
Expand Down
1 change: 1 addition & 0 deletions src/types/onyx/IOU.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ type Participant = {
login?: string;
displayName?: string;
isPolicyExpenseChat?: boolean;
isInvoiceRoom?: boolean;
isOwnPolicyExpenseChat?: boolean;
chatType?: ValueOf<typeof CONST.REPORT.CHAT_TYPE>;
reportID?: string;
Expand Down
Loading