diff --git a/src/libs/ReportUtils.js b/src/libs/ReportUtils.js index c657aa1af07a..eb558e7ac066 100644 --- a/src/libs/ReportUtils.js +++ b/src/libs/ReportUtils.js @@ -2468,6 +2468,7 @@ function getIOUReportActionMessage(iouReportID, type, total, comment, currency, * @param {Boolean} [isSendMoneyFlow] - Whether this is send money flow * @param {Object} [receipt] * @param {Boolean} [isOwnPolicyExpenseChat] - Whether this is an expense report create from the current user's policy expense chat + * @param {String} [created] - Action created time * @returns {Object} */ function buildOptimisticIOUReportAction( @@ -2483,6 +2484,7 @@ function buildOptimisticIOUReportAction( isSendMoneyFlow = false, receipt = {}, isOwnPolicyExpenseChat = false, + created = DateUtils.getDBTime(), ) { const IOUReportID = iouReportID || generateReportID(); @@ -2540,7 +2542,7 @@ function buildOptimisticIOUReportAction( ], reportActionID: NumberUtils.rand64(), shouldShow: true, - created: DateUtils.getDBTime(), + created, pendingAction: CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD, whisperedToAccountIDs: _.contains([CONST.IOU.RECEIPT_STATE.SCANREADY, CONST.IOU.RECEIPT_STATE.SCANNING], receipt.state) ? [currentUserAccountID] : [], }; @@ -2849,9 +2851,10 @@ function buildOptimisticChatReport( /** * Returns the necessary reportAction onyx data to indicate that the chat has been created optimistically * @param {String} emailCreatingAction + * @param {String} [created] - Action created time * @returns {Object} */ -function buildOptimisticCreatedReportAction(emailCreatingAction) { +function buildOptimisticCreatedReportAction(emailCreatingAction, created = DateUtils.getDBTime()) { return { reportActionID: NumberUtils.rand64(), actionName: CONST.REPORT.ACTIONS.TYPE.CREATED, @@ -2878,7 +2881,7 @@ function buildOptimisticCreatedReportAction(emailCreatingAction) { ], automatic: false, avatar: lodashGet(allPersonalDetails, [currentUserAccountID, 'avatar'], UserUtils.getDefaultAvatar(currentUserAccountID)), - created: DateUtils.getDBTime(), + created, shouldShow: true, }; } diff --git a/src/libs/actions/IOU.js b/src/libs/actions/IOU.js index 6afdba5348f9..714ea7b9aa9f 100644 --- a/src/libs/actions/IOU.js +++ b/src/libs/actions/IOU.js @@ -525,8 +525,9 @@ function getMoneyRequestInformation( // 3. IOU action for the iouReport // 4. REPORTPREVIEW action for the chatReport // Note: The CREATED action for the IOU report must be optimistically generated before the IOU action so there's no chance that it appears after the IOU action in the chat + const currentTime = DateUtils.getDBTime(); const optimisticCreatedActionForChat = ReportUtils.buildOptimisticCreatedReportAction(payeeEmail); - const optimisticCreatedActionForIOU = ReportUtils.buildOptimisticCreatedReportAction(payeeEmail); + const optimisticCreatedActionForIOU = ReportUtils.buildOptimisticCreatedReportAction(payeeEmail, DateUtils.subtractMillisecondsFromDateTime(currentTime, 1)); const iouAction = ReportUtils.buildOptimisticIOUReportAction( CONST.IOU.REPORT_ACTION_TYPE.CREATE, amount, @@ -539,6 +540,8 @@ function getMoneyRequestInformation( false, false, receiptObject, + false, + currentTime, ); let reportPreviewAction = isNewIOUReport ? null : ReportActionsUtils.getReportPreviewAction(chatReport.reportID, iouReport.reportID); @@ -1122,8 +1125,9 @@ function createSplitsAndOnyxData(participants, currentUserLogin, currentUserAcco // 3. IOU action for the iouReport // 4. REPORTPREVIEW action for the chatReport // Note: The CREATED action for the IOU report must be optimistically generated before the IOU action so there's no chance that it appears after the IOU action in the chat + const currentTime = DateUtils.getDBTime(); const oneOnOneCreatedActionForChat = ReportUtils.buildOptimisticCreatedReportAction(currentUserEmailForIOUSplit); - const oneOnOneCreatedActionForIOU = ReportUtils.buildOptimisticCreatedReportAction(currentUserEmailForIOUSplit); + const oneOnOneCreatedActionForIOU = ReportUtils.buildOptimisticCreatedReportAction(currentUserEmailForIOUSplit, DateUtils.subtractMillisecondsFromDateTime(currentTime, 1)); const oneOnOneIOUAction = ReportUtils.buildOptimisticIOUReportAction( CONST.IOU.REPORT_ACTION_TYPE.CREATE, splitAmount, @@ -1133,6 +1137,11 @@ function createSplitsAndOnyxData(participants, currentUserLogin, currentUserAcco oneOnOneTransaction.transactionID, '', oneOnOneIOUReport.reportID, + undefined, + undefined, + undefined, + undefined, + currentTime, ); // Add optimistic personal details for new participants diff --git a/tests/actions/IOUTest.js b/tests/actions/IOUTest.js index 71a5558e921e..7b780802e9b8 100644 --- a/tests/actions/IOUTest.js +++ b/tests/actions/IOUTest.js @@ -107,7 +107,7 @@ describe('actions/IOU', () => { iouAction = iouActions[0]; // The CREATED action should not be created after the IOU action - expect(Date.parse(createdAction.created)).toBeLessThanOrEqual(Date.parse(iouAction.created)); + expect(Date.parse(createdAction.created)).toBeLessThan(Date.parse(iouAction.created)); // The IOUReportID should be correct expect(iouAction.originalMessage.IOUReportID).toBe(iouReportID); @@ -214,6 +214,7 @@ describe('actions/IOU', () => { }; let iouReportID; let iouAction; + let iouCreatedAction; let transactionID; fetch.pause(); return Onyx.set(`${ONYXKEYS.COLLECTION.REPORT}${chatReport.reportID}`, chatReport) @@ -262,10 +263,11 @@ describe('actions/IOU', () => { // The chat report should have a CREATED and an IOU action expect(_.size(allIOUReportActions)).toBe(2); + iouCreatedAction = _.find(allIOUReportActions, (reportAction) => reportAction.actionName === CONST.REPORT.ACTIONS.TYPE.CREATED); iouAction = _.find(allIOUReportActions, (reportAction) => reportAction.actionName === CONST.REPORT.ACTIONS.TYPE.IOU); // The CREATED action should not be created after the IOU action - expect(Date.parse(createdAction.created)).toBeLessThanOrEqual(Date.parse(iouAction.created)); + expect(Date.parse(iouCreatedAction.created)).toBeLessThan(Date.parse(iouAction.created)); // The IOUReportID should be correct expect(iouAction.originalMessage.IOUReportID).toBe(iouReportID); @@ -599,7 +601,7 @@ describe('actions/IOU', () => { iouAction = iouActions[0]; // The CREATED action should not be created after the IOU action - expect(Date.parse(createdAction.created)).toBeLessThanOrEqual(Date.parse(iouAction.created)); + expect(Date.parse(createdAction.created)).toBeLessThan(Date.parse(iouAction.created)); // The IOUReportID should be correct expect(iouAction.originalMessage.IOUReportID).toBe(iouReportID); @@ -866,9 +868,11 @@ describe('actions/IOU', () => { let carlosIOUReport; let carlosIOUAction; + let carlosIOUCreatedAction; let carlosTransaction; let julesIOUAction; + let julesIOUCreatedAction; let julesTransaction; let vitChatReport; @@ -1011,17 +1015,19 @@ describe('actions/IOU', () => { // Carlos DM should have two reportActions – the existing CREATED action and a pending IOU action expect(_.size(carlosReportActions)).toBe(2); + carlosIOUCreatedAction = _.find(carlosReportActions, (reportAction) => reportAction.actionName === CONST.REPORT.ACTIONS.TYPE.CREATED); carlosIOUAction = _.find(carlosReportActions, (reportAction) => reportAction.actionName === CONST.REPORT.ACTIONS.TYPE.IOU); expect(carlosIOUAction.pendingAction).toBe(CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD); expect(carlosIOUAction.originalMessage.IOUReportID).toBe(carlosIOUReport.reportID); expect(carlosIOUAction.originalMessage.amount).toBe(amount / 4); expect(carlosIOUAction.originalMessage.comment).toBe(comment); expect(carlosIOUAction.originalMessage.type).toBe(CONST.IOU.REPORT_ACTION_TYPE.CREATE); - expect(Date.parse(carlosCreatedAction.created)).toBeLessThanOrEqual(Date.parse(carlosIOUAction.created)); + expect(Date.parse(carlosIOUCreatedAction.created)).toBeLessThan(Date.parse(carlosIOUAction.created)); // Jules DM should have three reportActions, the existing CREATED action, the existing IOU action, and a new pending IOU action expect(_.size(julesReportActions)).toBe(3); expect(julesReportActions[julesCreatedAction.reportActionID]).toStrictEqual(julesCreatedAction); + julesIOUCreatedAction = _.find(julesReportActions, (reportAction) => reportAction.actionName === CONST.REPORT.ACTIONS.TYPE.CREATED); julesIOUAction = _.find( julesReportActions, (reportAction) => @@ -1032,7 +1038,7 @@ describe('actions/IOU', () => { expect(julesIOUAction.originalMessage.amount).toBe(amount / 4); expect(julesIOUAction.originalMessage.comment).toBe(comment); expect(julesIOUAction.originalMessage.type).toBe(CONST.IOU.REPORT_ACTION_TYPE.CREATE); - expect(Date.parse(julesCreatedAction.created)).toBeLessThanOrEqual(Date.parse(julesIOUAction.created)); + expect(Date.parse(julesIOUCreatedAction.created)).toBeLessThan(Date.parse(julesIOUAction.created)); // Vit DM should have two reportActions – a pending CREATED action and a pending IOU action expect(_.size(vitReportActions)).toBe(2); @@ -1044,7 +1050,7 @@ describe('actions/IOU', () => { expect(vitIOUAction.originalMessage.amount).toBe(amount / 4); expect(vitIOUAction.originalMessage.comment).toBe(comment); expect(vitIOUAction.originalMessage.type).toBe(CONST.IOU.REPORT_ACTION_TYPE.CREATE); - expect(Date.parse(vitCreatedAction.created)).toBeLessThanOrEqual(Date.parse(vitIOUAction.created)); + expect(Date.parse(vitCreatedAction.created)).toBeLessThan(Date.parse(vitIOUAction.created)); // Group chat should have two reportActions – a pending CREATED action and a pending IOU action w/ type SPLIT expect(_.size(groupReportActions)).toBe(2);