Skip to content

[Payment due @Krishna2323] Align QBO and Xero Default vendor rows with the shared Intacct pattern - #99867

Merged
Beamanator merged 14 commits into
mainfrom
claude-alignQboXeroDefaultVendorRow
Sep 3, 2026
Merged

[Payment due @Krishna2323] Align QBO and Xero Default vendor rows with the shared Intacct pattern#99867
Beamanator merged 14 commits into
mainfrom
claude-alignQboXeroDefaultVendorRow

Conversation

@MelvinBot

@MelvinBot MelvinBot commented Aug 30, 2026

Copy link
Copy Markdown
Contributor

Explanation of Change

Aligns the QBO and Xero Default vendor rows with the pattern Sage Intacct adopted in #97016, so all three integrations render the same navigable arrow row and reuse the same workspace.accounting copy.

QuickBooks Online — DynamicQuickbooksCompanyCardExpenseAccountPage.tsx

  • Credit-card / debit-card branch: added the shared defaultVendorHelperText below the existing Default vendor row. The "Otherwise, they'll export as Credit Card Misc." fallback is specific to this branch, so the helper is scoped here only.
  • Vendor Bill branch: replaced the legacy ToggleSettingOptionRow + Accordion with a single always-visible Default vendor row that opens the existing bill default-vendor selector. The underlying setting values are untouched — the Advanced page's Create new entities (autoCreateVendor) toggle and its API action are unchanged.

Xero

  • Standardized on Default vendor (was "Default supplier") on the export row and the picker title, per the design direction in the linked issue.
  • Added the shared defaultVendorHelperText below the row.

Shared select-page header

  • Both the QBO and Xero default-vendor pickers now render workspace.accounting.defaultVendorSelectHeader, matching Intacct.
  • defaultVendorSelectHeader no longer interpolates the connection name. The design-approved copy (and the Xero R4 QA acceptance copy) is Choose a default vendor for expenses that don't match automatically. — the merged string read Choose a default QuickBooks Online vendor…, which would have failed the same QA check again. This also affects the Intacct picker, which is the intent of standardizing.

Pending / error subscriptions

  • The QBO export row previously subscribed to autoCreateVendor and only subscribed to nonReimbursableBillDefaultVendor when autoCreateVendor was on. Both the Export configuration page and the Accounting page now subscribe to whichever default-vendor key matches the active export destination, so a pending or failed default-vendor change on the card/debit path (nonReimbursableCreditCardDefaultVendor, which was subscribed nowhere before) surfaces its pending state and error dot on the parent rows. autoCreateVendor stays subscribed under the Advanced settings, where it is now edited.

Fixed Issues

$ https://github.com/Expensify/Expensify/issues/664722

Tests

Prerequisites: use the PR build; use a QBO workspace with at least two vendors and access to Credit Card, Debit Card, and Vendor Bill company-card export destinations; use a Xero workspace with Vendor Matching enabled and at least two contacts.

  1. Navigate to Workspace settings > Accounting > QuickBooks Online > Export > Export company card expenses and choose Credit Card.
  2. With no default vendor selected, verify the Default vendor row displays: Expenses that don't auto-match will default to this vendor. Otherwise, they'll export as Credit Card Misc.
  3. Open the row and verify the selector header is exactly: Choose a default vendor for expenses that don't match automatically. Select Vendor A, return, and verify Vendor A displays with the one-sentence helper: Expenses that don't auto-match will default to this vendor.
  4. Repeat steps 1-3 with Debit Card. With no default vendor selected, the fallback must be Debit Card Misc.; once Vendor A is selected, the helper must be the same one-sentence copy.
  5. Choose Vendor Bill. Verify there is one arrow-style Default vendor row—no legacy toggle/accordion and no helper text. Select Vendor A, return, and verify the selection is preserved.
  6. Change Create new entities on the QBO Advanced page and return to the Vendor Bill configuration. Verify this PR has not introduced a new relationship between that existing setting and the Default vendor selection. This PR deliberately leaves the existing autoCreateVendor behavior unchanged.
  7. Navigate to Workspace settings > Accounting > Xero > Export with Vendor Matching enabled. Verify the row is named Default vendor (not “Default supplier”). With no vendor selected, verify the helper is exactly: Expenses that don't auto-match will default to this vendor. It must not mention a Credit Card Misc. fallback.
  8. Open the Xero selector and verify the same exact selector header from step 3. Select Contact A, return, and verify Contact A displays with the one-sentence helper. Reopen the selector, choose None, and verify the row clears and retains that one-sentence helper.
  9. If an Intacct test workspace is available, open its default-vendor selector and verify it uses the same shared header and still works normally.
  10. Verify no new JS-console errors occur during all flows.

Offline tests

  1. For QBO Credit Card, Debit Card, and Vendor Bill, disconnect the network and change the Default vendor.
  2. Verify the selected vendor updates optimistically and pending/offline feedback appears. Reconnect and verify the new value persists.
  3. Using the team's normal dev/mock tooling, force the default-vendor update request to fail. Verify error feedback appears both on the default-vendor setting and on the parent Export company card expenses / relevant Accounting export row.
  4. If a failed request cannot be induced, record error-propagation coverage as unverified rather than passed.

QA Steps

ping alex & @heyjennahay to test

For complete integration confidence, also export a non-matching company-card expense for each configured QBO destination and confirm existing fallback/export behavior is preserved; for Xero with no default vendor, confirm no fabricated fallback vendor is created.

Acceptance decisions: this PR is complete only if QBO's existing Create new entities semantics are intentionally left unchanged, and Jenna confirms Xero's accurate no-fallback helper copy. If QBO-setting decoupling is required, it is a separate follow-up rather than behavior delivered by this PR.

