-
Notifications
You must be signed in to change notification settings - Fork 2.9k
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
Create Draft reports optimistically #32157
Changes from all commits
23bfbf9
545059a
5f2b55f
c2030a2
52f52d7
b66b1de
6d7f9c8
c87ad6a
4f18257
a56c5cb
ffcbf2b
b057c95
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -110,6 +110,7 @@ type OptimisticExpenseReport = Pick< | |
| 'reportName' | ||
| 'state' | ||
| 'stateNum' | ||
| 'statusNum' | ||
| 'total' | ||
| 'notificationPreference' | ||
| 'parentReportID' | ||
|
@@ -545,6 +546,13 @@ function isReportApproved(report: OnyxEntry<Report>): boolean { | |
return report?.stateNum === CONST.REPORT.STATE_NUM.SUBMITTED && report?.statusNum === CONST.REPORT.STATUS.APPROVED; | ||
} | ||
|
||
/** | ||
* Checks if the supplied report is an expense report in Open state and status. | ||
*/ | ||
function isDraftExpenseReport(report: OnyxEntry<Report>): boolean { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Just saw this method... why, oh, why did we introduce a new term There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I followed the terminology used in the App so its clearer for external engineers who dont have context of the Open reports, however, I agree in the hindsight it would be better to follow the backend terminology and keep |
||
return isExpenseReport(report) && report?.stateNum === CONST.REPORT.STATE_NUM.OPEN && report?.statusNum === CONST.REPORT.STATUS.OPEN; | ||
} | ||
|
||
/** | ||
* Given a collection of reports returns them sorted by last read | ||
*/ | ||
|
@@ -1669,7 +1677,6 @@ function getPolicyExpenseChatName(report: OnyxEntry<Report>, policy: OnyxEntry<P | |
|
||
/** | ||
* Get the title for an IOU or expense chat which will be showing the payer and the amount | ||
* | ||
*/ | ||
function getMoneyRequestReportName(report: OnyxEntry<Report>, policy: OnyxEntry<Policy> | undefined = undefined): string { | ||
const moneyRequestTotal = getMoneyRequestReimbursableTotal(report); | ||
|
@@ -1688,7 +1695,7 @@ function getMoneyRequestReportName(report: OnyxEntry<Report>, policy: OnyxEntry< | |
return Localize.translateLocal('iou.payerSpentAmount', {payer: payerName, amount: formattedAmount}); | ||
} | ||
|
||
if (!!report?.hasOutstandingIOU || moneyRequestTotal === 0) { | ||
if (!!report?.hasOutstandingIOU || isDraftExpenseReport(report) || moneyRequestTotal === 0) { | ||
return Localize.translateLocal('iou.payerOwesAmount', {payer: payerName, amount: formattedAmount}); | ||
} | ||
|
||
|
@@ -2545,9 +2552,16 @@ function buildOptimisticExpenseReport(chatReportID: string, policyID: string, pa | |
const storedTotal = total * -1; | ||
const policyName = getPolicyName(allReports?.[`${ONYXKEYS.COLLECTION.REPORT}${chatReportID}`]); | ||
const formattedTotal = CurrencyUtils.convertToDisplayString(storedTotal, currency); | ||
const policy = getPolicy(policyID); | ||
|
||
// The expense report is always created with the policy's output currency | ||
const outputCurrency = allPolicies?.[`${ONYXKEYS.COLLECTION.POLICY}${policyID}`]?.outputCurrency ?? CONST.CURRENCY.USD; | ||
const outputCurrency = policy?.outputCurrency ?? CONST.CURRENCY.USD; | ||
const isFree = policy?.type === CONST.POLICY.TYPE.FREE; | ||
|
||
// Define the state and status of the report based on whether the policy is free or paid | ||
const state = isFree ? CONST.REPORT.STATE.SUBMITTED : CONST.REPORT.STATE.OPEN; | ||
const stateNum = isFree ? CONST.REPORT.STATE_NUM.PROCESSING : CONST.REPORT.STATE_NUM.OPEN; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Discussed elsewhere but I will make a follow up PR to clean up the naming mess of processing/ submitted states/ status, to make it all aligned |
||
const statusNum = isFree ? CONST.REPORT.STATUS.SUBMITTED : CONST.REPORT.STATUS.OPEN; | ||
|
||
return { | ||
reportID: generateReportID(), | ||
|
@@ -2560,8 +2574,9 @@ function buildOptimisticExpenseReport(chatReportID: string, policyID: string, pa | |
|
||
// We don't translate reportName because the server response is always in English | ||
reportName: `${policyName} owes ${formattedTotal}`, | ||
state: CONST.REPORT.STATE.SUBMITTED, | ||
stateNum: CONST.REPORT.STATE_NUM.PROCESSING, | ||
state, | ||
stateNum, | ||
statusNum, | ||
Comment on lines
+2578
to
+2579
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Adding statusNum too because Draft report is defined by having both state and status set to 0 |
||
total: storedTotal, | ||
notificationPreference: CONST.REPORT.NOTIFICATION_PREFERENCE.HIDDEN, | ||
parentReportID: chatReportID, | ||
|
@@ -4134,10 +4149,6 @@ function getIOUReportActionDisplayMessage(reportAction: OnyxEntry<ReportAction>) | |
}); | ||
} | ||
|
||
function isReportDraft(report: OnyxEntry<Report>): boolean { | ||
return isExpenseReport(report) && report?.stateNum === CONST.REPORT.STATE_NUM.OPEN && report?.statusNum === CONST.REPORT.STATUS.OPEN; | ||
} | ||
|
||
/** | ||
* Return room channel log display message | ||
*/ | ||
|
@@ -4372,7 +4383,7 @@ export { | |
getIOUReportActionDisplayMessage, | ||
isWaitingForAssigneeToCompleteTask, | ||
isGroupChat, | ||
isReportDraft, | ||
isDraftExpenseReport, | ||
shouldUseFullTitleToDisplay, | ||
parseReportRouteParams, | ||
getReimbursementQueuedActionMessage, | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -459,6 +459,15 @@ function getMoneyRequestInformation( | |
const isNewIOUReport = !chatReport.iouReportID || ReportUtils.hasIOUWaitingOnCurrentUserBankAccount(chatReport); | ||
let iouReport = isNewIOUReport ? null : allReports[`${ONYXKEYS.COLLECTION.REPORT}${chatReport.iouReportID}`]; | ||
|
||
// If the linked expense report on paid policy is not draft, we need to create a new draft expense report | ||
if (isPolicyExpenseChat && iouReport) { | ||
const policyType = ReportUtils.getPolicy(iouReport.policyID).type || ''; | ||
const isFromPaidPolicy = policyType === CONST.POLICY.TYPE.TEAM || policyType === CONST.POLICY.TYPE.CORPORATE; | ||
if (isFromPaidPolicy && !ReportUtils.isDraftExpenseReport(iouReport)) { | ||
iouReport = null; | ||
} | ||
} | ||
|
||
if (iouReport) { | ||
if (isPolicyExpenseChat) { | ||
iouReport = {...iouReport}; | ||
|
@@ -2659,30 +2668,46 @@ function approveMoneyRequest(expenseReport) { | |
*/ | ||
function submitReport(expenseReport) { | ||
const optimisticSubmittedReportAction = ReportUtils.buildOptimisticSubmittedReportAction(expenseReport.total, expenseReport.currency, expenseReport.reportID); | ||
const parentReport = ReportUtils.getReport(expenseReport.parentReportID); | ||
|
||
const optimisticReportActionsData = { | ||
onyxMethod: Onyx.METHOD.MERGE, | ||
key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${expenseReport.reportID}`, | ||
value: { | ||
[optimisticSubmittedReportAction.reportActionID]: { | ||
...optimisticSubmittedReportAction, | ||
pendingAction: CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD, | ||
const optimisticData = [ | ||
{ | ||
onyxMethod: Onyx.METHOD.MERGE, | ||
key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${expenseReport.reportID}`, | ||
value: { | ||
[optimisticSubmittedReportAction.reportActionID]: { | ||
...optimisticSubmittedReportAction, | ||
pendingAction: CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD, | ||
}, | ||
}, | ||
}, | ||
}; | ||
const optimisticIOUReportData = { | ||
onyxMethod: Onyx.METHOD.MERGE, | ||
key: `${ONYXKEYS.COLLECTION.REPORT}${expenseReport.reportID}`, | ||
value: { | ||
...expenseReport, | ||
lastMessageText: optimisticSubmittedReportAction.message[0].text, | ||
lastMessageHtml: optimisticSubmittedReportAction.message[0].html, | ||
state: CONST.REPORT.STATE.SUBMITTED, | ||
stateNum: CONST.REPORT.STATE_NUM.PROCESSING, | ||
statusNum: CONST.REPORT.STATUS.SUBMITTED, | ||
{ | ||
onyxMethod: Onyx.METHOD.MERGE, | ||
key: `${ONYXKEYS.COLLECTION.REPORT}${expenseReport.reportID}`, | ||
value: { | ||
...expenseReport, | ||
lastMessageText: lodashGet(optimisticSubmittedReportAction, 'message.0.text', ''), | ||
lastMessageHtml: lodashGet(optimisticSubmittedReportAction, 'message.0.html', ''), | ||
state: CONST.REPORT.STATE.SUBMITTED, | ||
stateNum: CONST.REPORT.STATE_NUM.PROCESSING, | ||
statusNum: CONST.REPORT.STATUS.SUBMITTED, | ||
}, | ||
}, | ||
}; | ||
const optimisticData = [optimisticIOUReportData, optimisticReportActionsData]; | ||
...(parentReport.reportID | ||
? [ | ||
{ | ||
onyxMethod: Onyx.METHOD.MERGE, | ||
key: `${ONYXKEYS.COLLECTION.REPORT}${parentReport.reportID}`, | ||
value: { | ||
...parentReport, | ||
hasOutstandingIOU: false, | ||
hasOutstandingChildRequest: false, | ||
iouReportID: null, | ||
Comment on lines
+2703
to
+2705
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The submitter does not have an outstanding child request anymore on the workspace chat even if they did not have one before. removing the |
||
}, | ||
}, | ||
] | ||
: []), | ||
]; | ||
|
||
const successData = [ | ||
{ | ||
|
@@ -2714,6 +2739,19 @@ function submitReport(expenseReport) { | |
stateNum: CONST.REPORT.STATE_NUM.OPEN, | ||
}, | ||
}, | ||
...(parentReport.reportID | ||
? [ | ||
{ | ||
onyxMethod: Onyx.METHOD.MERGE, | ||
key: `${ONYXKEYS.COLLECTION.REPORT}${parentReport.reportID}`, | ||
value: { | ||
hasOutstandingIOU: parentReport.hasOutstandingIOU, | ||
hasOutstandingChildRequest: parentReport.hasOutstandingChildRequest, | ||
iouReportID: expenseReport.reportID, | ||
}, | ||
}, | ||
] | ||
: []), | ||
]; | ||
|
||
API.write( | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is to ensure we show the next steps on any Paid policy expense report in any state/status not only as draft