Skip to content

Commit 03484e9

Browse files
authored
Merge pull request #79524 from hungvu193/issues-74575
Update Optimistically copy submission/approval related report actions to the new report after partial approval
2 parents b9fd4e3 + 24786fc commit 03484e9

File tree

2 files changed

+113
-0
lines changed

2 files changed

+113
-0
lines changed

src/libs/API/parameters/ApproveMoneyRequestParams.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,14 @@ type ApproveMoneyRequestParams = {
1212
* }>
1313
*/
1414
optimisticHoldReportExpenseActionIDs?: string;
15+
/**
16+
* Stringified JSON object of type Record<string, string> with the following structure:
17+
* {
18+
* [oldReportActionID]: optimisticReportActionID,
19+
* }
20+
* where optimisticReportActionID is the optimistic report action ID and oldReportActionID is the old report action ID
21+
*/
22+
optimisticReportActionCopyIDs?: string;
1523

1624
/** The optimistic action ID for the report created for unapproved transactions */
1725
optimisticCreatedReportForUnapprovedTransactionsActionID?: string;

src/libs/actions/IOU/index.ts

Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9447,6 +9447,95 @@ function getHoldReportActionsAndTransactions(reportID: string | undefined) {
94479447
return {holdReportActions, holdTransactions};
94489448
}
94499449

