Skip to content

Commit 1b5fd75

Browse files
authored
Merge pull request #89551 from wildan-m/wildan/81636-clear-stale-iou-report-id-on-dm-after-pay-to-workspace
Clear stale iouReportID on DM chat after IOU is moved to a new workspace
2 parents c22e8b6 + ec4831a commit 1b5fd75

2 files changed

Lines changed: 63 additions & 1 deletion

File tree

src/libs/actions/Policy/Policy.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4494,19 +4494,23 @@ function createWorkspaceFromIOUPayment(
44944494
});
44954495
}
44964496

4497-
// To optimistically remove the GBR from the DM we need to update the hasOutstandingChildRequest param to false
4497+
// To optimistically remove the GBR from the DM we need to update the hasOutstandingChildRequest param to false.
4498+
// We also clear iouReportID so the moved IOU report is no longer resolved from this DM when a new expense is
4499+
// created there (otherwise the moved report would be reused and "reappear" in the DM preview).
44984500
optimisticData.push({
44994501
onyxMethod: Onyx.METHOD.MERGE,
45004502
key: `${ONYXKEYS.COLLECTION.REPORT}${oldChatReportID}`,
45014503
value: {
45024504
hasOutstandingChildRequest: false,
4505+
iouReportID: null,
45034506
},
45044507
});
45054508
failureData.push({
45064509
onyxMethod: Onyx.METHOD.MERGE,
45074510
key: `${ONYXKEYS.COLLECTION.REPORT}${oldChatReportID}`,
45084511
value: {
45094512
hasOutstandingChildRequest: true,
4513+
iouReportID,
45104514
},
45114515
});
45124516

tests/actions/PolicyTest.ts

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7035,5 +7035,63 @@ describe('actions/Policy', () => {
70357035
apiWriteSpy.mockRestore();
70367036
isIOUReportUsingReportSpy.mockRestore();
70377037
});
7038+
7039+
it('should clear iouReportID on the old DM chat optimistically and restore it on failure', async () => {
7040+
await Onyx.set(ONYXKEYS.SESSION, {email: ESH_EMAIL, accountID: ESH_ACCOUNT_ID});
7041+
await waitForBatchedUpdates();
7042+
7043+
const employeeAccountID = 400;
7044+
const iouReportOwnerEmail = 'employee@example.com';
7045+
const oldChatReportID = '901';
7046+
const movedIouReportID = '900';
7047+
7048+
const iouReport: Report = {
7049+
...createRandomReport(1, undefined),
7050+
reportID: movedIouReportID,
7051+
type: CONST.REPORT.TYPE.IOU,
7052+
ownerAccountID: employeeAccountID,
7053+
chatReportID: oldChatReportID,
7054+
policyID: 'oldPolicyID',
7055+
currency: CONST.CURRENCY.USD,
7056+
total: 1500,
7057+
};
7058+
7059+
await Onyx.set(`${ONYXKEYS.COLLECTION.REPORT}${iouReport.reportID}`, iouReport);
7060+
await waitForBatchedUpdates();
7061+
7062+
const isIOUReportUsingReportSpy = jest.spyOn(ReportUtils, 'isIOUReportUsingReport').mockReturnValue(true);
7063+
const apiWriteSpy = jest.spyOn(require('@libs/API'), 'write').mockImplementation(() => Promise.resolve());
7064+
7065+
const mockTranslate = ((key: string) => key) as unknown as Parameters<typeof Policy.createWorkspaceFromIOUPayment>[8];
7066+
Policy.createWorkspaceFromIOUPayment(iouReport, undefined, ESH_ACCOUNT_ID, ESH_EMAIL, iouReportOwnerEmail, undefined, CONST.CURRENCY.USD, undefined, mockTranslate, {});
7067+
await waitForBatchedUpdates();
7068+
7069+
const writeOptions = apiWriteSpy.mock.calls.at(0)?.at(2) as {
7070+
optimisticData?: Array<{onyxMethod?: string; key?: string; value?: Record<string, unknown> | null}>;
7071+
failureData?: Array<{onyxMethod?: string; key?: string; value?: Record<string, unknown> | null}>;
7072+
};
7073+
7074+
const oldChatKey = `${ONYXKEYS.COLLECTION.REPORT}${oldChatReportID}`;
7075+
const optimisticOldChatUpdate = (writeOptions?.optimisticData ?? []).find(
7076+
(update) => update.key === oldChatKey && (update.value as {iouReportID?: string | null} | null)?.iouReportID !== undefined,
7077+
);
7078+
const failureOldChatUpdate = (writeOptions?.failureData ?? []).find(
7079+
(update) => update.key === oldChatKey && (update.value as {iouReportID?: string | null} | null)?.iouReportID !== undefined,
7080+
);
7081+
7082+
// Optimistic update should clear the dangling pointer so a fresh IOU report is built
7083+
// for the next expense in this DM (the moved report otherwise gets reused via getMoneyRequestInformation).
7084+
expect(optimisticOldChatUpdate).toBeDefined();
7085+
expect((optimisticOldChatUpdate?.value as {iouReportID?: string | null})?.iouReportID).toBeNull();
7086+
expect((optimisticOldChatUpdate?.value as {hasOutstandingChildRequest?: boolean})?.hasOutstandingChildRequest).toBe(false);
7087+
7088+
// Failure rollback must restore the previous iouReportID so the DM chat is back to its prior state.
7089+
expect(failureOldChatUpdate).toBeDefined();
7090+
expect((failureOldChatUpdate?.value as {iouReportID?: string | null})?.iouReportID).toBe(movedIouReportID);
7091+
expect((failureOldChatUpdate?.value as {hasOutstandingChildRequest?: boolean})?.hasOutstandingChildRequest).toBe(true);
7092+
7093+
apiWriteSpy.mockRestore();
7094+
isIOUReportUsingReportSpy.mockRestore();
7095+
});
70387096
});
70397097
});

0 commit comments

Comments
 (0)