Skip to content

[Due for payment 2025-11-06] [$250] Wallet - Blank popup on selecting Transfer balance option when BA has Business bank account #71437

Closed

Description

@nlemma

If you haven’t already, check out our contributing guidelines for onboarding and email contributors@expensify.com to request to join our Slack channel!


Version Number: v9.2.19-0
Reproducible in staging?: Yes
Reproducible in production?: Yes
If this was caught during regression testing, add the test name, ID and link from TestRail: Exploratory
Email or phone of affected tester (no customers): kiatest.78+ck92725@gmail.com
Issue reported by: Applause Internal Team
Device used: Windows 11/Chrome
App Component: User Settings

Action Performed:

Precondition: User logged in with gmail account & has created new workspace

  1. Navigate to staging.new.expensify.com
  2. Navigate to WS settings >> Workflows >> Make & track payments
  3. Add VBA (Regions bank) going through plaid flow
  4. Navigate to Accounts >> Wallet >> click Enable wallet
  5. Go through the enable wallet flow
  6. Tap on Transfer balance option
  7. Observe blank popup displayed

Expected Result:

Transfer balance page RHP (or if popup appears, it should display relevant info) should be displayed when wallet has added business bank account

Actual Result:

Blank popup on selecting Transfer balance option when BA has only Business bank account. Issue happens when wallet has only business bank account

Note: If bank account has both Personal BA & Business BA, transfer balance RHP opens as expected on selecting transfer balance option.

Workaround:

Unknown

Platforms:

  • Android: App
  • Android: mWeb Chrome
  • iOS: App
  • iOS: mWeb Safari
  • iOS: mWeb Chrome
  • Windows: Chrome
  • MacOS: Chrome / Safari
  • MacOS: Desktop

Screenshots/Videos

Bug6958169_1759029116764.27.09.2025_13.18.46_REC51.mp4

View all open jobs on GitHub

Upwork Automation - Do Not Edit
  • Upwork Job URL: https://www.upwork.com/jobs/~021972730652326576464
  • Upwork Job ID: 1972730652326576464
  • Last Price Increase: 2025-10-13
  • Automatic offers:
    • gijoe0295 | Contributor | 109146761
Issue OwnerCurrent Issue Owner: @lschurr

Activity

  1. added
    BugSomething is broken. Auto assigns a BugZero manager.
    on Sep 28, 2025
  2. melvin-bot commented on Sep 28, 2025

    @melvin-bot

    Triggered auto assignment to @lschurr (Bug), see https://stackoverflow.com/c/expensify/questions/14418 for more details. Please add this bug to a GH project, as outlined in the SO.

  3. gijoe0295 commented on Sep 28, 2025

    @gijoe0295
    Contributor

    Proposal

    Please re-state the problem that we are trying to solve in this issue.

    Blank popup on selecting Transfer balance option when BA has Business bank account

    What is the root cause of that problem?

    BaseKYCWall checks if you had a valid personal bank account by hasExpensifyPaymentMethod here to display the add payment method menu if you don't. But since the linked account is a business one, the AddPaymentMethodMenu shows nothing because all the conditions here fails.

    However the problem here is not about the AddPaymentMethodMenu shows nothing but that the add bank account step in enable wallet flow is mistakenly skipped because it incorrectly assumes that user already has a valid personal bank account even though he only has a business account.

    const currentStep = isEmptyObject(bankAccountList) ? CONST.WALLET.STEP.ADD_BANK_ACCOUNT : userWallet?.currentStep || CONST.WALLET.STEP.ADDITIONAL_DETAILS;

    Taking a look at the condition to render initial step in EnablePaymentsPage above, we incorrectly assume that if bankAccountList is not empty, the initial step will be ADDITIONAL_DETAILS (personal info step) => the add bank account step is skipped. But bankAccountList can have accounts of either BUSINESS or PERSONAL type. To enable the wallet, we must have a PERSONAL one. If you only have a business bank account, you still need to go through the add bank account step in enable wallet flow.

    What changes do you think we should make in order to solve the problem?

    const currentStep = isEmptyObject(bankAccountList) ? CONST.WALLET.STEP.ADD_BANK_ACCOUNT : userWallet?.currentStep || CONST.WALLET.STEP.ADDITIONAL_DETAILS;

    Modify this condition to check if user actually has a valid personal bank account using hasExpensifyPaymentMethod.

    So it would become:

    const hasActivatedWallet = ([CONST.WALLET.TIER_NAME.GOLD, CONST.WALLET.TIER_NAME.PLATINUM]).includes(userWallet.tierName);
    const enablePaymentsStep = !hasExpensifyPaymentMethod(paymentCardList, bankAccountList, hasActivatedWallet) ? CONST.WALLET.STEP.ADD_BANK_ACCOUNT : userWallet?.currentStep || CONST.WALLET.STEP.ADDITIONAL_DETAILS;

    What specific scenarios should we cover in automated tests to prevent reintroducing this issue in the future?

    None

    What alternative solutions did you explore? (Optional)

    None

  4. ShridharGoel commented on Sep 29, 2025

    @ShridharGoel
    Contributor

    Proposal

    Please re-state the problem that we are trying to solve in this issue.

    The Wallet › Transfer balance entry point renders a blank right-hand panel on web when a workspace has enabled the business wallet flow but the user only linked a business bank account. Transfer should still be possible for business-only wallets, so the RN/web page must render their balance and payout options instead of blocking them behind an empty KYC wall.

    What is the root cause of that problem?

    The helper that decides whether a user has an eligible payout method, hasExpensifyPaymentMethod, only treated personal bank accounts as valid

    * Check to see if user has either a debit card or personal US bank account added that can be used with a wallet.
    */
    function hasExpensifyPaymentMethod(fundList: Record<string, Fund>, bankAccountList: Record<string, BankAccount>, shouldIncludeDebitCard = true): boolean {
    const validBankAccount = Object.values(bankAccountList).some((bankAccountJSON) => {
    const bankAccount = new BankAccountModel(bankAccountJSON);
    return (
    bankAccount.getPendingAction() !== CONST.RED_BRICK_ROAD_PENDING_ACTION.DELETE &&
    bankAccount.isOpen() &&
    bankAccount.getType() === CONST.BANK_ACCOUNT.TYPE.PERSONAL &&
    bankAccount?.getCountry() === CONST.COUNTRY.US
    );
    });

    Because the KYC wall’s transfer-balance gate reuses that helper, it still rejected business-only customers even after the wallet had been upgraded

    // Check to see if user has a valid payment method on file and display the add payment popover if they don't
    if (
    (isExpenseReport && reimbursementAccount?.achData?.state !== CONST.BANK_ACCOUNT.STATE.OPEN) ||
    (!isExpenseReport && bankAccountList !== null && !hasExpensifyPaymentMethod(paymentCardList, bankAccountList, shouldIncludeDebitCard))
    ) {
    Log.info('[KYC Wallet] User does not have valid payment method');
    if (!shouldIncludeDebitCard) {
    selectPaymentMethod(CONST.PAYMENT_METHODS.PERSONAL_BANK_ACCOUNT);
    return;
    }
    // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing
    if (paymentMethod || policy) {
    setShouldShowAddPaymentMenu(false);
    selectPaymentMethod(paymentMethod, policy);
    return;
    }
    if (iouPaymentType && isExpenseReport) {
    setShouldShowAddPaymentMenu(false);
    selectPaymentMethod(CONST.PAYMENT_METHODS.BUSINESS_BANK_ACCOUNT);
    return;
    }
    const clickedElementLocation = getClickedTargetLocation(targetElement as HTMLDivElement);
    const position = getAnchorPosition(clickedElementLocation);
    setPositionAddPaymentMenu(position);
    setShouldShowAddPaymentMenu(true);
    return;
    }

    As a result, both the Wallet page and the stand-alone transfer view bailed out early, leaving users with an empty screen.

    What changes do you think we should make in order to solve the problem?

    We can allow consumers of the helper method hasExpensifyPaymentMethod to opt into business-bank-account eligibility when they explicitly need to support that flow and pass the new flag from the transfer UI and its KYC gate.

    // src/libs/PaymentUtils.ts
    function hasExpensifyPaymentMethod(
        fundList: Record<string, Fund>,
        bankAccountList: Record<string, BankAccount>,
        shouldIncludeDebitCard = true,
        shouldIncludeBusinessBankAccount = false,
    ): boolean {
        const validBankAccount = Object.values(bankAccountList).some((bankAccountJSON) => {
            const bankAccount = new BankAccountModel(bankAccountJSON);
    
            const isSupportedType =
                bankAccount.getType() === CONST.BANK_ACCOUNT.TYPE.PERSONAL ||
                (shouldIncludeBusinessBankAccount && bankAccount.getType() === CONST.BANK_ACCOUNT.TYPE.BUSINESS);
    
            return (
                bankAccount.getPendingAction() !== CONST.RED_BRICK_ROAD_PENDING_ACTION.DELETE &&
                bankAccount.isOpen() &&
                isSupportedType &&
                bankAccount?.getCountry() === CONST.COUNTRY.US
            );
        });
    
        const validDebitCard = Object.values(fundList).some((card) => card?.accountData?.additionalData?.isP2PDebitCard ?? false);
    
        return validBankAccount || (shouldIncludeDebitCard && validDebitCard);
    }
    // src/pages/settings/Wallet/TransferBalancePage.tsx
    const shouldShowTransferView =
        hasExpensifyPaymentMethod(paymentCardList, bankAccountList ?? {}, true, true) && TRANSFER_TIER_NAMES.includes(userWallet?.tierName ?? '');
    // src/components/KYCWall/BaseKYCWall.tsx
    const shouldIncludeBusinessBankAccount = currentSource === CONST.KYC_WALL_SOURCE.TRANSFER_BALANCE;
    
    if (
        (isExpenseReport && reimbursementAccount?.achData?.state !== CONST.BANK_ACCOUNT.STATE.OPEN) ||
        (!isExpenseReport &&
            bankAccountList !== null &&
            !hasExpensifyPaymentMethod(paymentCardList, bankAccountList, shouldIncludeDebitCard, shouldIncludeBusinessBankAccount))
    ) {
        Log.info('[KYC Wallet] User does not have valid payment method');
        ...
    }
    // src/types/onyx/BankAccount.ts
    accountType?: typeof CONST.PAYMENT_METHODS.PERSONAL_BANK_ACCOUNT | typeof CONST.PAYMENT_METHODS.BUSINESS_BANK_ACCOUNT;
    Screen.Recording.2025-09-29.at.11.25.45.AM.mov

    Together, these changes let the transfer flow short-circuit in favour of business banking whenever the source is the wallet transfer entry point while keeping existing behaviour intact for the other KYC wall use cases.

    What specific scenarios should we cover in automated tests to prevent reintroducing this issue in the future?

    Unit test for hasExpensifyPaymentMethod that exercises personal-only, debit-only, and business-only input combinations when the business flag is on or off.

  5. added
    ExternalAdded to denote the issue can be worked on by a contributor
    on Sep 29, 2025
  6. changed the title [-]Wallet - Blank popup on selecting Transfer balance option when BA has Business bank account[/-] [+][$250] Wallet - Blank popup on selecting Transfer balance option when BA has Business bank account[/+] on Sep 29, 2025
  7. melvin-bot commented on Sep 29, 2025

    @melvin-bot
  8. added
    Help WantedApply this label when an issue is open to proposals by contributors
    on Sep 29, 2025
  9. melvin-bot commented on Sep 29, 2025

    @melvin-bot

    Triggered auto assignment to Contributor-plus team member for initial proposal review - @ahmedGaber93 (External)

  10. moved this to Bugs and Follow Up Issues in #expensify-bugson Oct 3, 2025
  11. ShridharGoel commented on Oct 5, 2025

    @ShridharGoel
    Contributor

    Do we have any updates on this?

  12. 41 remaining items

  13. lschurr commented on Nov 5, 2025

    @lschurr
    Contributor

    @ahmedGaber93 could you post the checklist here?

  14. gijoe0295 commented on Nov 5, 2025

    @gijoe0295
    Contributor

    @lschurr @joekaufmanexpensify I'm being paid via NewDot now. Given the increased scope (#71437 (comment) and #71437 (comment)), we can consider to increase the compensation. I think $375 makes sense as they seem not too complicated.

    cc @ahmedGaber93

  15. ahmedGaber93 commented on Nov 9, 2025

    @ahmedGaber93
    Contributor

    BugZero Checklist:

    Regression Test Proposal

    Precondition:

    • Have a business bank account connected to a workspace (open workspace settings -> Workflows > Add bank account if needed)
    • Have no connected personal bank account (shows in Wallet -> Bank accounts section)

    Test:

    1. Open Wallet > Enable wallet
    2. Verify you're asked to add a (personal) bank account
    3. Go through the enable wallet flow
    4. Tap on Transfer balance option
    5. Verify Transfer balance page displays

    Do we agree 👍 or 👎

  16. ahmedGaber93 commented on Nov 9, 2025

    @ahmedGaber93
    Contributor

    @lschurr The checklist have been completed.

  17. mallenexpensify commented on Nov 10, 2025

    @mallenexpensify
    Contributor

    we can consider to increase the compensation. I think $375 makes sense as they seem not too complicated.

    @youssef-lr are you cool with the above? I appreciate the additional work being done, especially if it keeps us from having a separate bug we'd need to fix later. The only reason to possibly not increase the rate would be if the additional work was minuscule or if it was intended to be included from what's outlined in the OP.

  18. lschurr commented on Nov 12, 2025

    @lschurr
    Contributor

    @youssef-lr are you able to confirm here?

  19. youssef-lr commented on Nov 12, 2025

    @youssef-lr
    Contributor

    Yeah I think as per our instructions for additional fixes, we can add $75 to the original price.

    he standard payout for a small improvement on top of the original fix is 25% (rounded up to $75 if it’s a $250 job) and the submitter of the first proposal should include the later improvement in their PR.

  20. lschurr commented on Nov 13, 2025

    @lschurr
    Contributor

    Payment Summary

    Contributor: @gijoe0295 due $325 via NewDot
    Contributor+: @ahmedGaber93 due $325 via NewDot

  21. moved this from Bugs and Follow Up Issues to Done in #expensify-bugson Nov 13, 2025
  22. trjExpensify commented on Nov 17, 2025

    @trjExpensify
    Contributor

    approved $325 for @ahmedGaber93.

  23. JmillsExpensify commented on Nov 26, 2025

    @JmillsExpensify
    Contributor

    $325 approved for @gijoe0295

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Labels

Awaiting PaymentAuto-added when associated PR is deployed to productionBugSomething is broken. Auto assigns a BugZero manager.DailyKSv2ExternalAdded to denote the issue can be worked on by a contributor

Type

No type

Projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions