Skip to content

Commit

Permalink
Merge pull request #27306 from bernhardoj/fix/24366-iou-transaction
Browse files Browse the repository at this point in the history
Fix all offline created transaction is deleted when we delete one of the transaction
  • Loading branch information
bondydaa authored Oct 26, 2023
2 parents 9802795 + df77b50 commit 6c2e087
Show file tree
Hide file tree
Showing 3 changed files with 29 additions and 11 deletions.
9 changes: 6 additions & 3 deletions src/libs/ReportUtils.js
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand All @@ -2483,6 +2484,7 @@ function buildOptimisticIOUReportAction(
isSendMoneyFlow = false,
receipt = {},
isOwnPolicyExpenseChat = false,
created = DateUtils.getDBTime(),
) {
const IOUReportID = iouReportID || generateReportID();

Expand Down Expand Up @@ -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] : [],
};
Expand Down Expand Up @@ -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,
Expand All @@ -2878,7 +2881,7 @@ function buildOptimisticCreatedReportAction(emailCreatingAction) {
],
automatic: false,
avatar: lodashGet(allPersonalDetails, [currentUserAccountID, 'avatar'], UserUtils.getDefaultAvatar(currentUserAccountID)),
created: DateUtils.getDBTime(),
created,
shouldShow: true,
};
}
Expand Down
13 changes: 11 additions & 2 deletions src/libs/actions/IOU.js
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -539,6 +540,8 @@ function getMoneyRequestInformation(
false,
false,
receiptObject,
false,
currentTime,
);

let reportPreviewAction = isNewIOUReport ? null : ReportActionsUtils.getReportPreviewAction(chatReport.reportID, iouReport.reportID);
Expand Down Expand Up @@ -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,
Expand All @@ -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
Expand Down
18 changes: 12 additions & 6 deletions tests/actions/IOUTest.js
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -866,9 +868,11 @@ describe('actions/IOU', () => {

let carlosIOUReport;
let carlosIOUAction;
let carlosIOUCreatedAction;
let carlosTransaction;

let julesIOUAction;
let julesIOUCreatedAction;
let julesTransaction;

let vitChatReport;
Expand Down Expand Up @@ -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) =>
Expand All @@ -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);
Expand All @@ -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);
Expand Down

0 comments on commit 6c2e087

Please sign in to comment.