diff --git a/src/libs/OptionsListUtils/index.ts b/src/libs/OptionsListUtils/index.ts index 6d6829915dda..6baacd6bb367 100644 --- a/src/libs/OptionsListUtils/index.ts +++ b/src/libs/OptionsListUtils/index.ts @@ -934,8 +934,8 @@ function createOption( /** * Get the option for a given report. */ -function getReportOption(participant: Participant, reportAttributesDerived?: ReportAttributesDerivedValue['reports']): OptionData { - const report = getReportOrDraftReport(participant.reportID); +function getReportOption(participant: Participant, reportAttributesDerived?: ReportAttributesDerivedValue['reports'], reportDrafts?: OnyxCollection): OptionData { + const report = getReportOrDraftReport(participant.reportID, undefined, undefined, reportDrafts); const visibleParticipantAccountIDs = getParticipantsAccountIDsForDisplay(report, true); const option = createOption( diff --git a/src/libs/ReportUtils.ts b/src/libs/ReportUtils.ts index 8a5dc27950b1..fc18b6a23ef8 100644 --- a/src/libs/ReportUtils.ts +++ b/src/libs/ReportUtils.ts @@ -1001,6 +1001,13 @@ Onyx.connect({ callback: (value) => (allPolicies = value), }); +let allPolicyDrafts: OnyxCollection; +Onyx.connectWithoutView({ + key: ONYXKEYS.COLLECTION.POLICY_DRAFTS, + waitForCollectionCallback: true, + callback: (value) => (allPolicyDrafts = value), +}); + let allReports: OnyxCollection; let reportsByPolicyID: ReportByPolicyMap; Onyx.connect({ @@ -1208,10 +1215,10 @@ function getChatType(report: OnyxInputOrEntry | Participant): ValueOf { +function getReportOrDraftReport(reportID: string | undefined, searchReports?: Report[], fallbackReport?: Report, reportDrafts?: OnyxCollection): OnyxEntry { const searchReport = searchReports?.find((report) => report.reportID === reportID); const onyxReport = allReports?.[`${ONYXKEYS.COLLECTION.REPORT}${reportID}`]; - return searchReport ?? onyxReport ?? allReportsDraft?.[`${ONYXKEYS.COLLECTION.REPORT_DRAFT}${reportID}`] ?? fallbackReport; + return searchReport ?? onyxReport ?? (reportDrafts ?? allReportsDraft)?.[`${ONYXKEYS.COLLECTION.REPORT_DRAFT}${reportID}`] ?? fallbackReport; } function reportTransactionsSelector(transactions: OnyxCollection, reportID: string | undefined): Transaction[] { @@ -4187,10 +4194,11 @@ function getReportFieldsByPolicyID(policyID: string | undefined): Record key.replace(ONYXKEYS.COLLECTION.POLICY, '') === policyID); - const fieldList = policyReportFields?.[1]?.fieldList; + const policy = allPolicies?.[`${ONYXKEYS.COLLECTION.POLICY}${policyID}`]; + const policyDraft = allPolicyDrafts?.[`${ONYXKEYS.COLLECTION.POLICY_DRAFTS}${policyID}`]; + const fieldList = (policy ?? policyDraft)?.fieldList; - if (!policyReportFields || !fieldList) { + if ((!policy && !policyDraft) || !fieldList) { return {}; } @@ -6570,12 +6578,14 @@ function buildOptimisticExpenseReport( // The amount for Expense reports are stored as negative value in the database const storedTotal = total * -1; const storedNonReimbursableTotal = nonReimbursableTotal * -1; - const report = chatReportID ? getReport(chatReportID, allReports) : undefined; + const report = chatReportID ? getReportOrDraftReport(chatReportID) : undefined; const policyName = getPolicyName({report}); const formattedTotal = convertToDisplayString(storedTotal, currency); // This will be fixed as part of https://github.com/Expensify/Expensify/issues/507850 // eslint-disable-next-line @typescript-eslint/no-deprecated - const policy = getPolicy(policyID); + const policyReal = getPolicy(policyID); + const policyDraft = allPolicyDrafts?.[`${ONYXKEYS.COLLECTION.POLICY_DRAFTS}${policyID}`]; + const policy = policyReal ?? policyDraft; const {stateNum, statusNum} = getExpenseReportStateAndStatus(policy); @@ -6611,7 +6621,7 @@ function buildOptimisticExpenseReport( } const titleReportField = getTitleReportField(getReportFieldsByPolicyID(policyID) ?? {}); - if (!!titleReportField && isPaidGroupPolicyExpenseReport(expenseReport)) { + if (!!titleReportField && isGroupPolicy(policy?.type ?? '')) { expenseReport.reportName = populateOptimisticReportFormula(titleReportField.defaultValue, expenseReport, policy); } diff --git a/src/libs/actions/Policy/Policy.ts b/src/libs/actions/Policy/Policy.ts index 473f88086eae..d655b4425020 100644 --- a/src/libs/actions/Policy/Policy.ts +++ b/src/libs/actions/Policy/Policy.ts @@ -2571,6 +2571,17 @@ function createDraftWorkspace( disabledFields: {defaultBillable: true, reimbursable: false}, requiresCategory: true, defaultReimbursable: true, + fieldList: { + [CONST.POLICY.FIELDS.FIELD_LIST_TITLE]: { + defaultValue: CONST.POLICY.DEFAULT_REPORT_NAME_PATTERN, + pendingFields: {defaultValue: CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD, deletable: CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD}, + type: CONST.POLICY.DEFAULT_FIELD_LIST_TYPE, + target: CONST.POLICY.DEFAULT_FIELD_LIST_TARGET, + name: CONST.POLICY.DEFAULT_FIELD_LIST_NAME, + fieldID: CONST.POLICY.FIELDS.FIELD_LIST_TITLE, + deletable: true, + }, + }, }, }, { diff --git a/src/pages/iou/request/step/IOURequestStepConfirmation.tsx b/src/pages/iou/request/step/IOURequestStepConfirmation.tsx index 3b05dc5a2495..afe208ebc4c1 100644 --- a/src/pages/iou/request/step/IOURequestStepConfirmation.tsx +++ b/src/pages/iou/request/step/IOURequestStepConfirmation.tsx @@ -155,6 +155,8 @@ function IOURequestStepConfirmation({ const draftPolicyID = getIOURequestPolicyID(initialTransaction, reportDraft); const [policyDraft] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY_DRAFTS}${draftPolicyID}`, {canBeMissing: true}); const [policyReal] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY}${realPolicyID}`, {canBeMissing: true}); + const [reportDrafts] = useOnyx(ONYXKEYS.COLLECTION.REPORT_DRAFT, {canBeMissing: true}); + /* * We want to use a report from the transaction if it exists * Also if the report was submitted and delayed submission is on, then we should use an initial report @@ -260,9 +262,9 @@ function IOURequestStepConfirmation({ if (participant.isSender && iouType === CONST.IOU.TYPE.INVOICE) { return participant; } - return participant.accountID ? getParticipantsOption(participant, personalDetails) : getReportOption(participant, reportAttributesDerived); + return participant.accountID ? getParticipantsOption(participant, personalDetails) : getReportOption(participant, reportAttributesDerived, reportDrafts); }) ?? [], - [transaction?.participants, iouType, personalDetails, reportAttributesDerived], + [transaction?.participants, iouType, personalDetails, reportAttributesDerived, reportDrafts], ); const isPolicyExpenseChat = useMemo(() => participants?.some((participant) => participant.isPolicyExpenseChat), [participants]); const shouldGenerateTransactionThreadReport = !isBetaEnabled(CONST.BETAS.NO_OPTIMISTIC_TRANSACTION_THREADS); diff --git a/tests/unit/ReportUtilsTest.ts b/tests/unit/ReportUtilsTest.ts index 6a5fe13583c8..baba72c4b8da 100644 --- a/tests/unit/ReportUtilsTest.ts +++ b/tests/unit/ReportUtilsTest.ts @@ -8,6 +8,7 @@ import type {LocaleContextProps} from '@components/LocaleContextProvider'; import useReportIsArchived from '@hooks/useReportIsArchived'; import {putOnHold} from '@libs/actions/IOU'; import type {OnboardingTaskLinks} from '@libs/actions/Welcome/OnboardingFlow'; +import {convertToDisplayString} from '@libs/CurrencyUtils'; import DateUtils from '@libs/DateUtils'; import {getEnvironmentURL} from '@libs/Environment/Environment'; import getBase62ReportID from '@libs/getBase62ReportID'; @@ -8511,6 +8512,27 @@ describe('ReportUtils', () => { }); }); + describe('buildOptimisticExpenseReport', () => { + beforeEach(Onyx.clear); + + it('should include the policy name in report name from report draft', async () => { + const chatReportID = '1'; + const policyID = '2'; + const reportDraft: Report = { + ...createRandomReport(Number(chatReportID), CONST.REPORT.CHAT_TYPE.POLICY_EXPENSE_CHAT), + policyID, + }; + const fakePolicy: Policy = createRandomPolicy(Number(policyID)); + await Onyx.merge(`${ONYXKEYS.COLLECTION.REPORT_DRAFT}${chatReportID}`, reportDraft); + await Onyx.merge(`${ONYXKEYS.COLLECTION.POLICY}${policyID}`, fakePolicy); + + const total = 100; + const currency = CONST.CURRENCY.USD; + const expenseReport = buildOptimisticExpenseReport(chatReportID, undefined, 1, total, currency); + expect(expenseReport.reportName).toBe(`${fakePolicy.name} owes ${convertToDisplayString(-total, currency)}`); + }); + }); + describe('hasEmptyReportsForPolicy', () => { const policyID = 'workspace-001'; const otherPolicyID = 'workspace-002';