Skip to content

[CFI] [$175] Show the Reimbursable toggle on company card expenses when the card feed is set to Do Not Force #103341

Open

Description

@melvin-bot

Coming from here, we want to show the Reimbursable toggle on company card expenses when the card feed allows the value to change, matching cash expenses and company card expenses in Expensify Classic.

Details

  • Today, New Expensify hides the Reimbursable toggle on every company card expense in the expense detail view and in bulk edit. Expensify Classic shows the toggle when the card feed is set to either Do Not Force option, but customers on those settings can't change reimbursability on card expenses in New Expensify.
  • The feed's Reimbursable setting doesn't exist in New Expensify yet. This issue doesn't need it: the toggle uses the forceReimbursable value stamped on each card expense at import.
  • Adding the feed setting to New Expensify is tracked separately: [CFI] Add a Reimbursable setting to company card feed settings in New Expensify #103342
  • Forced value: We will use the forceReimbursable value stamped on each card expense at import to decide whether the toggle appears. Changing the feed setting only affects expenses imported afterward, matching Classic.
    • Force No (force_no, default): Toggle hidden.
    • Force Yes (force_yes): Toggle hidden.
    • Do Not Force (Defaults to Reimbursable) (default_yes): Toggle shown and editable.
    • Do Not Force (Defaults to Non-Reimbursable) (default_no, or legacy none): Toggle shown and editable.
  • For new card transactions, the feed setting sets the starting value. Do Not Force (Defaults to Reimbursable) starts as reimbursable, and Do Not Force (Defaults to Non-Reimbursable) starts as non-reimbursable.
  • The Do Not Force settings don't restrict edits after an expense is imported, so users can change the value on each expense. The toggle shows each expense's current value.
  • The toggle uses the existing Reimbursable label, matching cash expenses in NewDot today.
  • Bulk edit expense: We will show the Reimbursable row when none of the selected expenses has a forced value stamped on it. Selections that mix cash and non-forced card expenses show the row. If any selected expense is forced to reimbursable/non-reimbursable, the row is hidden, matching how New Expensify already handles forced cash expenses.
  • This change does not apply Expensify Card transactions, which can never be reimbursable.

Existing reimbursable toggle on cash expenses

Image

Existing reimbursable feed setting in Expensify Classic that controls whether we will show this reimbursable toggle on card expenses in New Expensify

Image
Upwork Automation - Do Not Edit
Issue OwnerCurrent Issue Owner: @dmkt9

Activity

  1. added
    PlanningChanges still in the thought process
    ExternalAdded to denote the issue can be worked on by a contributor
    NewFeatureSomething to build that is a new item.
    and removed
    PlanningChanges still in the thought process
    on Oct 7, 2026
  2. melvin-bot commented on Oct 8, 2026

    @melvin-bot
    Author

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

  3. melvin-bot commented on Oct 8, 2026

    @melvin-bot
    Author

    Triggered auto assignment to Design team member for new feature review - @dannymcclain (NewFeature)

  4. changed the title [-]Show the Reimbursable toggle on company card expenses when the card feed is set to Do Not Force[/-] [+][$175] Show the Reimbursable toggle on company card expenses when the card feed is set to Do Not Force[/+] on Oct 8, 2026
  5. melvin-bot commented on Oct 8, 2026

    @melvin-bot
    Author
  6. joekaufmanexpensify commented on Oct 8, 2026

    @joekaufmanexpensify
    Contributor

    @dannymcclain I don't think we need any mocks here. This issue is just showing the existing reimbursable toggle on company card expenses based on an existing setting in Expensify Classic. Going ahead for now, but please let me know if you disagree. 👍

  7. 18 remaining items

  8. dmkt9 commented on Oct 14, 2026

    @dmkt9
    Contributor

    @MelvinBot In addition to the transaction values, we also need to check the policy settings #103342

  9. MelvinBot commented on Oct 14, 2026

    @MelvinBot
    Contributor

    Proposal (updated: also check feed and workspace settings)

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

    New Expensify hides the Reimbursable toggle on every company card expense. We want to show it on company card expenses set to Do Not Force. The check should use the transaction's stamped value and the feed's Reimbursable setting from Add a Reimbursable setting to company card feed settings in New Expensify.

    What is the root cause of that problem?

    This is a new feature. Every reimbursable check hides the row when isManagedCardTransaction(transaction) is true. None of them read forceReimbursable from the transaction or the feed. The workspace Cash expenses rule (disabledFields.reimbursable) sits in the same condition, but it should only apply to cash expenses.

    Code references

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

    1. Add CONST.COMPANY_CARD.FORCE_REIMBURSABLE with force_yes, force_no, default_yes, default_no and none.
    2. Add forceReimbursable to the transaction Comment type, next to liabilityType.
    3. Add isCardTransactionReimbursableEditable(transaction, feedSettings) to TransactionUtils. It returns:
      • true for non-card expenses, so cash behavior doesn't change.
      • false for Expensify Card expenses.
      • false if the transaction's stamped value is forced.
      • false if the feed setting is forced. If the feed settings exist but have no value, treat it as force_no, per the feed settings issue.
      • true only when the stamped value is Do Not Force and the feed isn't forced. If the stamp is missing, use the feed setting. If both are missing, return false.
    4. Get feed settings with getFeedSettingsForCard(card, allCardFeeds). If the viewer has no feed data, use the stamped value alone.
    5. For company card expenses, skip the workspace Cash expenses rule. Keep the expense-report, unreported and invoice checks. This fixes the cases zeryns reported, such as the toggle disappearing after one change.
    6. Use the helper in the expense view, split edit and bulk edit. In bulk edit, look up each card from NON_PERSONAL_AND_WORKSPACE_CARD_LIST and its feed from the SHARED_NVP_PRIVATE_DOMAIN_MEMBER collection. Hide the row if any selected card expense is forced.

    Tests:

    • Helper unit tests for each combination of stamped and feed values, plus missing values, Expensify Card and cash expenses.
    • A default_yes card expense on a feed changed to force_no hides the row.
    • A Do Not Force card expense on an "Always non-reimbursable" workspace shows the toggle, and it stays visible after toggling.
    • In bulk edit, Do Not Force card expenses on an "Always" workspace show the row. A selection with one forced card expense hides it.
    Open questions
    • Product (joekaufmanexpensify): The issue says feed changes only affect newly imported expenses. Checking the current feed setting changes that: switching a feed to Force hides the toggle on older Do Not Force expenses. Please confirm that's intended.
    • Backend: Please confirm that approvers who aren't admins receive sharedNVP_private_domain_member_<fundID>. If they don't, they only get the stamped value. Please also confirm the stamped transaction key (I assumed comment.forceReimbursable) and that search results include it.

    What alternative solutions did you explore? (Optional)

    Use only the stamped value, as in my previous proposal. That ignores the feed setting and leaves the workspace Cash expenses rule applied to card expenses.


    Next Steps for Contributor+ team:
    To accept: @MelvinBot implement [this](https://github.com/Expensify/App/issues/103341) to create a draft PR.
    To refine: @MelvinBot <your feedback>
    To reject: Explain why you are rejecting Melvin's proposal.


    view run

  10. dmkt9 commented on Oct 14, 2026

    @dmkt9
    Contributor

    Changing the feed setting only affects expenses imported afterward, matching Classic

    @MelvinBot Only check feedSettings if the value doesn't exist in the transaction

  11. MelvinBot commented on Oct 14, 2026

    @MelvinBot
    Contributor

    Proposal (updated: feed setting is only a fallback)

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

    New Expensify hides the Reimbursable toggle on every company card expense. We want to show it on company card expenses set to Do Not Force. The transaction's stamped forceReimbursable decides. The feed's Reimbursable setting from Add a Reimbursable setting to company card feed settings in New Expensify is used only when the transaction has no stamped value. This way, changing the feed setting only affects expenses imported afterward, matching Classic.

    What is the root cause of that problem?

    This is a new feature. Every reimbursable check hides the row when isManagedCardTransaction(transaction) is true. None of them read forceReimbursable from the transaction or the feed. The workspace Cash expenses rule (disabledFields.reimbursable) sits in the same condition, but it should only apply to cash expenses.

    Code references

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

    1. Add CONST.COMPANY_CARD.FORCE_REIMBURSABLE with force_yes, force_no, default_yes, default_no and none.
    2. Add forceReimbursable to the transaction Comment type, next to liabilityType.
    3. Add isCardTransactionReimbursableEditable(transaction, feedSettings) to TransactionUtils. It returns:
      • true for non-card expenses, so cash behavior doesn't change.
      • false for Expensify Card expenses.
      • If the transaction has a stamped value, it uses only that value: true for default_yes, default_no or none, and false for force_yes or force_no. The feed setting is ignored.
      • If the transaction has no stamped value, it uses the feed setting the same way. If the feed settings exist but have no value, treat it as force_no, per the feed settings issue.
      • false if both values are missing.
    4. Get feed settings with getFeedSettingsForCard(card, allCardFeeds). Look them up only when the transaction has no stamped value.
    5. For company card expenses, skip the workspace Cash expenses rule. Keep the expense-report, unreported and invoice checks. This fixes the cases zeryns reported, such as the toggle disappearing after one change.
    6. Use the helper in the expense view, split edit and bulk edit. In bulk edit, look up each card from NON_PERSONAL_AND_WORKSPACE_CARD_LIST and its feed from the SHARED_NVP_PRIVATE_DOMAIN_MEMBER collection. Hide the row if any selected card expense is forced.

    Tests:

    • Helper unit tests for each stamped value, each feed value with no stamp, both missing, Expensify Card and cash expenses.
    • A default_yes card expense on a feed later changed to force_no still shows the row.
    • A force_no card expense on a feed later changed to default_yes still hides the row.
    • A card expense with no stamp on a default_no feed shows the row.
    • A Do Not Force card expense on an "Always non-reimbursable" workspace shows the toggle, and it stays visible after toggling.
    • In bulk edit, Do Not Force card expenses on an "Always" workspace show the row. A selection with one forced card expense hides it.
    Open questions for the internal engineer
    • Please confirm the stamped transaction key (I assumed comment.forceReimbursable) and that search results include it.
    • For expenses with no stamp, please confirm that approvers who aren't admins receive sharedNVP_private_domain_member_<fundID>. If they don't, those expenses stay hidden for them.

    What alternative solutions did you explore? (Optional)

    Check both the stamped value and the current feed setting, as in my previous update. That makes a feed change affect expenses that were already imported, which doesn't match Classic.


    Next Steps for Contributor+ team:
    To accept: @MelvinBot implement [this](https://github.com/Expensify/App/issues/103341) to create a draft PR.
    To refine: @MelvinBot <your feedback>
    To reject: Explain why you are rejecting Melvin's proposal.


    view run

  12. dmkt9 commented on Oct 14, 2026

    @dmkt9
    Contributor

    MelvinBot's proposal looks good to me

    🎀 👀 🎀 C+

  13. melvin-bot commented on Oct 14, 2026

    @melvin-bot
    Author

    Triggered auto assignment to @blimpich, see https://stackoverflow.com/c/expensify/questions/7972 for more details.

  14. blimpich commented on Oct 14, 2026

    @blimpich
    Contributor

    LGTM, feel free to ask Melving to raise the PR @dmkt9 👍

  15. dmkt9 commented on Oct 15, 2026

    @dmkt9
    Contributor
  16. MelvinBot commented on Oct 15, 2026

    @MelvinBot
    Contributor

    🤖 Draft PR created: Show the Reimbursable toggle on Do Not Force company card expenses
    Please mark it as "Ready for review" or ask me to do that for you when it is ready for review.

    It follows the approved proposal:

    • Which value decides: The value stamped on the expense decides. The feed setting is used only when the expense has no stamped value.
    • Workspace rule: Card expenses skip the workspace Cash expenses rule.
    • Where it applies: The expense view, split edit and bulk edit.

    Typecheck, lint, spelling and the related Jest suites pass, including 17 new tests. I didn't test it manually in the app, because a fresh test account has no company card expenses with a stamped value.

    The backend key is still unconfirmed. I assumed the stamped value is comment.forceReimbursable, and search results need to include it too.


    view run

  17. melvin-bot commented on Oct 16, 2026

    @melvin-bot
    Author

    📣 @dmkt9 We're missing your Upwork ID to automatically send you an offer for the Reviewer role.
    Once you apply to the Upwork job, your Upwork ID will be stored and you will be automatically hired for future jobs!

  18. joekaufmanexpensify commented on Oct 26, 2026

    @joekaufmanexpensify
    Contributor

    PR review ongoing.

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

Metadata

Metadata

Labels

ExternalAdded to denote the issue can be worked on by a contributorNewFeatureSomething to build that is a new item.ReviewingHas a PR in reviewWeeklyKSv2

Type

No type

Projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions