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
1 change: 1 addition & 0 deletions src/CONST.ts
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,7 @@ const CONST = {
DATE: {
SQL_DATE_TIME: 'YYYY-MM-DD HH:mm:ss',
FNS_FORMAT_STRING: 'yyyy-MM-dd',
FNS_DATE_TIME_FORMAT_STRING: 'yyyy-MM-dd HH:mm:ss',
LOCAL_TIME_FORMAT: 'h:mm a',
YEAR_MONTH_FORMAT: 'yyyyMM',
MONTH_FORMAT: 'MMMM',
Expand Down
47 changes: 45 additions & 2 deletions src/libs/ReportUtils.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import {format} from 'date-fns';
import ExpensiMark from 'expensify-common/lib/ExpensiMark';
import Str from 'expensify-common/lib/str';
import {isEmpty} from 'lodash';
Expand Down Expand Up @@ -1977,6 +1978,13 @@ function getFormulaTypeReportField(reportFields: PolicyReportFields) {
return Object.values(reportFields).find((field) => field.type === 'formula');
}

/**
* Given a set of report fields, return the field that refers to title
*/
function getTitleReportField(reportFields: PolicyReportFields) {
return Object.values(reportFields).find((field) => isReportFieldOfTypeTitle(field));
}

/**
* Get the report fields attached to the policy given policyID
*/
Expand Down Expand Up @@ -2884,6 +2892,38 @@ function buildOptimisticIOUReport(payeeAccountID: number, payerAccountID: number
};
}

function getHumanReadableStatus(statusNum: number): string {
const status = Object.keys(CONST.REPORT.STATUS_NUM).find((key) => CONST.REPORT.STATUS_NUM[key as keyof typeof CONST.REPORT.STATUS_NUM] === statusNum);
return status ? `${status.charAt(0)}${status.slice(1).toLowerCase()}` : '';
}

/**
* Populates the report field formula with the values from the report and policy.
* Currently, this only supports optimistic expense reports.
* Each formula field is either replaced with a value, or removed.
* If after all replacements the formula is empty, the original formula is returned.
Comment thread
paultsimura marked this conversation as resolved.
* See {@link https://help.expensify.com/articles/expensify-classic/insights-and-custom-reporting/Custom-Templates}
*/
function populateOptimisticReportFormula(formula: string, report: OptimisticExpenseReport, policy: Policy | EmptyObject): string {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's a couple more we can handle here optimistically

{report:created}
{report:created:yyyy-MM-dd}
{report:status}
{user:email}
{user:email|frontPart} would output bob assuming that is the currently logged in Expensify user’s email.

const createdDate = report.lastVisibleActionCreated ? new Date(report.lastVisibleActionCreated) : undefined;
const result = formula
.replaceAll('{report:id}', report.reportID)
// We don't translate because the server response is always in English
.replaceAll('{report:type}', 'Expense Report')
.replaceAll('{report:startdate}', createdDate ? format(createdDate, CONST.DATE.FNS_FORMAT_STRING) : '')
.replaceAll('{report:total}', report.total?.toString() ?? '')
.replaceAll('{report:currency}', report.currency ?? '')
.replaceAll('{report:policyname}', policy.name ?? '')
.replaceAll('{report:created}', createdDate ? format(createdDate, CONST.DATE.FNS_DATE_TIME_FORMAT_STRING) : '')
.replaceAll('{report:created:yyyy-MM-dd}', createdDate ? format(createdDate, CONST.DATE.FNS_FORMAT_STRING) : '')
.replaceAll('{report:status}', report.statusNum !== undefined ? getHumanReadableStatus(report.statusNum) : '')
.replaceAll('{user:email}', currentUserEmail ?? '')
.replaceAll('{user:email|frontPart}', currentUserEmail ? currentUserEmail.split('@')[0] : '')
.replaceAll(/\{report:(.+)}/g, '');

return result.trim().length ? result : formula;
}

/**
* Builds an optimistic Expense report with a randomly generated reportID
*
Expand All @@ -2893,7 +2933,6 @@ function buildOptimisticIOUReport(payeeAccountID: number, payerAccountID: number
* @param total - Amount in cents
* @param currency
*/

function buildOptimisticExpenseReport(chatReportID: string, policyID: string, payeeAccountID: number, total: number, currency: string): OptimisticExpenseReport {
// The amount for Expense reports are stored as negative value in the database
const storedTotal = total * -1;
Expand All @@ -2914,7 +2953,6 @@ function buildOptimisticExpenseReport(chatReportID: string, policyID: string, pa
type: CONST.REPORT.TYPE.EXPENSE,
ownerAccountID: payeeAccountID,
currency,

// We don't translate reportName because the server response is always in English
reportName: `${policyName} owes ${formattedTotal}`,
stateNum,
Expand All @@ -2930,6 +2968,11 @@ function buildOptimisticExpenseReport(chatReportID: string, policyID: string, pa
expenseReport.managerID = policy.submitsTo;
}

const titleReportField = getTitleReportField(getReportFieldsByPolicyID(policyID) ?? {});
if (!!titleReportField && reportFieldsEnabled(expenseReport)) {
expenseReport.reportName = populateOptimisticReportFormula(titleReportField.defaultValue, expenseReport, policy);
}

return expenseReport;
}

Expand Down