Skip to content

Commit ec1f5e6

Browse files
committed
refactor payMoneyRequest to use conciergeReportID from useOnyx
1 parent 39d1d17 commit ec1f5e6

9 files changed

Lines changed: 127 additions & 1 deletion

File tree

src/components/MoneyReportHeaderActions/MoneyReportHeaderSecondaryActions.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,7 @@ function MoneyReportHeaderSecondaryActionsInner({reportID, primaryAction, isRepo
104104
`${ONYXKEYS.COLLECTION.POLICY}${chatReport?.invoiceReceiver && 'policyID' in chatReport.invoiceReceiver ? chatReport.invoiceReceiver.policyID : undefined}`,
105105
{},
106106
);
107+
const [conciergeReportID] = useOnyx(ONYXKEYS.CONCIERGE_REPORT_ID);
107108

108109
const currentUserPersonalDetails = useCurrentUserPersonalDetails();
109110
const {login: currentUserLogin, accountID, email} = currentUserPersonalDetails;
@@ -195,6 +196,7 @@ function MoneyReportHeaderSecondaryActionsInner({reportID, primaryAction, isRepo
195196
amountOwed,
196197
ownerBillingGracePeriodEnd,
197198
methodID: type === CONST.IOU.PAYMENT_TYPE.VBBA ? methodID : undefined,
199+
conciergeReportID,
198200
onPaid: () => {
199201
startAnimation();
200202
},

src/components/MoneyReportHeaderActions/MoneyReportHeaderSelectionDropdown.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,7 @@ function MoneyReportHeaderSelectionDropdown({reportID, primaryAction, isReportIn
118118

119119
const [activePolicyID] = useOnyx(ONYXKEYS.NVP_ACTIVE_POLICY_ID);
120120
const [isSelfTourViewed = false] = useOnyx(ONYXKEYS.NVP_ONBOARDING, {selector: hasSeenTourSelector});
121+
const [conciergeReportID] = useOnyx(ONYXKEYS.CONCIERGE_REPORT_ID);
121122
const activePolicy = usePolicy(activePolicyID);
122123
const chatReportPolicy = usePolicy(chatReport?.policyID);
123124
const existingB2BInvoiceReport = useParticipantsInvoiceReport(activePolicyID, CONST.REPORT.INVOICE_RECEIVER_TYPE.BUSINESS, chatReport?.policyID);
@@ -293,6 +294,7 @@ function MoneyReportHeaderSelectionDropdown({reportID, primaryAction, isReportIn
293294
amountOwed,
294295
ownerBillingGracePeriodEnd,
295296
methodID: type === CONST.IOU.PAYMENT_TYPE.VBBA ? methodID : undefined,
297+
conciergeReportID,
296298
onPaid: () => {
297299
startAnimation();
298300
},

src/components/MoneyReportHeaderPrimaryAction/PayPrimaryAction.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ function PayPrimaryAction({reportID, chatReportID}: PayPrimaryActionProps) {
5858
const [ownerBillingGracePeriodEnd] = useOnyx(ONYXKEYS.NVP_PRIVATE_OWNER_BILLING_GRACE_PERIOD_END);
5959
const [activePolicyID] = useOnyx(ONYXKEYS.NVP_ACTIVE_POLICY_ID);
6060
const [reportMetadata] = useOnyx(`${ONYXKEYS.COLLECTION.REPORT_METADATA}${moneyRequestReport?.reportID}`);
61+
const [conciergeReportID] = useOnyx(ONYXKEYS.CONCIERGE_REPORT_ID);
6162

6263
const activePolicy = usePolicy(activePolicyID);
6364
const chatReportPolicy = usePolicy(chatReport?.policyID);
@@ -164,6 +165,7 @@ function PayPrimaryAction({reportID, chatReportID}: PayPrimaryActionProps) {
164165
amountOwed,
165166
ownerBillingGracePeriodEnd,
166167
methodID: type === CONST.IOU.PAYMENT_TYPE.VBBA ? methodID : undefined,
168+
conciergeReportID,
167169
onPaid: startAnimation,
168170
});
169171
if (currentSearchQueryJSON && !isOffline) {

src/components/ReportActionItem/MoneyRequestReportPreview/PayActionButton.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,7 @@ function PayActionButton({
8989
const [betas] = useOnyx(ONYXKEYS.BETAS);
9090
const [delegateEmail] = useOnyx(ONYXKEYS.ACCOUNT, {selector: delegateEmailSelector});
9191
const [isSelfTourViewed] = useOnyx(ONYXKEYS.NVP_ONBOARDING, {selector: hasSeenTourSelector});
92+
const [conciergeReportID] = useOnyx(ONYXKEYS.CONCIERGE_REPORT_ID);
9293

9394
const reportTransactionsCollection = useReportTransactionsCollection(iouReportID);
9495
const transactions = Object.values(reportTransactionsCollection ?? {}).filter(
@@ -205,6 +206,7 @@ function PayActionButton({
205206
userBillingGracePeriodEnds,
206207
amountOwed,
207208
ownerBillingGracePeriodEnd,
209+
conciergeReportID,
208210
onPaid: startAnimation,
209211
});
210212
}

src/hooks/useHoldMenuSubmit.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ function useHoldMenuSubmit({moneyRequestReport, chatReport, requestType, payment
4040
const [delegateEmail] = useOnyx(ONYXKEYS.ACCOUNT, {selector: delegateEmailSelector});
4141
const [isSelfTourViewed] = useOnyx(ONYXKEYS.NVP_ONBOARDING, {selector: hasSeenTourSelector});
4242
const [moneyRequestReportNextStep] = useOnyx(`${ONYXKEYS.COLLECTION.NEXT_STEP}${moneyRequestReport?.reportID}`);
43+
const [conciergeReportID] = useOnyx(ONYXKEYS.CONCIERGE_REPORT_ID);
4344
const {isBetaEnabled} = usePermissions();
4445
const [transactionViolations] = useOnyx(ONYXKEYS.COLLECTION.TRANSACTION_VIOLATIONS);
4546
const isASAPSubmitBetaEnabled = isBetaEnabled(CONST.BETAS.ASAP_SUBMIT);
@@ -96,6 +97,7 @@ function useHoldMenuSubmit({moneyRequestReport, chatReport, requestType, payment
9697
amountOwed,
9798
ownerBillingGracePeriodEnd,
9899
methodID,
100+
conciergeReportID,
99101
onPaid: animationCallback,
100102
});
101103
}

src/hooks/useSelectionModeReportActions.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,7 @@ function useSelectionModeReportActions({
114114
const {isOffline} = useNetwork();
115115

116116
const [activePolicyID] = useOnyx(ONYXKEYS.NVP_ACTIVE_POLICY_ID);
117+
const [conciergeReportID] = useOnyx(ONYXKEYS.CONCIERGE_REPORT_ID);
117118
const activePolicy = usePolicy(activePolicyID);
118119
const chatReportPolicy = usePolicy(chatReport?.policyID);
119120
const [invoiceReceiverPolicy] = useOnyx(
@@ -396,6 +397,7 @@ function useSelectionModeReportActions({
396397
amountOwed,
397398
ownerBillingGracePeriodEnd,
398399
methodID: type === CONST.IOU.PAYMENT_TYPE.VBBA ? methodID : undefined,
400+
conciergeReportID,
399401
});
400402
if (currentSearchQueryJSON && !isOffline) {
401403
search({

src/libs/actions/IOU/Hold.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -685,6 +685,7 @@ function getReportFromHoldRequestsOnyxData({
685685
createdTimestamp,
686686
betas,
687687
isApprovalFlow = false,
688+
conciergeReportID,
688689
}: {
689690
chatReport: OnyxTypes.Report;
690691
iouReport: OnyxEntry<OnyxTypes.Report>;
@@ -693,6 +694,8 @@ function getReportFromHoldRequestsOnyxData({
693694
createdTimestamp?: string;
694695
betas: OnyxEntry<OnyxTypes.Beta[]>;
695696
isApprovalFlow?: boolean;
697+
// TODO: This will be required eventually. Ref: https://github.com/Expensify/App/issues/66411
698+
conciergeReportID?: string;
696699
}): {
697700
optimisticHoldReportID: string;
698701
optimisticHoldActionID: string;
@@ -752,6 +755,7 @@ function getReportFromHoldRequestsOnyxData({
752755
firstHoldTransaction,
753756
optimisticExpenseReport.reportID,
754757
newParentReportActionID,
758+
conciergeReportID,
755759
);
756760

757761
let optimisticCreatedReportForUnapprovedAction: OnyxTypes.ReportAction | null = null;

src/libs/actions/IOU/PayMoneyRequest.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,7 @@ type PayMoneyRequestFunctionParams = {
9393
amountOwed: OnyxEntry<number>;
9494
ownerBillingGracePeriodEnd?: OnyxEntry<number>;
9595
methodID?: number;
96+
conciergeReportID: string | undefined;
9697
onPaid?: () => void;
9798
};
9899

@@ -116,6 +117,7 @@ function getPayMoneyRequestParams({
116117
betas,
117118
isSelfTourViewed,
118119
defaultWorkspaceName,
120+
conciergeReportID,
119121
}: {
120122
initialChatReport: OnyxTypes.Report;
121123
iouReport: OnyxEntry<OnyxTypes.Report>;
@@ -136,6 +138,8 @@ function getPayMoneyRequestParams({
136138
betas: OnyxEntry<OnyxTypes.Beta[]>;
137139
isSelfTourViewed: boolean | undefined;
138140
defaultWorkspaceName?: string;
141+
// TODO: This will be required eventually. Ref: https://github.com/Expensify/App/issues/66411
142+
conciergeReportID?: string;
139143
}): PayMoneyRequestData {
140144
const allTransactionViolations = getAllTransactionViolations();
141145

@@ -441,7 +445,7 @@ function getPayMoneyRequestParams({
441445
let optimisticHoldActionID;
442446
let optimisticHoldReportExpenseActionIDs;
443447
if (!full) {
444-
const holdReportOnyxData = getReportFromHoldRequestsOnyxData({chatReport, iouReport, recipient, policy: reportPolicy, betas});
448+
const holdReportOnyxData = getReportFromHoldRequestsOnyxData({chatReport, iouReport, recipient, policy: reportPolicy, betas, conciergeReportID});
445449

446450
onyxData.optimisticData?.push(...holdReportOnyxData.optimisticData);
447451
onyxData.successData?.push(...holdReportOnyxData.successData);
@@ -746,6 +750,7 @@ function payMoneyRequest(params: PayMoneyRequestFunctionParams) {
746750
amountOwed,
747751
ownerBillingGracePeriodEnd,
748752
methodID,
753+
conciergeReportID,
749754
onPaid,
750755
} = params;
751756
const policyForBillingRestriction = chatReportPolicy ?? (policy?.id === chatReport.policyID ? policy : undefined);
@@ -777,6 +782,7 @@ function payMoneyRequest(params: PayMoneyRequestFunctionParams) {
777782
betas,
778783
isSelfTourViewed,
779784
bankAccountID: paymentType === CONST.IOU.PAYMENT_TYPE.VBBA ? methodID : undefined,
785+
conciergeReportID,
780786
});
781787

782788
// For now, we need to call the PayMoneyRequestWithWallet API since PayMoneyRequest was not updated to work with

tests/actions/IOUTest/PayMoneyRequestTest.ts

Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
/* eslint-disable @typescript-eslint/no-unsafe-assignment */
22
import Onyx from 'react-native-onyx';
33
import type {OnyxEntry, OnyxInputValue} from 'react-native-onyx';
4+
import * as Hold from '@libs/actions/IOU/Hold';
45
import {putOnHold} from '@libs/actions/IOU/Hold';
56
import {cancelPayment, completePaymentOnboarding, payMoneyRequest} from '@libs/actions/IOU/PayMoneyRequest';
67
import {requestMoney} from '@libs/actions/IOU/TrackExpense';
@@ -9,6 +10,7 @@ import {createWorkspace, generatePolicyID} from '@libs/actions/Policy/Policy';
910
import {notifyNewAction} from '@libs/actions/Report';
1011
import type * as PolicyUtils from '@libs/PolicyUtils';
1112
import {getOriginalMessage, getReportActionHtml, getReportActionText, isMoneyRequestAction} from '@libs/ReportActionsUtils';
13+
import * as ReportUtils from '@libs/ReportUtils';
1214
import {buildOptimisticIOUReport, buildOptimisticIOUReportAction} from '@libs/ReportUtils';
1315
import {buildOptimisticTransaction} from '@libs/TransactionUtils';
1416
import CONST from '@src/CONST';
@@ -252,6 +254,7 @@ describe('actions/IOU/PayMoneyRequest', () => {
252254
userBillingGracePeriodEnds: undefined,
253255
amountOwed: 0,
254256
chatReportPolicy: chatReportPolicyFromChat(chatReport),
257+
conciergeReportID: undefined,
255258
});
256259
return waitForBatchedUpdates();
257260
})
@@ -464,6 +467,7 @@ describe('actions/IOU/PayMoneyRequest', () => {
464467
userBillingGracePeriodEnds: undefined,
465468
amountOwed: 0,
466469
chatReportPolicy: chatReportPolicyFromChat(chatReport),
470+
conciergeReportID: undefined,
467471
});
468472
return waitForBatchedUpdates();
469473
})
@@ -630,6 +634,7 @@ describe('actions/IOU/PayMoneyRequest', () => {
630634
userBillingGracePeriodEnds: undefined,
631635
amountOwed: 0,
632636
chatReportPolicy: chatReportPolicyFromChat(chatReport),
637+
conciergeReportID: undefined,
633638
});
634639
return waitForBatchedUpdates();
635640
})
@@ -684,6 +689,7 @@ describe('actions/IOU/PayMoneyRequest', () => {
684689
userBillingGracePeriodEnds: undefined,
685690
amountOwed: 0,
686691
chatReportPolicy,
692+
conciergeReportID: undefined,
687693
});
688694

689695
await waitForBatchedUpdates();
@@ -801,6 +807,7 @@ describe('actions/IOU/PayMoneyRequest', () => {
801807
userBillingGracePeriodEnds: undefined,
802808
amountOwed: 0,
803809
chatReportPolicy: chatReportPolicyFromChat(partialPayChatReport),
810+
conciergeReportID: undefined,
804811
});
805812
return waitForBatchedUpdates();
806813
})
@@ -898,6 +905,7 @@ describe('actions/IOU/PayMoneyRequest', () => {
898905
isSelfTourViewed: false,
899906
userBillingGracePeriodEnds: undefined,
900907
amountOwed: 0,
908+
conciergeReportID: undefined,
901909
});
902910
await waitForBatchedUpdates();
903911
const newExpenseReport = await getOnyxValue(`${ONYXKEYS.COLLECTION.REPORT}${newExpenseReportID}`);
@@ -935,6 +943,7 @@ describe('actions/IOU/PayMoneyRequest', () => {
935943
userBillingGracePeriodEnds: undefined,
936944
amountOwed: 0,
937945
chatReportPolicy: chatReportPolicyTrueTour,
946+
conciergeReportID: undefined,
938947
});
939948

940949
await waitForBatchedUpdates();
@@ -985,6 +994,7 @@ describe('actions/IOU/PayMoneyRequest', () => {
985994
userBillingGracePeriodEnds: undefined,
986995
amountOwed: 0,
987996
chatReportPolicy: chatReportPolicyFalseTour,
997+
conciergeReportID: undefined,
988998
});
989999

9901000
await waitForBatchedUpdates();
@@ -1056,6 +1066,7 @@ describe('actions/IOU/PayMoneyRequest', () => {
10561066
ownerBillingGracePeriodEnd: pastDate,
10571067
policy,
10581068
chatReportPolicy: policy,
1069+
conciergeReportID: undefined,
10591070
});
10601071

10611072
await waitForBatchedUpdates();
@@ -1122,6 +1133,7 @@ describe('actions/IOU/PayMoneyRequest', () => {
11221133
ownerBillingGracePeriodEnd: pastDate,
11231134
policy: expensePolicy,
11241135
chatReportPolicy: workspacePolicy,
1136+
conciergeReportID: undefined,
11251137
});
11261138

11271139
await waitForBatchedUpdates();
@@ -1178,6 +1190,7 @@ describe('actions/IOU/PayMoneyRequest', () => {
11781190
ownerBillingGracePeriodEnd: futureGraceEnd,
11791191
chatReportPolicy: workspacePolicy,
11801192
policy: workspacePolicy,
1193+
conciergeReportID: undefined,
11811194
});
11821195

11831196
await waitForBatchedUpdates();
@@ -1214,6 +1227,7 @@ describe('actions/IOU/PayMoneyRequest', () => {
12141227
userBillingGracePeriodEnds: undefined,
12151228
amountOwed: 0,
12161229
chatReportPolicy: chatReportPolicyAmountZero,
1230+
conciergeReportID: undefined,
12171231
});
12181232

12191233
await waitForBatchedUpdates();
@@ -1233,6 +1247,94 @@ describe('actions/IOU/PayMoneyRequest', () => {
12331247

12341248
mockFetch?.resume?.();
12351249
});
1250+
1251+
it('forwards the provided conciergeReportID to buildOptimisticReportPreview when partially paying', async () => {
1252+
// Given an iou report with two transactions, one of which is held (so partial pay is possible)
1253+
const iouReport = buildOptimisticIOUReport(1, 2, 100, '1', 'USD');
1254+
const transaction1 = buildOptimisticTransaction({
1255+
transactionParams: {amount: 100, currency: 'USD', reportID: iouReport.reportID},
1256+
});
1257+
const transaction2 = buildOptimisticTransaction({
1258+
transactionParams: {amount: 100, currency: 'USD', reportID: iouReport.reportID},
1259+
});
1260+
const concierge42TransactionDataSet: TransactionCollectionDataSet = {
1261+
[`${ONYXKEYS.COLLECTION.TRANSACTION}${transaction1.transactionID}`]: transaction1,
1262+
[`${ONYXKEYS.COLLECTION.TRANSACTION}${transaction2.transactionID}`]: transaction2,
1263+
};
1264+
await Onyx.multiSet(concierge42TransactionDataSet);
1265+
putOnHold(transaction1.transactionID, 'comment', iouReport.reportID, false, RORY_EMAIL, RORY_ACCOUNT_ID);
1266+
await waitForBatchedUpdates();
1267+
1268+
const buildOptimisticReportPreviewSpy = jest.spyOn(ReportUtils, 'buildOptimisticReportPreview');
1269+
const partialPayChatReport = {reportID: topMostReportID, policyID: CONST.POLICY.ID_FAKE};
1270+
const conciergeReportID = 'concierge_report_id_42';
1271+
1272+
// When partial paying with a specific conciergeReportID
1273+
payMoneyRequest({
1274+
paymentType: CONST.IOU.PAYMENT_TYPE.ELSEWHERE,
1275+
chatReport: partialPayChatReport,
1276+
iouReport,
1277+
introSelected: undefined,
1278+
iouReportCurrentNextStepDeprecated: undefined,
1279+
currentUserAccountID: CARLOS_ACCOUNT_ID,
1280+
currentUserLogin: CARLOS_EMAIL,
1281+
full: false,
1282+
betas: [CONST.BETAS.ALL],
1283+
isSelfTourViewed: false,
1284+
userBillingGracePeriodEnds: undefined,
1285+
amountOwed: 0,
1286+
chatReportPolicy: chatReportPolicyFromChat(partialPayChatReport),
1287+
conciergeReportID,
1288+
});
1289+
await waitForBatchedUpdates();
1290+
1291+
// Then buildOptimisticReportPreview should receive the same conciergeReportID
1292+
expect(buildOptimisticReportPreviewSpy).toHaveBeenCalled();
1293+
const callsWithConciergeID = buildOptimisticReportPreviewSpy.mock.calls.filter((args) => args.at(6) === conciergeReportID);
1294+
expect(callsWithConciergeID.length).toBeGreaterThan(0);
1295+
1296+
buildOptimisticReportPreviewSpy.mockRestore();
1297+
});
1298+
1299+
it('does not invoke getReportFromHoldRequestsOnyxData when full paying, so conciergeReportID is not forwarded', async () => {
1300+
// Given an iou report and a non-partial pay (full=true is the default)
1301+
const chatReport = {
1302+
...createRandomReport(0, undefined),
1303+
lastReadTime: DateUtils.getDBTime(),
1304+
lastVisibleActionCreated: DateUtils.getDBTime(),
1305+
};
1306+
const iouReport = {
1307+
...createRandomReport(1, undefined),
1308+
chatType: undefined,
1309+
type: CONST.REPORT.TYPE.IOU,
1310+
total: 10,
1311+
};
1312+
const getReportFromHoldRequestsOnyxDataSpy = jest.spyOn(Hold, 'getReportFromHoldRequestsOnyxData');
1313+
const conciergeReportID = 'concierge_report_id_should_not_propagate';
1314+
1315+
// When fully paying
1316+
payMoneyRequest({
1317+
paymentType: CONST.IOU.PAYMENT_TYPE.ELSEWHERE,
1318+
chatReport,
1319+
iouReport,
1320+
introSelected: undefined,
1321+
iouReportCurrentNextStepDeprecated: undefined,
1322+
currentUserAccountID: CARLOS_ACCOUNT_ID,
1323+
currentUserLogin: CARLOS_EMAIL,
1324+
betas: [CONST.BETAS.ALL],
1325+
isSelfTourViewed: false,
1326+
userBillingGracePeriodEnds: undefined,
1327+
amountOwed: 0,
1328+
chatReportPolicy: chatReportPolicyFromChat(chatReport),
1329+
conciergeReportID,
1330+
});
1331+
await waitForBatchedUpdates();
1332+
1333+
// Then getReportFromHoldRequestsOnyxData is not called at all because full pay skips the hold flow
1334+
expect(getReportFromHoldRequestsOnyxDataSpy).not.toHaveBeenCalled();
1335+
1336+
getReportFromHoldRequestsOnyxDataSpy.mockRestore();
1337+
});
12361338
});
12371339

12381340
describe('a expense chat with a cancelled payment', () => {
@@ -1338,6 +1440,7 @@ describe('actions/IOU/PayMoneyRequest', () => {
13381440
userBillingGracePeriodEnds: undefined,
13391441
amountOwed: 0,
13401442
chatReportPolicy: chatReportPolicyFromChat(chatReport),
1443+
conciergeReportID: undefined,
13411444
});
13421445
return waitForBatchedUpdates();
13431446
})
@@ -1563,6 +1666,7 @@ describe('actions/IOU/PayMoneyRequest', () => {
15631666
userBillingGracePeriodEnds: undefined,
15641667
amountOwed: 0,
15651668
chatReportPolicy: chatReportPolicyFromChat(chatReport),
1669+
conciergeReportID: undefined,
15661670
});
15671671
}
15681672
await waitForBatchedUpdates();

0 commit comments

Comments
 (0)