diff --git a/src/languages/en.ts b/src/languages/en.ts index 478abaefe5c8..c44ac6f2cedf 100755 --- a/src/languages/en.ts +++ b/src/languages/en.ts @@ -915,7 +915,11 @@ const translations = { managerApprovedAmount: ({manager, amount}: ManagerApprovedAmountParams) => `${manager} approved ${amount}`, payerSettled: ({amount}: PayerSettledParams) => `paid ${amount}`, payerSettledWithMissingBankAccount: ({amount}: PayerSettledParams) => `paid ${amount}. Add a bank account to receive your payment.`, + automaticallyApprovedAmount: ({amount}: ApprovedAmountParams) => + `automatically approved ${amount} via workspace rules`, approvedAmount: ({amount}: ApprovedAmountParams) => `approved ${amount}`, + automaticallyForwardedAmount: ({amount}: ForwardedAmountParams) => + `automatically approved ${amount} via workspace rules`, forwardedAmount: ({amount}: ForwardedAmountParams) => `approved ${amount}`, rejectedThisReport: 'rejected this report', waitingOnBankAccount: ({submitterDisplayName}: WaitingOnBankAccountParams) => `started settling up. Payment is on hold until ${submitterDisplayName} adds a bank account.`, diff --git a/src/languages/es.ts b/src/languages/es.ts index 771285c97c2e..76cb22772f88 100644 --- a/src/languages/es.ts +++ b/src/languages/es.ts @@ -909,7 +909,11 @@ const translations = { managerApprovedAmount: ({manager, amount}: ManagerApprovedAmountParams) => `${manager} aprobó ${amount}`, payerSettled: ({amount}: PayerSettledParams) => `pagó ${amount}`, payerSettledWithMissingBankAccount: ({amount}: PayerSettledParams) => `pagó ${amount}. Agrega una cuenta bancaria para recibir tu pago.`, + automaticallyApprovedAmount: ({amount}: ApprovedAmountParams) => + `aprobado automáticamente ${amount} según las reglas del espacio de trabajo`, approvedAmount: ({amount}: ApprovedAmountParams) => `aprobó ${amount}`, + automaticallyForwardedAmount: ({amount}: ForwardedAmountParams) => + `aprobado automáticamente ${amount} según las reglas del espacio de trabajo`, forwardedAmount: ({amount}: ForwardedAmountParams) => `aprobó ${amount}`, rejectedThisReport: 'rechazó este informe', waitingOnBankAccount: ({submitterDisplayName}: WaitingOnBankAccountParams) => `inició el pago, pero no se procesará hasta que ${submitterDisplayName} añada una cuenta bancaria`, diff --git a/src/libs/OptionsListUtils.ts b/src/libs/OptionsListUtils.ts index 11d8385d538b..a004974b88e4 100644 --- a/src/libs/OptionsListUtils.ts +++ b/src/libs/OptionsListUtils.ts @@ -717,10 +717,20 @@ function getLastMessageTextForReport(report: OnyxEntry, lastActorDetails } else { lastMessageTextFromReport = ReportUtils.getIOUSubmittedMessage(lastReportAction); } - } else if (lastReportAction?.actionName === CONST.REPORT.ACTIONS.TYPE.APPROVED) { - lastMessageTextFromReport = ReportUtils.getIOUApprovedMessage(lastReportAction); - } else if (lastReportAction?.actionName === CONST.REPORT.ACTIONS.TYPE.FORWARDED) { - lastMessageTextFromReport = ReportUtils.getIOUForwardedMessage(lastReportAction, report); + } else if (ReportActionUtils.isActionOfType(lastReportAction, CONST.REPORT.ACTIONS.TYPE.APPROVED)) { + const {automaticAction} = ReportActionUtils.getOriginalMessage(lastReportAction) ?? {}; + if (automaticAction) { + lastMessageTextFromReport = ReportUtils.getReportAutomaticallyApprovedMessage(lastReportAction); + } else { + lastMessageTextFromReport = ReportUtils.getIOUApprovedMessage(lastReportAction); + } + } else if (ReportActionUtils.isActionOfType(lastReportAction, CONST.REPORT.ACTIONS.TYPE.FORWARDED)) { + const {automaticAction} = ReportActionUtils.getOriginalMessage(lastReportAction) ?? {}; + if (automaticAction) { + lastMessageTextFromReport = ReportUtils.getReportAutomaticallyForwardedMessage(lastReportAction, reportID); + } else { + lastMessageTextFromReport = ReportUtils.getIOUForwardedMessage(lastReportAction, report); + } } else if (lastReportAction?.actionName === CONST.REPORT.ACTIONS.TYPE.REJECTED) { lastMessageTextFromReport = ReportUtils.getRejectedReportMessage(); } else if (ReportActionUtils.isActionableAddPaymentCard(lastReportAction)) { diff --git a/src/libs/ReportUtils.ts b/src/libs/ReportUtils.ts index 4485c597b0a4..09b05090de8b 100644 --- a/src/libs/ReportUtils.ts +++ b/src/libs/ReportUtils.ts @@ -3819,15 +3819,27 @@ function getReportName( ReportActionsUtils.isActionOfType(parentReportAction, CONST.REPORT.ACTIONS.TYPE.SUBMITTED) || ReportActionsUtils.isActionOfType(parentReportAction, CONST.REPORT.ACTIONS.TYPE.SUBMITTED_AND_CLOSED) ) { + const {harvesting} = ReportActionsUtils.getOriginalMessage(parentReportAction) ?? {}; + if (harvesting) { + return Parser.htmlToText(getReportAutomaticallySubmittedMessage(parentReportAction)); + } return getIOUSubmittedMessage(parentReportAction); } - if (parentReportAction?.actionName === CONST.REPORT.ACTIONS.TYPE.FORWARDED) { + if (ReportActionsUtils.isActionOfType(parentReportAction, CONST.REPORT.ACTIONS.TYPE.FORWARDED)) { + const {automaticAction} = ReportActionsUtils.getOriginalMessage(parentReportAction) ?? {}; + if (automaticAction) { + return Parser.htmlToText(getReportAutomaticallyForwardedMessage(parentReportAction, reportID)); + } return getIOUForwardedMessage(parentReportAction, report); } if (parentReportAction?.actionName === CONST.REPORT.ACTIONS.TYPE.REJECTED) { return getRejectedReportMessage(); } - if (parentReportAction?.actionName === CONST.REPORT.ACTIONS.TYPE.APPROVED) { + if (ReportActionsUtils.isActionOfType(parentReportAction, CONST.REPORT.ACTIONS.TYPE.APPROVED)) { + const {automaticAction} = ReportActionsUtils.getOriginalMessage(parentReportAction) ?? {}; + if (automaticAction) { + return Parser.htmlToText(getReportAutomaticallyApprovedMessage(parentReportAction)); + } return getIOUApprovedMessage(parentReportAction); } @@ -4573,7 +4585,11 @@ function getIOUSubmittedMessage(reportAction: ReportAction) { + return Localize.translateLocal('iou.automaticallyApprovedAmount', {amount: getFormattedAmount(reportAction)}); +} + +function getIOUApprovedMessage(reportAction: ReportAction) { return Localize.translateLocal('iou.approvedAmount', {amount: getFormattedAmount(reportAction)}); } @@ -4581,7 +4597,26 @@ function getIOUApprovedMessage(reportAction: ReportAction) { * We pass the reportID as older FORWARDED actions do not have the amount & currency stored in the message * so we retrieve the amount from the report instead */ -function getIOUForwardedMessage(reportAction: ReportAction, reportOrID: OnyxInputOrEntry | string) { +function getReportAutomaticallyForwardedMessage(reportAction: ReportAction, reportOrID: OnyxInputOrEntry | string) { + const expenseReport = typeof reportOrID === 'string' ? getReport(reportOrID) : reportOrID; + const originalMessage = ReportActionsUtils.getOriginalMessage(reportAction) as OriginalMessageIOU; + let formattedAmount; + + // Older FORWARDED action might not have the amount stored in the original message, we'll fallback to getting the amount from the report instead. + if (originalMessage?.amount) { + formattedAmount = getFormattedAmount(reportAction); + } else { + formattedAmount = CurrencyUtils.convertToDisplayString(getMoneyRequestSpendBreakdown(expenseReport).totalDisplaySpend, expenseReport?.currency); + } + + return Localize.translateLocal('iou.automaticallyForwardedAmount', {amount: formattedAmount}); +} + +/** + * We pass the reportID as older FORWARDED actions do not have the amount & currency stored in the message + * so we retrieve the amount from the report instead + */ +function getIOUForwardedMessage(reportAction: ReportAction, reportOrID: OnyxInputOrEntry | string) { const expenseReport = typeof reportOrID === 'string' ? getReport(reportOrID) : reportOrID; const originalMessage = ReportActionsUtils.getOriginalMessage(reportAction) as OriginalMessageIOU; let formattedAmount; @@ -7232,7 +7267,7 @@ function getIOUReportActionDisplayMessage(reportAction: OnyxEntry, const amount = TransactionUtils.getAmount(transaction, !isEmptyObject(iouReport) && isExpenseReport(iouReport)) ?? 0; const formattedAmount = CurrencyUtils.convertToDisplayString(amount, TransactionUtils.getCurrency(transaction)) ?? ''; - const isRequestSettled = isSettled(originalMessage?.IOUReportID); + const isRequestSettled = isSettled(IOUReportID); const isApproved = isReportApproved(iouReport); if (isRequestSettled) { return Localize.translateLocal('iou.payerSettled', { @@ -8172,7 +8207,9 @@ export { getGroupChatName, getIOUReportActionDisplayMessage, getIOUReportActionMessage, + getReportAutomaticallyApprovedMessage, getIOUApprovedMessage, + getReportAutomaticallyForwardedMessage, getIOUForwardedMessage, getRejectedReportMessage, getWorkspaceNameUpdatedMessage, diff --git a/src/pages/home/report/ContextMenu/ContextMenuActions.tsx b/src/pages/home/report/ContextMenu/ContextMenuActions.tsx index 7e420f548106..80f0b1de8a46 100644 --- a/src/pages/home/report/ContextMenu/ContextMenuActions.tsx +++ b/src/pages/home/report/ContextMenu/ContextMenuActions.tsx @@ -443,13 +443,31 @@ const ContextMenuActions: ContextMenuAction[] = [ ReportActionsUtils.isActionOfType(reportAction, CONST.REPORT.ACTIONS.TYPE.SUBMITTED) || ReportActionsUtils.isActionOfType(reportAction, CONST.REPORT.ACTIONS.TYPE.SUBMITTED_AND_CLOSED) ) { - const displayMessage = ReportUtils.getIOUSubmittedMessage(reportAction); + const {harvesting} = ReportActionsUtils.getOriginalMessage(reportAction) ?? {}; + let displayMessage = ''; + if (harvesting) { + displayMessage = ReportUtils.getReportAutomaticallySubmittedMessage(reportAction); + } else { + displayMessage = ReportUtils.getIOUSubmittedMessage(reportAction); + } Clipboard.setString(displayMessage); - } else if (reportAction?.actionName === CONST.REPORT.ACTIONS.TYPE.APPROVED) { - const displayMessage = ReportUtils.getIOUApprovedMessage(reportAction); + } else if (ReportActionsUtils.isActionOfType(reportAction, CONST.REPORT.ACTIONS.TYPE.APPROVED)) { + const {automaticAction} = ReportActionsUtils.getOriginalMessage(reportAction) ?? {}; + let displayMessage = ''; + if (automaticAction) { + displayMessage = ReportUtils.getReportAutomaticallyApprovedMessage(reportAction); + } else { + displayMessage = ReportUtils.getIOUApprovedMessage(reportAction); + } Clipboard.setString(displayMessage); - } else if (reportAction?.actionName === CONST.REPORT.ACTIONS.TYPE.FORWARDED) { - const displayMessage = ReportUtils.getIOUForwardedMessage(reportAction, reportID); + } else if (ReportActionsUtils.isActionOfType(reportAction, CONST.REPORT.ACTIONS.TYPE.FORWARDED)) { + const {automaticAction} = ReportActionsUtils.getOriginalMessage(reportAction) ?? {}; + let displayMessage = ''; + if (automaticAction) { + displayMessage = ReportUtils.getReportAutomaticallyForwardedMessage(reportAction, reportID); + } else { + displayMessage = ReportUtils.getIOUForwardedMessage(reportAction, reportID); + } Clipboard.setString(displayMessage); } else if (reportAction?.actionName === CONST.REPORT.ACTIONS.TYPE.REJECTED) { const displayMessage = ReportUtils.getRejectedReportMessage(); diff --git a/src/pages/home/report/ReportActionItem.tsx b/src/pages/home/report/ReportActionItem.tsx index 0d2efbfded2c..5d63b7a03952 100644 --- a/src/pages/home/report/ReportActionItem.tsx +++ b/src/pages/home/report/ReportActionItem.tsx @@ -646,10 +646,28 @@ function ReportActionItem({ } else { children = ; } - } else if (action.actionName === CONST.REPORT.ACTIONS.TYPE.APPROVED) { - children = ; - } else if (action.actionName === CONST.REPORT.ACTIONS.TYPE.FORWARDED) { - children = ; + } else if (ReportActionsUtils.isActionOfType(action, CONST.REPORT.ACTIONS.TYPE.APPROVED)) { + const wasAutoApproved = ReportActionsUtils.getOriginalMessage(action)?.automaticAction ?? false; + if (wasAutoApproved) { + children = ( + + ${ReportUtils.getReportAutomaticallyApprovedMessage(action)}`} /> + + ); + } else { + children = ; + } + } else if (ReportActionsUtils.isActionOfType(action, CONST.REPORT.ACTIONS.TYPE.FORWARDED)) { + const wasAutoForwarded = ReportActionsUtils.getOriginalMessage(action)?.automaticAction ?? false; + if (wasAutoForwarded) { + children = ( + + ${ReportUtils.getReportAutomaticallyForwardedMessage(action, reportID)}`} /> + + ); + } else { + children = ; + } } else if (action.actionName === CONST.REPORT.ACTIONS.TYPE.REJECTED) { children = ; } else if (action.actionName === CONST.REPORT.ACTIONS.TYPE.HOLD) { diff --git a/src/types/onyx/OriginalMessage.ts b/src/types/onyx/OriginalMessage.ts index 73377e81c4ef..eb5db8a0dbbf 100644 --- a/src/types/onyx/OriginalMessage.ts +++ b/src/types/onyx/OriginalMessage.ts @@ -438,6 +438,9 @@ type OriginalMessageApproved = { /** Approved expense amount */ amount: number; + /** Was the action created automatically, not by a human */ + automaticAction?: boolean; + /** Currency of the approved expense amount */ currency: string; @@ -450,6 +453,9 @@ type OriginalMessageForwarded = { /** Forwarded expense amount */ amount: number; + /** Was the action created automatically, not by a human */ + automaticAction?: boolean; + /** Currency of the forwarded expense amount */ currency: string; diff --git a/tests/unit/ReportUtilsTest.ts b/tests/unit/ReportUtilsTest.ts index 091a8cafa37e..e4eee7241d80 100644 --- a/tests/unit/ReportUtilsTest.ts +++ b/tests/unit/ReportUtilsTest.ts @@ -270,6 +270,28 @@ describe('ReportUtils', () => { }); }); }); + + describe('ParentReportAction is', () => { + test('Manually Submitted Report Action', () => { + const threadOfSubmittedReportAction = { + ...LHNTestUtils.getFakeReport(), + type: CONST.REPORT.TYPE.EXPENSE, + stateNum: CONST.REPORT.STATE_NUM.SUBMITTED, + statusNum: CONST.REPORT.STATUS_NUM.SUBMITTED, + parentReportID: '101', + policyID: policy.id, + }; + const submittedParentReportAction = { + actionName: CONST.REPORT.ACTIONS.TYPE.SUBMITTED, + originalMessage: { + amount: 169, + currency: 'USD', + }, + } as ReportAction; + + expect(ReportUtils.getReportName(threadOfSubmittedReportAction, policy, submittedParentReportAction)).toBe('submitted $1.69'); + }); + }); }); describe('requiresAttentionFromCurrentUser', () => {