You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
[$175] Show the workspace default bank account first in the Pay menu #104909
Coming from customer feedback @trjExpensify and I were discussing, let's show the workspace's default bank account first in NewDot's Pay menu.
Details
When multiple eligible accounts belong to different entities, selecting the wrong account can require intercompany journal entries to correct the payment.
Today, admins who can pay a report see all their eligible business bank accounts matching the report currency in the Pay menu. The workspace's default account isn't prioritized in any way.
If the workspace's default bank account is among the eligible accounts, let's move it to the top of the account list. We can preserve the existing relative order of all remaining accounts.
If the workspace has no default bank account, or it isn't eligible, preserve the current order.
Keep the existing account eligibility and payment flow unchanged, including the ability to choose another eligible account introduced in #82853.
Example workspace bank account in workspace settings
Workspace bank account shown second in pay menu today
changed the title [-]Show the workspace default bank account first in the Pay menu[/-][+][$175] Show the workspace default bank account first in the Pay menu[/+]on Oct 23, 2026
Please re-state the problem that we are trying to solve in this issue.
The Pay menu lists every eligible business bank account in an arbitrary order. The workspace's default bank account is not shown first, so admins can easily pick the wrong account.
What is the root cause of that problem?
getBusinessBankAccountOptions builds the account list for the Pay menu. It filters accounts but never sorts them. The order comes from Object.values(bankAccountList) in formatPaymentMethods, which is just the key order of the Onyx bank account list. The function never receives the workspace's default account (policy.achAccount.bankAccountID), so it can't put it first.
Two places render this list, and both use the helper's order as-is:
What changes do you think we should make in order to solve the problem?
Add an optional defaultBankAccountID parameter to getBusinessBankAccountOptions. After the existing filter, if an option's methodID matches it, move that option to the front. Keep the rest in their current order. If there is no match, return the list unchanged. The filter (eligibility) stays exactly the same.
In SettlementButton, pass policy?.achAccount?.bankAccountID. The component already loads the policy with usePolicy(policyID) and reads achAccount elsewhere.
In useBulkPayOptions, read the selected policy's achAccount.bankAccountID with useOnyx (using a selector) on ${ONYXKEYS.COLLECTION.POLICY}${selectedPolicyID}. Pass it to the helper.
The payment flow does not change. Each option still carries its own methodID, so admins can still choose any other eligible account.
Tests: Add cases to the existing getBusinessBankAccountOptions block in tests/unit/PaymentUtilsTest.ts:
The default account is eligible: it moves to the top, and the others keep their order.
The default account is ineligible (for example, a different currency) or missing: the order does not change.
No default ID is given: the order does not change.
What alternative solutions did you explore? (Optional)
Reorder the list separately in SettlementButton and useBulkPayOptions. This repeats the same logic twice, so changing the shared helper is cleaner.
Reuse sortDefaultToTop in src/libs/ListUtils.tsx. It is typed for ListItem, needs styles, and adds a footer separator, so it doesn't fit dropdown options.
Open questions for the C+ reviewer
The helper treats LOCKED business accounts as eligible. A LOCKED workspace default would therefore move to the top as well. This matches "keep eligibility unchanged," but please confirm it is the intended behavior.
BankAccount.isDefault marks the user's personal wallet default, not the workspace default. It should not be used for this feature.
Next Steps for Contributor+ team: To accept:@MelvinBot implement [this](https://github.com/Expensify/App/issues/104909) to create a draft PR. To refine:@MelvinBot <your feedback> To reject: Explain why you are rejecting Melvin's proposal.
Please re-state the problem that we are trying to solve in this issue.
When an admin pays a report and multiple eligible business bank accounts exist, the Pay menu lists them in arbitrary (Onyx key) order. The workspace's default bank account is not prioritized, so admins can easily pick the wrong account - and correcting that requires intercompany journal entries.
What is the root cause of that problem?
The Pay menu's business bank account list is built by getBusinessBankAccountOptions in src/libs/PaymentUtils.ts. It filters accounts for eligibility but never sorts them: the final order comes from Object.values(bankAccountList) in formatPaymentMethods, i.e. raw Onyx key order. The helper never receives the workspace's default account (policy.achAccount.bankAccountID), so it has no way to prioritize it. Both consumers render the helper's order as-is: the report Pay button (src/components/SettlementButton/index.tsx) and the bulk-pay flow (src/hooks/useBulkPayOptions.ts).
What changes do you think we should make in order to solve the problem?
Thread the workspace's default bank account ID (policy.achAccount.bankAccountID) into getBusinessBankAccountOptions (and formatPaymentMethods if the partition lives there).
After eligibility filtering, stable-partition the list: if the default account is among the eligible accounts, move it to the front, preserving the existing relative order of all remaining accounts (per the issue's Details spec).
If the workspace has no default bank account, or the default is not eligible, preserve the current order exactly (no behavior change).
What alternative solutions did you explore? (Optional)
Sorting the entire list alphabetically: rejected - it changes the order of all accounts instead of the minimal re-order the issue asks for (default first, everything else untouched).
Changing formatPaymentMethods globally: rejected - that helper is shared; the re-order should be scoped to the Pay menu's eligible-account list only.
What automated tests can you add to prevent this from re-occurring?
Extend tests/unit/PaymentUtilsTest.ts:
default bank account among eligible accounts -> appears first, remaining accounts keep their relative order;
workspace has no default bank account -> order unchanged;
default bank account present but not eligible -> order unchanged;
eligibility filtering itself unchanged (no account added/removed by the change).
Please re-state the problem that we are trying to solve in this issue.
When an admin can pay a report using multiple eligible business bank accounts, the Pay menu currently preserves the underlying bank-account list order instead of prioritizing the workspace's configured default account.
This increases the chance of paying from the wrong entity/account and potentially requiring intercompany corrections afterward.
The requested behavior is intentionally narrow: when the workspace default bank account is already eligible for the payment, show it first while preserving the relative order of every other eligible account. If the default account is missing or ineligible, preserve today's ordering exactly.
What is the root cause of that problem?
getBusinessBankAccountOptions() in src/libs/PaymentUtils.ts currently receives only:
the formatted payment methods;
the payment currency.
It filters those methods for eligible business bank accounts and maps them directly to menu options, but it has no workspace-level defaultBankAccountID.
Therefore it cannot distinguish the workspace's default business account from the other eligible accounts.
Both payment entry points consume that ordering:
SettlementButton for an individual report;
useBulkPayOptions for bulk payments.
The underlying eligibility logic is already correct and should remain unchanged.
What changes do you think we should make in order to solve the problem?
Extend getBusinessBankAccountOptions() with an optional workspace defaultBankAccountID.
Keep the existing eligibility filter unchanged.
After generating the eligible options, locate the option whose methodID matches defaultBankAccountID.
If a matching eligible account exists and it is not already first, move only that option to index 0.
Preserve the relative order of every other option exactly.
If there is no default ID, or the default account is not part of the eligible list, return the existing order unchanged.
Pass the relevant workspace's policy.achAccount.bankAccountID from both consumers:
SettlementButton;
useBulkPayOptions.
This keeps the behavior scoped to the Pay menu and does not change account eligibility, payment execution, or the ability to choose another eligible business account.
What automated tests can you add to prevent this from re-occurring?
Extend the existing getBusinessBankAccountOptions tests to verify:
eligible default account in the middle of the list -> moved to the first position;
relative order of all non-default accounts is preserved;
default account already first -> ordering unchanged;
default account is absent -> ordering unchanged;
default account exists but is ineligible because of currency/state -> ordering unchanged;
no defaultBankAccountID -> behavior identical to today.
I would also cover both consumer paths to ensure the correct workspace default ID is supplied for single-report and bulk-pay flows.
Alternative solutions considered
Globally sorting formatted payment methods: rejected because it could alter ordering outside this Pay-menu requirement.
Sorting independently in each consumer: rejected because it duplicates behavior and makes the two payment paths easier to diverge.
Using a generic list sorting helper: unnecessary here; this is a simple stable promotion of one eligible account and should remain localized to the business-bank-account option helper.
Please re-state the problem that we are trying to solve in this issue.
When an admin opens the Pay menu on a report (or via Search bulk pay) and has access to multiple eligible business bank accounts matching the report currency, the accounts are listed in raw Onyx key order rather than prioritizing the workspace's designated default bank account (policy.achAccount.bankAccountID) first.
What is the root cause of that problem?
getBusinessBankAccountOptions in src/libs/PaymentUtils.ts filters formattedPaymentMethods for eligible business bank accounts matching the currency, but it neither accepts a default bank account ID nor prioritizes accounts. Because formatPaymentMethods iterates over Object.values(bankAccountList), the returned options remain in arbitrary Onyx key order.
Both consumers of getBusinessBankAccountOptions render the returned array order directly (both in the primary Pay dropdown and the secondary business bank account picker):
What changes do you think we should make in order to solve the problem?
1. Update getBusinessBankAccountOptions in src/libs/PaymentUtils.ts:
Add an optional defaultBankAccountID?: number parameter. After filtering and mapping the eligible business bank accounts:
If defaultBankAccountID !== undefined and an eligible option has option.methodID === defaultBankAccountID, move that option to index 0 while strictly preserving the relative order of all remaining accounts (stable partition).
If no matching default account is found, or if no default ID is provided, return the filtered list unmodified:
Currency Mismatch: If the workspace's default bank account is in USD but the report is in EUR, matchesCurrency(method, currency) safely filters it out during the initial filter phase, so it will never erroneously appear at the top.
No Default Configured: If the workspace has no ACH account (policy.achAccount is undefined), defaultBankAccountID is undefined and the list order is preserved identically to production.
Onyx Reactivity: If an admin updates the workspace default bank account in settings, Onyx reactive subscriptions in SettlementButton and useBulkPayOptions automatically trigger a re-render with the updated priority.
Locked Accounts: Per existing Expensify policy, LOCKED accounts that pass eligibility remain selectable; if a locked account is the default, it correctly surfaces at index 0 with the standard unlock flow intact.
What alternative solutions did you explore? (Optional)
Sorting in formatPaymentMethods: Rejected because formatPaymentMethods is a global payment utility used in wallet transfers and personal settings where workspace-specific prioritization does not belong.
Sorting independently in SettlementButton and useBulkPayOptions: Rejected because duplicating sorting logic across consumers violates DRY and risks visual divergence between single-report pay and bulk pay.
What automated tests can you add to prevent this from re-occurring?
Extend tests/unit/PaymentUtilsTest.ts:
it('should place the workspace default bank account first while preserving relative order of other accounts',()=>{constoptions=getBusinessBankAccountOptions(mockPaymentMethods,'USD',202);expect(options[0].methodID).toBe(202);expect(options.slice(1).map(o=>o.methodID)).toEqual([101,303]);});it('should preserve original order if default bank account is not eligible or currency does not match',()=>{constoptions=getBusinessBankAccountOptions(mockPaymentMethods,'EUR',202);// 202 is USDexpect(options.map(o=>o.methodID)).toEqual([101,303]);});it('should preserve original order if defaultBankAccountID is undefined',()=>{constoptions=getBusinessBankAccountOptions(mockPaymentMethods,'USD',undefined);expect(options.map(o=>o.methodID)).toEqual([101,202,303]);});
Please re-state the problem that we are trying to solve in this issue.
When paying a report from a workspace with multiple eligible business bank accounts (VBBA), the Pay dropdown menu displays the accounts in arbitrary order (governed by Onyx object key ordering) rather than placing the workspace's designated default bank account first.
What is the root cause of that problem?
In src/libs/PaymentUtils.ts, getBusinessBankAccountOptions() filters eligible business bank accounts by status and currency, but returns them in the order provided by formattedPaymentMethods (which derives from Object.values(bankAccountList)).
When rendering payment options in both SettlementButton (src/components/SettlementButton/index.tsx) and Search bulk pay (src/hooks/useBulkPayOptions.ts), getBusinessBankAccountOptions() is invoked without taking into account the workspace's default bank account ID (policy?.achAccount?.bankAccountID). Consequently, an admin paying an expense report must scan through the accounts, risking selecting the wrong account and triggering intercompany accounting corrections.
What changes do you think we should make in order to solve the problem?
Update getBusinessBankAccountOptions in src/libs/PaymentUtils.ts:
Add an optional defaultBankAccountID?: number parameter. After filtering eligible business bank accounts matching the report currency, sort the array so that the account matching defaultBankAccountID is placed at the top (index 0), preserving the relative order of the remaining accounts:
Pass default bank account in SettlementButton (src/components/SettlementButton/index.tsx): policy is already loaded via usePolicy(policyID). Pass policy?.achAccount?.bankAccountID to getBusinessBankAccountOptions:
Pass default bank account in useBulkPayOptions (src/hooks/useBulkPayOptions.ts):
Read selectedPolicy using useOnyx(${ONYXKEYS.COLLECTION.POLICY}${selectedPolicyID}) or pass policy?.achAccount?.bankAccountID:
No default set: If the workspace does not have an ACH account configured or achAccount.bankAccountID is undefined, the original list order is maintained without regressions.
Default account in different currency: If the workspace default bank account currency differs from the report currency, matchesCurrency(method, currency) filters it out; the remaining valid accounts are displayed safely.
Changing default account in settings: When an admin updates the workspace default bank account in Workspace Settings, Onyx reactively updates policy.achAccount, automatically re-sorting the dropdown on the next render.
What alternative solutions did you explore? (Optional)
Sorting directly in SettlementButton and useBulkPayOptions separately: Duplicates sorting logic in multiple places. Centralizing the prioritization in getBusinessBankAccountOptions guarantees consistency across single report settlements and Search bulk payments.
What automated tests can you add to prevent this from re-occurring?
Add unit tests in tests/unit/PaymentUtilsTest.ts:
Verify getBusinessBankAccountOptions places the account matching defaultBankAccountID as the first item when multiple eligible accounts exist.
Verify original ordering is preserved when defaultBankAccountID is omitted or does not match any eligible account.
Verify sorting handles mixed currencies correctly when the default bank account is filtered out due to currency mismatch.
Please re-state the problem that we are trying to solve in this issue.
In the NewDot Pay menu (both single report settlement in \SettlementButton\ and Search bulk pay in \useBulkPayOptions), eligible business bank accounts (VBBA) are displayed in an arbitrary order dictated by \Object.values(bankAccountList). The workspace's default bank account is not prioritized to the top, creating a risk that admins select the wrong account belonging to a different corporate entity and require intercompany journal entries to correct.
What is the root cause of that problem?
In \src/libs/PaymentUtils.ts, \getBusinessBankAccountOptions()\ filters eligible business accounts matching the report currency, but does not take into account the workspace's default bank account ID (\policy?.achAccount?.bankAccountID):
}
\ (Using \String(...)\ coercion ensures safe comparison whether the Onyx property is represented as a number or string. Using \splice\ + \unshift\ avoids unnecessary sorting and preserves 100% stable relative order).
Pass default bank account in \SettlementButton\ (\src/components/SettlementButton/index.tsx):
\policy\ is already loaded via \usePolicy(policyID). Pass \policy?.achAccount?.bankAccountID:
\\diff
Pass default bank account in \useBulkPayOptions\ (\src/hooks/useBulkPayOptions.ts):
Read \selectedPolicy\ via \useOnyx\ using the existing \selectedPolicyID\ prop:
\\diff
No default set / personal workspace: If \�chAccount.bankAccountID\ is undefined or null, the list order is preserved identically to current behavior.
Default account in different currency: If the workspace's default bank account currency does not match the report currency, \matchesCurrency(method, currency)\ filters it out cleanly; the remaining valid accounts are displayed in their current relative order.
Changing default account in settings: Updating the default account in Workspace Settings triggers Onyx reactivity on \policy.achAccount, automatically reordering the Pay menu immediately.
What alternative solutions did you explore? (Optional)
Using \Array.prototype.sort()\ with a comparator: While viable, sorting introduces (N \log N)$ overhead and can alter relative order of peer accounts depending on engine stability. Moving the matched element via \splice\ + \unshift\ is (N)$ and strictly preserves the existing relative order of all other accounts as requested.
What automated tests can you add to prevent this from re-occurring?
Add unit tests in \ ests/unit/PaymentUtilsTest.ts:
Verify \getBusinessBankAccountOptions\ places the account matching \defaultBankAccountID\ at index 0 when multiple eligible accounts exist.
Verify the relative order of all non-default accounts is preserved.
Verify original ordering is retained when \defaultBankAccountID\ is undefined or does not match any eligible account.
Verify behavior when the default account currency does not match the requested currency.
Activity
melvin-bot commentedon Oct 23, 2026
Triggered auto assignment to Contributor-plus team member for initial proposal review - @daledah (
External)[-]Show the workspace default bank account first in the Pay menu[/-][+][$175] Show the workspace default bank account first in the Pay menu[/+]melvin-bot commentedon Oct 23, 2026
Job added to Upwork: https://www.upwork.com/jobs/~022113728112261071671
joekaufmanexpensify commentedon Oct 23, 2026
@MelvinBot could you please draft a proposal for this issue using Expensify's standard guidelines?
MelvinBot commentedon Oct 23, 2026
Proposal
Please re-state the problem that we are trying to solve in this issue.
The Pay menu lists every eligible business bank account in an arbitrary order. The workspace's default bank account is not shown first, so admins can easily pick the wrong account.
What is the root cause of that problem?
getBusinessBankAccountOptionsbuilds the account list for the Pay menu. It filters accounts but never sorts them. The order comes fromObject.values(bankAccountList)informatPaymentMethods, which is just the key order of the Onyx bank account list. The function never receives the workspace's default account (policy.achAccount.bankAccountID), so it can't put it first.Two places render this list, and both use the helper's order as-is:
SettlementButton).useBulkPayOptions).Code references
Object.values(bankAccountList): src/libs/PaymentUtils.ts:116-155What changes do you think we should make in order to solve the problem?
defaultBankAccountIDparameter togetBusinessBankAccountOptions. After the existing filter, if an option'smethodIDmatches it, move that option to the front. Keep the rest in their current order. If there is no match, return the list unchanged. The filter (eligibility) stays exactly the same.SettlementButton, passpolicy?.achAccount?.bankAccountID. The component already loads the policy withusePolicy(policyID)and readsachAccountelsewhere.useBulkPayOptions, read the selected policy'sachAccount.bankAccountIDwithuseOnyx(using a selector) on${ONYXKEYS.COLLECTION.POLICY}${selectedPolicyID}. Pass it to the helper.methodID, so admins can still choose any other eligible account.Tests: Add cases to the existing
getBusinessBankAccountOptionsblock intests/unit/PaymentUtilsTest.ts:What alternative solutions did you explore? (Optional)
SettlementButtonanduseBulkPayOptions. This repeats the same logic twice, so changing the shared helper is cleaner.sortDefaultToTopinsrc/libs/ListUtils.tsx. It is typed forListItem, needsstyles, and adds a footer separator, so it doesn't fit dropdown options.Open questions for the C+ reviewer
LOCKEDbusiness accounts as eligible. ALOCKEDworkspace default would therefore move to the top as well. This matches "keep eligibility unchanged," but please confirm it is the intended behavior.BankAccount.isDefaultmarks the user's personal wallet default, not the workspace default. It should not be used for this feature.Next Steps for Contributor+ team:
To accept:
@MelvinBot implement [this](https://github.com/Expensify/App/issues/104909)to create a draft PR.To refine:
@MelvinBot <your feedback>To reject: Explain why you are rejecting Melvin's proposal.
view run
khizzcr7 commentedon Oct 24, 2026
Proposal
Please re-state the problem that we are trying to solve in this issue.
When an admin pays a report and multiple eligible business bank accounts exist, the Pay menu lists them in arbitrary (Onyx key) order. The workspace's default bank account is not prioritized, so admins can easily pick the wrong account - and correcting that requires intercompany journal entries.
What is the root cause of that problem?
The Pay menu's business bank account list is built by
getBusinessBankAccountOptionsinsrc/libs/PaymentUtils.ts. It filters accounts for eligibility but never sorts them: the final order comes fromObject.values(bankAccountList)informatPaymentMethods, i.e. raw Onyx key order. The helper never receives the workspace's default account (policy.achAccount.bankAccountID), so it has no way to prioritize it. Both consumers render the helper's order as-is: the report Pay button (src/components/SettlementButton/index.tsx) and the bulk-pay flow (src/hooks/useBulkPayOptions.ts).What changes do you think we should make in order to solve the problem?
policy.achAccount.bankAccountID) intogetBusinessBankAccountOptions(andformatPaymentMethodsif the partition lives there).What alternative solutions did you explore? (Optional)
formatPaymentMethodsglobally: rejected - that helper is shared; the re-order should be scoped to the Pay menu's eligible-account list only.What automated tests can you add to prevent this from re-occurring?
Extend
tests/unit/PaymentUtilsTest.ts:hgreco85 commentedon Oct 24, 2026
Proposal
Please re-state the problem that we are trying to solve in this issue.
When an admin can pay a report using multiple eligible business bank accounts, the Pay menu currently preserves the underlying bank-account list order instead of prioritizing the workspace's configured default account.
This increases the chance of paying from the wrong entity/account and potentially requiring intercompany corrections afterward.
The requested behavior is intentionally narrow: when the workspace default bank account is already eligible for the payment, show it first while preserving the relative order of every other eligible account. If the default account is missing or ineligible, preserve today's ordering exactly.
What is the root cause of that problem?
getBusinessBankAccountOptions()insrc/libs/PaymentUtils.tscurrently receives only:It filters those methods for eligible business bank accounts and maps them directly to menu options, but it has no workspace-level
defaultBankAccountID.Therefore it cannot distinguish the workspace's default business account from the other eligible accounts.
Both payment entry points consume that ordering:
SettlementButtonfor an individual report;useBulkPayOptionsfor bulk payments.The underlying eligibility logic is already correct and should remain unchanged.
What changes do you think we should make in order to solve the problem?
getBusinessBankAccountOptions()with an optional workspacedefaultBankAccountID.methodIDmatchesdefaultBankAccountID.policy.achAccount.bankAccountIDfrom both consumers:SettlementButton;useBulkPayOptions.This keeps the behavior scoped to the Pay menu and does not change account eligibility, payment execution, or the ability to choose another eligible business account.
What automated tests can you add to prevent this from re-occurring?
Extend the existing
getBusinessBankAccountOptionstests to verify:defaultBankAccountID-> behavior identical to today.I would also cover both consumer paths to ensure the correct workspace default ID is supplied for single-report and bulk-pay flows.
Alternative solutions considered
Globally sorting formatted payment methods: rejected because it could alter ordering outside this Pay-menu requirement.
Sorting independently in each consumer: rejected because it duplicates behavior and makes the two payment paths easier to diverge.
Using a generic list sorting helper: unnecessary here; this is a simple stable promotion of one eligible account and should remain localized to the business-bank-account option helper.
Enes2553 commentedon Oct 24, 2026
Proposal
Please re-state the problem that we are trying to solve in this issue.
When an admin opens the Pay menu on a report (or via Search bulk pay) and has access to multiple eligible business bank accounts matching the report currency, the accounts are listed in raw Onyx key order rather than prioritizing the workspace's designated default bank account (
policy.achAccount.bankAccountID) first.What is the root cause of that problem?
getBusinessBankAccountOptionsinsrc/libs/PaymentUtils.tsfiltersformattedPaymentMethodsfor eligible business bank accounts matching the currency, but it neither accepts a default bank account ID nor prioritizes accounts. BecauseformatPaymentMethodsiterates overObject.values(bankAccountList), the returned options remain in arbitrary Onyx key order.Both consumers of
getBusinessBankAccountOptionsrender the returned array order directly (both in the primary Pay dropdown and the secondary business bank account picker):src/components/SettlementButton/index.tsx(line 270)src/hooks/useBulkPayOptions.ts(line 130)What changes do you think we should make in order to solve the problem?
1. Update
getBusinessBankAccountOptionsinsrc/libs/PaymentUtils.ts:Add an optional
defaultBankAccountID?: numberparameter. After filtering and mapping the eligible business bank accounts:defaultBankAccountID !== undefinedand an eligible option hasoption.methodID === defaultBankAccountID, move that option to index0while strictly preserving the relative order of all remaining accounts (stable partition).2. Pass workspace default bank account in
src/components/SettlementButton/index.tsx:policyis already subscribed and available viausePolicy(policyID). Passpolicy?.achAccount?.bankAccountIDtogetBusinessBankAccountOptions:3. Pass selected policy default bank account in
src/hooks/useBulkPayOptions.ts:Subscribe to the selected policy's
achAccount.bankAccountIDusinguseOnyxselector and pass it:4. Edge Cases & Resilience Analysis:
matchesCurrency(method, currency)safely filters it out during the initial filter phase, so it will never erroneously appear at the top.policy.achAccountis undefined),defaultBankAccountIDis undefined and the list order is preserved identically to production.SettlementButtonanduseBulkPayOptionsautomatically trigger a re-render with the updated priority.LOCKEDaccounts that pass eligibility remain selectable; if a locked account is the default, it correctly surfaces at index0with the standard unlock flow intact.What alternative solutions did you explore? (Optional)
formatPaymentMethods: Rejected becauseformatPaymentMethodsis a global payment utility used in wallet transfers and personal settings where workspace-specific prioritization does not belong.SettlementButtonanduseBulkPayOptions: Rejected because duplicating sorting logic across consumers violates DRY and risks visual divergence between single-report pay and bulk pay.What automated tests can you add to prevent this from re-occurring?
Extend
tests/unit/PaymentUtilsTest.ts:Contributor details
Your Expensify account email: enesbilalolgun0@gmail.com
Upwork Profile Link: https://www.upwork.com/freelancers/~010415b62c29eb990f
melvin-bot commentedon Oct 24, 2026
✅ Contributor details stored successfully. Thank you for contributing to Expensify!
camesenin commentedon Oct 24, 2026
Proposal
Please re-state the problem that we are trying to solve in this issue.
When paying a report from a workspace with multiple eligible business bank accounts (VBBA), the Pay dropdown menu displays the accounts in arbitrary order (governed by Onyx object key ordering) rather than placing the workspace's designated default bank account first.
What is the root cause of that problem?
In
src/libs/PaymentUtils.ts,getBusinessBankAccountOptions()filters eligible business bank accounts by status and currency, but returns them in the order provided byformattedPaymentMethods(which derives fromObject.values(bankAccountList)).When rendering payment options in both
SettlementButton(src/components/SettlementButton/index.tsx) and Search bulk pay (src/hooks/useBulkPayOptions.ts),getBusinessBankAccountOptions()is invoked without taking into account the workspace's default bank account ID (policy?.achAccount?.bankAccountID). Consequently, an admin paying an expense report must scan through the accounts, risking selecting the wrong account and triggering intercompany accounting corrections.What changes do you think we should make in order to solve the problem?
Update
getBusinessBankAccountOptionsinsrc/libs/PaymentUtils.ts:Add an optional
defaultBankAccountID?: numberparameter. After filtering eligible business bank accounts matching the report currency, sort the array so that the account matchingdefaultBankAccountIDis placed at the top (index 0), preserving the relative order of the remaining accounts:Pass default bank account in
SettlementButton(src/components/SettlementButton/index.tsx):policyis already loaded viausePolicy(policyID). Passpolicy?.achAccount?.bankAccountIDtogetBusinessBankAccountOptions:Pass default bank account in
useBulkPayOptions(src/hooks/useBulkPayOptions.ts):Read
selectedPolicyusinguseOnyx(${ONYXKEYS.COLLECTION.POLICY}${selectedPolicyID})or passpolicy?.achAccount?.bankAccountID:User Mutation & Edge Cases:
achAccount.bankAccountIDis undefined, the original list order is maintained without regressions.matchesCurrency(method, currency)filters it out; the remaining valid accounts are displayed safely.policy.achAccount, automatically re-sorting the dropdown on the next render.What alternative solutions did you explore? (Optional)
SettlementButtonanduseBulkPayOptionsseparately: Duplicates sorting logic in multiple places. Centralizing the prioritization ingetBusinessBankAccountOptionsguarantees consistency across single report settlements and Search bulk payments.What automated tests can you add to prevent this from re-occurring?
Add unit tests in
tests/unit/PaymentUtilsTest.ts:getBusinessBankAccountOptionsplaces the account matchingdefaultBankAccountIDas the first item when multiple eligible accounts exist.defaultBankAccountIDis omitted or does not match any eligible account.Contributor details
Your Expensify account email: camesenin@gmail.com
Upwork Profile Link: https://www.upwork.com/freelancers/~01b60d704ba377be83
melvin-bot commentedon Oct 24, 2026
✅ Contributor details stored successfully. Thank you for contributing to Expensify!
huynhnhatquandongnai-source commentedon Oct 24, 2026
Contributor details
Your Expensify account email: huynhnhatquan.dongnai@gmail.com
Upwork Profile Link: https://www.upwork.com/freelancers/~0184a035069597c5a9
Proposal
Please re-state the problem that we are trying to solve in this issue.
In the NewDot Pay menu (both single report settlement in \SettlementButton\ and Search bulk pay in \useBulkPayOptions), eligible business bank accounts (VBBA) are displayed in an arbitrary order dictated by \Object.values(bankAccountList). The workspace's default bank account is not prioritized to the top, creating a risk that admins select the wrong account belonging to a different corporate entity and require intercompany journal entries to correct.
What is the root cause of that problem?
In \src/libs/PaymentUtils.ts, \getBusinessBankAccountOptions()\ filters eligible business accounts matching the report currency, but does not take into account the workspace's default bank account ID (\policy?.achAccount?.bankAccountID):
Both consumers invoke \getBusinessBankAccountOptions\ without supplying the default account:
What changes do you think we should make in order to solve the problem?
**Update \getBusinessBankAccountOptions\ in \src/libs/PaymentUtils.ts**:
Add an optional \defaultBankAccountID?: number | string\ parameter. If provided, locate the default account using \indIndex\ and move it to index 0, guaranteeing linear (N)$ performance and strictly preserving the relative order of all remaining accounts:
\\ ypescript
function getBusinessBankAccountOptions(
formattedPaymentMethods: PaymentMethod[],
currency?: string,
defaultBankAccountID?: number | string,
): BusinessBankAccountOption[] {
const options = formattedPaymentMethods
.filter((method) => {
if (!isAccountData(method?.accountData)) {
return false;
}
const accountData = method.accountData;
const isPartiallySetup = isBankAccountPartiallySetup(accountData.state);
return (
accountData.type === CONST.BANK_ACCOUNT.TYPE.BUSINESS &&
(accountData.state === CONST.BANK_ACCOUNT.STATE.OPEN || accountData.state === CONST.BANK_ACCOUNT.STATE.LOCKED) &&
method?.methodID != null &&
!isPartiallySetup &&
matchesCurrency(method, currency)
);
})
.map((formattedPaymentMethod) => ({
text: formattedPaymentMethod?.title ?? '',
description: formattedPaymentMethod?.description ?? '',
icon: formattedPaymentMethod?.icon,
iconStyles: formattedPaymentMethod?.iconStyles,
iconSize: formattedPaymentMethod?.iconSize,
methodID: formattedPaymentMethod?.methodID,
}));
}
\
(Using \String(...)\ coercion ensures safe comparison whether the Onyx property is represented as a number or string. Using \splice\ + \unshift\ avoids unnecessary sorting and preserves 100% stable relative order).
Pass default bank account in \SettlementButton\ (\src/components/SettlementButton/index.tsx):
\policy\ is already loaded via \usePolicy(policyID). Pass \policy?.achAccount?.bankAccountID:
\\diff
\\
Pass default bank account in \useBulkPayOptions\ (\src/hooks/useBulkPayOptions.ts):
Read \selectedPolicy\ via \useOnyx\ using the existing \selectedPolicyID\ prop:
\\diff
\\
Edge cases handled:
What alternative solutions did you explore? (Optional)
Using \Array.prototype.sort()\ with a comparator: While viable, sorting introduces (N \log N)$ overhead and can alter relative order of peer accounts depending on engine stability. Moving the matched element via \splice\ + \unshift\ is (N)$ and strictly preserves the existing relative order of all other accounts as requested.
What automated tests can you add to prevent this from re-occurring?
Add unit tests in \ ests/unit/PaymentUtilsTest.ts:
melvin-bot commentedon Oct 24, 2026
✅ Contributor details stored successfully. Thank you for contributing to Expensify!