Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 3 additions & 6 deletions src/components/SettlementButton/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -562,14 +562,11 @@ function SettlementButton({
return;
}

const {paymentType, selectedPolicy, shouldSelectPaymentMethod} = getActivePaymentType(selectedOption, activeAdminPolicies, latestBankItem, policyIDKey);

// Payment type for 'Pay via workspace' option is "Elsewhere" but selected option points to one of workspaces where user is admin
const isPayingViaWorkspace = paymentType === CONST.IOU.PAYMENT_TYPE.ELSEWHERE && activeAdminPolicies.find((activeAdminPolicy) => activeAdminPolicy.id === selectedOption);
const {paymentType, policyFromPaymentMethod, policyFromContext, shouldSelectPaymentMethod} = getActivePaymentType(selectedOption, activeAdminPolicies, latestBankItem, policyIDKey);
const isPayingWithMethod = paymentType !== CONST.IOU.PAYMENT_TYPE.ELSEWHERE;

if ((!!selectedPolicy || shouldSelectPaymentMethod) && (isPayingWithMethod || isPayingViaWorkspace)) {
selectPaymentMethod(event, paymentType, triggerKYCFlow, selectedOption as PaymentMethod, selectedPolicy);
if ((!!policyFromPaymentMethod || shouldSelectPaymentMethod) && (isPayingWithMethod || !!policyFromPaymentMethod)) {
selectPaymentMethod(event, paymentType, triggerKYCFlow, selectedOption as PaymentMethod, policyFromPaymentMethod ?? policyFromContext);
return;
}

Expand Down
13 changes: 9 additions & 4 deletions src/libs/PaymentUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -220,13 +220,11 @@ const isSecondaryActionAPaymentOption = (item: PopoverMenuItem): item is Payment
};

/**
* Get the appropriate payment type, selected policy, and whether a payment method should be selected
* Get the appropriate payment type, policy from context (policy related to payment type), policy from payment method, and whether a payment method should be selected
* based on the provided payment method, active admin policies, and latest bank items.
*/
function getActivePaymentType(paymentMethod: string | undefined, activeAdminPolicies: Policy[], latestBankItems: BankAccountMenuItem[] | undefined, policyID?: string | undefined) {
const isPaymentMethod = Object.values(CONST.PAYMENT_METHODS).includes(paymentMethod as ValueOf<typeof CONST.PAYMENT_METHODS>);
// payment method is equal to policyID when user selects "Pay via workspace" option
const selectedPolicy = activeAdminPolicies.find((activePolicy) => activePolicy.id === policyID || activePolicy.id === paymentMethod);

let paymentType;
switch (paymentMethod) {
Expand All @@ -241,12 +239,19 @@ function getActivePaymentType(paymentMethod: string | undefined, activeAdminPoli
break;
}

// Policy related to the context ie: Policy related to opened chat
const policyFromContext = activeAdminPolicies.find((activePolicy) => activePolicy.id === policyID);

// Policy that is part of payment method ie: Policy when user presses on 'Pay via workspace' option
const policyFromPaymentMethod = activeAdminPolicies.find((activePolicy) => activePolicy.id === paymentMethod);

// When user explicitly selects "Pay Elsewhere" / "Mark as Paid", don't require payment method selection since payment happens outside of Expensify
const shouldSelectPaymentMethod = paymentMethod !== CONST.IOU.PAYMENT_TYPE.ELSEWHERE && (isPaymentMethod || !isEmpty(latestBankItems));

return {
paymentType,
selectedPolicy,
policyFromContext,
policyFromPaymentMethod,
shouldSelectPaymentMethod,
};
}
Expand Down
9 changes: 4 additions & 5 deletions src/libs/actions/Search.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1201,10 +1201,9 @@ function handleBulkPayItemSelected(params: {
showDelegateNoAccessModal,
confirmPayment,
} = params;
const {paymentType, selectedPolicy, shouldSelectPaymentMethod} = getActivePaymentType(item.key, activeAdminPolicies, latestBankItems, policy?.id);
const isPolicyBasedPaymentOption = activeAdminPolicies.some((activePolicy) => activePolicy.id === item.key);
const {paymentType, policyFromPaymentMethod, policyFromContext, shouldSelectPaymentMethod} = getActivePaymentType(item.key, activeAdminPolicies, latestBankItems, policy?.id);
// Early return if item is not a valid payment method and not a policy-based payment option
if (!isValidBulkPayOption(item) && !isPolicyBasedPaymentOption) {
if (!isValidBulkPayOption(item) && !policyFromPaymentMethod) {
return;
}

Expand All @@ -1228,12 +1227,12 @@ function handleBulkPayItemSelected(params: {
return;
}

if ((!!selectedPolicy || shouldSelectPaymentMethod) && item.key !== CONST.IOU.PAYMENT_TYPE.ELSEWHERE) {
if ((!!policyFromPaymentMethod || shouldSelectPaymentMethod) && item.key !== CONST.IOU.PAYMENT_TYPE.ELSEWHERE) {
triggerKYCFlow({
event: undefined,
iouPaymentType: paymentType,
paymentMethod: item.key as PaymentMethod,
policy: selectedPolicy,
policy: policyFromPaymentMethod ?? policyFromContext,
});

if (paymentType === CONST.IOU.PAYMENT_TYPE.EXPENSIFY || paymentType === CONST.IOU.PAYMENT_TYPE.VBBA) {
Expand Down
34 changes: 24 additions & 10 deletions tests/unit/PaymentUtilsTest.ts
Original file line number Diff line number Diff line change
Expand Up @@ -76,31 +76,35 @@ describe('PaymentUtils', () => {

expect(result.paymentType).toBe(CONST.IOU.PAYMENT_TYPE.EXPENSIFY);
expect(result.shouldSelectPaymentMethod).toBe(true);
expect(result.selectedPolicy).toBeUndefined();
expect(result.policyFromContext).toBeUndefined();
expect(result.policyFromPaymentMethod).toBeUndefined();
});

it('should return VBBA payment type when paymentMethod is BUSINESS_BANK_ACCOUNT', () => {
const result = getActivePaymentType(CONST.PAYMENT_METHODS.BUSINESS_BANK_ACCOUNT, [], undefined);

expect(result.paymentType).toBe(CONST.IOU.PAYMENT_TYPE.VBBA);
expect(result.shouldSelectPaymentMethod).toBe(true);
expect(result.selectedPolicy).toBeUndefined();
expect(result.policyFromContext).toBeUndefined();
expect(result.policyFromPaymentMethod).toBeUndefined();
});

it('should return ELSEWHERE payment type when paymentMethod is DEBIT_CARD', () => {
const result = getActivePaymentType(CONST.PAYMENT_METHODS.DEBIT_CARD, [], undefined);

expect(result.paymentType).toBe(CONST.IOU.PAYMENT_TYPE.ELSEWHERE);
expect(result.shouldSelectPaymentMethod).toBe(true);
expect(result.selectedPolicy).toBeUndefined();
expect(result.policyFromContext).toBeUndefined();
expect(result.policyFromPaymentMethod).toBeUndefined();
});

it('should return ELSEWHERE payment type when paymentMethod is undefined', () => {
const result = getActivePaymentType(undefined, [], undefined);

expect(result.paymentType).toBe(CONST.IOU.PAYMENT_TYPE.ELSEWHERE);
expect(result.shouldSelectPaymentMethod).toBe(false);
expect(result.selectedPolicy).toBeUndefined();
expect(result.policyFromContext).toBeUndefined();
expect(result.policyFromPaymentMethod).toBeUndefined();
});

it('should set shouldSelectPaymentMethod to true when latestBankItems is not empty', () => {
Expand All @@ -117,24 +121,34 @@ describe('PaymentUtils', () => {
expect(result.shouldSelectPaymentMethod).toBe(false);
});

it('should find selectedPolicy by policyID', () => {
it('should find policyFromContext by policyID', () => {
const result = getActivePaymentType(undefined, [randomPolicyA, randomPolicyB], undefined, randomPolicyA.id);

expect(result.selectedPolicy).toEqual(randomPolicyA);
expect(result.policyFromContext).toEqual(randomPolicyA);
expect(result.policyFromPaymentMethod).toBeUndefined();
});

it('should find selectedPolicy by paymentMethod when it matches policy id (Pay via workspace scenario)', () => {
it('should find policyFromPaymentMethod when paymentMethod matches policy id (Pay via workspace scenario)', () => {
const result = getActivePaymentType(randomPolicyB.id, [randomPolicyA, randomPolicyB], undefined);

expect(result.selectedPolicy).toEqual(randomPolicyB);
expect(result.policyFromPaymentMethod).toEqual(randomPolicyB);
expect(result.policyFromContext).toBeUndefined();
expect(result.paymentType).toBe(CONST.IOU.PAYMENT_TYPE.ELSEWHERE);
expect(result.shouldSelectPaymentMethod).toBe(false);
});

it('should return undefined selectedPolicy when no matching policy is found', () => {
it('should return both policyFromContext and policyFromPaymentMethod when both match', () => {
const result = getActivePaymentType(randomPolicyB.id, [randomPolicyA, randomPolicyB], undefined, randomPolicyA.id);

expect(result.policyFromContext).toEqual(randomPolicyA);
expect(result.policyFromPaymentMethod).toEqual(randomPolicyB);
});

it('should return undefined policies when no matching policy is found', () => {
const result = getActivePaymentType(undefined, [randomPolicyA], undefined, 'non-existent-policy');

expect(result.selectedPolicy).toBeUndefined();
expect(result.policyFromContext).toBeUndefined();
expect(result.policyFromPaymentMethod).toBeUndefined();
});
});
});
Loading