PR Author Checklist

  • I linked the correct issue in the ### Fixed Issues section above
  • I wrote clear testing steps that cover the changes made in this PR
    • I added steps for local testing in the Tests section
    • I added steps for the expected offline behavior in the Offline steps section
    • I added steps for Staging and/or Production testing in the QA steps section
    • I added steps to cover failure scenarios (i.e. verify an input displays the correct error message if the entered data is not correct)
    • I turned off my network connection and tested it while offline to ensure it matches the expected behavior (i.e. verify the default avatar icon is displayed if app is offline)
    • I tested this PR with a High Traffic account against the staging or production API to ensure there are no regressions (e.g. long loading states that impact usability).
  • I included screenshots or videos for tests on all platforms
  • I ran the tests on all platforms & verified they passed on:
    • Android: Native
    • Android: mWeb Chrome
    • iOS: Native
    • iOS: mWeb Safari
    • MacOS: Chrome / Safari
  • I verified there are no console errors (if there's a console error not related to the PR, report it or open an issue for it to be fixed)
  • I followed proper code patterns (see Reviewing the code)
    • I verified that comments were added to code that is not self explanatory
    • I verified that any new or modified comments were clear, correct English, and explained "why" the code was doing something instead of only explaining "what" the code was doing.
    • I verified any copy / text that was added to the app is grammatically correct in English. It adheres to proper capitalization guidelines (note: only the first word of header/labels should be capitalized), and is either coming verbatim from figma or has been approved by marketing (in order to get marketing approval, ask the Bug Zero team member to add the Waiting for copy label to the issue)
  • If a new code pattern is added I verified it was agreed to be used by multiple Expensify engineers
  • I followed the guidelines as stated in the Review Guidelines
  • I tested other components that can be impacted by my changes (i.e. if the PR modifies a shared library or component like Avatar, I verified the components using Avatar are working as expected)
  • If a new CSS style is added I verified that:
    • A similar style doesn't already exist
    • The style can't be created with an existing StyleUtils function (i.e. StyleUtils.getBackgroundAndBorderStyle(theme.componentBG))
  • If new assets were added or existing ones were modified, I verified that:
    • The assets are optimized and compressed (for SVG files, run npm run compress-svg)
    • The assets load correctly across all supported platforms.
  • If the PR modifies code that runs when editing or sending messages, I tested and verified there is no unexpected behavior for all supported markdown - URLs, single line code, code blocks, quotes, headings, bold, strikethrough, and italic.
  • If the PR modifies a generic component, I tested and verified that those changes do not break usages of that component in the rest of the App (i.e. if a shared library or component like Avatar is modified, I verified that Avatar is working as expected in all cases)
  • If the PR modifies a component related to any of the existing Storybook stories, I tested and verified all stories for that component are still working as expected.
  • If the PR modifies a component or page that can be accessed by a direct deeplink, I verified that the code functions as expected when the deeplink is used - from a logged in and logged out account.
  • If the PR modifies the UI (e.g. new buttons, new UI components, changing the padding/spacing/sizing, moving components, etc) or modifies the form input styles:
    • I verified that all the inputs inside a form are aligned with each other.
    • I added Design label and/or tagged @Expensify/design so the design team can review the changes.
  • I added unit tests for any new feature or bug fix in this PR to help automatically prevent regressions in this user flow.
  • If the main branch was merged into this PR after a review, I tested again and verified the outcome was still expected according to the Test steps.

Screenshots/Videos

Android: Native
Android: mWeb Chrome
iOS: Native
iOS: mWeb Safari
MacOS: Chrome / Safari

- QBO card/debit-card export: render the shared two-state default-vendor helper text below the Default vendor row.
- QBO Vendor Bill export: replace the legacy toggle + accordion with a single always-visible navigable Default vendor row that opens the existing bill default-vendor selector. Underlying setting values and the Advanced-page autoCreateVendor flow are unchanged.
- QBO and Xero default-vendor select pages: render the shared 'Choose a default vendor...' header.
- Xero: standardize on 'Default vendor' terminology and add the shared helper text.
- workspace.accounting.defaultVendorSelectHeader no longer interpolates the connection name, matching the design-approved copy.
- Subscribe the QBO export row to the default-vendor key matching the active export destination; autoCreateVendor stays subscribed under Advanced.

Co-authored-by: Alex Beaman <Beamanator@users.noreply.github.com>
@melvin-bot melvin-bot Bot added Melvin-Test-Android Melvin-Test-Web Triggers Melvin to run the testing steps of the PR on web labels Aug 30, 2026
@MelvinBot
MelvinBot requested a review from a team August 30, 2026 21:58
@OSBotify

This comment has been minimized.

@codecov

codecov Bot commented Aug 30, 2026

Copy link
Copy Markdown

@MelvinBot

Copy link
Copy Markdown
Contributor Author

There's nothing to fix — no code check is failing.

The single failing check is Check independent approval, and it fails on the Verify peer review step. That's the peer-review gate: it stays red until a human reviewer other than the author approves the PR. No push can turn it green.

Everything else on the branch is green, including the two perf jobs that were still running when you asked:

Check Result
ESLint check pass
typecheck pass
Jest unit tests (jobs 1–8) pass
Bun tests / Storybook tests pass
Oxfmt, spellcheck, knip, unused styles pass
React Compiler Compliance pass
generateTranslations, validateSchemas pass
All 4 build jobs pass
Reassure performance tests pass

Next step: get a reviewer to approve the PR. Note the body still has the Tests, Offline tests, and QA Steps sections unfilled — those need a human before this goes ready for review.


view run

@MelvinBot

Copy link
Copy Markdown
Contributor Author

Web test: blocked — could not connect an accounting integration

Result: partial (0 of 6 steps verified). Every change in this PR lives behind a connected QuickBooks Online, Xero, or Sage Intacct connection. In this CI sandbox the Connect button starts an OAuth redirect to a callback host that has no DNS entry, so the browser tab lands on DNS_PROBE_FINISHED_NXDOMAIN and the connection never completes. None of the Default vendor UI could be reached.

Two things also worth flagging:

  1. The PR has no test steps. The Tests and QA Steps sections are still // TODO: The human co-author must fill out.... I derived the six checks below from the Explanation of Change, so they may not match what you intended to be tested.
  2. The Xero row is additionally gated behind the VENDOR_MATCHING beta, which would need to be on for that account.
Step Status Observation
1. QBO Export → Company card expenses (Credit/Debit card): "Default vendor" row shows the new helper text blocked Reached Workspace → Accounting → Connections and clicked Connect on QuickBooks Online. Tab navigated to the OAuth callback host, which fails DNS resolution in the sandbox. QBO never connected, so Export settings were never reached.
2. Tapping the QBO row opens a "Default vendor" selector with header Choose a default vendor for expenses that don't match automatically. blocked Same blocker — QBO was never connected.
3. QBO "Vendor bill" destination: Default vendor row always visible as a plain chevron row, no toggle, no accordion blocked Same blocker — QBO was never connected.
4. Xero Export row reads "Default vendor" (not "Default supplier"), with helper text and matching selector header blocked Never attempted: the tab was stuck on the DNS error page after the QBO attempt, and there is no in-tool back navigation on web.
5. Sage Intacct Default vendor selector header no longer interpolates the connection name blocked Same reason as step 4.
6. No JS console errors partial No error banners appeared on the pages actually reached (Home, Workspaces, Overview, Members, More features, Accounting connections). Console inspection is not available on the web driver, and the target pages were never reached.
Evidence (2)

Workspace > Accounting > Connections list — furthest point reached

Workspace > Accounting > Connections list showing Connect buttons for QuickBooks Online, Xero, Sage Intacct — furthest point reached

Tab stuck on DNS_PROBE_FINISHED_NXDOMAIN after clicking QuickBooks Online Connect

Browser tab stuck on DNS_PROBE_FINISHED_NXDOMAIN for the OAuth callback host after clicking QuickBooks Online Connect

What would unblock this: a test account with QBO / Xero / Sage Intacct already connected (and the VENDOR_MATCHING beta enabled for Xero), or a DNS/hosts mapping for the OAuth callback host in the CI sandbox. Automated web testing can't complete the third-party OAuth handshake on its own.

The PR branch (claude-alignQboXeroDefaultVendorRow, e89adae) built and ran fine — the blocker is only the integration connection.


view run

@MelvinBot

Copy link
Copy Markdown
Contributor Author

Android test: blocked — no accounting integration could be connected

Result: partial (0 of 5 UI steps verified). Every change in this PR lives behind a connected QuickBooks Online, Xero, or Sage Intacct integration. On the Android build I got as far as Workspace → Accounting → Connections for all three, and each hit a different hard gate that needs real third-party credentials:

  • QuickBooks Online — Connect opens the genuine Intuit OAuth sign-in WebView. No test Intuit account available.
  • Xero — Connect is gated on "Please enable two-factor authentication. For security purposes, Xero requires two-factor authentication to connect the integration."
  • Sage Intacct — first paywalled behind the Control plan (upgraded the trial workspace, no payment needed), then asks for a live Sage Intacct tenant: Company ID / User ID / Password.

Also worth flagging: the PR has no test steps. Tests and QA Steps are still // TODO: The human co-author must fill out..., so I derived the checks below from the Explanation of Change. The Xero row is additionally gated behind the VENDOR_MATCHING beta.

Step Status Observation
1. QBO Export → Company card expenses (Credit/Debit card): "Default vendor" row shows the new helper text blocked Connect opened a real Intuit OAuth login page requiring live credentials. Export settings never reached.
2. Tapping the QBO row opens a "Default vendor" selector with header Choose a default vendor for expenses that don't match automatically. blocked Same blocker — QBO never connected, so the selector was never reachable.
3. QBO "Vendor bill" destination: Default vendor row always visible as a plain chevron row, no toggle, no accordion blocked Same blocker as step 1.
4. Xero Export row reads "Default vendor" (not "Default supplier"), with helper text and matching selector header blocked Connect showed the "enable two-factor authentication" gate. Setting up 2FA on a third-party account is out of scope, so Xero could not be connected.
5. Sage Intacct Default vendor selector header no longer interpolates the connection name blocked Upgraded the trial workspace past the Control-plan paywall, then reached the "Enter your Sage Intacct credentials" form. No live Sage Intacct tenant available.
6. No crashes or JS errors pass Home, the Connections list, the QBO OAuth WebView, the Xero 2FA modal, the Intacct paywall/upgrade confirmation, and the Intacct credentials page all rendered without crashes or error boundaries. Based on visual observation only — no console log stream was attached, and the target Export pages were never reached.
Evidence (5)

Workspace > Accounting > Connections list (QBO, Xero, Sage Intacct all unconnected)

Workspace > Accounting > Connections list (QBO, Xero, Sage Intacct all unconnected)

QuickBooks Online Connect opens the real Intuit OAuth sign-in WebView

QuickBooks Online Connect opens the real Intuit OAuth sign-in WebView

Xero Connect blocked by the 'Please enable two-factor authentication' gate

Xero Connect blocked by the 'Please enable two-factor authentication' gate

Sage Intacct Connect blocked by the Control-plan paywall

Sage Intacct Connect blocked by the Control-plan paywall

Sage Intacct credentials entry (Company ID / User ID / Password) after upgrading the trial workspace to Control

Sage Intacct credentials entry (Company ID / User ID / Password) after upgrading the trial workspace to Control

What would unblock this: a test account with QBO / Xero / Sage Intacct already connected (plus the VENDOR_MATCHING beta for Xero). Automated testing can't complete a third-party OAuth handshake, a Xero 2FA enrollment, or a Sage Intacct tenant login on its own. The web run hit the same wall for the same reason.


view run

@Beamanator

Copy link
Copy Markdown
Contributor

@codex review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: e89adae730

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Aug 31, 2026

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ⚠️ Failed 2026-08-31T19:33:01.570193Z 6f423d1 Draft marked ready
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

The shared default-vendor helper text hardcoded "Credit Card Misc." in its
no-default state. That fallback is created by QuickBooks Online and Sage
Intacct on their card export paths only, so the Xero row told admins their
expenses would export as a vendor Xero never creates, and QBO's debit-card
path named the credit-card vendor instead of "Debit Card Misc.".

- workspace.accounting.defaultVendorHelperText now takes an optional
  fallbackVendorName and only appends the fallback sentence when one is
  passed (all 11 locales).
- QBO passes the name matching the active card destination; Intacct passes
  the credit-card one; Xero passes none, so it renders the accurate first
  sentence in both states.
- Add CONST.NON_REIMBURSABLE_FALLBACK_VENDOR_NAME for the two vendor names.
- Correct the stale "default-supplier row" comment after the vendor rename.

Co-authored-by: Alex Beaman <Beamanator@users.noreply.github.com>
@OSBotify

This comment has been minimized.

@Beamanator

Copy link
Copy Markdown
Contributor

🤖 Posted by Codex, an AI coding agent acting for @Beamanator.

The Polyglot Parrot feedback is valid: the new optional fallback-vendor argument changed the English source copy and parameter signature, while 10 locale entries still used the prior wording/signature. I applied the check’s proposed translation updates to de, el, es, fr, it, ja, nl, pl, pt-BR, and zh-hans.

Validation: git diff --check, npm run lint-changed, and npm run typecheck all passed. Committed and pushed as a4025842107a89aae5eccd2389a3bdec761ea585 (Update default vendor translations).

@MelvinBot

Copy link
Copy Markdown
Contributor Author

No fix pushed — all 5 failing checks are broken on main, not caused by this PR

typecheck, ESLint check, and test jobs 2/5/6 all fail inside files this PR never touches. This branch is 319 commits behind main, so its checks run against a merge with a currently-red main. Nothing in the 22 changed files (all src/pages/workspace/accounting/**, src/languages/*.ts, src/CONST/index.ts, and two accounting tests) appears in any failure.

There are three independent breakages on main:

A. BulkEditTest.ts uses undeclared getCurrencyDecimals / getCurrencySymbol
tests/actions/IOUTest/BulkEditTest.ts:2385 (and 2475, 2557) references the bare names, but line 18 only imports the …Local variants. This single mistake fails three checks: typecheck (TS2552 ×6), ESLint check (no-unsafe-assignment ×6), and test (job 5) (ReferenceError: getCurrencyDecimals is not defined ×3).

B. #99303 added a shouldShowViolation call missing an argument
Merge e33c4887 (landed 18:16 UTC, ~8 min before these checks) added to hasNoticeTypeViolation:

shouldShowViolation(iouReport, policy, violation.name, currentUserEmail, true, transaction)

But the signature is (iouReport, policy, violationName, currentUserEmail, currentUserAccountID: number, shouldShowRterForSettledReport = true, transaction?). currentUserAccountID was skipped, so true lands in the number slot and transaction lands in shouldShowRterForSettledReport. That fails typecheck (TS2345 at src/libs/TransactionUtils/index.ts:2461) and both remaining test jobs, because isCurrentUserSubmitter(iouReport, true) can never match an accountID — so the violation is never hidden from the submitter.

C. @components/Avatar has no index.tsx
HeaderWithBackButton.tsx:1 imports it, but src/components/Avatar/ on main contains no index.tsxtypecheck TS2307.

What to do: these need fixing on main by the owners of #99303 and the Avatar/CurrencyUtils refactors — not here. Once main is green, merge main into this branch and the checks should pass. I did not push anything, since fixing them would mean editing files well outside this PR's scope.

Evidence and per-check mapping
Check Failure Source
typecheck TS2552 ×6 in BulkEditTest.ts A
typecheck TS2345 src/libs/TransactionUtils/index.ts:2461 B
typecheck TS2353 isPolicyExpenseChatEnabled at tests/unit/ReportUtilsTest.ts:16971 B (added by e33c4887; not a Policy field)
typecheck TS2307 Cannot find module '@components/Avatar' C
ESLint check no-unsafe-assignment ×6 in BulkEditTest.ts A
test (job 5) ReferenceError: getCurrencyDecimals is not defined ×3 A
test (job 6) TransactionUtils › hasNoticeTypeViolation › should hide RECEIPT_NOT_SMART_SCANNED from the submitter — expected false, got true B
test (job 2) ReportUtils › getViolatingReportIDForRBRInLHN › should return null for a processing report whose remaining notice is RECEIPT_NOT_SMART_SCANNED B

Cross-check that A and C predate this PR's run: the unrelated branch krishna2323/issue-99410 typecheck run 33423708142 at 18:12 UTC shows the identical @components/Avatar, getCurrencyDecimals, and getCurrencySymbol errors — but not the TransactionUtils TS2345, which only appears after e33c4887 landed at 18:16. The chronology matches exactly.

Ignored per policy: checklist and Check independent approval (expected on a draft PR awaiting a human author/reviewer).

The 3 error-line pairs in BulkEditTest.ts (2385/2386, 2475/2476, 2557/2558) correspond one-to-one with the 3 failing tests in job 5, confirming the runtime failure and the type error share one cause.


view run

@MelvinBot

Copy link
Copy Markdown
Contributor Author

Still no fix pushed — main is red, and I've now pinned each breakage to its owning PR

Re-ran the analysis against the new main HEAD (f6a4920). Nothing changed: the same 4 checks fail (typecheck, test jobs 2/5/6), all inside files this PR never touches. No fix or revert is in flight for any of them, and no deploy blocker has been filed.

Three PRs merged within 14 minutes today, each colliding with code that had already landed. Every one was green on its own branch, so nothing caught them until they met on main:

Merged (UTC) PR What it broke
18:02 #99571 Deleted the getCurrencyDecimals/getCurrencySymbol import from BulkEditTest.ts and rewrote call sites to the …Local variants — but missed the three attendees blocks added on 08-29. Those bare references are now undefined.
18:08 #99553 Removed src/components/Avatar/index.tsx, but HeaderWithBackButton.tsx (added 12:42 by #98160) still imports the @components/Avatar barrel.
18:16 #99303 Added a shouldShowViolation(...) call that skips the currentUserAccountID argument, so true lands in the number slot.

The #99571 miss alone accounts for 3 of the 4 failing checks, because the same 6 lines fail three different ways: typecheck (TS2552 ×6), ESLint check (no-unsafe-assignment ×6), and test (job 5) (ReferenceError: getCurrencyDecimals is not defined ×3).

What needs to happen: these are three separate main fixes owned by shubham1206agra, the Avatar decomposition authors, and nkdengineer respectively — not changes that belong in a QBO/Xero vendor-row PR. Once main is green, merge main into this branch and these checks should clear. Happy to file a deploy blocker for the red main if you want — just say so.

Per-check mapping and evidence (permalinks at f6a4920)
Check Failure Cause
typecheck TS2552 ×6 at BulkEditTest.ts:2385 (+2475, 2557) vs the import at line 18 #99571
ESLint check no-unsafe-assignment ×6, same lines #99571
test (job 5) ReferenceError: getCurrencyDecimals is not defined ×3 in actions/IOU/BulkEdit › updateMultipleMoneyRequests #99571
typecheck TS2307 Cannot find module '@components/Avatar' at HeaderWithBackButton.tsx:1 #99553
typecheck TS2345 at src/libs/TransactionUtils/index.ts:2461 vs the signature #99303
typecheck TS2353 isPolicyExpenseChatEnabled at ReportUtilsTest.ts:16971 — not a Policy field #99303
test (job 6) TransactionUtils › hasNoticeTypeViolation › should hide RECEIPT_NOT_SMART_SCANNED from the submitter — expected false, got true #99303
test (job 2) ReportUtils › getViolatingReportIDForRBRInLHN › should return null for a processing report whose remaining notice is RECEIPT_NOT_SMART_SCANNED #99303

On #99303: shouldShowViolation takes (iouReport, policy, violationName, currentUserEmail, currentUserAccountID: number, shouldShowRterForSettledReport = true, transaction?), but the new call passes (iouReport, policy, violation.name, currentUserEmail, true, transaction). currentUserAccountID is skipped, so isCurrentUserSubmitter(iouReport, true) can never match an accountID and the violation is never hidden from the submitter — which is exactly what both failing tests assert.

Independent confirmation these aren't from this branch: the unrelated branch krishna2323/issue-99410 typecheck run 33423708142 at 18:12 UTC shows the identical @components/Avatar and getCurrencyDecimals/getCurrencySymbol errors, but not the TransactionUtils TS2345 — which appears only after #99303 landed at 18:16. The chronology lines up exactly with the table above.

This branch is 319 commits behind main, so its checks build a merge against current main and inherit all of its breakage. The 22 changed files here are confined to src/pages/workspace/accounting/**, src/languages/*.ts, src/CONST/index.ts, and two accounting tests — zero overlap with any failure location.


view run

@MelvinBot

Copy link
Copy Markdown
Contributor Author

Still nothing to fix here — main is red, and I've now pinned all three breakages plus their owning PRs

Re-checked against the new main HEAD (f6a49200) and your new commit a4025842. The failure set is byte-for-byte identical, and none of it touches this PR's 22 files.

Proof main is red for everyone, not just this branch: every typecheck run started since f6a49200 landed has failed — 5 for 5, across 4 unrelated branches (fix/regressions-from-93854-part-5, codex/fix-bulk-edit-currency-helper-references, 95210-bump-expensify-common-2-0-201, and this one).

Three merges in a 14-minute window each broke main independently:

# Breakage Landed Owning PR Fix status
A BulkEditTest.ts:2385 (+2475, 2557) calls bare getCurrencyDecimals / getCurrencySymbol; line 18 imports only the …Local variants 18:02 (3e7b4291) #99571 ✅ fix already open: #99952
C #99553 deleted src/components/Avatar/index.tsx, but HeaderWithBackButton.tsx:1 still imports @components/Avatar 18:08 (e5d439d0) #99553 ❌ no fix open
B TransactionUtils/index.ts:2461 calls shouldShowViolation without currentUserAccountID, so true lands in the number slot (signature) 18:16 (e33c4887) #99303 ❌ no fix open

What unblocks you: #99952 clears A. Someone needs to own B and C — nkdengineer for #99303 and software-mansion-labs for #99553. Once main is green, merge it into this branch and these checks go green with it. I'm not pushing anything, because all three fixes belong in files far outside this PR's scope and A is already being fixed elsewhere.

Your PR itself looks healthy: both of its test files pass — tests/unit/pages/workspace/accounting/qbo/defaultVendorSubscriptionsTest.ts and tests/unit/TranslateTest.ts — and all three perf checks now pass.

Per-check mapping and evidence
Check Failure Cause
typecheck TS2552 ×6 in BulkEditTest.ts A
typecheck TS2307 Cannot find module '@components/Avatar' C
typecheck TS2345 at src/libs/TransactionUtils/index.ts:2461 B
typecheck TS2353 isPolicyExpenseChatEnabled at tests/unit/ReportUtilsTest.ts:16971 B
test (job 5) ReferenceError: getCurrencyDecimals is not defined ×3 A
test (job 2) ReportUtils › getViolatingReportIDForRBRInLHN › should return null for a processing report whose remaining notice is RECEIPT_NOT_SMART_SCANNED B
test (job 6) TransactionUtils › hasNoticeTypeViolation › should hide RECEIPT_NOT_SMART_SCANNED from the submitter — expected false, got true B
ESLint check no-unsafe-assignment ×6 in BulkEditTest.ts (was failing last run; still running now) A

Verified directly against main HEAD f6a49200, not the merge ref:

  • tsconfig.json maps @components/*./src/components/*; the git tree for src/components/Avatar contains no index.tsx or index.ts, and src/components/Avatar.tsx does not exist either. e5d439d0 shows removed src/components/Avatar/index.tsx.
  • Line 2461 reads shouldShowViolation(iouReport, policy, violation.name, currentUserEmail, true, transaction) against a signature of (iouReport, policy, violationName, currentUserEmail, currentUserAccountID: number, shouldShowRterForSettledReport = true, transaction?). Because isCurrentUserSubmitter(iouReport, true) can never match an accountID, the violation is never hidden from the submitter — which is exactly what both failing tests assert.

Chronology cross-check: the unrelated branch krishna2323/issue-99410 failed at 18:12 with A and C errors but not B — matching B landing at 18:16. An earlier run on ionatan_linkhomeaddress at 17:59 passed cleanly, before any of the three merged.

Ignored per policy: checklist and Check independent approval.


view run

@Beamanator

Copy link
Copy Markdown
Contributor

🤖 Posted by Codex, an AI coding agent acting for @Beamanator.

Confirmed: the code failures came from the GitHub Actions synthetic merge of the prior PR head with current main, not from the translation commit alone. I merged current main into this branch and fixed the regressions exposed by that merged source:

  • restored the composed header’s explicit UserAvatar/WorkspaceAvatar rendering after the Avatar facade was removed;
  • passed currentUserAccountID (rather than true) to shouldShowViolation, which fixes the RBR/notice behavior and its tests;
  • mapped the refactored local currency helpers in BulkEditTest;
  • removed a deleted policy fixture property; and
  • made the bundled author-checklist action resolve @babel/traverse correctly under Node 24.

Validation passed: npm run typecheck, lint on all changed files, oxfmt --check, git diff --check, and bun test ./tests/tooling/detectReactComponent.test.ts (9/9). The three targeted Jest suites could not initialize locally because this temporary worktree shares stale dependencies that lack the ReactNativeHybridApp TurboModule; CI uses a clean install.

Pushed as aba047b7b29d9c3c6db38343c5831a94c907f61d (Fix checks against current main). The independent-approval and author-checklist gates still require human review/attestation; I did not approve the PR or mark human checklist items complete.

@Beamanator

Copy link
Copy Markdown
Contributor

🤖 Posted by Codex, an AI coding agent acting for @Beamanator.

Correction to my previous update: the checklist workflow runs with pull_request_target and checks out trusted main action code. Its latest log still executes the old import_traverse.default call, which proves changes to .github/actions/javascript/authorChecklist on this PR cannot affect that check. I removed that ineffective change from this branch in 6f423d12bb4.

The actionable source/test fixes remain in aba047b7b29 (now in the PR history) and will affect the TypeScript and Jest checks. The remaining checklist error requires a separate fix merged to main, then a rerun; its separate author-attestation requirement and the independent-approval gate require human action. I did not mark any checklist items or approve the PR.

@MelvinBot

Copy link
Copy Markdown
Contributor Author

Nothing to push — the checks are green now

You'd already fixed them yourself before this run started. On the current head (6f423d12), every real check passes: typecheck, ESLint check, all 8 test jobs, Bun tests, Storybook tests, React Compiler Compliance, knip, spellcheck, generateTranslations, and both perf jobs.

Your aba047b7 ("Fix checks against current main") landed exactly the four fixes the earlier failures pointed at, after merging main in via a7c85461:

  • shouldShowViolation(...) — restored the missing currentUserAccountID argument
  • BulkEditTest.ts — pointed the 3 call sites at getCurrencyDecimalsLocal / getCurrencySymbolLocal
  • HeaderWithBackButton.tsx — split the dead @components/Avatar import into UserAvatar / WorkspaceAvatar
  • ReportUtilsTest.ts — dropped the non-existent isPolicyExpenseChatEnabled field

The two still-red checks are both expected and not code problems:

  • checklist — the PR Author Checklist boxes are unticked, and the Tests / Offline tests / QA Steps sections are still the // TODO placeholders. This clears when you fill those in before marking the PR ready.
  • Check independent approval — waiting on a human reviewer.
One thing worth knowing about the checklist job

Separate from the unticked boxes, that job also logs a genuine crash:

An unknown error occurred with the GitHub API:  TypeError: (0 , import_traverse.default) is not a function

This is the bug your aba047b7 fixed in newComponentCategory.ts and then 6f423d12 deliberately reverted to keep this PR scoped — which I agree with. It's a real defect on main: the bundled action runs under Node, where the CJS default export is nested at .default, so detectReactComponent throws and new-component detection silently never fires. It deserves its own PR.

Note it doesn't change anything here — checklist would still fail on the unticked boxes even with that crash fixed.


view run

@MelvinBot

Copy link
Copy Markdown
Contributor Author

Nothing left for me to fix — the code checks are green

typecheck, ESLint check, and all 8 test jobs now pass. Your merge of main (a7c85461) plus aba047b7 cleared the main-side breakages I described in my earlier comment, so I pushed nothing.

Current tally: 30 pass, 2 skipping, 2 fail. Both failures are human-gated and can't be fixed by a commit:

  • checklist — "PR Author Checklist is not completely filled out." The body still has // TODO placeholders in Tests, Offline tests, and QA Steps, and unchecked author-checklist boxes.
  • Check independent approvalapprovers: []. Needs an independent Expensify employee review.

view run

@Beamanator Beamanator added the InternalQA This pull request required internal QA label Aug 31, 2026
@Beamanator
Beamanator marked this pull request as ready for review August 31, 2026 19:21
@Beamanator
Beamanator requested a review from a team as a code owner August 31, 2026 19:21
@Beamanator

Beamanator commented Sep 2, 2026

Copy link
Copy Markdown
Contributor

@Krishna2323 Your feedback was valid. I independently confirmed that QBO honors a Vendor Bill default vendor while autoCreateVendor is off; the exporter uses the configured default before the fallback creation path. The issue was in App: toggling Create new entities also overwrote nonReimbursableBillDefaultVendor with vendors[0] or NONE, despite the settings being independent.

Changed in b47ec34:

  • Preserve the existing Vendor Bill default vendor when toggling Create new entities.
  • Keep the QBO fallback names untranslated, but make translation templates own sentence punctuation so the displayed record names remain Credit Card Misc. and Debit Card Misc.
  • Restore German, Japanese, and Simplified Chinese typography and terminal punctuation; applied the punctuation fix to every affected locale.
  • Added translation regression coverage for the QBO fallback names and locale-specific punctuation. I also added the missing native-module mock needed for this existing test file to run in the owned Jest environment.

No backend PR is required: the backend already treats the two settings independently and continues to own the literal QBO vendor names.

Checks passed: targeted Jest TranslateTest (12/12), npm run lint-changed, npm run typecheck, npm run spell-changed, oxfmt check, and React Compiler compliance.

🤖 Posted by Codex, an AI coding agent acting for @Beamanator.

@OSBotify

OSBotify commented Sep 2, 2026

Copy link
Copy Markdown
Contributor

🦜 Polyglot Parrot! 🦜

Squawk! Looks like you added some shiny new English strings. Allow me to parrot them back to you in other tongues:

View the translation diff
diff --git a/src/languages/de.ts b/src/languages/de.ts
index 87aaa970..618d1e49 100644
--- a/src/languages/de.ts
+++ b/src/languages/de.ts
@@ -7255,8 +7255,8 @@ Der Control-Tarif beginnt bei 9 $ pro aktivem Mitglied und Monat.`,
             defaultVendor: 'Standardanbieter',
             defaultVendorHelperText: (isSet: boolean, fallbackVendorName?: string) =>
                 isSet || !fallbackVendorName
-                    ? `Ausgaben, die nicht automatisch zugeordnet werden, werden standardmäßig diesem Lieferanten zugewiesen.`
-                    : `Ausgaben, die nicht automatisch abgeglichen werden, werden standardmäßig diesem Lieferanten zugeordnet. Andernfalls werden sie als „${fallbackVendorName}.“ exportiert.`,
+                    ? `Ausgaben, die nicht automatisch abgeglichen werden, werden standardmäßig diesem Lieferanten zugeordnet.`
+                    : `Ausgaben, die nicht automatisch zugeordnet werden, werden standardmäßig diesem Lieferanten zugewiesen. Andernfalls werden sie als ${fallbackVendorName} exportiert.`,
             defaultVendorSelectHeader: `Wählen Sie einen Standardanbieter für Ausgaben, die nicht automatisch zugeordnet werden.`,
             defaultAccount: 'Standardkonto',
             autoSync: 'Automatische Synchronisierung',
diff --git a/src/languages/el.ts b/src/languages/el.ts
index 477f40fc..14d10711 100644
--- a/src/languages/el.ts
+++ b/src/languages/el.ts
@@ -7412,9 +7412,9 @@ _Για πιο αναλυτικές οδηγίες, [επισκεφθείτε τ
             },
             defaultVendorHelperText: (isSet: boolean, fallbackVendorName?: string) =>
                 isSet || !fallbackVendorName
-                    ? `Οι δαπάνες που δεν αντιστοιχίζονται αυτόματα θα αντιστοιχίζονται σε αυτόν τον προμηθευτή από προεπιλογή.`
-                    : `Οι δαπάνες που δεν θα αντιστοιχίζονται αυτόματα θα αντιστοιχίζονται από προεπιλογή σε αυτόν τον προμηθευτή. Διαφορετικά, θα εξαχθούν ως ${fallbackVendorName}.`,
-            defaultVendorSelectHeader: `Επιλέξτε έναν προεπιλεγμένο προμηθευτή για δαπάνες που δεν ταιριάζουν αυτόματα.`,
+                    ? `Οι δαπάνες που δεν αντιστοιχίζονται αυτόματα θα αντιστοιχίζονται από προεπιλογή σε αυτόν τον προμηθευτή.`
+                    : `Οι δαπάνες που δεν αντιστοιχίζονται αυτόματα θα αντιστοιχίζονται σε αυτόν τον προμηθευτή από προεπιλογή. Διαφορετικά, θα εξαχθούν ως ${fallbackVendorName}.`,
+            defaultVendorSelectHeader: `Επιλέξτε έναν προεπιλεγμένο προμηθευτή για δαπάνες που δεν αντιστοιχίζονται αυτόματα.`,
         },
         hr: {
             title: 'HR',
diff --git a/src/languages/es.ts b/src/languages/es.ts
index 118769cf..e7c2bdcd 100644
--- a/src/languages/es.ts
+++ b/src/languages/es.ts
@@ -7071,8 +7071,8 @@ El plan Controlar empieza en 9 $ por miembro activo al mes.`,
             defaultVendor: 'Proveedor predeterminado',
             defaultVendorHelperText: (isSet: boolean, fallbackVendorName?: string) =>
                 isSet || !fallbackVendorName
-                    ? `Los gastos que no se asignen automáticamente se asociarán por defecto a este proveedor.`
-                    : `Los gastos que no se emparejen automáticamente se asociarán a este proveedor de forma predeterminada. De lo contrario, se exportarán como ${fallbackVendorName}.`,
+                    ? `Los gastos que no se concilien automáticamente se asignarán por defecto a este proveedor.`
+                    : `Los gastos que no se concilien automáticamente se asignarán a este proveedor de forma predeterminada. En caso contrario, se exportarán como ${fallbackVendorName}.`,
             defaultVendorSelectHeader: `Elige un proveedor predeterminado para los gastos que no se asignen automáticamente.`,
             defaultAccount: 'Cuenta predeterminada',
             autoSync: 'Autosincronización',
diff --git a/src/languages/fr.ts b/src/languages/fr.ts
index 07c32099..4f29400a 100644
--- a/src/languages/fr.ts
+++ b/src/languages/fr.ts
@@ -7276,7 +7276,7 @@ Le forfait Control commence à 9 $ par Membre actif et par mois.`,
             defaultVendorHelperText: (isSet: boolean, fallbackVendorName?: string) =>
                 isSet || !fallbackVendorName
                     ? `Les dépenses qui ne correspondent pas automatiquement seront par défaut associées à ce fournisseur.`
-                    : `Les dépenses qui ne sont pas appariées automatiquement seront associées par défaut à ce fournisseur. Sinon, elles seront exportées comme ${fallbackVendorName}.`,
+                    : `Les dépenses qui ne se rapprochent pas automatiquement utiliseront par défaut ce fournisseur. Sinon, elles seront exportées sous ${fallbackVendorName}.`,
             defaultVendorSelectHeader: `Choisissez un fournisseur par défaut pour les dépenses qui ne correspondent pas automatiquement.`,
             defaultAccount: 'Compte par défaut',
             autoSync: 'Synchronisation automatique',
diff --git a/src/languages/it.ts b/src/languages/it.ts
index e1efa6d5..8ecefeab 100644
--- a/src/languages/it.ts
+++ b/src/languages/it.ts
@@ -7220,8 +7220,8 @@ Il piano Control parte da 9 $ al mese per ogni membro attivo.`,
             defaultVendor: 'Fornitore predefinito',
             defaultVendorHelperText: (isSet: boolean, fallbackVendorName?: string) =>
                 isSet || !fallbackVendorName
-                    ? `Le spese che non vengono abbinate automaticamente verranno assegnate a questo fornitore per impostazione predefinita.`
-                    : `Le spese che non vengono abbinate automaticamente useranno questo fornitore per impostazione predefinita. In caso contrario, verranno esportate come ${fallbackVendorName}.`,
+                    ? `Le spese che non vengono abbinate automaticamente verranno associate per impostazione predefinita a questo fornitore.`
+                    : `Le spese che non vengono abbinate automaticamente avranno questo fornitore predefinito. In caso contrario, verranno esportate come ${fallbackVendorName}.`,
             defaultVendorSelectHeader: `Scegli un fornitore predefinito per le spese che non vengono abbinate automaticamente.`,
             defaultAccount: 'Conto predefinito',
             autoSync: 'Sincronizzazione automatica',
diff --git a/src/languages/ja.ts b/src/languages/ja.ts
index e060eebf..6556844a 100644
--- a/src/languages/ja.ts
+++ b/src/languages/ja.ts
@@ -7130,8 +7130,8 @@ Control プランは、アクティブメンバー1人あたり月額 $9 から
             defaultVendorHelperText: (isSet: boolean, fallbackVendorName?: string) =>
                 isSet || !fallbackVendorName
                     ? `自動照合されない経費は、デフォルトでこのベンダーに割り当てられます。`
-                    : `自動照合されない経費はデフォルトでこのベンダーに割り当てられます。それ以外は「${fallbackVendorName}.」としてエクスポートされます。`,
-            defaultVendorSelectHeader: `自動的に一致しない経費に使用するデフォルトの取引先を選択します。`,
+                    : `自動で照合されない経費は既定でこのベンダーになります。それ以外は ${fallbackVendorName} としてエクスポートされます。`,
+            defaultVendorSelectHeader: `自動的に一致しない経費のためのデフォルトの取引先を選択します。`,
             defaultAccount: 'デフォルトのアカウント',
             autoSync: '自動同期',
             autoSyncDescription: 'NetSuite と Expensify を毎日自動で同期。確定したレポートをリアルタイムでエクスポート',
diff --git a/src/languages/nl.ts b/src/languages/nl.ts
index 5c5e0d2c..c3dc5cff 100644
--- a/src/languages/nl.ts
+++ b/src/languages/nl.ts
@@ -7203,9 +7203,9 @@ Het Control-abonnement begint bij $9 per actieve deelnemer per maand.`,
             defaultVendor: 'Standaardleverancier',
             defaultVendorHelperText: (isSet: boolean, fallbackVendorName?: string) =>
                 isSet || !fallbackVendorName
-                    ? `Uitgaven die niet automatisch worden gekoppeld, worden standaard aan deze leverancier toegewezen.`
+                    ? `Declaraties die niet automatisch worden gematcht, worden standaard aan deze leverancier gekoppeld.`
                     : `Declaraties die niet automatisch worden gekoppeld, worden standaard aan deze leverancier toegewezen. Anders worden ze geëxporteerd als ${fallbackVendorName}.`,
-            defaultVendorSelectHeader: `Kies een standaardleverancier voor uitgaven die niet automatisch worden gekoppeld.`,
+            defaultVendorSelectHeader: `Kies een standaardleverancier voor uitgaven die niet automatisch worden herkend.`,
             defaultAccount: 'Standaardrekening',
             autoSync: 'Automatisch synchroniseren',
             autoSyncDescription: 'Synchroniseer NetSuite en Expensify automatisch, elke dag. Exporteer een afgerond rapport in realtime',
diff --git a/src/languages/pl.ts b/src/languages/pl.ts
index 95ed67a5..5e2b4f12 100644
--- a/src/languages/pl.ts
+++ b/src/languages/pl.ts
@@ -7226,8 +7226,8 @@ Plan Control zaczyna się od 9 USD za aktywnego członka miesięcznie.`,
             defaultVendor: 'Domyślny dostawca',
             defaultVendorHelperText: (isSet: boolean, fallbackVendorName?: string) =>
                 isSet || !fallbackVendorName
-                    ? `Wydatki, które nie zostaną automatycznie dopasowane, będą domyślnie przypisywane temu kontrahentowi.`
-                    : `Wydatki, które nie zostaną automatycznie dopasowane, zostaną domyślnie przypisane do tego dostawcy. W przeciwnym razie będą eksportowane jako ${fallbackVendorName}.`,
+                    ? `Wydatki, które nie zostaną automatycznie dopasowane, zostaną domyślnie przypisane do tego dostawcy.`
+                    : `Wydatki, które nie zostaną dopasowane automatycznie, będą domyślnie przypisane do tego dostawcy. W przeciwnym razie zostaną wyeksportowane jako ${fallbackVendorName}.`,
             defaultVendorSelectHeader: `Wybierz domyślnego dostawcę dla wydatków, które nie dopasują się automatycznie.`,
             defaultAccount: 'Domyślne konto',
             autoSync: 'Automatyczna synchronizacja',
diff --git a/src/languages/pt-BR.ts b/src/languages/pt-BR.ts
index 8b38a7b5..df4dcd68 100644
--- a/src/languages/pt-BR.ts
+++ b/src/languages/pt-BR.ts
@@ -7207,9 +7207,9 @@ O plano Control começa em US$ 9 por membro ativo por mês.`,
             defaultVendor: 'Fornecedor padrão',
             defaultVendorHelperText: (isSet: boolean, fallbackVendorName?: string) =>
                 isSet || !fallbackVendorName
-                    ? `Despesas que não forem conciliadas automaticamente serão atribuídas a este fornecedor por padrão.`
-                    : `Despesas que não tiverem correspondência automática serão atribuídas a este fornecedor por padrão. Caso contrário, serão exportadas como ${fallbackVendorName}.`,
-            defaultVendorSelectHeader: `Escolha um fornecedor padrão para despesas que não sejam correspondidas automaticamente.`,
+                    ? `Despesas que não tiverem correspondência automática serão associadas a este fornecedor por padrão.`
+                    : `Despesas que não forem conciliadas automaticamente serão atribuídas a este fornecedor por padrão. Caso contrário, serão exportadas como ${fallbackVendorName}.`,
+            defaultVendorSelectHeader: `Escolha um fornecedor padrão para as despesas que não forem correspondidas automaticamente.`,
             defaultAccount: 'Conta padrão',
             autoSync: 'Sincronização automática',
             autoSyncDescription: 'Sincronize NetSuite e Expensify automaticamente, todos os dias. Exporte relatórios finalizados em tempo real',
diff --git a/src/languages/zh-hans.ts b/src/languages/zh-hans.ts
index 5e832496..d1a11d17 100644
--- a/src/languages/zh-hans.ts
+++ b/src/languages/zh-hans.ts
@@ -6952,8 +6952,8 @@ _如需更详细的说明,请[访问我们的帮助网站](${CONST.NETSUITE_IM
             exportDate: '导出日期',
             defaultVendor: '默认供应商',
             defaultVendorHelperText: (isSet: boolean, fallbackVendorName?: string) =>
-                isSet || !fallbackVendorName ? `无法自动匹配的报销将默认归属为此供应商。` : `未自动匹配的报销将默认归属于此供应商。否则,它们将按“${fallbackVendorName}.”导出。`,
-            defaultVendorSelectHeader: `为未能自动匹配的报销选择一个默认供应商。`,
+                isSet || !fallbackVendorName ? `未自动匹配的报销将默认归属为此供应商。` : `无法自动匹配的报销将默认使用此供应商。否则,它们将以 ${fallbackVendorName} 导出。`,
+            defaultVendorSelectHeader: `为未自动匹配的费用选择一个默认供应商。`,
             defaultAccount: '默认账户',
             autoSync: '自动同步',
             autoSyncDescription: '每天自动同步 NetSuite 和 Expensify。实时导出已完成报表',

Note

You can apply these changes to your branch by copying the patch to your clipboard, then running pbpaste | git apply 😉

View workflow run

@Beamanator

Beamanator commented Sep 2, 2026

Copy link
Copy Markdown
Contributor

@OSBotify Applied the non-conflicting language updates from your suggested diff in 84bc3eb.

I intentionally retained the fallback branches in de, ja, and zh-hans: the suggested versions remove the German/Japanese/Chinese quotes and reintroduce the missing terminal punctuation identified by Krishna. The remaining helper-text and selector-header translations were applied.

Validation passed: npm test -- tests/unit/TranslateTest.ts --runInBand (12/12), npm run lint-changed, npm run typecheck, npm run spell-changed, and oxfmt check.

🤖 Posted by Codex, an AI coding agent acting for @Beamanator.

@Beamanator

Copy link
Copy Markdown
Contributor

back to you @Krishna2323 🙏

@MelvinBot

Copy link
Copy Markdown
Contributor Author

No code fix is needed — every automated check passes on the current head (84bc3eb). The one remaining failure is Check independent approval, which only a human reviewer can clear:

Insufficient independent peer review
Expensify/App#99867 does not have enough independent Expensify employee approvals.
  approvers: [], independentApprovers: []

Because I authored this PR, it needs an approval from an Expensify employee other than me. That check will stay red until someone approves.

What actually failed earlier, and where it was fixed

The real failures were on the Aug 31 commits, and they were already resolved before this request:

Commit Failing checks Resolved by
4c8be53 ESLint, TypeScript, Jest aba047b "Fix checks against current main"
a402584 ESLint, TypeScript, Jest aba047b "Fix checks against current main"

Everything after that is green. Latest run status on 84bc3eb:

  • ESLint, Oxfmt, typecheck, spellcheck, actionlint — pass
  • Jest (jobs 1-8), Bun tests, Storybook tests — pass
  • generateTranslations, validateSchemas, validateImmutableActionRefs, knip, unused styles, React Compiler — pass
  • Android + iOS builds, codecov, Reassure perf tests — pass
  • Check independent approval — fail (needs a human approval)

The PR Author Checklist and PR Reviewer Checklist failures visible in the older run history are also human-gated and are green now.


view run

@Krishna2323

Copy link
Copy Markdown
Contributor

Reviewer Checklist

  • I have verified the author checklist is complete (all boxes are checked off).
  • I verified the correct issue is linked in the ### Fixed Issues section above
  • I verified testing steps are clear and they cover the changes made in this PR
    • I verified the steps for local testing are in the Tests section
    • I verified the steps for Staging and/or Production testing are in the QA steps section
    • I verified the steps cover any possible failure scenarios (i.e. verify an input displays the correct error message if the entered data is not correct)
    • I turned off my network connection and tested it while offline to ensure it matches the expected behavior (i.e. verify the default avatar icon is displayed if app is offline)
  • I checked that screenshots or videos are included for tests on all platforms
  • I included screenshots or videos for tests on all platforms
  • I verified that the composer does not automatically focus or open the keyboard on mobile unless explicitly intended. This includes checking that returning the app from the background does not unexpectedly open the keyboard.
  • I verified tests pass on all platforms & I tested again on:
    • Android: HybridApp
    • Android: mWeb Chrome
    • iOS: HybridApp
    • iOS: mWeb Safari
    • MacOS: Chrome / Safari
  • If there are any errors in the console that are unrelated to this PR, I either fixed them (preferred) or linked to where I reported them in Slack
  • I verified proper code patterns were followed (see Reviewing the code)
    • I verified that any callback methods that were added or modified are named for what the method does and never what callback they handle (i.e. toggleReport and not onIconClick).
    • I verified that comments were added to code that is not self explanatory
    • I verified that any new or modified comments were clear, correct English, and explained "why" the code was doing something instead of only explaining "what" the code was doing.
    • I verified any copy / text that was added to the app is grammatically correct in English. It adheres to proper capitalization guidelines (note: only the first word of header/labels should be capitalized), and is either coming verbatim from figma or has been approved by marketing (in order to get marketing approval, ask the Bug Zero team member to add the Waiting for copy label to the issue)
  • If a new code pattern is added I verified it was agreed to be used by multiple Expensify engineers
  • I verified that this PR follows the guidelines as stated in the Review Guidelines
  • I verified other components that can be impacted by these changes have been tested, and I retested again (i.e. if the PR modifies a shared library or component like Avatar, I verified the components using Avatar have been tested & I retested again)
  • If a new component is created I verified that:
    • A similar component doesn't exist in the codebase
    • All props are defined accurately and each prop has a /** comment above it */
    • The file is named correctly
    • The component has a clear name that is non-ambiguous and the purpose of the component can be inferred from the name alone
    • The only data being stored in the state is data necessary for rendering and nothing else
    • For Class Components, any internal methods passed to components event handlers are bound to this properly so there are no scoping issues (i.e. for onClick={this.submit} the method this.submit should be bound to this in the constructor)
    • Any internal methods bound to this are necessary to be bound (i.e. avoid this.submit = this.submit.bind(this); if this.submit is never passed to a component event handler like onClick)
    • All JSX used for rendering exists in the render method
    • The component has the minimum amount of code necessary for its purpose, and it is broken down into smaller components in order to separate concerns and functions
  • If any new file was added I verified that:
    • The file has a description of what it does and/or why is needed at the top of the file if the code is not self explanatory
  • If a new CSS style is added I verified that:
    • A similar style doesn't already exist
    • The style can't be created with an existing StyleUtils function (i.e. StyleUtils.getBackgroundAndBorderStyle(theme.componentBG)
  • If the PR modifies code that runs when editing or sending messages, I tested and verified there is no unexpected behavior for all supported markdown - URLs, single line code, code blocks, quotes, headings, bold, strikethrough, and italic.
  • If the PR modifies a generic component, I tested and verified that those changes do not break usages of that component in the rest of the App (i.e. if a shared library or component like Avatar is modified, I verified that Avatar is working as expected in all cases)
  • If the PR modifies a component related to any of the existing Storybook stories, I tested and verified all stories for that component are still working as expected.
  • If the PR modifies a component or page that can be accessed by a direct deeplink, I verified that the code functions as expected when the deeplink is used - from a logged in and logged out account.
  • If the PR modifies the UI (e.g. new buttons, new UI components, changing the padding/spacing/sizing, moving components, etc) or modifies the form input styles:
    • I verified that all the inputs inside a form are aligned with each other.
    • I added Design label and/or tagged @Expensify/design so the design team can review the changes.
  • For any bug fix or new feature in this PR, I verified that sufficient unit tests are included to prevent regressions in this flow.
  • If the main branch was merged into this PR after a review, I tested again and verified the outcome was still expected according to the Test steps.
  • I have checked off every checkbox in the PR reviewer checklist, including those that don't apply to this PR.

Screenshots/Videos

Android: HybridApp
android_hybrid.mp4
Android: mWeb Chrome
android_mWeb.mp4
iOS: HybridApp
ios_hybrid.mp4
iOS: mWeb Safari
ios_mWeb.mp4
MacOS: Chrome / Safari
web_chrom_QBO.mp4
web_chrom_sage_inttact.mp4
web_chrom_xero.mp4

@Krishna2323 Krishna2323 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM!

@melvin-bot melvin-bot Bot changed the title Align QBO and Xero Default vendor rows with the shared Intacct pattern [Payment due @Krishna2323] Align QBO and Xero Default vendor rows with the shared Intacct pattern Sep 3, 2026
@melvin-bot

melvin-bot Bot commented Sep 3, 2026

Copy link
Copy Markdown

🎯 @Krishna2323, thanks for reviewing and testing this PR! 🎉

A payment issue will be created for your review once this PR is deployed to production.
E/E issue linked to the PR - https://www.github.com/Expensify/Expensify/issues/664722.

If payment is not needed (e.g., regression PR review fix etc), react with 👎 to this comment to prevent the payment issue from being created.

…endor-fixes

# Conflicts:
#	src/languages/el.ts
@Beamanator

Beamanator commented Sep 3, 2026

Copy link
Copy Markdown
Contributor

Merged current main into this PR and pushed d5a6e48.

There was one conflict in src/languages/el.ts. I retained this PR's parameterized default-vendor helper and standardized header, and also preserved main's two newly added travel-billing tooltip translations. No QBO behavior or the Krishna punctuation fix was changed by the resolution.

Validation passed: TranslateTest (12/12), typecheck, changed-file lint, merge pre-commit formatting/action build, and React Compiler compliance.

🤖 Posted by Codex, an AI coding agent acting for @Beamanator.

@Beamanator

Beamanator commented Sep 3, 2026

Copy link
Copy Markdown
Contributor

Fixed the failing Verify check in 4b409a5.

Cause: this worktree's node_modules is a symlink to /Users/alexbeaman/Expensidev/App/node_modules. Rebuilding the authorChecklist action through that symlink emitted absolute local paths into its generated index.js. CI uses a clean install and emits repository-relative paths, so Verify detected a generated-file diff.

The authorChecklist action source is identical to current main; only its generated bundle differed. I restored the clean-build bundle from main and verified the resulting file is byte-identical to main's version. No product or QBO code changed.

🤖 Posted by Codex, an AI coding agent acting for @Beamanator.

@Beamanator

Beamanator commented Sep 3, 2026

Copy link
Copy Markdown
Contributor

Follow-up cleanup in 5e542c8: I removed 24 unrelated generated JavaScript Action bundle diffs that were retained by the merge. Their Action sources are identical to main, so they were restored to main's generated versions.

The net PR diff is now 23 relevant QBO/Xero/default-vendor files (238 additions / 154 deletions); no generated Action bundles remain. This also retains the authorChecklist clean-build fix needed by Verify.

🤖 Posted by Codex, an AI coding agent acting for @Beamanator.

@MelvinBot

Copy link
Copy Markdown
Contributor Author

The verify job (Validate Github Actions) was failing because 25 committed GitHub Action bundles under .github/actions/javascript/*/index.js had an absolute local path baked into them, so a clean rebuild in CI never reproduced them.

The bundles contained:

// ../../../Users/alexbeaman/Expensidev/App/node_modules/tunnel/lib/tunnel.js

where a rebuild from the repo root produces:

// node_modules/tunnel/lib/tunnel.js

verifyActions.sh runs npm run gh-actions-build then git diff --exit-code, so that path difference alone failed the check. The bundles were regenerated from a working directory outside the repo root, which is what leaked the path prefix in. It came in with the main merge d5a6e48.

This is now fixed. You pushed the same fix yourself while I was working on it — 4b409a5 for authorChecklist and 5e542c8 for the remaining 24. I verified your 5e542c8 tree is byte-identical to the fix I had prepared, so I did not push a redundant commit.

All checks now pass on 5e542c8. The only red check left is Check independent approval, which needs an Expensify employee other than me to approve.

Verification

Confirmed locally on 5e542c8:

  • npm run gh-actions-build followed by git diff --exit-code → exit 0, no diff. This is exactly what .github/scripts/verifyActions.sh runs.
  • Zero remaining references to the local path prefix anywhere under .github/.
  • My independently rebuilt bundles were byte-identical to main's, which confirms the correct content is just main's bundles — the PR changed no action source, only the generated output.

CI on 5e542c8:

Check Result
Validate Github Actions and Workflows (verify) pass
ESLint, Oxfmt, TypeScript, spellcheck, Knip, unused styles pass
Jest (8 jobs), Bun tests, Storybook pass
Reassure perf tests (baseline, branch, validate) pass
Generate static translations, React Compiler, signed commits pass
Check independent approval fail — needs a human approval

npm run test:bun shows 13 local failures in artifactsResolver, proposalPoliceComment, and createOrUpdateDeployChecklist. Those are pre-existing and unrelated — they fail identically on the pre-fix bundles, and CI's own Bun tests check passes.


view run

@MelvinBot

Copy link
Copy Markdown
Contributor Author

Still nothing for me to fix — all automated checks pass on the current head (5e542c8). The only red check is Check independent approval, which is human-gated:

Insufficient independent peer review
Expensify/App#99867 does not have enough independent Expensify employee approvals.
  approvers: [], independentApprovers: []

I authored this PR, so it needs an approval from a different Expensify employee. No commit can clear it, and it's what's holding mergeStateStatus at BLOCKED.

Full check status on 5e542c8

Since my last reply, three commits landed (d5a6e48 merge main, 4b409a5 fix generated author checklist action, 5e542c8 remove stale generated action bundles). Everything re-ran and is green:

Check Result
ESLint, Oxfmt, TypeScript, Spell check, Check unused styles pass
Jest Unit Tests, Bun tests, Reassure Performance Tests pass
Generate static translations, Knip, React Compiler Compliance pass
Validate GitHub Actions and Workflows, Check validateCode terminology pass
Verify signed commits, CLA Assistant, Onyx.connectWithoutView reviewers pass
PR Author Checklist pass
Check independent approval fail — needs a human approval

view run

@mollfpr mollfpr left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM!

@Beamanator
Beamanator merged commit 2fb1e5e into main Sep 3, 2026
35 of 36 checks passed
@Beamanator
Beamanator deleted the claude-alignQboXeroDefaultVendorRow branch September 3, 2026 14:16
@OSBotify

OSBotify commented Sep 3, 2026

Copy link
Copy Markdown
Contributor

✋ This PR was not deployed to staging yet because QA is ongoing. It will be automatically deployed to staging after the next production release.

@github-actions

github-actions Bot commented Sep 3, 2026

Copy link
Copy Markdown
Contributor

🚧 Beamanator has triggered a test Expensify/App build. You can view the workflow run here.

@OSBotify

OSBotify commented Sep 3, 2026

Copy link
Copy Markdown
Contributor

🚀 Deployed to staging by https://github.com/Beamanator in version: 9.4.70-0 🚀

platform result
🕸 web 🕸 success ✅
🤖 android 🤖 success ✅
🍎 iOS 🍎 success ✅

@MelvinBot

Copy link
Copy Markdown
Contributor Author

Yes — help site changes were required. Draft PR: #100344

Three user-visible changes in this PR weren't reflected in docs/articles:

  1. Xero's row was renamed "Default supplier" → "Default vendor" — and no help article documented that setting under either name, so there was nothing to correct, only a gap to fill.
  2. The QuickBooks Online Vendor bill default vendor is now selected directly, instead of sitting behind a toggle.
  3. Auto-create entities no longer rewrites the Default vendor — toggling it used to reset or auto-fill that setting.
What changed, and why

docs/articles/Unlisted/Manage-Vendor-Matching-for-Xero.md (new)

Documents the Xero Default vendor setting, the None option that clears it, and the fact that Xero applies no stand-in supplier when nothing is set — there's no Credit Card Misc equivalent, which is the exact distinction the new defaultVendorHelperText signature encodes.

Filed under Unlisted/ with noindex: true / sitemap: false, matching Manage-Vendor-Matching-for-Intacct.md, because Xero vendor matching is still behind the vendorMatching beta while QuickBooks Online is GA.

It also explains why the field on an expense reads Supplier while the workspace setting reads Default vendor — that split is the most likely confusion the rename creates for a Xero admin.

docs/articles/new-expensify/connections/quickbooks-online/Configure-Quickbooks-Online.md

  • Default vendor was nested under Debit card only, implying it didn't apply to Credit card. Now attached to both.
  • Bolded Default vendor on the Vendor bill line to match the UI label, and noted there's no Credit Card Misc / Debit Card Misc fallback for vendor bills.
  • Corrected the Advanced toggle label from "Automatically create entities" to the actual UI label Auto-create entities, and stated that toggling it doesn't change the Default vendor.
  • Dropped a stray .md from a relative article link.

docs/articles/new-expensify/connections/quickbooks-online/Manage-Vendor-Matching-for-QuickBooks-Online.md

Fixed a stray period in the fallback-vendor list. Left otherwise untouched — its internalScope is Credit card / Debit card exports, so the Vendor bill guidance went into the configuration article rather than widening this one.

Not changed: Configure-Xero.md. The Default vendor row is beta-gated, so it stays out of the public configuration article until the beta ships.

Verification note: the workspace Accounting navigation labels were confirmed against dev NewDot on web. The QuickBooks Online and Xero Export configuration pages sit behind a real OAuth connection that the test account can't establish, so those labels were verified against src/languages/en.ts and the page components instead of a running app.

@Beamanator, please review the linked help site PR and confirm it reflects the current behavior. Then mark the linked help site PR Ready for review


view run

@OSBotify

OSBotify commented Sep 4, 2026

Copy link
Copy Markdown
Contributor

🚀 Deployed to staging by https://github.com/Beamanator in version: 9.4.72-0 🚀

platform result
🕸 web 🕸 success ✅
🤖 android 🤖 success ✅
🍎 iOS 🍎 success ✅

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

Labels

InternalQA This pull request required internal QA Melvin-Test-Android Melvin-Test-Web Triggers Melvin to run the testing steps of the PR on web

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants