From 903527ff2ac49138d5248b140d43c3819c2f2500 Mon Sep 17 00:00:00 2001 From: Pavlo Tsimura Date: Fri, 23 Feb 2024 20:28:20 +0100 Subject: [PATCH 1/2] Use formula for the optimistic expense report --- src/libs/ReportUtils.ts | 35 +++++++++++++++++++++++++++++++++-- 1 file changed, 33 insertions(+), 2 deletions(-) diff --git a/src/libs/ReportUtils.ts b/src/libs/ReportUtils.ts index e0c474e3d8fb..6b22c48ac534 100644 --- a/src/libs/ReportUtils.ts +++ b/src/libs/ReportUtils.ts @@ -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'; @@ -1996,6 +1997,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 */ @@ -2904,6 +2912,26 @@ function buildOptimisticIOUReport(payeeAccountID: number, payerAccountID: number }; } +/** + * Populates the report field formula with the values from the report and policy. + * Currently, is supports only 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. + */ +function populateOptimisticReportFormula(formula: string, report: OptimisticExpenseReport, policy: Policy | EmptyObject): string { + 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}', report.lastVisibleActionCreated ? format(new Date(report.lastVisibleActionCreated), CONST.DATE.FNS_FORMAT_STRING) : '') + .replaceAll('{report:total}', report.total?.toString() ?? '') + .replaceAll('{report:currency}', report.currency ?? '') + .replaceAll('{report:policyname}', policy.name ?? '') + .replaceAll(/\{report:(.+)}/g, ''); + + return result.trim().length ? result : formula; +} + /** * Builds an optimistic Expense report with a randomly generated reportID * @@ -2913,7 +2941,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; @@ -2934,7 +2961,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, @@ -2950,6 +2976,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; } From f898f071dfae6fe77eab5adbe6c3987ce7389acb Mon Sep 17 00:00:00 2001 From: Pavlo Tsimura Date: Wed, 28 Feb 2024 22:49:49 +0100 Subject: [PATCH 2/2] Add more formulas --- src/CONST.ts | 1 + src/libs/ReportUtils.ts | 16 ++++++++++++++-- 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/src/CONST.ts b/src/CONST.ts index 8abd4c087b16..cf0b54bceb42 100755 --- a/src/CONST.ts +++ b/src/CONST.ts @@ -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', diff --git a/src/libs/ReportUtils.ts b/src/libs/ReportUtils.ts index 91b5ceaf872a..dc83d3ee876f 100644 --- a/src/libs/ReportUtils.ts +++ b/src/libs/ReportUtils.ts @@ -2892,21 +2892,33 @@ 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, is supports only optimistic expense reports. + * 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. + * 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 { + 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}', report.lastVisibleActionCreated ? format(new Date(report.lastVisibleActionCreated), CONST.DATE.FNS_FORMAT_STRING) : '') + .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;