9450+
type OptimisticReportActionCopyIDs = Record<string, string>;
9451+
9452+
/**
9453+
* Gets duplicate workflow actions for a partial expense report.
9454+
* Used when splitting held expenses into a new partial report to maintain action history.
9455+
*
9456+
* @param sourceReportID - The ID of the original report to copy actions from
9457+
* @param targetReportID - The ID of the new partial expense report to copy actions to
9458+
* @returns A tuple of [optimisticData, successData, failureData, duplicatedReportActionIDs]
9459+
*/
9460+
function getDuplicateActionsForPartialReport(
9461+
sourceReportID: string | undefined,
9462+
targetReportID: string | undefined,
9463+
): [
9464+
Array<OnyxUpdate<typeof ONYXKEYS.COLLECTION.REPORT_ACTIONS>>,
9465+
Array<OnyxUpdate<typeof ONYXKEYS.COLLECTION.REPORT_ACTIONS>>,
9466+
Array<OnyxUpdate<typeof ONYXKEYS.COLLECTION.REPORT_ACTIONS>>,
9467+
OptimisticReportActionCopyIDs,
9468+
] {
9469+
const optimisticData: Array<OnyxUpdate<typeof ONYXKEYS.COLLECTION.REPORT_ACTIONS>> = [];
9470+
const successData: Array<OnyxUpdate<typeof ONYXKEYS.COLLECTION.REPORT_ACTIONS>> = [];
9471+
const failureData: Array<OnyxUpdate<typeof ONYXKEYS.COLLECTION.REPORT_ACTIONS>> = [];
9472+
const optimisticReportActionCopyIDs: OptimisticReportActionCopyIDs = {};
9473+
9474+
if (!sourceReportID || !targetReportID) {
9475+
return [optimisticData, successData, failureData, optimisticReportActionCopyIDs];
9476+
}
9477+
9478+
const sourceReportActions = getAllReportActions(sourceReportID);
9479+
9480+
// Match the backend's WORKFLOW_ACTIONS list
9481+
const workflowActionTypes = [
9482+
CONST.REPORT.ACTIONS.TYPE.SUBMITTED,
9483+
CONST.REPORT.ACTIONS.TYPE.SUBMITTED_AND_CLOSED,
9484+
CONST.REPORT.ACTIONS.TYPE.APPROVED,
9485+
CONST.REPORT.ACTIONS.TYPE.UNAPPROVED,
9486+
CONST.REPORT.ACTIONS.TYPE.REJECTED,
9487+
CONST.REPORT.ACTIONS.TYPE.RETRACTED,
9488+
CONST.REPORT.ACTIONS.TYPE.CLOSED,
9489+
CONST.REPORT.ACTIONS.TYPE.REOPENED,
9490+
CONST.REPORT.ACTIONS.TYPE.FORWARDED,
9491+
CONST.REPORT.ACTIONS.TYPE.TAKE_CONTROL,
9492+
CONST.REPORT.ACTIONS.TYPE.REROUTE,
9493+
] as const;
9494+
9495+
const copiedActions: Record<string, OnyxTypes.ReportAction> = {};
9496+
const copiedActionsSuccess: OnyxCollection<NullishDeep<ReportAction>> = {};
9497+
const copiedActionsFailure: Record<string, null> = {};
9498+
9499+
for (const action of Object.values(sourceReportActions)) {
9500+
if (action && (workflowActionTypes as readonly string[]).includes(action.actionName)) {
9501+
const newActionID = NumberUtils.rand64();
9502+
copiedActions[newActionID] = {
9503+
...action,
9504+
reportActionID: newActionID,
9505+
reportID: targetReportID,
9506+
pendingAction: CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD,
9507+
};
9508+
copiedActionsSuccess[newActionID] = {
9509+
pendingAction: null,
9510+
};
9511+
copiedActionsFailure[newActionID] = null;
9512+
optimisticReportActionCopyIDs[action.reportActionID] = newActionID;
9513+
}
9514+
}
9515+
9516+
if (Object.keys(copiedActions).length > 0) {
9517+
optimisticData.push({
9518+
onyxMethod: Onyx.METHOD.MERGE,
9519+
key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${targetReportID}`,
9520+
value: copiedActions,
9521+
});
9522+
9523+
successData.push({
9524+
onyxMethod: Onyx.METHOD.MERGE,
9525+
key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${targetReportID}`,
9526+
value: copiedActionsSuccess,
9527+
});
9528+
9529+
failureData.push({
9530+
onyxMethod: Onyx.METHOD.MERGE,
9531+
key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${targetReportID}`,
9532+
value: copiedActionsFailure,
9533+
});
9534+
}
9535+
9536+
return [optimisticData, successData, failureData, optimisticReportActionCopyIDs];
9537+
}
9538+
94509539
function getReportFromHoldRequestsOnyxData({
94519540
chatReport,
94529541
iouReport,
@@ -9466,6 +9555,7 @@ function getReportFromHoldRequestsOnyxData({
94669555
optimisticHoldActionID: string;
94679556
optimisticCreatedReportForUnapprovedTransactionsActionID: string | undefined;
94689557
optimisticHoldReportExpenseActionIDs: OptimisticHoldReportExpenseActionID[];
9558+
optimisticReportActionCopyIDs: OptimisticReportActionCopyIDs;
94699559
optimisticData: OnyxUpdate[];
94709560
successData: OnyxUpdate[];
94719561
failureData: OnyxUpdate[];
@@ -9710,6 +9800,17 @@ function getReportFromHoldRequestsOnyxData({
97109800
},
97119801
];
97129802

9803+
// Copy submission/approval actions to the new report
9804+
const [copiedActionsOptimistic, copiedActionsSuccess, copiedActionsFailure, optimisticReportActionCopyIDs] = getDuplicateActionsForPartialReport(
9805+
iouReport?.reportID,
9806+
optimisticExpenseReport.reportID,
9807+
);
9808+
// Only copy the report action for approval flow
9809+
if (isApprovalFlow && !isEmptyObject(optimisticReportActionCopyIDs)) {
9810+
optimisticData.push(...copiedActionsOptimistic);
9811+
successData.push(...copiedActionsSuccess);
9812+
failureData.push(...copiedActionsFailure);
9813+
}
97139814
// add optimistic system message explaining the created report for unapproved transactions
97149815
if (isApprovalFlow && optimisticCreatedReportForUnapprovedAction) {
97159816
optimisticData.push({
@@ -9748,6 +9849,7 @@ function getReportFromHoldRequestsOnyxData({
97489849
successData,
97499850
optimisticHoldReportID: optimisticExpenseReport.reportID,
97509851
optimisticHoldReportExpenseActionIDs,
9852+
optimisticReportActionCopyIDs,
97519853
};
97529854
}
97539855

@@ -10454,6 +10556,7 @@ function approveMoneyRequest(
1045410556
let optimisticHoldReportID;
1045510557
let optimisticHoldActionID;
1045610558
let optimisticHoldReportExpenseActionIDs;
10559+
let optimisticReportActionCopyIDs;
1045710560
let optimisticCreatedReportForUnapprovedTransactionsActionID;
1045810561
if (!full && !!chatReport && !!expenseReport) {
1045910562
const originalCreated = getReportOriginalCreationTimestamp(expenseReport);
@@ -10473,6 +10576,7 @@ function approveMoneyRequest(
1047310576
optimisticHoldActionID = holdReportOnyxData.optimisticHoldActionID;
1047410577
optimisticCreatedReportForUnapprovedTransactionsActionID = holdReportOnyxData.optimisticCreatedReportForUnapprovedTransactionsActionID;
1047510578
optimisticHoldReportExpenseActionIDs = JSON.stringify(holdReportOnyxData.optimisticHoldReportExpenseActionIDs);
10579+
optimisticReportActionCopyIDs = JSON.stringify(holdReportOnyxData.optimisticReportActionCopyIDs);
1047610580
}
1047710581

1047810582
// Remove duplicates violations if we approve the report
@@ -10515,6 +10619,7 @@ function approveMoneyRequest(
1051510619
optimisticHoldReportID,
1051610620
optimisticHoldActionID,
1051710621
optimisticHoldReportExpenseActionIDs,
10622+
optimisticReportActionCopyIDs,
1051810623
optimisticCreatedReportForUnapprovedTransactionsActionID,
1051910624
};
1052010625

0 commit comments

Comments
 (0)