From 40649389ab2ffa08457f5f0c28f7ccbd59be4de0 Mon Sep 17 00:00:00 2001 From: "Roji Philip (via MelvinBot)" Date: Fri, 6 Mar 2026 11:14:05 +0000 Subject: [PATCH 1/8] Update option display names when derived reportAttributes change Add a dedicated effect in OptionsListContextProvider that watches reportAttributes.reports and updates option display names (text) when the derived value provides a name that differs from what is currently stored. This fixes the timing gap where options can be initialized before derived report names are computed, causing reports like Chronos to show "Chat Report" instead of their correct name in search results. Co-authored-by: Roji Philip --- src/components/OptionListContextProvider.tsx | 32 ++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/src/components/OptionListContextProvider.tsx b/src/components/OptionListContextProvider.tsx index 1aa1cb33ca950..ecf8707abddcf 100644 --- a/src/components/OptionListContextProvider.tsx +++ b/src/components/OptionListContextProvider.tsx @@ -184,6 +184,38 @@ function OptionsListContextProvider({children}: OptionsListProviderProps) { }); }, [changedReportActions, personalDetails, currentUserAccountID, reports, reportAttributes?.reports, privateIsArchivedMap]); + /** + * This effect is responsible for updating option display names when reportAttributes + * provides a name that differs from what's currently stored. This handles the timing + * gap where options may be initialized before derived report names are computed. + */ + useEffect(() => { + if (!areOptionsInitialized.current || !reportAttributes?.reports) { + return; + } + + setOptions((prevOptions) => { + let hasChanges = false; + const updatedReports = prevOptions.reports.map((option) => { + const derivedName = reportAttributes.reports[option.reportID]?.reportName; + if (derivedName && derivedName !== option.text) { + hasChanges = true; + return {...option, text: derivedName}; + } + return option; + }); + + if (!hasChanges) { + return prevOptions; + } + + return { + ...prevOptions, + reports: updatedReports, + }; + }); + }, [reportAttributes?.reports]); + /** * This effect is used to update the options list when personal details change. */ From b17d3613a126a908e10147bca6230f15ad92270e Mon Sep 17 00:00:00 2001 From: "Roji Philip (via MelvinBot)" Date: Mon, 9 Mar 2026 08:44:00 +0000 Subject: [PATCH 2/8] Replace reportAttributes effect with Chronos display name constant Mirror the existing Concierge pattern by adding CHRONOS_DISPLAY_NAME and a chatIncludesChronos check in both computeReportName and getReportName. This ensures Chronos always resolves to its correct display name regardless of personal details loading timing, instead of relying on a dedicated effect in OptionsListContextProvider. Co-authored-by: Roji Philip --- src/CONST/index.ts | 1 + src/components/OptionListContextProvider.tsx | 32 -------------------- src/libs/ReportNameUtils.ts | 5 +++ src/libs/ReportUtils.ts | 4 +++ 4 files changed, 10 insertions(+), 32 deletions(-) diff --git a/src/CONST/index.ts b/src/CONST/index.ts index f95f82031b13e..7fb6a7fc8db69 100644 --- a/src/CONST/index.ts +++ b/src/CONST/index.ts @@ -2391,6 +2391,7 @@ const CONST = { }, CONCIERGE_DISPLAY_NAME: 'Concierge', + CHRONOS_DISPLAY_NAME: 'Chronos', INTEGRATION_ENTITY_MAP_TYPES: { DEFAULT: 'DEFAULT', diff --git a/src/components/OptionListContextProvider.tsx b/src/components/OptionListContextProvider.tsx index ecf8707abddcf..1aa1cb33ca950 100644 --- a/src/components/OptionListContextProvider.tsx +++ b/src/components/OptionListContextProvider.tsx @@ -184,38 +184,6 @@ function OptionsListContextProvider({children}: OptionsListProviderProps) { }); }, [changedReportActions, personalDetails, currentUserAccountID, reports, reportAttributes?.reports, privateIsArchivedMap]); - /** - * This effect is responsible for updating option display names when reportAttributes - * provides a name that differs from what's currently stored. This handles the timing - * gap where options may be initialized before derived report names are computed. - */ - useEffect(() => { - if (!areOptionsInitialized.current || !reportAttributes?.reports) { - return; - } - - setOptions((prevOptions) => { - let hasChanges = false; - const updatedReports = prevOptions.reports.map((option) => { - const derivedName = reportAttributes.reports[option.reportID]?.reportName; - if (derivedName && derivedName !== option.text) { - hasChanges = true; - return {...option, text: derivedName}; - } - return option; - }); - - if (!hasChanges) { - return prevOptions; - } - - return { - ...prevOptions, - reports: updatedReports, - }; - }); - }, [reportAttributes?.reports]); - /** * This effect is used to update the options list when personal details change. */ diff --git a/src/libs/ReportNameUtils.ts b/src/libs/ReportNameUtils.ts index f22c3d83229c9..64cbdb026212a 100644 --- a/src/libs/ReportNameUtils.ts +++ b/src/libs/ReportNameUtils.ts @@ -121,6 +121,7 @@ import { isChatRoom, isChatThread, isClosedExpenseReportWithNoExpenses, + chatIncludesChronos, isConciergeChatReport, isExpenseReport, isGroupChat, @@ -865,6 +866,10 @@ function computeReportName( formattedName = CONST.CONCIERGE_DISPLAY_NAME; } + if (chatIncludesChronos(report)) { + formattedName = CONST.CHRONOS_DISPLAY_NAME; + } + const isArchivedNonExpense = isArchivedNonExpenseReport(report, !!privateIsArchivedValue); if (formattedName) { diff --git a/src/libs/ReportUtils.ts b/src/libs/ReportUtils.ts index 10a66a5c69bef..8b3d846e44a56 100644 --- a/src/libs/ReportUtils.ts +++ b/src/libs/ReportUtils.ts @@ -5942,6 +5942,10 @@ function getReportName(reportNameInformation: GetReportNameParams): string { formattedName = CONST.CONCIERGE_DISPLAY_NAME; } + if (chatIncludesChronos(report)) { + formattedName = CONST.CHRONOS_DISPLAY_NAME; + } + if (formattedName) { return formatReportLastMessageText(isArchivedNonExpense ? generateArchivedReportName(formattedName) : formattedName); } From 43ee364bf2402d0c9ae1129f4f86221c71e8d18c Mon Sep 17 00:00:00 2001 From: "Roji Philip (via MelvinBot)" Date: Mon, 9 Mar 2026 08:46:22 +0000 Subject: [PATCH 3/8] Fix: Sort imports to match Prettier configuration Co-authored-by: Roji Philip --- src/libs/ReportNameUtils.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libs/ReportNameUtils.ts b/src/libs/ReportNameUtils.ts index 64cbdb026212a..9ac0cbc0d10b3 100644 --- a/src/libs/ReportNameUtils.ts +++ b/src/libs/ReportNameUtils.ts @@ -101,6 +101,7 @@ import { } from './ReportActionsUtils'; // eslint-disable-next-line import/no-cycle import { + chatIncludesChronos, formatReportLastMessageText, getDisplayNameForParticipant, getMoneyRequestSpendBreakdown, @@ -121,7 +122,6 @@ import { isChatRoom, isChatThread, isClosedExpenseReportWithNoExpenses, - chatIncludesChronos, isConciergeChatReport, isExpenseReport, isGroupChat, From b1ac72ff06e8295d20c8f93385cef7490b339b9b Mon Sep 17 00:00:00 2001 From: "Roji Philip (via MelvinBot)" Date: Mon, 9 Mar 2026 08:59:22 +0000 Subject: [PATCH 4/8] Fix Chronos display name overriding Concierge in report name resolution Use else-if so the Chronos check doesn't overwrite the Concierge name when both account IDs resolve to the same value (e.g. in dev/test envs). Co-authored-by: Roji Philip --- src/libs/ReportNameUtils.ts | 4 +--- src/libs/ReportUtils.ts | 4 +--- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/src/libs/ReportNameUtils.ts b/src/libs/ReportNameUtils.ts index 9ac0cbc0d10b3..e0058320d9b08 100644 --- a/src/libs/ReportNameUtils.ts +++ b/src/libs/ReportNameUtils.ts @@ -864,9 +864,7 @@ function computeReportName( if (isConciergeChatReport(report)) { formattedName = CONST.CONCIERGE_DISPLAY_NAME; - } - - if (chatIncludesChronos(report)) { + } else if (chatIncludesChronos(report)) { formattedName = CONST.CHRONOS_DISPLAY_NAME; } diff --git a/src/libs/ReportUtils.ts b/src/libs/ReportUtils.ts index 8b3d846e44a56..82a38e79c633c 100644 --- a/src/libs/ReportUtils.ts +++ b/src/libs/ReportUtils.ts @@ -5940,9 +5940,7 @@ function getReportName(reportNameInformation: GetReportNameParams): string { if (isConciergeChatReport(report, conciergeReportID)) { formattedName = CONST.CONCIERGE_DISPLAY_NAME; - } - - if (chatIncludesChronos(report)) { + } else if (chatIncludesChronos(report)) { formattedName = CONST.CHRONOS_DISPLAY_NAME; } From 2bb44a775470a66e6fb6aa3b0648bd0f55ab79f5 Mon Sep 17 00:00:00 2001 From: "Roji Philip (via MelvinBot)" Date: Thu, 19 Mar 2026 03:43:11 +0000 Subject: [PATCH 5/8] Re-apply Chronos display name changes after merge with main Co-authored-by: Roji Philip --- src/CONST/index.ts | 1 + src/libs/ReportNameUtils.ts | 3 +++ src/libs/ReportUtils.ts | 2 ++ 3 files changed, 6 insertions(+) diff --git a/src/CONST/index.ts b/src/CONST/index.ts index aa4b86c00de74..490829ee5482f 100644 --- a/src/CONST/index.ts +++ b/src/CONST/index.ts @@ -2452,6 +2452,7 @@ const CONST = { }, CONCIERGE_DISPLAY_NAME: 'Concierge', + CHRONOS_DISPLAY_NAME: 'Chronos', CONCIERGE_GREETING_ACTION_ID: 'concierge-side-panel-greeting', INTEGRATION_ENTITY_MAP_TYPES: { diff --git a/src/libs/ReportNameUtils.ts b/src/libs/ReportNameUtils.ts index 909a05d6b99f2..66d043e358343 100644 --- a/src/libs/ReportNameUtils.ts +++ b/src/libs/ReportNameUtils.ts @@ -102,6 +102,7 @@ import { } from './ReportActionsUtils'; // eslint-disable-next-line import/no-cycle import { + chatIncludesChronos, formatReportLastMessageText, getDisplayNameForParticipant, getMoneyRequestSpendBreakdown, @@ -915,6 +916,8 @@ function computeReportName({ if (isConciergeChatReport(report)) { formattedName = CONST.CONCIERGE_DISPLAY_NAME; + } else if (chatIncludesChronos(report)) { + formattedName = CONST.CHRONOS_DISPLAY_NAME; } const isArchivedNonExpense = isArchivedNonExpenseReport(report, !!privateIsArchivedValue); diff --git a/src/libs/ReportUtils.ts b/src/libs/ReportUtils.ts index bf7da4cfcdd01..4a998f8817af7 100644 --- a/src/libs/ReportUtils.ts +++ b/src/libs/ReportUtils.ts @@ -5987,6 +5987,8 @@ function getReportName(reportNameInformation: GetReportNameParams): string { if (isConciergeChatReport(report, conciergeReportID)) { formattedName = CONST.CONCIERGE_DISPLAY_NAME; + } else if (chatIncludesChronos(report)) { + formattedName = CONST.CHRONOS_DISPLAY_NAME; } if (formattedName) { From 86b67287560a30062e66000467f78ce4ba671a10 Mon Sep 17 00:00:00 2001 From: "Roji Philip (via MelvinBot)" Date: Thu, 19 Mar 2026 03:46:03 +0000 Subject: [PATCH 6/8] Remove stale old-version sentry patch files These patches (for sentry 10.24.0 and react-native 7.6.0) were superseded by updated versions on main but remained as merge artifacts. Removing them fixes the validate-patches CI check. Co-authored-by: Roji Philip --- ...owser+10.24.0+001+request-id-support.patch | 15 --- ...0.24.0+001+data-sentry-label-support.patch | 122 ------------------ ...+core+10.24.0+002+request-id-support.patch | 16 --- .../@sentry+react-native+7.6.0.patch | 33 ----- 4 files changed, 186 deletions(-) delete mode 100644 patches/sentry-browser/@sentry+browser+10.24.0+001+request-id-support.patch delete mode 100644 patches/sentry-core/@sentry+core+10.24.0+001+data-sentry-label-support.patch delete mode 100644 patches/sentry-core/@sentry+core+10.24.0+002+request-id-support.patch delete mode 100644 patches/sentry-react-native/@sentry+react-native+7.6.0.patch diff --git a/patches/sentry-browser/@sentry+browser+10.24.0+001+request-id-support.patch b/patches/sentry-browser/@sentry+browser+10.24.0+001+request-id-support.patch deleted file mode 100644 index 85725e4e067b0..0000000000000 --- a/patches/sentry-browser/@sentry+browser+10.24.0+001+request-id-support.patch +++ /dev/null @@ -1,15 +0,0 @@ -diff --git a/node_modules/@sentry/browser/build/npm/esm/tracing/request.js b/node_modules/@sentry/browser/build/npm/esm/tracing/request.js -index da5822e..04f3c80 100644 ---- a/node_modules/@sentry/browser/build/npm/esm/tracing/request.js -+++ b/node_modules/@sentry/browser/build/npm/esm/tracing/request.js -@@ -225,6 +225,10 @@ function xhrCallback( - const span = spans[spanId]; - if (span && sentryXhrData.status_code !== undefined) { - setHttpStatus(span, sentryXhrData.status_code); -+ const requestId = handlerData.xhr.getResponseHeader('x-request-id'); -+ if (requestId) { -+ span.setAttribute('request-id', requestId) -+ } - span.end(); - - onRequestSpanEnd?.(span, { diff --git a/patches/sentry-core/@sentry+core+10.24.0+001+data-sentry-label-support.patch b/patches/sentry-core/@sentry+core+10.24.0+001+data-sentry-label-support.patch deleted file mode 100644 index 351f1bad7c2f9..0000000000000 --- a/patches/sentry-core/@sentry+core+10.24.0+001+data-sentry-label-support.patch +++ /dev/null @@ -1,122 +0,0 @@ -diff --git a/node_modules/@sentry/core/build/cjs/utils/browser.js b/node_modules/@sentry/core/build/cjs/utils/browser.js -index 3169c25..19acc49 100644 ---- a/node_modules/@sentry/core/build/cjs/utils/browser.js -+++ b/node_modules/@sentry/core/build/cjs/utils/browser.js -@@ -9,8 +9,8 @@ const DEFAULT_MAX_STRING_LENGTH = 80; - - /** - * Given a child DOM element, returns a query-selector statement describing that -- * and its ancestors -- * e.g. [HTMLElement] => body > div > input#foo.btn[name=baz] -+ * and its ancestors, prefixed with data-sentry-label if found on ancestor -+ * e.g. [HTMLElement] => [data-sentry-label="MyLabel"] div.css-146c3p1.r-1udh08x.r-1udbk01.r-1iln25a > svg - * @returns generated DOM path - */ - function htmlTreeAsString( -@@ -53,7 +53,30 @@ function htmlTreeAsString( - currentElem = currentElem.parentNode; - } - -- return out.reverse().join(separator); -+ const cssSelector = out.reverse().join(separator); -+ -+ // If cssSelector already contains data-sentry-label, return as is -+ if (cssSelector.includes('[data-sentry-label="')) { -+ return cssSelector; -+ } -+ -+ // Search for data-sentry-label up to 15 levels (beyond the 5 levels of cssSelector) -+ let labelElem = elem; -+ let dataLabel = null; -+ for (let i = 0; i < 15 && labelElem; i++) { -+ // @ts-expect-error WINDOW has HTMLElement -+ if (WINDOW.HTMLElement && labelElem instanceof HTMLElement && labelElem.dataset && labelElem.dataset['sentryLabel']) { -+ dataLabel = labelElem.dataset['sentryLabel']; -+ break; -+ } -+ labelElem = labelElem.parentNode; -+ } -+ -+ if (dataLabel) { -+ return `[data-sentry-label="${dataLabel}"] ${cssSelector}`; -+ } -+ -+ return cssSelector; - } catch { - return ''; - } -@@ -77,8 +100,12 @@ function _htmlElementAsString(el, keyAttrs) { - - // @ts-expect-error WINDOW has HTMLElement - if (WINDOW.HTMLElement) { -- // If using the component name annotation plugin, this value may be available on the DOM node - if (elem instanceof HTMLElement && elem.dataset) { -+ // Check for data-sentry-label first - return in attribute format [data-sentry-label="value"] -+ if (elem.dataset['sentryLabel']) { -+ return `[data-sentry-label="${elem.dataset['sentryLabel']}"]`; -+ } -+ // If using the component name annotation plugin, this value may be available on the DOM node - if (elem.dataset['sentryComponent']) { - return elem.dataset['sentryComponent']; - } -diff --git a/node_modules/@sentry/core/build/esm/utils/browser.js b/node_modules/@sentry/core/build/esm/utils/browser.js -index 2ad52b0..fd184fb 100644 ---- a/node_modules/@sentry/core/build/esm/utils/browser.js -+++ b/node_modules/@sentry/core/build/esm/utils/browser.js -@@ -7,8 +7,8 @@ const DEFAULT_MAX_STRING_LENGTH = 80; - - /** - * Given a child DOM element, returns a query-selector statement describing that -- * and its ancestors -- * e.g. [HTMLElement] => body > div > input#foo.btn[name=baz] -+ * and its ancestors, prefixed with data-sentry-label if found on ancestor -+ * e.g. [HTMLElement] => [data-sentry-label="MyLabel"] div.css-146c3p1.r-1udh08x.r-1udbk01.r-1iln25a > svg - * @returns generated DOM path - */ - function htmlTreeAsString( -@@ -51,7 +51,30 @@ function htmlTreeAsString( - currentElem = currentElem.parentNode; - } - -- return out.reverse().join(separator); -+ const cssSelector = out.reverse().join(separator); -+ -+ // If cssSelector already contains data-sentry-label, return as is -+ if (cssSelector.includes('[data-sentry-label="')) { -+ return cssSelector; -+ } -+ -+ // Search for data-sentry-label up to 15 levels (beyond the 5 levels of cssSelector) -+ let labelElem = elem; -+ let dataLabel = null; -+ for (let i = 0; i < 15 && labelElem; i++) { -+ // @ts-expect-error WINDOW has HTMLElement -+ if (WINDOW.HTMLElement && labelElem instanceof HTMLElement && labelElem.dataset && labelElem.dataset['sentryLabel']) { -+ dataLabel = labelElem.dataset['sentryLabel']; -+ break; -+ } -+ labelElem = labelElem.parentNode; -+ } -+ -+ if (dataLabel) { -+ return `[data-sentry-label="${dataLabel}"] ${cssSelector}`; -+ } -+ -+ return cssSelector; - } catch { - return ''; - } -@@ -75,8 +98,12 @@ function _htmlElementAsString(el, keyAttrs) { - - // @ts-expect-error WINDOW has HTMLElement - if (WINDOW.HTMLElement) { -- // If using the component name annotation plugin, this value may be available on the DOM node - if (elem instanceof HTMLElement && elem.dataset) { -+ // Check for data-sentry-label first - return in attribute format [data-sentry-label="value"] -+ if (elem.dataset['sentryLabel']) { -+ return `[data-sentry-label="${elem.dataset['sentryLabel']}"]`; -+ } -+ // If using the component name annotation plugin, this value may be available on the DOM node - if (elem.dataset['sentryComponent']) { - return elem.dataset['sentryComponent']; - } diff --git a/patches/sentry-core/@sentry+core+10.24.0+002+request-id-support.patch b/patches/sentry-core/@sentry+core+10.24.0+002+request-id-support.patch deleted file mode 100644 index 4792ef44bb96a..0000000000000 --- a/patches/sentry-core/@sentry+core+10.24.0+002+request-id-support.patch +++ /dev/null @@ -1,16 +0,0 @@ -diff --git a/node_modules/@sentry/core/build/esm/fetch.js b/node_modules/@sentry/core/build/esm/fetch.js -index 3c6eafb..33481e8 100644 ---- a/node_modules/@sentry/core/build/esm/fetch.js -+++ b/node_modules/@sentry/core/build/esm/fetch.js -@@ -235,7 +235,10 @@ function _addTracingHeadersToFetchRequest( - function endSpan(span, handlerData) { - if (handlerData.response) { - setHttpStatus(span, handlerData.response.status); -- -+ const requestId = handlerData.response?.headers?.get('x-request-id'); -+ if (requestId) { -+ span.setAttribute('request-id', requestId) -+ } - const contentLength = handlerData.response?.headers?.get('content-length'); - - if (contentLength) { diff --git a/patches/sentry-react-native/@sentry+react-native+7.6.0.patch b/patches/sentry-react-native/@sentry+react-native+7.6.0.patch deleted file mode 100644 index 0b50294fd9b27..0000000000000 --- a/patches/sentry-react-native/@sentry+react-native+7.6.0.patch +++ /dev/null @@ -1,33 +0,0 @@ -diff --git a/node_modules/@sentry/react-native/scripts/sentry_utils.rb b/node_modules/@sentry/react-native/scripts/sentry_utils.rb -index 5dc57a3..8887025 100644 ---- a/node_modules/@sentry/react-native/scripts/sentry_utils.rb -+++ b/node_modules/@sentry/react-native/scripts/sentry_utils.rb -@@ -1,8 +1,24 @@ - def parse_rn_package_json() -- rn_path = File.dirname(`node --print "require.resolve('react-native/package.json')"`) -- env_rn_path = ENV['REACT_NATIVE_NODE_MODULES_DIR'] -- if env_rn_path != nil -- rn_path = env_rn_path -+ # Try to resolve from installation root first (similar to react-native-svg and react-native-reanimated) -+ rn_path = nil -+ begin -+ rn_path = File.dirname(`cd "#{Pod::Config.instance.installation_root.to_s}" && node --print "require.resolve('react-native/package.json')" 2>/dev/null`.strip) -+ rescue -+ # node resolution failed, will try ENV fallback -+ end -+ -+ # Fall back to ENV variable if node resolution didn't work -+ if rn_path.nil? || rn_path.empty? -+ env_rn_path = ENV['REACT_NATIVE_NODE_MODULES_DIR'] -+ if env_rn_path != nil -+ # Check if ENV points to node_modules or node_modules/react-native -+ # Support both conventions for compatibility -+ if File.exist?(File.join(env_rn_path, 'package.json')) -+ rn_path = env_rn_path # Already points to react-native directory -+ elsif File.exist?(File.join(env_rn_path, 'react-native/package.json')) -+ rn_path = File.join(env_rn_path, 'react-native') # Points to node_modules -+ end -+ end - end - - rn_package_json_path = File.join(rn_path, 'package.json') From abf32aaac3c32ef60ae1f0b7511ed7055fdb4f55 Mon Sep 17 00:00:00 2001 From: "Roji Philip (via MelvinBot)" Date: Thu, 19 Mar 2026 04:00:15 +0000 Subject: [PATCH 7/8] Remove stale files from old branch base that no longer exist on main The branch was based on an older version of main that had files since removed. After merging with current main, these 106 stale files were incorrectly retained as merge artifacts. Removing them to fix the Changed files ESLint check, which was flagging ESLint errors in these unrelated files. Co-authored-by: Roji Philip --- .../connections/TravelPerk.md | 52 --- .../certinia/Certinia-Troubleshooting.md | 175 --------- .../Overview.md | 9 - .../Connection-errors/Overview.md | 9 - .../Troubleshooting/Sync-Errors/Overview.md | 9 - .../netsuite/Netsuite-Troubleshooting.md | 289 -------------- .../Overview.md | 9 - .../Connection-errors/Overview.md | 9 - .../Troubleshooting/Export-Errors/Overview.md | 9 - .../Troubleshooting/Sync-Errors/Overview.md | 9 - .../Quickbooks-Desktop-Troubleshooting.md | 125 ------ .../Overview.md | 9 - .../Connection-errors/Overview.md | 9 - .../Troubleshooting/Export-Errors/Overview.md | 9 - .../Troubleshooting/Sync-Errors/Overview.md | 9 - .../Quickbooks-Online-Troubleshooting.md | 176 --------- .../Overview.md | 9 - .../Troubleshooting/Export-Errors/Overview.md | 9 - .../Troubleshooting/Sync-Errors/Overview.md | 9 - .../Sage-Intacct-Troubleshooting.md | 206 ---------- .../Overview.md | 9 - .../Connection-errors/Overview.md | 9 - .../Troubleshooting/Export-Errors/Overview.md | 9 - .../Troubleshooting/Sync-Errors/Overview.md | 9 - .../Overview.md | 9 - .../Connection-errors/Overview.md | 9 - .../Troubleshooting/Export-Errors/Overview.md | 9 - .../Troubleshooting/Sync-Errors/Overview.md | 9 - .../connections/xero/Xero-Troubleshooting.md | 144 ------- ...Export- Expenses-from-the-Expenses-Page.md | 73 ---- .../netsuite/Netsuite-Troubleshooting.md | 366 ------------------ .../Overview.md | 9 - .../Connection-errors/Overview.md | 9 - .../Troubleshooting/Export-Errors/Overview.md | 9 - .../Troubleshooting/Sync-Errors/Overview.md | 9 - .../QuickBooks-Desktop-Troubleshooting.md | 116 ------ .../Overview.md | 9 - .../Connection-errors/Overview.md | 9 - .../Troubleshooting/Export-Errors/Overview.md | 9 - .../Troubleshooting/Sync-Errors/Overview.md | 9 - .../Quickbooks-Online-Troubleshooting.md | 204 ---------- .../Overview.md | 9 - .../Connection-errors/Overview.md | 9 - .../Troubleshooting/Sync-Errors/Overview.md | 9 - .../Sage-Intacct-Troubleshooting.md | 206 ---------- .../Troubleshooting/Export-Errors/Overview.md | 9 - .../Troubleshooting/Sync-Errors/Overview.md | 9 - .../Overview.md | 9 - .../Troubleshooting/Export-Errors/Overview.md | 9 - .../Troubleshooting/Sync-Errors/Overview.md | 9 - .../connections/xero/Xero-Troubleshooting.md | 44 --- .../workspaces/Create-expense-tags.md | 170 -------- src/components/Deferred.tsx | 30 -- .../numberOfConcurrentLightboxes/types.ts | 5 - .../Search/ActionCell/BadgeActionCell.tsx | 50 --- .../ScrollableTabSelector.tsx | 76 ---- .../ScrollableTabSelectorBase.tsx | 108 ------ .../ScrollableTabSelectorContext.tsx | 85 ---- .../ScrollableTabSelectorItem.tsx | 74 ---- .../scrollToTab/index.native.ts | 24 -- .../scrollToTab/index.ts | 11 - .../scrollToTab/types.ts | 15 - ...elpMessageAccessibilityAnnouncement.ios.ts | 31 -- ...ormHelpMessageAccessibilityAnnouncement.ts | 6 - src/hooks/useDismissModalForUSD.tsx | 19 - src/hooks/useExportedToAutocompleteList.ts | 30 -- ...onalDetailsAndRevealExpensifyCardParams.ts | 16 - .../Navigation/guards/TestDriveModalGuard.ts | 163 -------- .../Navigation/helpers/createDynamicRoute.ts | 35 -- .../helpers/getLastSuffixFromPath.ts | 23 -- .../helpers/getStateForDynamicRoute.ts | 69 ---- .../helpers/isDynamicRouteSuffix.ts | 11 - .../Navigation/helpers/splitPathAndQuery.ts | 13 - src/libs/migrations/RenameEmojiSkinTone.ts | 36 -- .../RequireTwoFactorAuthenticationPage.tsx | 90 ----- .../types.ts | 5 - .../index.native.tsx | 54 --- .../step/DiscardChangesConfirmation/index.tsx | 119 ------ .../step/DiscardChangesConfirmation/types.ts | 7 - .../NavigationAwareCamera/Camera.tsx | 22 -- .../NavigationAwareCamera/WebCamera.tsx | 32 -- .../NavigationAwareCamera/types.ts | 16 - .../SubmitButtonShadow/index.native.tsx | 12 - .../SubmitButtonShadow/index.tsx | 12 - .../ReceiptPreviews/index.tsx | 147 ------- .../step/IOURequestStepScan/useReceiptScan.ts | 314 --------------- .../IOURequestStepScan/useScanShortcutSpan.ts | 22 -- .../PersonalDetails/CountrySelectionPage.tsx | 96 ----- ...pensifyCardMissingDetailsMagicCodePage.tsx | 98 ----- .../ExpensifyCardMissingDetailsPage.tsx | 37 -- .../NewBankAccountVerifyAccountPage.tsx | 30 -- .../substeps/ChooseCustomListStep.tsx | 60 --- .../substeps/ChooseSegmentTypeStep.tsx | 73 ---- .../substeps/ConfirmCustomListStep.tsx | 60 --- .../substeps/ConfirmCustomSegmentList.tsx | 63 --- .../substeps/CustomListMappingStep.tsx | 74 ---- .../substeps/CustomSegmentInternalIdStep.tsx | 92 ----- .../substeps/CustomSegmentMappingStep.tsx | 74 ---- .../substeps/CustomSegmentNameStep.tsx | 90 ----- .../substeps/CustomSegmentScriptIdStep.tsx | 94 ----- .../substeps/TransactionFieldIDStep.tsx | 82 ---- .../navigation/getLastSuffixFromPathTests.ts | 39 -- tests/unit/ForegroundNotificationsTest.ts | 84 ---- .../guards/TestDriveModalGuard.test.ts | 220 ----------- .../useExportedToAutocompleteList.test.ts | 130 ------- tests/unit/useDismissModalForUSDTest.ts | 22 -- 106 files changed, 5988 deletions(-) delete mode 100644 docs/articles/expensify-classic/connections/TravelPerk.md delete mode 100644 docs/articles/expensify-classic/connections/certinia/Certinia-Troubleshooting.md delete mode 100644 docs/articles/expensify-classic/connections/certinia/Troubleshooting/Authentication-and-Login-errors/Overview.md delete mode 100644 docs/articles/expensify-classic/connections/certinia/Troubleshooting/Connection-errors/Overview.md delete mode 100644 docs/articles/expensify-classic/connections/certinia/Troubleshooting/Sync-Errors/Overview.md delete mode 100644 docs/articles/expensify-classic/connections/netsuite/Netsuite-Troubleshooting.md delete mode 100644 docs/articles/expensify-classic/connections/netsuite/Troubleshooting/Authentication-and-Login-errors/Overview.md delete mode 100644 docs/articles/expensify-classic/connections/netsuite/Troubleshooting/Connection-errors/Overview.md delete mode 100644 docs/articles/expensify-classic/connections/netsuite/Troubleshooting/Export-Errors/Overview.md delete mode 100644 docs/articles/expensify-classic/connections/netsuite/Troubleshooting/Sync-Errors/Overview.md delete mode 100644 docs/articles/expensify-classic/connections/quickbooks-desktop/Quickbooks-Desktop-Troubleshooting.md delete mode 100644 docs/articles/expensify-classic/connections/quickbooks-desktop/Troubleshooting/Authentication-and-Login-errors/Overview.md delete mode 100644 docs/articles/expensify-classic/connections/quickbooks-desktop/Troubleshooting/Connection-errors/Overview.md delete mode 100644 docs/articles/expensify-classic/connections/quickbooks-desktop/Troubleshooting/Export-Errors/Overview.md delete mode 100644 docs/articles/expensify-classic/connections/quickbooks-desktop/Troubleshooting/Sync-Errors/Overview.md delete mode 100644 docs/articles/expensify-classic/connections/quickbooks-online/Quickbooks-Online-Troubleshooting.md delete mode 100644 docs/articles/expensify-classic/connections/quickbooks-online/Troubleshooting/Authentication-and-Login-errors/Overview.md delete mode 100644 docs/articles/expensify-classic/connections/quickbooks-online/Troubleshooting/Export-Errors/Overview.md delete mode 100644 docs/articles/expensify-classic/connections/quickbooks-online/Troubleshooting/Sync-Errors/Overview.md delete mode 100644 docs/articles/expensify-classic/connections/sage-intacct/Sage-Intacct-Troubleshooting.md delete mode 100644 docs/articles/expensify-classic/connections/sage-intacct/Troubleshooting/Authentication-and-Login-errors/Overview.md delete mode 100644 docs/articles/expensify-classic/connections/sage-intacct/Troubleshooting/Connection-errors/Overview.md delete mode 100644 docs/articles/expensify-classic/connections/sage-intacct/Troubleshooting/Export-Errors/Overview.md delete mode 100644 docs/articles/expensify-classic/connections/sage-intacct/Troubleshooting/Sync-Errors/Overview.md delete mode 100644 docs/articles/expensify-classic/connections/xero/Troubleshooting/Authentication-and-Login-errors/Overview.md delete mode 100644 docs/articles/expensify-classic/connections/xero/Troubleshooting/Connection-errors/Overview.md delete mode 100644 docs/articles/expensify-classic/connections/xero/Troubleshooting/Export-Errors/Overview.md delete mode 100644 docs/articles/expensify-classic/connections/xero/Troubleshooting/Sync-Errors/Overview.md delete mode 100644 docs/articles/expensify-classic/connections/xero/Xero-Troubleshooting.md delete mode 100644 docs/articles/expensify-classic/expenses/Export- Expenses-from-the-Expenses-Page.md delete mode 100644 docs/articles/new-expensify/connections/netsuite/Netsuite-Troubleshooting.md delete mode 100644 docs/articles/new-expensify/connections/netsuite/Troubleshooting/Authentication-and-Login-errors/Overview.md delete mode 100644 docs/articles/new-expensify/connections/netsuite/Troubleshooting/Connection-errors/Overview.md delete mode 100644 docs/articles/new-expensify/connections/netsuite/Troubleshooting/Export-Errors/Overview.md delete mode 100644 docs/articles/new-expensify/connections/netsuite/Troubleshooting/Sync-Errors/Overview.md delete mode 100644 docs/articles/new-expensify/connections/quickbooks-desktop/QuickBooks-Desktop-Troubleshooting.md delete mode 100644 docs/articles/new-expensify/connections/quickbooks-desktop/Troubleshooting/Authentication-and-Login-errors/Overview.md delete mode 100644 docs/articles/new-expensify/connections/quickbooks-desktop/Troubleshooting/Connection-errors/Overview.md delete mode 100644 docs/articles/new-expensify/connections/quickbooks-desktop/Troubleshooting/Export-Errors/Overview.md delete mode 100644 docs/articles/new-expensify/connections/quickbooks-desktop/Troubleshooting/Sync-Errors/Overview.md delete mode 100644 docs/articles/new-expensify/connections/quickbooks-online/Quickbooks-Online-Troubleshooting.md delete mode 100644 docs/articles/new-expensify/connections/quickbooks-online/Troubleshooting/Authentication-and-Login-errors/Overview.md delete mode 100644 docs/articles/new-expensify/connections/quickbooks-online/Troubleshooting/Connection-errors/Overview.md delete mode 100644 docs/articles/new-expensify/connections/quickbooks-online/Troubleshooting/Sync-Errors/Overview.md delete mode 100644 docs/articles/new-expensify/connections/sage-intacct/Sage-Intacct-Troubleshooting.md delete mode 100644 docs/articles/new-expensify/connections/sage-intacct/Troubleshooting/Export-Errors/Overview.md delete mode 100644 docs/articles/new-expensify/connections/sage-intacct/Troubleshooting/Sync-Errors/Overview.md delete mode 100644 docs/articles/new-expensify/connections/xero/Troubleshooting/Authentication-and-Login-errors/Overview.md delete mode 100644 docs/articles/new-expensify/connections/xero/Troubleshooting/Export-Errors/Overview.md delete mode 100644 docs/articles/new-expensify/connections/xero/Troubleshooting/Sync-Errors/Overview.md delete mode 100644 docs/articles/new-expensify/connections/xero/Xero-Troubleshooting.md delete mode 100644 docs/articles/new-expensify/workspaces/Create-expense-tags.md delete mode 100644 src/components/Deferred.tsx delete mode 100644 src/components/Lightbox/numberOfConcurrentLightboxes/types.ts delete mode 100644 src/components/SelectionListWithSections/Search/ActionCell/BadgeActionCell.tsx delete mode 100644 src/components/TabSelector/ScrollableTabSelector/ScrollableTabSelector.tsx delete mode 100644 src/components/TabSelector/ScrollableTabSelector/ScrollableTabSelectorBase.tsx delete mode 100644 src/components/TabSelector/ScrollableTabSelector/ScrollableTabSelectorContext.tsx delete mode 100644 src/components/TabSelector/ScrollableTabSelector/ScrollableTabSelectorItem.tsx delete mode 100644 src/components/TabSelector/ScrollableTabSelector/scrollToTab/index.native.ts delete mode 100644 src/components/TabSelector/ScrollableTabSelector/scrollToTab/index.ts delete mode 100644 src/components/TabSelector/ScrollableTabSelector/scrollToTab/types.ts delete mode 100644 src/components/utils/useFormHelpMessageAccessibilityAnnouncement.ios.ts delete mode 100644 src/components/utils/useFormHelpMessageAccessibilityAnnouncement.ts delete mode 100644 src/hooks/useDismissModalForUSD.tsx delete mode 100644 src/hooks/useExportedToAutocompleteList.ts delete mode 100644 src/libs/API/parameters/SetPersonalDetailsAndRevealExpensifyCardParams.ts delete mode 100644 src/libs/Navigation/guards/TestDriveModalGuard.ts delete mode 100644 src/libs/Navigation/helpers/createDynamicRoute.ts delete mode 100644 src/libs/Navigation/helpers/getLastSuffixFromPath.ts delete mode 100644 src/libs/Navigation/helpers/getStateForDynamicRoute.ts delete mode 100644 src/libs/Navigation/helpers/isDynamicRouteSuffix.ts delete mode 100644 src/libs/Navigation/helpers/splitPathAndQuery.ts delete mode 100644 src/libs/migrations/RenameEmojiSkinTone.ts delete mode 100644 src/pages/RequireTwoFactorAuthenticationPage.tsx delete mode 100644 src/pages/inbox/sidebar/NavigationTabBarFloatingActionButton/types.ts delete mode 100644 src/pages/iou/request/step/DiscardChangesConfirmation/index.native.tsx delete mode 100644 src/pages/iou/request/step/DiscardChangesConfirmation/index.tsx delete mode 100644 src/pages/iou/request/step/DiscardChangesConfirmation/types.ts delete mode 100644 src/pages/iou/request/step/IOURequestStepScan/NavigationAwareCamera/Camera.tsx delete mode 100644 src/pages/iou/request/step/IOURequestStepScan/NavigationAwareCamera/WebCamera.tsx delete mode 100644 src/pages/iou/request/step/IOURequestStepScan/NavigationAwareCamera/types.ts delete mode 100644 src/pages/iou/request/step/IOURequestStepScan/ReceiptPreviews/SubmitButtonShadow/index.native.tsx delete mode 100644 src/pages/iou/request/step/IOURequestStepScan/ReceiptPreviews/SubmitButtonShadow/index.tsx delete mode 100644 src/pages/iou/request/step/IOURequestStepScan/ReceiptPreviews/index.tsx delete mode 100644 src/pages/iou/request/step/IOURequestStepScan/useReceiptScan.ts delete mode 100644 src/pages/iou/request/step/IOURequestStepScan/useScanShortcutSpan.ts delete mode 100644 src/pages/settings/Profile/PersonalDetails/CountrySelectionPage.tsx delete mode 100644 src/pages/settings/Wallet/ExpensifyCardPage/ExpensifyCardMissingDetailsMagicCodePage.tsx delete mode 100644 src/pages/settings/Wallet/ExpensifyCardPage/ExpensifyCardMissingDetailsPage.tsx delete mode 100644 src/pages/settings/Wallet/NewBankAccountVerifyAccountPage.tsx delete mode 100644 src/pages/workspace/accounting/netsuite/import/NetSuiteImportCustomFieldNew/substeps/ChooseCustomListStep.tsx delete mode 100644 src/pages/workspace/accounting/netsuite/import/NetSuiteImportCustomFieldNew/substeps/ChooseSegmentTypeStep.tsx delete mode 100644 src/pages/workspace/accounting/netsuite/import/NetSuiteImportCustomFieldNew/substeps/ConfirmCustomListStep.tsx delete mode 100644 src/pages/workspace/accounting/netsuite/import/NetSuiteImportCustomFieldNew/substeps/ConfirmCustomSegmentList.tsx delete mode 100644 src/pages/workspace/accounting/netsuite/import/NetSuiteImportCustomFieldNew/substeps/CustomListMappingStep.tsx delete mode 100644 src/pages/workspace/accounting/netsuite/import/NetSuiteImportCustomFieldNew/substeps/CustomSegmentInternalIdStep.tsx delete mode 100644 src/pages/workspace/accounting/netsuite/import/NetSuiteImportCustomFieldNew/substeps/CustomSegmentMappingStep.tsx delete mode 100644 src/pages/workspace/accounting/netsuite/import/NetSuiteImportCustomFieldNew/substeps/CustomSegmentNameStep.tsx delete mode 100644 src/pages/workspace/accounting/netsuite/import/NetSuiteImportCustomFieldNew/substeps/CustomSegmentScriptIdStep.tsx delete mode 100644 src/pages/workspace/accounting/netsuite/import/NetSuiteImportCustomFieldNew/substeps/TransactionFieldIDStep.tsx delete mode 100644 tests/navigation/getLastSuffixFromPathTests.ts delete mode 100644 tests/unit/ForegroundNotificationsTest.ts delete mode 100644 tests/unit/Navigation/guards/TestDriveModalGuard.test.ts delete mode 100644 tests/unit/hooks/useExportedToAutocompleteList.test.ts delete mode 100644 tests/unit/useDismissModalForUSDTest.ts diff --git a/docs/articles/expensify-classic/connections/TravelPerk.md b/docs/articles/expensify-classic/connections/TravelPerk.md deleted file mode 100644 index 6747d836374f3..0000000000000 --- a/docs/articles/expensify-classic/connections/TravelPerk.md +++ /dev/null @@ -1,52 +0,0 @@ ---- - -title: Connecting TravelPerk to Expensify -description: Learn how to seamlessly integrate TravelPerk with Expensify to automate travel expense tracking and improve financial workflows. -keywords: [Expensify Classic, TravelPerk, travel expenses, corporate travel] ---- - - -Connect your TravelPerk and Expensify accounts to automatically sync travel bookings as expenses, making travel management effortless and efficient. - ---- - -# Prerequisites - -Before you begin, make sure you have: - -- An **active Expensify account** -- **Workspace admin** level permissions in Expensify -- An **active TravelPerk account** -- **Admin access** in TravelPerk - ---- - -# Connect TravelPerk to Expensify - -1. Navigate to **Settings > Workspaces > Workspace Name > Accounting > TravelPerk**. -2. **Connect TravelPerk** and follow the prompts to log in to your TravelPerk account. -3. **Authorize the integration**: Review the requested permissions and click **Authorize**. -4. **Customize your settings**: Choose how you want expenses to be categorized and tagged. -5. Click **Save** when done. -6. Test the connection by booking a test trip in TravelPerk -- The expense should appear automatically in Expensify. - ---- - -# How to Book Travel with TravelPerk - -1. In TravelPerk, go to **Trips > Create Trip**. -2. Enter a trip name and select flights and hotels. -3. Review your itinerary and click **Confirm payment**. -4. Your TravelPerk invoice and itinerary will automatically sync to Expensify. - ---- - -# Benefits of the TravelPerk integration - -- **Real-time expense syncing** – No manual uploads needed -- **Policy compliance** – Bookings follow your company’s rules -- **Finance visibility** – See travel spend as it happens -- **Faster approvals** – Managers can review expenses more easily - -By connecting TravelPerk and Expensify, you eliminate manual data entry and simplify your travel workflow. - diff --git a/docs/articles/expensify-classic/connections/certinia/Certinia-Troubleshooting.md b/docs/articles/expensify-classic/connections/certinia/Certinia-Troubleshooting.md deleted file mode 100644 index 4697835aad09d..0000000000000 --- a/docs/articles/expensify-classic/connections/certinia/Certinia-Troubleshooting.md +++ /dev/null @@ -1,175 +0,0 @@ ---- -title: Certinia Troubleshooting -description: Troubleshoot common Certinia sync and export errors, including Salesforce expense export limitations. -keywords: [Certinia, Expensify Classic, sync errors] ---- - - -If your reports fail to export or your connection does not sync, it may be due to discrepancies in settings, missing data, or configuration issues within Certinia, Expensify, or Salesforce. - -This guide helps you identify and resolve common sync and export errors for a seamless financial integration. - ---- - -# Salesforce Expense Export Limitations - -If an expense report does not export to Certinia, check the **Salesforce project settings** to confirm that expenses can be entered and exported. - -## Expenses can be exported when: -- **Project Status** = Active/In Progress -- **Assignment** = Closed, Active, or Completed *(Assignment status does not block expense entry.)* -- **Closed for Expense Entry** = Unchecked - -## Expenses cannot be exported when: -- **Project Status** = Closed, **or** -- **Closed for Expense Entry** = Checked - -## Troubleshooting Steps: -1. **Check the project status in Salesforce** - - If **Project Status** is **Closed**, expenses **cannot** be entered or exported. - - If **Active** or **In Progress**, proceed to step 2. - -2. **Verify the "Closed for Expense Entry" setting** - - If **checked**, uncheck it to allow expense exports. - -3. **Manually test expense entry** - - Try entering an expense manually in Salesforce. If successful, the Expensify-Certinia integration should also allow it. - ---- - -# ExpensiError FF0047: Ops Edit Permission Required - -**Cause:** -The connected user lacks the **Ops Edit** permission needed to edit approved records. - -**Resolution:** -1. In Certinia, go to **Permission Controls**. -2. Select the relevant permission set. -3. Ensure **Expense Ops Edit** is enabled. - -**What is Ops Edit?** -This permission allows users to modify approved records, a requirement for exporting expenses in Certinia. - ---- - -# ExpensiError FF0061: Object Validation Failed (Credit Terms) - -**Cause:** -The credit terms for the selected account are incorrectly configured. - -**Resolution:** -1. Identify the account used for the report export: - - **PSA/SRP** users: Project account - - **FFA** users: Resource-linked account -2. In Certinia, update the account settings: - - **Base Date 1** → Set to **Invoice** - - **Days Offset** → Enter **1 or more** - - Ensure a **currency** is selected - -**What is Base Date 1?** -This field determines when payment terms begin (e.g., from the invoice date). - ---- - -# ExpensiError FF0074: Insufficient Permissions for Resource - -**Cause:** -The report creator/submitter lacks the necessary permission controls. - -**Resolution:** -1. Go to **Permission Controls** in Certinia. -2. Click **New** to create a permission control. -3. Enter the **User** and **Resource Fields**. -4. Check all required permission fields. - ---- - -# ExpensiError FF0076: Employee Not Found in Certinia - -**Resolution:** -1. In Certinia, go to **Contacts** and add the report creator/submitter’s **Expensify email address** to their employee record. -2. If a record already exists, search for the email to confirm it is not linked to multiple records. - ---- - -# ExpensiError FF0089: Assignment Required for Project - -**Cause:** -The project settings require an assignment for expenses. - -**Resolution:** -1. In Certinia, go to **Projects > [Project Name] > Project Attributes**. -2. Enable **Allow Expense Without Assignment**. - ---- - -# ExpensiError FF0091: Invalid Field Name - -**Cause:** -The specified field is not accessible for the user profile in Certinia. - -**Resolution:** -1. In Certinia, go to **Setup > Build** and expand **Create > Object**. -2. Navigate to **Payable Invoice > Custom Fields and Relationships**. -3. Click **View Field Accessibility**. -4. Locate the employee profile and select **Hidden**. -5. Ensure both checkboxes for **Visible** are selected. - -**Sync the Connection:** -1. In Expensify, go to **Settings > Workspaces > Groups > [Workspace Name] > Accounting**. -2. Click **Sync Now**. -3. Attempt to export the report again. - ---- - -# ExpensiError FF0132: Insufficient Access - -**Cause:** -The connected Certinia user lacks **Modify All Data** permission. - -**Resolution:** -1. Log into **Certinia**. -2. Navigate to **Setup > Manage Users > Users**. -3. Locate the user who established the connection. -4. Click their **profile**. -5. Go to **System > System Permissions**. -6. Enable **Modify All Data** and save. - -**What is Modify All Data?** -This permission allows full data access, ensuring reports sync properly. - -**Sync the Connection:** -1. In Expensify, go to **Settings > Workspaces > Groups > [Workspace Name] > Accounting**. -2. Click **Sync Now**. -3. Attempt to export the report again. - ---- - -# Certinia PSA Error: Duplicate Value on Record - -**Cause:** -Multiple projects failed during an initial export, causing subsequent failures. - -**Resolution:** -1. Delete any existing expense reports associated with the **Expensify Report ID** in Certinia. -2. **Sync the connection:** - - In Expensify, go to **Settings > Workspaces > Groups > [Workspace Name] > Accounting**. - - Click **Sync Now**. -3. Attempt to export the report again. - ---- - -# FAQ - -## Why do expenses fail to export when the project is closed? -Salesforce enforces a rule where a **Closed** project status **always** prevents expense entry, regardless of other settings. - -## What should I do if an expense still doesn’t export? -1. Check the project settings in Salesforce: - - Ensure **Project Status** is **Active** or **In Progress**. - - Verify **"Closed for Expense Entry"** is **unchecked**. -2. Try manually entering an expense to confirm restrictions. - -## Does assignment status affect expense exports? -No, **Assignment Status** (Closed, Active, or Completed) does not impact expense entry or export. - diff --git a/docs/articles/expensify-classic/connections/certinia/Troubleshooting/Authentication-and-Login-errors/Overview.md b/docs/articles/expensify-classic/connections/certinia/Troubleshooting/Authentication-and-Login-errors/Overview.md deleted file mode 100644 index c91ae3dba3e0c..0000000000000 --- a/docs/articles/expensify-classic/connections/certinia/Troubleshooting/Authentication-and-Login-errors/Overview.md +++ /dev/null @@ -1,9 +0,0 @@ ---- -title: Overview -description: This section is under construction. Content will be added in a follow-up PR. ---- - -# Overview - -This section is under construction. Content will be added in a follow-up PR. - diff --git a/docs/articles/expensify-classic/connections/certinia/Troubleshooting/Connection-errors/Overview.md b/docs/articles/expensify-classic/connections/certinia/Troubleshooting/Connection-errors/Overview.md deleted file mode 100644 index c91ae3dba3e0c..0000000000000 --- a/docs/articles/expensify-classic/connections/certinia/Troubleshooting/Connection-errors/Overview.md +++ /dev/null @@ -1,9 +0,0 @@ ---- -title: Overview -description: This section is under construction. Content will be added in a follow-up PR. ---- - -# Overview - -This section is under construction. Content will be added in a follow-up PR. - diff --git a/docs/articles/expensify-classic/connections/certinia/Troubleshooting/Sync-Errors/Overview.md b/docs/articles/expensify-classic/connections/certinia/Troubleshooting/Sync-Errors/Overview.md deleted file mode 100644 index c91ae3dba3e0c..0000000000000 --- a/docs/articles/expensify-classic/connections/certinia/Troubleshooting/Sync-Errors/Overview.md +++ /dev/null @@ -1,9 +0,0 @@ ---- -title: Overview -description: This section is under construction. Content will be added in a follow-up PR. ---- - -# Overview - -This section is under construction. Content will be added in a follow-up PR. - diff --git a/docs/articles/expensify-classic/connections/netsuite/Netsuite-Troubleshooting.md b/docs/articles/expensify-classic/connections/netsuite/Netsuite-Troubleshooting.md deleted file mode 100644 index 1ef8aa4937d4a..0000000000000 --- a/docs/articles/expensify-classic/connections/netsuite/Netsuite-Troubleshooting.md +++ /dev/null @@ -1,289 +0,0 @@ ---- -title: Netsuite Troubleshooting -description: Troubleshoot common NetSuite sync and export errors in Expensify and learn how to fix each issue. -keywords: [NetSuite, Expensify Classic, export errors, sync issues, troubleshooting] ---- - - -This guide helps you fix common sync and export issues between Expensify and NetSuite. Each section covers an error code, explains what it means, and walks you through how to resolve it. - ---- - -# ExpensiError NS0005: Please enter value(s) for Department, Location, or Class - -## Vendor bills - -This error occurs when required classification fields are missing in the vendor bill form. - -**How to fix:** -1. Go to **Customization > Forms > Transaction Forms** in NetSuite. -2. Click **Edit** next to the vendor bill form used. -3. Go to **Screen Fields > Main**. -4. Uncheck both **Show** and **Mandatory** for Department, Location, and Class. -5. In Expensify, go to **Settings > Workspaces > [Workspace Name] > Accounting** and click **Sync**. -6. Retry the export. - -## Journal entries and expense reports - -This version of the error means the employee doesn’t have default classifications set. - -**How to fix:** -1. In NetSuite, go to **Lists > Employees**. -2. Edit the employee's profile. -3. Set default values for **Department**, **Class**, and **Location**. -4. Save and sync the connection in Expensify. - ---- - -# ExpensiError NS0012: Currency does not exist in NetSuite - -## Scenario 1 - -The currency being used isn’t available in the NetSuite subsidiary. - -**How to fix:** -1. Confirm the report currency in Expensify matches what’s available in NetSuite. -2. Sync your connection and re-export. - -## Scenario 2 - -By default, non-OneWorld NetSuite instances only support **EUR**, **GBP**, **USD**, and **CAD**. - -**How to fix:** -1. In NetSuite, go to **Setup > Enable Features**. -2. Enable **Multiple Currencies**. -3. Add the required currency using the global search bar. - ---- - -# ExpensiError NS0021: Invalid Tax Code Reference Key - -Usually caused by incorrect tax group mapping in NetSuite. - -**How to fix:** -- **GST 10%** should map to **NCT-AU**, not **TS-AU**. -- **No GST 0%** should map to **NCF-AU**, not **TFS-AU**. - ---- - -# ExpensiError NS0023: Employee does not exist in NetSuite (Invalid employee) - -The employee’s subsidiary or email doesn’t match between NetSuite and Expensify. - -**How to fix:** -1. In NetSuite, confirm the employee's subsidiary matches the Expensify workspace. -2. Make sure the employee’s email matches in both systems. -3. Sync your NetSuite connection. - ---- - -# ExpensiError NS0024: Invalid customer or project tag - -This means the employee isn’t listed as a resource on the customer or project. - -**How to fix:** -1. In NetSuite, go to **Lists > Relationships > Customer/Projects**. -2. Edit the relevant customer or project and add the employee as a resource. -3. Sync and retry the export. - ---- - -# ExpensiError NS0034: This record already exists - -The report has already been exported to NetSuite. - -**How to fix:** -1. Search for the **Report ID** in NetSuite. -2. Delete the duplicate and re-export from Expensify. - ---- - -# ExpensiError NS0046: Billable expenses not coded with a NetSuite customer or billable project - -**How to fix:** -1. In Expensify, tag all billable expenses with a valid **Customer** or **Project**. -2. Retry the export. - ---- - -# ExpensiError NS0059: No credit card account selected for corporate card expenses - -**How to fix:** -1. In NetSuite, go to **Subsidiaries** and set the **Default Account for Corporate Card Expenses**. -2. Sync with Expensify. - ---- - -# ExpensiError NS0085: Expense does not have appropriate permissions for setting an exchange rate - -**How to fix:** -1. In NetSuite, ensure the **Exchange Rate** field is visible on the relevant form. -2. Sync and retry. - ---- - -# ExpensiError NS0079: The transaction date is not within the date range of your accounting period - -**How to fix:** -1. In NetSuite, go to **Accounting Preferences**. -2. Set **Allow Transaction Date Outside of the Posting Period** to **Warn**. -3. In Expensify, enable **Export to Next Open Period** and sync. - ---- - -# ExpensiError NS0055: Vendor doesn't have access to the currency - -**How to fix:** -1. In NetSuite, add the correct currency to the vendor's **Financial tab**. -2. Sync and retry. - ---- - -# ExpensiError NS0068: You do not have permission to set a value for element “Created From” - -**How to fix:** -1. In NetSuite, ensure the **Created From** field is visible in the transaction form. -2. Sync with Expensify. - ---- - -# ExpensiError NS0037: You do not have permission to set a value for element “Receipt URL” - -**How to fix:** -1. Make sure the **Receipt URL** field is visible in NetSuite. -2. Sync and retry. - ---- - -# ExpensiError NS0042: Error creating vendor – This entity already exists - -**How to fix:** -1. In NetSuite, check that the vendor's email and subsidiary match what's in Expensify. -2. Sync your connection and retry. - ---- - -# ExpensiError NS0109: Failed to login to NetSuite – Please verify your credentials - -**How to fix:** -1. Review [this guide](https://help.expensify.com/articles/expensify-classic/integrations/accounting-integrations/NetSuite) to ensure credentials are valid. -2. If needed, generate a new token for the connection. - ---- - -# ExpensiError NS0123: Login error – Please make sure that the Expensify integration is enabled - -**How to fix:** -1. In NetSuite, go to **Setup > Integrations > Manage Integrations**. -2. Enable the **Expensify Integration**. - ---- - -# ExpensiError NS0045: Expenses not categorized with a NetSuite account - -**How to fix:** -1. In NetSuite, confirm the **expense category** is active and properly named. -2. Sync your connection and try again. - ---- - -# ExpensiError NS0056: You do not have permissions to set a value for element... - -Common elements include: -- `class` -- `location` -- `memo` -- `amount` -- `isnonreimbursable` -- `department` -- `exchangerate` -- `entityID` -- `supervisor approval` - -**How to fix:** -1. Go to **Customization > Forms > Transaction Forms**. -2. Search for the correct form type (Expense Report, Journal Entry, Vendor Bill). -3. Edit the form with the **Preferred** checkbox selected. -4. Go to: - - **Screen Fields > Lines** for Journal Entries - - **Screen Fields > Main** for Vendor Bills -5. Make sure the listed field is marked as **Show**. - -## Additional fixes by element - -**Element:** `line.entity` - -1. Edit your **Journal Entry** form. -2. Under **Screen Fields > Main**, ensure the **Name** field is shown. - -**Element:** `entityid` - -1. Go to **Customization > Forms > Entry Forms** and edit the preferred **Vendor** form. -2. Set **Vendor ID** to: - - Show - - Quick Add - - Mandatory -3. Search **Auto-Generated Numbers** in NetSuite and: - - Disable them, or - - Enable **Allow Override**. - -**Element:** `approvalstatus` - -1. Edit your form and make sure **Approval Status** is shown. -2. Optional: Disable approval routing under **Setup > Accounting > Accounting Preferences > Approval Routing**. -3. Add missing permissions under **Setup > Users/Roles > Manage Roles > Expensify Integration > Edit**. -4. Under **Permissions > Transactions**, add **Approve Vendor Payments** with **Full** access. -5. Review **Customization > Workflows** and category-specific settings if issues persist. - -**Element:** `expense.foreignamount` - -1. In NetSuite, open each **Expense Category** and disable **Rate is Required**. -2. Sync and retry. - -**Element:** `tranid` - -1. In NetSuite, search **Auto-Generated Numbers**. -2. Enable **Allow Override** for Invoices. - -**Element:** `memo` - -It can appear if the report has a negative reimbursable total. Only positive reimbursable reports can be exported. - -**Element:** `nexus` - -1. Go to **Setup > Users/Roles > Manage Roles > Expensify Integration > Edit**. -2. Under **Permissions > Lists**, set **Tax Details Tab** to **Full**. - ---- - -# FAQ - -## Why am I seeing “You do not have permissions to set a value for element…” errors? - -This usually means a required field is hidden or restricted in NetSuite. Edit the preferred form and check that the field is visible. - -## What if I’ve made all changes and still see the error? - -- Check your Expensify bundle version in NetSuite. -- Review **Customization > Workflows** for blockers. -- Ask your NetSuite admin to confirm no custom scripts are interfering. - -## Why are reports exporting as "Accounting Approved" instead of "Paid in Full"? - -This may be due to missing **Location**, **Class**, or **Department** info, or misconfigured Expensify workspace settings. - -**How to fix:** -1. Update your **Bill Payment Form** in NetSuite. -2. Verify **Expensify workspace connection settings** under **Accounting > Accounting Integrations > Advanced**. - -## "Invite Employees & Set Approval Workflow" is enabled, why are NetSuite approvers not being set as Expensify approvers? - -The Invite Employees & Set Approval Workflow setting will not overwrite manual changes to the approval table, so if an employee was added before this setting was enabled, the integration will not automatically update their approver to their NetSuite approver/supervisor. - -**Fix**: -1. Remove the employee from the workspace from **Settings > Workspaces > Group > [Workspace Name] > Members**. -2. Sync the connection from **Settings > Workspaces > Group > [Workspace Name] > Accounting > Sync Now** to import the employee and their designated NetSuite approver. - -**Alternative fix:** -Manually update the employee's approver in **Settings > Workspaces > Group > [Workspace Name] > Members**. - diff --git a/docs/articles/expensify-classic/connections/netsuite/Troubleshooting/Authentication-and-Login-errors/Overview.md b/docs/articles/expensify-classic/connections/netsuite/Troubleshooting/Authentication-and-Login-errors/Overview.md deleted file mode 100644 index c91ae3dba3e0c..0000000000000 --- a/docs/articles/expensify-classic/connections/netsuite/Troubleshooting/Authentication-and-Login-errors/Overview.md +++ /dev/null @@ -1,9 +0,0 @@ ---- -title: Overview -description: This section is under construction. Content will be added in a follow-up PR. ---- - -# Overview - -This section is under construction. Content will be added in a follow-up PR. - diff --git a/docs/articles/expensify-classic/connections/netsuite/Troubleshooting/Connection-errors/Overview.md b/docs/articles/expensify-classic/connections/netsuite/Troubleshooting/Connection-errors/Overview.md deleted file mode 100644 index c91ae3dba3e0c..0000000000000 --- a/docs/articles/expensify-classic/connections/netsuite/Troubleshooting/Connection-errors/Overview.md +++ /dev/null @@ -1,9 +0,0 @@ ---- -title: Overview -description: This section is under construction. Content will be added in a follow-up PR. ---- - -# Overview - -This section is under construction. Content will be added in a follow-up PR. - diff --git a/docs/articles/expensify-classic/connections/netsuite/Troubleshooting/Export-Errors/Overview.md b/docs/articles/expensify-classic/connections/netsuite/Troubleshooting/Export-Errors/Overview.md deleted file mode 100644 index c91ae3dba3e0c..0000000000000 --- a/docs/articles/expensify-classic/connections/netsuite/Troubleshooting/Export-Errors/Overview.md +++ /dev/null @@ -1,9 +0,0 @@ ---- -title: Overview -description: This section is under construction. Content will be added in a follow-up PR. ---- - -# Overview - -This section is under construction. Content will be added in a follow-up PR. - diff --git a/docs/articles/expensify-classic/connections/netsuite/Troubleshooting/Sync-Errors/Overview.md b/docs/articles/expensify-classic/connections/netsuite/Troubleshooting/Sync-Errors/Overview.md deleted file mode 100644 index c91ae3dba3e0c..0000000000000 --- a/docs/articles/expensify-classic/connections/netsuite/Troubleshooting/Sync-Errors/Overview.md +++ /dev/null @@ -1,9 +0,0 @@ ---- -title: Overview -description: This section is under construction. Content will be added in a follow-up PR. ---- - -# Overview - -This section is under construction. Content will be added in a follow-up PR. - diff --git a/docs/articles/expensify-classic/connections/quickbooks-desktop/Quickbooks-Desktop-Troubleshooting.md b/docs/articles/expensify-classic/connections/quickbooks-desktop/Quickbooks-Desktop-Troubleshooting.md deleted file mode 100644 index 843e8ac7917c0..0000000000000 --- a/docs/articles/expensify-classic/connections/quickbooks-desktop/Quickbooks-Desktop-Troubleshooting.md +++ /dev/null @@ -1,125 +0,0 @@ ---- -title: QuickBooks Desktop Troubleshooting -description: Troubleshoot common QuickBooks Desktop issues, including connection problems, import/export errors, and sync failures. -keywords: [Expensify Classic, troubleshooting QuickBooks Desktop] ---- - - -QuickBooks Desktop integration issues can sometimes disrupt your workflow. This guide walks you through the most common connection, sync, and export problems and how to quickly resolve them to keep your Workspace connection running smoothly. - ---- - -# The Web Connector Cannot Be Reached - -These errors indicate a connection issue between Expensify and QuickBooks. - -## How to Resolve - -1. Ensure both the Web Connector and QuickBooks Desktop are running. -2. Verify that the Web Connector is installed in the same location as QuickBooks: - - If QuickBooks is on your local desktop, the Web Connector should be too. - - If QuickBooks is on a remote server, install the Web Connector there as well. - -If the error persists: - -1. Close the Web Connector completely using Task Manager if needed. -2. Right-click the Web Connector icon and select **Run as administrator**. -3. Sync your Workspace again. - -Final troubleshooting steps: - -1. Restart QuickBooks Desktop. -2. In Expensify, go to **Settings** > **Workspaces**. -3. Select the connected Workspace. -4. Click the **Accounting** tab and select **QuickBooks Desktop**. -5. Click **Sync Now**. -6. If the issue persists, reinstall the Web Connector. - ---- - -# Connection or Authentication Issues - -These errors indicate a credentials issue. - -## How to Resolve - -1. Ensure QuickBooks Desktop is open with the correct company file. -2. Confirm that the QuickBooks Web Connector is online. -3. Close any open dialogue boxes in QuickBooks that may interfere with syncing. -4. Check that you have the correct permissions: - - Log in to QuickBooks Desktop as an Admin in single-user mode. - - Go to **Edit** > **Preferences** > **Integrated Applications** > **Company Preferences**. - - ![QuickBooks Desktop Company Preferences](https://help.expensify.com/assets/images/quickbooks-desktop-company-preferences.png){:width="100%"} - -5. Select the Web Connector and click **Properties**. - - ![QuickBooks Desktop Web Connector Access Rights](https://help.expensify.com/assets/images/quickbooks-desktop-access-rights.png){:width="100%"} - -6. Check **Allow this application to login automatically** and click **OK**. - -If the issue persists, contact Concierge with: -- QuickBooks Desktop version (e.g., Enterprise 2016, Pro 2014) -- Installation details (local or remote) -- Web Connector installation location -- Remote environment provider (if applicable) - ---- - -# Import Issues or Missing Categories/Tags - -If the data is not importing, the integration may need updating. - -## How to Resolve - -1. Resync Expensify and QuickBooks Desktop. -2. Check your QuickBooks Desktop configuration: - - The Chart of Accounts imports as categories. - - Projects, customers, and jobs are imported as tags. - ---- - -# Export or "Can't Find Category/Class/Location/Account" Issues - -Errors during export are noted in the **Report Comments** section. - -## How to Resolve - -1. Resync Expensify and QuickBooks Desktop. -2. Reapply coding to expenses and re-export the report. -3. Verify that your QuickBooks Desktop version supports the selected export option. - -If the issue persists, contact Concierge with the Report ID and a screenshot of the error message. - ---- - -# "Oops!" Error When Syncing or Exporting - -This error may be temporary or a false flag. - -## How to Resolve - -1. Check if the sync or export was successful. -2. If not, attempt to sync or export again. - -If the problem persists, download the QuickBooks Desktop log file from the Web Connector and contact Concierge. - -**Note:** If you use a remote server (e.g., RightNetworks), you may need to contact their support team for logs. - ---- - -# Reports Not Exporting to QuickBooks Desktop - -This usually occurs when the QuickBooks Web Connector or Company File is not open during export. - -## How to Resolve - -1. Ensure both the Web Connector and QuickBooks Desktop Company File are open. -2. In the Web Connector, check that the **Last Status** is "Ok". - - ![QuickBooks Web Connector Status OK](https://help.expensify.com/assets/images/quickbooks-desktop-web-connector.png){:width="100%"} - -3. Check **Report Comments** in Expensify to confirm successful export. - - ![Expensify Exported Report](https://help.expensify.com/assets/images/quickbooks-desktop-exported-report-comments.png){:width="100%"} - diff --git a/docs/articles/expensify-classic/connections/quickbooks-desktop/Troubleshooting/Authentication-and-Login-errors/Overview.md b/docs/articles/expensify-classic/connections/quickbooks-desktop/Troubleshooting/Authentication-and-Login-errors/Overview.md deleted file mode 100644 index c91ae3dba3e0c..0000000000000 --- a/docs/articles/expensify-classic/connections/quickbooks-desktop/Troubleshooting/Authentication-and-Login-errors/Overview.md +++ /dev/null @@ -1,9 +0,0 @@ ---- -title: Overview -description: This section is under construction. Content will be added in a follow-up PR. ---- - -# Overview - -This section is under construction. Content will be added in a follow-up PR. - diff --git a/docs/articles/expensify-classic/connections/quickbooks-desktop/Troubleshooting/Connection-errors/Overview.md b/docs/articles/expensify-classic/connections/quickbooks-desktop/Troubleshooting/Connection-errors/Overview.md deleted file mode 100644 index c91ae3dba3e0c..0000000000000 --- a/docs/articles/expensify-classic/connections/quickbooks-desktop/Troubleshooting/Connection-errors/Overview.md +++ /dev/null @@ -1,9 +0,0 @@ ---- -title: Overview -description: This section is under construction. Content will be added in a follow-up PR. ---- - -# Overview - -This section is under construction. Content will be added in a follow-up PR. - diff --git a/docs/articles/expensify-classic/connections/quickbooks-desktop/Troubleshooting/Export-Errors/Overview.md b/docs/articles/expensify-classic/connections/quickbooks-desktop/Troubleshooting/Export-Errors/Overview.md deleted file mode 100644 index c91ae3dba3e0c..0000000000000 --- a/docs/articles/expensify-classic/connections/quickbooks-desktop/Troubleshooting/Export-Errors/Overview.md +++ /dev/null @@ -1,9 +0,0 @@ ---- -title: Overview -description: This section is under construction. Content will be added in a follow-up PR. ---- - -# Overview - -This section is under construction. Content will be added in a follow-up PR. - diff --git a/docs/articles/expensify-classic/connections/quickbooks-desktop/Troubleshooting/Sync-Errors/Overview.md b/docs/articles/expensify-classic/connections/quickbooks-desktop/Troubleshooting/Sync-Errors/Overview.md deleted file mode 100644 index c91ae3dba3e0c..0000000000000 --- a/docs/articles/expensify-classic/connections/quickbooks-desktop/Troubleshooting/Sync-Errors/Overview.md +++ /dev/null @@ -1,9 +0,0 @@ ---- -title: Overview -description: This section is under construction. Content will be added in a follow-up PR. ---- - -# Overview - -This section is under construction. Content will be added in a follow-up PR. - diff --git a/docs/articles/expensify-classic/connections/quickbooks-online/Quickbooks-Online-Troubleshooting.md b/docs/articles/expensify-classic/connections/quickbooks-online/Quickbooks-Online-Troubleshooting.md deleted file mode 100644 index 23d97fa3dec0b..0000000000000 --- a/docs/articles/expensify-classic/connections/quickbooks-online/Quickbooks-Online-Troubleshooting.md +++ /dev/null @@ -1,176 +0,0 @@ ---- -title: QuickBooks Online Troubleshooting -description: Learn how to troubleshoot common QuickBooks Online (QBO) export errors in Expensify and resolve them effectively. -keywords: [QuickBooks Online, Expensify Classic, troubleshooting, export errors, QuickBooks integration] ---- - - -If you're encountering errors when exporting expenses from Expensify to QuickBooks Online, this guide will help you understand the cause and provide step-by-step solutions. - ---- - -# ExpensiError QBO022: Billable Expenses Not Enabled - -**Why does this happen?** -This error occurs when the account category applied to an expense in Expensify is not marked as billable in QuickBooks Online. - -## How to Fix It -1. Log in to **QuickBooks Online**. -2. Click the **Gear** icon in the upper-right corner. -3. Select **Expenses** under **Company Settings**. -4. Enable **Make expenses and items billable**. -5. Click the **pencil icon** and check if **In multiple accounts** is selected. -6. If enabled, go to **Chart of Accounts** and click **Edit** on the relevant account. -7. Mark the account as billable and select an **income account**. -8. Sync your QuickBooks Online connection: - **Settings > Workspaces > [Workspace Name] > Accounting**. -9. Reattempt exporting: Open the report, click **Export**, and select **QuickBooks Online**. - ---- - -# ExpensiError QBO046: Feature Not Included in Subscription - -**Why does this happen?** -Your QuickBooks Online plan does not support the feature you're using in Expensify. - -## How to Fix It -- Check your QuickBooks Online subscription plan to verify which features are supported. - _Note: QuickBooks Self-Employed is not supported._ -- Refer to the table below for supported features: - - ![QuickBooks Online - Subscription types]({{site.url}}/assets/images/QBO1.png){:width="100%"} - ---- - -# ExpensiError QBO088: Error Creating Vendor - -**Why does this happen?** -This occurs when a submitter has an **Employee Record** in QuickBooks Online, preventing Expensify from creating a Vendor Record with the same name. - -## How to Fix It -### **Option 1: Edit Employee Name** -1. Log in to **QuickBooks Online**. -2. Go to **Employee Records**. -3. Edit the employee’s name to differentiate it from their Expensify account. -4. If you already have a vendor record for your employees, make sure there is an email on the profile that is an exact match with their Expensify login. -5. Sync your QuickBooks Online connection. -6. Reattempt exporting. - -### **Option 2: Manually Create Vendor Records** -1. Log in to **QuickBooks Online**. -2. Manually create Vendor Records with emails matching the ones in Expensify. -3. Disable **Automatically Create Entities**: - **Settings > Workspaces > [Workspace Name] > Accounting > Configure > Advanced**. - ---- - -# ExpensiError QBO097: Accounts Payable Requires Vendor Selection - -**Why does this happen?** -This error occurs when exporting reimbursable expenses as Journal Entries to an Accounts Payable (A/P) account while Employee Records are in use. - -## How to Fix It -You have three options: -- Change the **export type** for reimbursable expenses: - **Settings > Workspaces > [Workspace Name] > Accounting > Configure > Export**. -- Enable **Automatically Create Entities**: - **Settings > Workspaces > [Workspace Name] > Accounting > Configure > Advanced**. -- Manually create vendor records in QuickBooks Online. - ---- - -# ExpensiError QBO099: Billable Items Require Sales Information - -**Why does this happen?** -This occurs when an **Item category** on an expense lacks sales information in QuickBooks Online. - -## How to Fix It -1. Log in to **QuickBooks Online**. -2. Go to **Items List**. -3. Click **Edit** next to the item used on the report. -4. Enable **Sales**. -5. Assign an **Income Account**. -6. Save changes. -7. Sync your QuickBooks Online connection. -8. Reattempt exporting. - ---- - -# ExpensiError QBO193: Couldn't Connect to QuickBooks Online - -**Why does this happen?** -This error occurs when the QuickBooks Online credentials used to establish the connection have changed. -_Alternate error message: "QuickBooks Reconnect Error: OAuth Token Rejected."_ - -## How to Fix It -1. Go to **Settings > Workspaces > [Workspace Name] > Accounting**. -2. Click **Sync Now**. -3. In the pop-up window, click **Reconnect** and enter your QuickBooks Online credentials. -4. If using new credentials, reconfigure your settings and reselect your categories/tags. - _Tip: Take a screenshot of your configuration before reconnecting._ - ---- - -# ExpensiError QBO077: Duplicate Document Number - -**Why does this happen?** -This error occurs when QuickBooks Online has duplicate document number warnings enabled. - -## How to Fix It -1. Log in to **QuickBooks Online**. -2. Go to **Settings > Advanced**. -3. Under **Other Preferences**, set **Warn if duplicate bill number is used** to **Off**. -4. Sync your QuickBooks Online connection. -5. Reattempt exporting. - ---- - -# Export Error: Currency Mismatch for A/R and A/P Accounts - -**Why does this happen?** -The currency on the **Vendor Record** in QuickBooks Online does not match the currency on the **A/P account**. - -## How to Fix It -1. Log in to **QuickBooks Online**. -2. Open the **Vendor Record**. -3. Ensure the vendor’s currency matches the A/P account currency. - - Export your QuickBooks Online vendor list to a spreadsheet and search for the email address of the submitter. - - If multiple vendors have the same email but different currencies, remove the email from the incorrect vendor. -4. Sync your QuickBooks Online connection. -5. Reattempt exporting. - -_If the issue persists, confirm the A/P account currency:_ -1. Navigate to **Settings > Workspaces > [Workspace Name] > Accounting**. -2. Under **Exports**, verify that both A/P accounts have the correct currency. - ---- - -# Why Are Company Card Expenses Exporting to the Wrong Account? - -**Possible Causes:** -1. **Incorrect Card Mapping:** - - Confirm that company cards are correctly mapped in **Settings > Domains > Company Cards**. - - Click **Edit Export** for the card to check its assigned account. - -2. **Expense Source:** - - Expenses imported directly from a company card (marked with a **Card+Lock** icon) follow domain mapping settings. - - Expenses created via **SmartScan** or manually as **cash expenses** export to the **default bank account**. - -3. **Exporter Must Be a Domain Admin:** - - Verify that the person exporting the report is a **Domain Admin**. - - If reports export automatically via Concierge, the **Preferred Exporter** in **Settings > Workspaces > [Workspace Name] > Accounting > Configure** must be a **Domain Admin**. - -4. **Workspace Selection:** - - If multiple workspaces are connected to QuickBooks Online, ensure the correct one is selected. - - Each workspace has a separate list of export accounts. - ---- - -# FAQ - -## Can I Export Negative Expenses to QuickBooks Online? - -Yes, you can export negative expenses regardless of the export method. - -**Exception:** If **Check** is selected as the export method, the total report amount cannot be negative. - diff --git a/docs/articles/expensify-classic/connections/quickbooks-online/Troubleshooting/Authentication-and-Login-errors/Overview.md b/docs/articles/expensify-classic/connections/quickbooks-online/Troubleshooting/Authentication-and-Login-errors/Overview.md deleted file mode 100644 index c91ae3dba3e0c..0000000000000 --- a/docs/articles/expensify-classic/connections/quickbooks-online/Troubleshooting/Authentication-and-Login-errors/Overview.md +++ /dev/null @@ -1,9 +0,0 @@ ---- -title: Overview -description: This section is under construction. Content will be added in a follow-up PR. ---- - -# Overview - -This section is under construction. Content will be added in a follow-up PR. - diff --git a/docs/articles/expensify-classic/connections/quickbooks-online/Troubleshooting/Export-Errors/Overview.md b/docs/articles/expensify-classic/connections/quickbooks-online/Troubleshooting/Export-Errors/Overview.md deleted file mode 100644 index c91ae3dba3e0c..0000000000000 --- a/docs/articles/expensify-classic/connections/quickbooks-online/Troubleshooting/Export-Errors/Overview.md +++ /dev/null @@ -1,9 +0,0 @@ ---- -title: Overview -description: This section is under construction. Content will be added in a follow-up PR. ---- - -# Overview - -This section is under construction. Content will be added in a follow-up PR. - diff --git a/docs/articles/expensify-classic/connections/quickbooks-online/Troubleshooting/Sync-Errors/Overview.md b/docs/articles/expensify-classic/connections/quickbooks-online/Troubleshooting/Sync-Errors/Overview.md deleted file mode 100644 index c91ae3dba3e0c..0000000000000 --- a/docs/articles/expensify-classic/connections/quickbooks-online/Troubleshooting/Sync-Errors/Overview.md +++ /dev/null @@ -1,9 +0,0 @@ ---- -title: Overview -description: This section is under construction. Content will be added in a follow-up PR. ---- - -# Overview - -This section is under construction. Content will be added in a follow-up PR. - diff --git a/docs/articles/expensify-classic/connections/sage-intacct/Sage-Intacct-Troubleshooting.md b/docs/articles/expensify-classic/connections/sage-intacct/Sage-Intacct-Troubleshooting.md deleted file mode 100644 index fb670580814d0..0000000000000 --- a/docs/articles/expensify-classic/connections/sage-intacct/Sage-Intacct-Troubleshooting.md +++ /dev/null @@ -1,206 +0,0 @@ ---- -title: Sage-Intacct-Troubleshooting.md -description: Learn how to troubleshoot common synchronization and export errors between Expensify and Sage Intacct. -keywords: [Sage Intacct, troubleshooting, sync errors, export errors, Expensify Classic] ---- - - -Synchronizing and exporting data between Expensify and Sage Intacct streamlines financial processes, but errors can occasionally occur due to incorrect settings, missing data, or configuration issues. This guide outlines solutions to common issues, ensuring a seamless connection between your systems. - ---- - -# Common Sage Intacct Sync & Export Errors - -# Authentication Error - -**Error Message:** -*Sage Intacct experienced the following error trying to synchronize your workspace: Authentication error.* - -## Why This Happens -This error occurs when Expensify cannot authenticate the Sage Intacct connection due to incorrect credentials. - -## How to Fix It -1. **Verify Credentials** - - Ensure you are using the correct credentials for your `xmlgateway_expensify` web services user. - -2. **Add Expensify to Web Services Authorizations** - - In **Sage Intacct**, go to **Company > Setup > Company > Security > Edit**. - - Scroll to **Web Services Authorizations** and add `expensify` (all lowercase) as a **Sender ID**. - - Click **Save**. - -3. **Retry Connection** - - Attempt to sync again after making these changes. - -**Note:** If the error persists, remove and re-add Expensify from the Web Services authorizations list. - ---- - -# Company Card Expenses Exporting to the Wrong Account - -**Behavior:** -Company card transactions are exporting to the wrong account. - -## Why This Happens -This can be caused by incorrect account mapping, export settings, or user permissions. - -## How to Fix It - -1. **Check How the Expense Was Imported** - - **Company Card Import:** Only expenses with the locked card icon follow export mapping settings configured in **Domain Control**. - - **Other Imports:** Expenses from individually linked cards, SmartScanned receipts, or manually created cash expenses export to the **default account** in your connection settings. - -2. **Confirm Card Mapping in Domain Control** - - Ensure company cards are mapped to the correct accounts. - -3. **Merge SmartScanned Receipts** - - If SmartScanned receipts should have merged with company card transactions, verify and manually merge them if necessary. - -4. **Verify Export Options** - - Go to **Settings > Workspaces > [Workspace Name] > Accounting > Configure**. - - Select **"Credit Card"** as the non-reimbursable export option if mapping to specific credit card accounts. - -5. **Ensure the Exporter Has Domain Admin Permissions** - - Check the **Report Comments** section to see who exported the report. - - Ensure the **Preferred Exporter** in **Settings > Workspaces > [Workspace Name] > Accounting > Configure** is a **Domain Admin**. - -6. **Check Workspace Mapping** - - If multiple workspaces connect to the same accounting system, ensure expenses export under the correct workspace. - ---- - -# Credit Card Configuration is Missing - -**Error Message:** -*Sage Intacct: Credit Card Configuration is Missing / You haven't yet set up credit cards in Sage Intacct.* - -## Why This Happens -Sage Intacct requires a configured credit card account to process non-reimbursable expenses. - -## How to Fix It - -1. **Set Up a Credit Card Account in Sage Intacct** - - Go to **Cash Management > Setup > + Charge Card Accounts**. - - Fill in mandatory fields: - - **ID:** Recognizable name for the account. - - **Payment Method:** Select **Credit**. - - **Credit-card offset account:** Account credited when expenses post. - - **Expiration:** Required but not crucial for roll-up card accounts. - - **Vendor ID:** Typically, the bank or card provider. - -2. **Link the Account in Expensify** - - Go to **Expensify > Settings > Workspaces > [Workspace Name] > Accounting > Configure > Export**. - - Select the newly created credit card account. - - Click **Save**. - ---- - -# Expensify Not Displaying Customers/Projects - -**Behavior:** Customers or projects from Sage Intacct are not appearing in Expensify. - -## Why This Happens -The Sage Intacct web services user lacks the required permissions. - -## How to Fix It - -1. **Verify Permissions** - - In **Sage Intacct**, go to **Company > Users > Subscriptions**. - - Ensure the web services user has **Read-Only** permissions for the **Accounts Receivable (AR)** module. - -2. **Sync the Connection** - - In **Expensify**, go to **Settings > Workspaces > [Workspace Name] > Accounting > Sync Now**. - ---- - -# ExpensiError INT009: Employee Manager Does Not Have a User Associated - -## Why This Happens -This error occurs when an employee's manager in Sage Intacct lacks a user account. - -## How to Fix It - -- **If Not Using Approvals** - 1. Disable **Expense Report Approval** in **Sage Intacct > Time & Expenses > Configure Time & Expenses**. - 2. Sync Expensify: **Settings > Workspaces > [Workspace Name] > Accounting > Sync Now**. - -- **If Using Approvals** - 1. Set the **First Approver** in **Sage Intacct > Time & Expenses > Configure Time & Expenses**. - 2. Ensure the **First Approver** is a Sage Intacct admin. - ---- - -# ExpensiError INT012: "Reason for Expense" Note is Invalid - -## Why This Happens -Sage Intacct requires a "Reason for Expense" note, preventing export. - -## How to Fix It - -1. **Disable Requirement in Sage Intacct** - - Go to **Time & Expenses > Configure Time & Expenses**. - - Under **Expense Report Requirements**, uncheck **Reason for Expense**. - ---- - -# ExpensiError INT028: Use of an Empty Location is Invalid - -## Why This Happens -Sage Intacct requires a **Location** for employees, which is missing. - -## How to Fix It - -1. **Specify a Location in Sage Intacct** - - Locate the employee profile and add a Location. - -2. **Sync Expensify** - - Go to **Settings > Workspaces > [Workspace Name] > Accounting > Sync Now**. - -3. **Re-export the Report** - - Retry the export after syncing. - ---- - -# ExpensiError INT043: Not Authorized to Execute This Function - -## Why This Happens -The `xml_gateway` user lacks the necessary permissions in Sage Intacct. - -## How to Fix It - -1. **Enable Required Permissions** - - **User-Based Permissions:** Go to **Company > Users > Subscriptions**. - - **Role-Based Permissions:** Go to **Company > Roles > Subscriptions**. - - Ensure the following permissions are set: - - **Administration:** All - - **Company:** Read-only - - **Cash Management:** All - - **Time and Expense:** All - - **General Ledger:** All - - **Projects:** Read-only - - **Accounts Payable:** All - -2. **Sync Connection in Expensify** - - Go to **Settings > Workspaces > [Workspace Name] > Accounting > Sync Now**. - -3. **Retry Export** - - Attempt to export again. - ---- - -# ExpensiError INT054: No Sage Intacct Employee Found - -## Why This Happens -Expensify cannot find a matching employee record in Sage Intacct. - -## How to Fix It - -1. **Ensure the Employee Exists in Sage Intacct** - - Go to **Time & Expenses > + Employee**. - - Verify the email matches Expensify. - -2. **Check for Duplicate Employee Records** - - Delete duplicates if they exist. - -3. **Sync Expensify** - - Go to **Settings > Workspaces > [Workspace Name] > Accounting > Sync Now**. - diff --git a/docs/articles/expensify-classic/connections/sage-intacct/Troubleshooting/Authentication-and-Login-errors/Overview.md b/docs/articles/expensify-classic/connections/sage-intacct/Troubleshooting/Authentication-and-Login-errors/Overview.md deleted file mode 100644 index c91ae3dba3e0c..0000000000000 --- a/docs/articles/expensify-classic/connections/sage-intacct/Troubleshooting/Authentication-and-Login-errors/Overview.md +++ /dev/null @@ -1,9 +0,0 @@ ---- -title: Overview -description: This section is under construction. Content will be added in a follow-up PR. ---- - -# Overview - -This section is under construction. Content will be added in a follow-up PR. - diff --git a/docs/articles/expensify-classic/connections/sage-intacct/Troubleshooting/Connection-errors/Overview.md b/docs/articles/expensify-classic/connections/sage-intacct/Troubleshooting/Connection-errors/Overview.md deleted file mode 100644 index c91ae3dba3e0c..0000000000000 --- a/docs/articles/expensify-classic/connections/sage-intacct/Troubleshooting/Connection-errors/Overview.md +++ /dev/null @@ -1,9 +0,0 @@ ---- -title: Overview -description: This section is under construction. Content will be added in a follow-up PR. ---- - -# Overview - -This section is under construction. Content will be added in a follow-up PR. - diff --git a/docs/articles/expensify-classic/connections/sage-intacct/Troubleshooting/Export-Errors/Overview.md b/docs/articles/expensify-classic/connections/sage-intacct/Troubleshooting/Export-Errors/Overview.md deleted file mode 100644 index c91ae3dba3e0c..0000000000000 --- a/docs/articles/expensify-classic/connections/sage-intacct/Troubleshooting/Export-Errors/Overview.md +++ /dev/null @@ -1,9 +0,0 @@ ---- -title: Overview -description: This section is under construction. Content will be added in a follow-up PR. ---- - -# Overview - -This section is under construction. Content will be added in a follow-up PR. - diff --git a/docs/articles/expensify-classic/connections/sage-intacct/Troubleshooting/Sync-Errors/Overview.md b/docs/articles/expensify-classic/connections/sage-intacct/Troubleshooting/Sync-Errors/Overview.md deleted file mode 100644 index c91ae3dba3e0c..0000000000000 --- a/docs/articles/expensify-classic/connections/sage-intacct/Troubleshooting/Sync-Errors/Overview.md +++ /dev/null @@ -1,9 +0,0 @@ ---- -title: Overview -description: This section is under construction. Content will be added in a follow-up PR. ---- - -# Overview - -This section is under construction. Content will be added in a follow-up PR. - diff --git a/docs/articles/expensify-classic/connections/xero/Troubleshooting/Authentication-and-Login-errors/Overview.md b/docs/articles/expensify-classic/connections/xero/Troubleshooting/Authentication-and-Login-errors/Overview.md deleted file mode 100644 index c91ae3dba3e0c..0000000000000 --- a/docs/articles/expensify-classic/connections/xero/Troubleshooting/Authentication-and-Login-errors/Overview.md +++ /dev/null @@ -1,9 +0,0 @@ ---- -title: Overview -description: This section is under construction. Content will be added in a follow-up PR. ---- - -# Overview - -This section is under construction. Content will be added in a follow-up PR. - diff --git a/docs/articles/expensify-classic/connections/xero/Troubleshooting/Connection-errors/Overview.md b/docs/articles/expensify-classic/connections/xero/Troubleshooting/Connection-errors/Overview.md deleted file mode 100644 index c91ae3dba3e0c..0000000000000 --- a/docs/articles/expensify-classic/connections/xero/Troubleshooting/Connection-errors/Overview.md +++ /dev/null @@ -1,9 +0,0 @@ ---- -title: Overview -description: This section is under construction. Content will be added in a follow-up PR. ---- - -# Overview - -This section is under construction. Content will be added in a follow-up PR. - diff --git a/docs/articles/expensify-classic/connections/xero/Troubleshooting/Export-Errors/Overview.md b/docs/articles/expensify-classic/connections/xero/Troubleshooting/Export-Errors/Overview.md deleted file mode 100644 index c91ae3dba3e0c..0000000000000 --- a/docs/articles/expensify-classic/connections/xero/Troubleshooting/Export-Errors/Overview.md +++ /dev/null @@ -1,9 +0,0 @@ ---- -title: Overview -description: This section is under construction. Content will be added in a follow-up PR. ---- - -# Overview - -This section is under construction. Content will be added in a follow-up PR. - diff --git a/docs/articles/expensify-classic/connections/xero/Troubleshooting/Sync-Errors/Overview.md b/docs/articles/expensify-classic/connections/xero/Troubleshooting/Sync-Errors/Overview.md deleted file mode 100644 index c91ae3dba3e0c..0000000000000 --- a/docs/articles/expensify-classic/connections/xero/Troubleshooting/Sync-Errors/Overview.md +++ /dev/null @@ -1,9 +0,0 @@ ---- -title: Overview -description: This section is under construction. Content will be added in a follow-up PR. ---- - -# Overview - -This section is under construction. Content will be added in a follow-up PR. - diff --git a/docs/articles/expensify-classic/connections/xero/Xero-Troubleshooting.md b/docs/articles/expensify-classic/connections/xero/Xero-Troubleshooting.md deleted file mode 100644 index 3c8e6344400ca..0000000000000 --- a/docs/articles/expensify-classic/connections/xero/Xero-Troubleshooting.md +++ /dev/null @@ -1,144 +0,0 @@ ---- -title: Xero Troubleshooting -description: Troubleshooting common Xero integration errors in Expensify, including sync and export issues. -keywords: [Expensify Classic, Xero troubleshooting] ---- - - -Synchronizing and exporting data between Expensify and Xero can streamline your financial processes, but occasionally, errors may occur due to discrepancies in settings, missing data, or configuration issues. - -This guide provides step-by-step solutions to common Xero-related errors to ensure a seamless connection and accurate expense reporting. - ---- - -# ExpensiError XRO014: Billable Expenses Require a Customer - -## Why does this happen? -Xero requires all billable expenses exported from Expensify to have a customer assigned. This error occurs when one or more expenses are marked "billable" but lack an associated customer. - -## How to fix it -1. Navigate to **Settings > Workspaces > [workspace] > Accounting > Configure > Coding tab**. -2. Enable **Billable Expenses** by toggling the setting. -3. Click **Save** to sync the connection. -4. Open the report and apply a **Customer** tag to each billable expense. - - *Note: A Xero Contact becomes a Customer only after an invoice has been raised against them. If the Customer is missing, create a dummy invoice in Xero, then delete/void it and sync again.* -5. Retry the export by clicking **Export to > Xero**. - ---- - -# ExpensiError XRO027: Category No Longer Exists in Xero - -## Why does this happen? -Xero does not accept expenses categorized under accounts that no longer exist in the Chart of Accounts. - -## How to fix it -1. Log into Xero and navigate to **Settings > Chart of Accounts**. -2. Ensure all expense categories in Expensify are active in Xero. -3. If a category is missing, add it back in Xero and sync Expensify. -4. If the category exists, ensure **Show in Expense Claims** is enabled. -5. Sync Expensify, open the report, and recategorize expenses flagged with a red violation. -6. Click **Export to > Xero**. - ---- - -# ExpensiError XRO031: Payment Already Allocated to Reimbursable Expenses - -## Why does this happen? -Xero does not allow modifications to paid expenses. If a reimbursable expense is re-exported, Xero rejects it as a modification. - -## How to fix it -1. In Xero, go to **Business > Bills to Pay > Paid tab**. -2. Locate and open the report with the error. -3. Click on the blue **Payment** link. -4. Click **Options > Remove and Redo** (*Do not void the bill*). -5. In Expensify, open the report and click **Export to > Xero**. - - The new export will override the previous report while retaining the same ID. - ---- - -# ExpensiError XRO087: No or Incorrect Bank Account - -## Why does this happen? -Xero requires bank transactions from Expensify to be posted to an active bank account. This error occurs when the destination account is missing or incorrect. - -## How to fix it -1. In Expensify, go to **Settings > Workspaces > [workspace] > Accounting > Configure**. -2. Select a **Xero Bank Account** for non-reimbursable expenses. -3. Click **Save** to sync the connection. -4. Open the report and retry the export. - ---- - -# ExpensiError XRO052: Expenses Not Categorized with a Xero Account - -## Why does this happen? -Xero requires all expenses to be categorized under valid accounts in the Chart of Accounts. - -## How to fix it -1. Sync Expensify with Xero under **Settings > Workspaces > [Workspace Name] > Accounting > Sync Now**. -2. Review expenses for red category violations and recategorize them. -3. Click **Export to > Xero**. -4. If errors persist: - - Verify category settings under **Settings > Workspaces > Categories**. - - Ensure categories match exactly with Xero’s Chart of Accounts. -5. Sync again and retry the export. - ---- - -# ExpensiError XRO068: Currency Not Subscribed in Xero - -## Why does this happen? -Xero requires all currencies used in Expensify to be added before exporting expenses in that currency. - -## How to fix it -1. In Xero, go to **Settings > General Settings > Features > Currencies**. -2. Click **Add Currency** and select the required currency. -3. Sync Expensify with Xero (**Settings > Workspaces > Accounting**). -4. Open the report and click **Export to > Xero**. - - *Note: Adding currencies requires the Established Xero plan. [Upgrade if necessary](https://www.xero.com/us/pricing-plans/).* - ---- - -# ExpensiError XRO076: Report Previously Exported and Voided - -## Why does this happen? -Xero does not allow modifications to voided purchase bills. - -## How to fix it -1. In Expensify, locate the report on the **Reports** page. -2. Select the report and click **Copy**. -3. Submit the copied report for approval and export it to Xero. - ---- - -# ExpensiError XRO099: Xero Invoice Approval Limit Reached - -## Why does this happen? -The Early plan in Xero allows only 5 bills per month. This error occurs when the limit is reached. - -## How to fix it -Upgrade your Xero account to a **Growing or Established plan**. [See Xero pricing](https://www.xero.com/us/pricing-plans/). - ---- - -# Why Are Company Card Expenses Exported to the Wrong Account? - -1. Confirm that **company cards** are mapped correctly: - - **Settings > Domains > Company Cards > Edit Export**. -2. Verify that expenses have the **Card+Lock icon** (indicating they were imported from a company card). -3. Ensure the exporter is a **Domain Admin**: - - Check the **Preferred Exporter** setting under **Settings > Workspaces > Accounting > Configure**. -4. Verify company card mapping under the correct workspace. - ---- - -# Why Do Non-Reimbursable Expenses Show 'Credit Card Misc' Instead of the Merchant? - -If a merchant in Expensify **matches** a contact in Xero, expenses will reflect the vendor name. Otherwise, they default to \"Expensify Credit Card Misc\" to prevent duplicates. - -## How to fix it -Use **Expense Rules** in Expensify to standardize merchant names. Learn more [here](https://help.expensify.com/articles/expensify-classic/expenses/Create-Expense-Rules). - ---- - - diff --git a/docs/articles/expensify-classic/expenses/Export- Expenses-from-the-Expenses-Page.md b/docs/articles/expensify-classic/expenses/Export- Expenses-from-the-Expenses-Page.md deleted file mode 100644 index 689cdda2d6535..0000000000000 --- a/docs/articles/expensify-classic/expenses/Export- Expenses-from-the-Expenses-Page.md +++ /dev/null @@ -1,73 +0,0 @@ ---- -title: Export Expenses from the Expenses Page -description: Learn how to efficiently filter and export expenses from the Expenses page ---- - -# Export Expenses - -The **Expenses** page allows you to efficiently manage and export your expenses. If you are an admin, you can also access expenses submitted by Workspace members. Use this page to filter and export expenses based on your specific needs. - ---- - -# Filter Expenses for Export - -Before exporting expenses, use filters to refine your search: - -1. Click the **Expenses** tab. -2. Adjust the filters at the top of the page: - - **Date Range** – Select a specific time frame. - - **Merchant Name** – Find expenses from a particular vendor (partial searches work). - - **Workspace** – View expenses for a specific Group or Individual Workspace. - - **Categories** – Filter by category to refine your search. - - **Tags** – Locate expenses based on assigned tags. - - **Submitters** – Find expenses by employee or vendor. - - **Personal Expenses** – Show expenses that have not yet been added to a report. - - **Draft, Outstanding, Approved, Paid, Done** – View expenses at different reporting stages. - -**Note:** Some filters adjust dynamically based on your current selections. If results aren’t as expected, click **Reset** to clear all filters. - -**Mobile Users:** The Expensify Classic mobile app does not include a search bar or filters in the **Expenses** tab. To find an expense, you must manually scroll through the list, which is ordered chronologically with the most recent at the top. - ---- - -# Export Expenses to CSV - -Once you’ve applied filters, export your expenses as needed: - -1. Select expenses using the checkboxes. -2. Click **Export To** in the upper-right corner. -3. Choose from: - - **Default CSV** – Expensify’s standard template. - - **Create new CSV export layout** – Customize your CSV format. - ---- - -# Print or Download an Expense Report - -For additional documentation or sharing, you can print or download an expense report: - -1. Click the **Reports** tab. -2. Select the desired report. -3. Click **Details** in the upper-right corner. -4. Use the available icons to: - - **Print** – Generate a hard copy. - - **Download** – Save as a PDF. - - **Share** – Send via email or SMS. - ---- - -# FAQ - -## Can I edit multiple expenses before exporting? - -Yes! Select multiple expenses and click **Edit Multiple** to make bulk changes before exporting. - -## What submitter expenses can a Workspace Admin see? - -A Workspace admin can view **Outstanding, Approved, and Paid** expenses if they were submitted under the Workspace they manage. Unreported expenses remain invisible until added to a report. - -Admins can edit **tags** and **categories**, but can only modify the amount, date, or merchant name if the report is **Outstanding**. Reports can be rejected back to the last approver to put them back in an outstanding state. For company card reconciliation, refer to [this article](https://help.expensify.com/articles/expensify-classic/bank-accounts-and-credit-cards/company-cards/Reconciliation). - -## Can I search for expenses in the mobile app? - -No, the Expensify Classic mobile app does not have a search bar or filters in the **Expenses** tab. You must scroll through your expenses manually, which are listed in chronological order with the most recent at the top. For advanced filtering and search options, use the web version of Expensify on your desktop. New Expensify does offer some filtering which you can learn about [here](https://help.expensify.com/articles/new-expensify/getting-started/Using-Reports-in-New-Expensify). diff --git a/docs/articles/new-expensify/connections/netsuite/Netsuite-Troubleshooting.md b/docs/articles/new-expensify/connections/netsuite/Netsuite-Troubleshooting.md deleted file mode 100644 index 8f8d076700a4b..0000000000000 --- a/docs/articles/new-expensify/connections/netsuite/Netsuite-Troubleshooting.md +++ /dev/null @@ -1,366 +0,0 @@ ---- -title: NetSuite Troubleshooting -description: Troubleshoot common NetSuite sync and export errors. ---- - -Synchronizing and exporting data between Expensify and NetSuite helps streamline financial processes, but errors can occasionally disrupt the integration. These errors typically arise from missing data, incorrect settings, or configuration issues in NetSuite or Expensify. - -This guide provides step-by-step solutions for resolving common NetSuite sync and export errors, ensuring accurate and efficient expense reporting and data management. - ---- -# ExpensiError NS0005: Please Enter Value(s) for Department, Location, or Class - -## Why does this happen? -This error occurs when NetSuite requires classifications (Department, Location, or Class) at the header level, but Expensify only exports them at the line item level. - -## Fix for Vendor Bills -1. Go to **Customization > Forms > Transaction Forms**. -2. Click **Edit** on your preferred Vendor Bill form. -3. Navigate to **Screen Fields > Main**. -4. Uncheck **Show** and **Mandatory** for the fields listed in the error message. -5. Sync NetSuite in Expensify: **Settings > Workspaces > Workspace Name > Accounting > Three-dot menu > Sync Now**. -6. Reattempt the export. - -## Fix for Journal Entries and Expense Reports -1. Go to **Lists > Employees** in NetSuite. -2. Click **Edit** next to the employee who submitted the report. -3. Scroll to **Classification** and assign a **Department**, **Class**, and **Location**. -4. Click **Save**. -5. Sync NetSuite in Expensify. -6. Reattempt the export. - ---- -# ExpensiError NS0012: Currency Does Not Exist in NetSuite - -## Why does this happen? -This occurs when: -- Expensify sends a currency not listed in your NetSuite subsidiary. -- You are using a non-OneWorld NetSuite instance and exporting a currency other than EUR, GBP, USD, or CAD. - -## How to Fix It -1. Ensure the currency in Expensify matches NetSuite. -2. Sync NetSuite in Expensify. -3. Enable **Multiple Currencies** in NetSuite: **Setup > Enable Features**. -4. Add the missing currency via **New Currencies** in the NetSuite global search. -5. Reattempt the export. - ---- -# ExpensiError NS0021: Invalid Tax Code Reference Key - -## Why does this happen? -This error usually results from an issue with Tax Group settings in NetSuite, such as a Tax Code being mapped incorrectly. - -## How to Fix It -1. Verify that Tax Codes on Sales Transactions are not mapped to Tax Groups. -2. Ensure the correct Tax Code is assigned to Purchase Transactions. -3. For Australian users: - - **GST 10%** should be mapped to **NCT-AU** (not TS-AU). - - **No GST 0%** should be mapped to **NCF-AU** (not TFS-AU). -4. Ensure Tax Groups are enabled under **Set Up Taxes** in NetSuite. -5. Reattempt the export. - ---- -# ExpensiError NS0023: Employee Does Not Exist in NetSuite - -## Why does this happen? -This occurs when the employee’s subsidiary in NetSuite does not match the one selected for the connection in Expensify. - -## How to Fix It -1. Verify the employee's subsidiary in NetSuite. -2. Confirm the Expensify workspace’s subsidiary under **Settings > Workspaces > Accounting > Subsidiary**. -3. Check **Lists > Employees > Edit > Access** and uncheck **Restrict Access to Expensify**. -4. Ensure the employee’s email matches in both NetSuite and Expensify. -5. Sync NetSuite in Expensify. -6. Reattempt the export. - ---- -# ExpensiError NS0085: Expense Lacks Permissions to Set Exchange Rate - -## Why does this happen? -This occurs when NetSuite’s exchange rate settings are not configured correctly. - -## How to Fix It -1. Go to **Customization > Forms > Transaction Forms**. -2. Select the form being used for export (Expense Report, Journal Entry, or Vendor Bill) and click **Edit**. -3. Ensure the **Exchange Rate** field is set to **Show** under: - - **Screen Fields > Expenses** (Expense Reports) - - **Screen Fields > Main** (Vendor Bills) - - **Screen Fields > Lines** and **Screen Fields > Main** (Journal Entries) -4. Sync NetSuite in Expensify. -5. Reattempt the export. - ---- - -# ExpensiError NS0079: Transaction Date Outside Accounting Period - -## Why does this happen? -NetSuite prevents transactions from being posted outside of designated accounting periods. - -## How to Fix It -1. In NetSuite, go to **Setup > Accounting > Accounting Preferences**. -2. Under **General Ledger**, set **Allow Transaction Date Outside of Posting Period** to **Warn**. -3. Enable **Export to Next Open Period** in Expensify under **Settings > Workspaces > Accounting > Export**. -4. Sync NetSuite in Expensify. -5. Reattempt the export. - ---- -# ExpensiError NS0055: Vendor Lacks Access to Currency - -## Why does this happen? -This occurs when a vendor in NetSuite is not configured to accept a specific currency. - -## How to Fix It -1. In NetSuite, go to **Lists > Relationships > Vendors**. -2. Edit the vendor assigned to the report. -3. Under the **Financial** tab, add the missing currency. -4. Click **Save**. -5. Sync NetSuite in Expensify. -6. Reattempt the export. - ---- -# ExpensiError NS0068: Missing "Created From" Permission - -## Why does this happen? -This occurs due to insufficient permissions on the transaction form being used for export. - -## How to Fix It -1. Go to **Customization > Forms > Transaction Forms**. -2. Edit the form marked as **Preferred**. -3. Ensure the **Created From** field is set to **Show** under **Screen Fields > Main**. -4. Sync NetSuite in Expensify. -5. Reattempt the export. - ---- -# ExpensiError NS0109: NetSuite Login Failed - -## Why does this happen? -This error indicates a problem with the authentication tokens used to connect NetSuite and Expensify. - -## How to Fix It -1. Review the [NetSuite Connection Guide](https://help.expensify.com/articles/new-expensify/connections/netsuite/Connect-to-NetSuite). -2. If using an existing token, create a new one and update the connection in Expensify. -3. Sync NetSuite in Expensify. -4. Reattempt the export. - ---- -# ExpensiError NS0037: You Do Not Have Permission to Set a Value for “Receipt URL” - -## Why does this happen? -This error occurs when the **Receipt URL** field is not visible in NetSuite's transaction form settings. - -## How to Fix It -1. **Go to NetSuite**: Navigate to **Customization > Forms > Transaction Forms**. -2. **Find the transaction form**: Locate the form used for the export type (Expense Report, Journal Entry, or Vendor Bill). -3. **Edit the form**: - - **Expense Reports**: Go to **Screen Fields > Expenses** and ensure **ReceiptURL** is set to **Show**. - - **Journal Entries**: Go to **Screen Fields > Lines** and ensure **ReceiptURL** is set to **Show**. - - **Vendor Bills**: Go to **Screen Fields > Main** and ensure **ReceiptURL** is set to **Show**. -4. **Save the changes** and **sync NetSuite in Expensify** (**Settings > Workspaces > Accounting > Sync Now**). -5. **Retry the export**. - ---- - -# ExpensiError NS0042: Error Creating Vendor - This Entity Already Exists - -## Why does this happen? -Expensify is trying to create a new vendor in NetSuite, but a vendor with the same name or email **already exists**. - -## How to Fix It -1. **Verify vendor details in NetSuite**: - - Go to **Lists > Relationships > Vendors** and search for the vendor's name and email. -2. **Ensure email matches**: - - The email in NetSuite should match the email of the **report submitter in Expensify**. - - If missing, update the NetSuite vendor record with the correct email. -3. **Check subsidiary association**: - - Ensure the vendor belongs to the **same subsidiary** as set in Expensify (**Settings > Workspaces > Accounting > Subsidiary**). -4. **Enable automatic vendor creation (if needed)**: - - In Expensify, go to **Settings > Workspaces > Accounting > Advanced** and enable **Auto-create employees/vendors**. -5. **Sync NetSuite in Expensify** and **retry the export**. - ---- - -# ExpensiError NS0045: Expenses Not Categorized with a NetSuite Account - -## Why does this happen? -This error occurs when expenses in Expensify are assigned to a **category that does not exist in NetSuite** or **was not imported into Expensify**. - -## How to Fix It -1. **Check the missing category in NetSuite**: - - Search for the category using the **NetSuite Global Search**. - - Ensure it is **active** and correctly named. - - Confirm it is associated with the correct **subsidiary**. -2. **Re-sync categories**: - - In Expensify, go to **Settings > Workspaces > Accounting > Sync Now**. -3. **Reapply the category in Expensify**: - - Open the report, select the affected expense(s), and **reapply the correct category**. -4. **Retry the export**. - ---- - -# ExpensiError NS0046: Billable Expenses Not Coded with a NetSuite Customer or Billable Project - -## Why does this happen? -In NetSuite, **billable expenses** must be assigned to a **Customer** or **Billable Project**. If they are missing, this error occurs. - -## How to Fix It -1. **Check the affected expenses in Expensify**: - - Open the report and review **each billable expense**. - - Confirm that a **Customer or Project** tag is assigned. -2. **Update the expense**: - - Apply the correct **Customer or Project** in Expensify. -3. **Retry the export**. - ---- - -# ExpensiError NS0061: Please Enter Value(s) for: Tax Code - -## Why does this happen? -This error occurs when attempting to export **expense reports to a NetSuite Canadian subsidiary** that requires a **Tax Code**, but none is set. - -## How to Fix It -1. **Enable Tax in NetSuite**: - - Go to **Setup > Company > Enable Features** and confirm that **Tax Codes** are enabled. -2. **Ensure the Tax Code exists**: - - In NetSuite, go to **Setup > Accounting > Tax Codes** and confirm the correct tax codes exist. -3. **Assign a Tax Posting Account in Expensify**: - - Go to **Settings > Workspaces > Accounting > Export** and select a **Journal Entry tax posting account**. -4. **Sync NetSuite in Expensify** and **retry the export**. - ---- - -# ExpensiError NS0068 (Expensify Card Expenses): Missing "Created From" Permission - -## Why does this happen? -Expensify Card expenses export as **Journal Entries**. If the **Created From** field is not visible in the Journal Entry form, this error occurs. - -## How to Fix It -1. **Edit the Journal Entry form in NetSuite**: - - Go to **Customization > Forms > Transaction Forms**. - - Click **Edit** next to the preferred Journal Entry form. - - Navigate to **Screen Fields > Main**. - - Ensure **Created From** is set to **Show**. -2. **Save the changes** and **sync NetSuite in Expensify**. -3. **Retry the export**. - ---- - -# ExpensiError NS0123: Login Error - Expensify Integration Not Enabled - -## Why does this happen? -This error occurs when **Expensify is not enabled** as an integration in NetSuite. - -## How to Fix It -1. **Check if Expensify is enabled in NetSuite**: - - Go to **Setup > Integrations > Manage Integrations**. - - Look for **Expensify Integration** and ensure its **State** is **Enabled**. -2. **If Expensify is missing**: - - Click **Show Inactives** to see if Expensify is listed. - - If it appears, **reactivate it**. -3. **Sync NetSuite in Expensify** and **retry the export**. - ---- - -# Error Creating Employee: Your Role Does Not Have Permission to Access This Record - -## Why does this happen? -The **NetSuite role** used for the Expensify connection **does not have permission** to create or access employees. - -## How to Fix It -1. **Verify permissions in NetSuite**: - - Follow the [NetSuite Setup Guide](https://help.expensify.com/articles/new-expensify/connections/netsuite/Connect-to-NetSuite) to configure the correct permissions. -2. **Ensure the report submitter exists in NetSuite**: - - The email in NetSuite should match the **report submitter’s email in Expensify**. - - The employee must belong to the **correct subsidiary**. -3. **Disable automatic employee creation (if needed)**: - - In Expensify, go to **Settings > Workspaces > Accounting > Advanced**. - - Toggle **Auto-create employees/vendors** **off**. -4. **Sync NetSuite in Expensify** and **retry the export**. - ---- - -# ExpensiError: Elimination Settings for X Do Not Match - -## Why does this happen? -This occurs when an **Intercompany Payable account** is set as the default **Payable Account** in NetSuite **subsidiary preferences** while **Accounting Approval** is enabled for Expense Reports. - -## How to Fix It -1. **Edit the Default Payable Account for Expense Reports**: - - In NetSuite, go to **Setup > Company > Subsidiaries**. - - Click **Edit** next to the affected subsidiary. - - Go to the **Preferences** tab. - - Select a **valid payable account** for **Default Payable Account for Expense Reports**. -2. **Repeat this for all subsidiaries** to ensure consistency. -3. **Sync NetSuite in Expensify** and **retry the export**. - ---- - -# FAQ - -## Why Are Reports Exporting as _Accounting Approved_ Instead of _Paid in Full_? - -This happens due to: -- **Missing Locations, Classes, or Departments in the Bill Payment Form** -- **Incorrect Expensify Workspace Settings** - -## How to fix for Missing Locations, Classes, or Departments - -If your accounting classifications require locations, classes, or departments but they are not set to "Show" in your bill payment form, update them in NetSuite: - -- Go to **Customization > Forms > Transaction Forms**. -- Find the **preferred Bill Payment form** (checkmarked). -- Click **Edit or Customize**. -- Under **Screen Fields > Main**, enable "Show" for **Department, Class, and Location**. - -## How to fix for Incorrect Expensify Workspace Settings: -Check your NetSuite connection settings in Expensify: - -- Go to **Settings > Workspaces > [Select Workspace] > Accounting > Advanced**. -- Ensure: - - **Sync Reimbursed Reports** is enabled with a payment account selected. - - **Journal Entry Approval Level** is set to **Approved for Posting**. - - **A/P Approval Account** matches the account used for bill payments. - -**To verify the A/P Approval Account:** -- Open the **bill or expense report** causing the issue. -- Click **Make Payment**. -- Ensure the account matches what is set in Expensify. - -Lastly, confirm that the **A/P Approval Account** is selected on the **Expense Report List**. - ---- - -## Why Are Reports Exporting as _Pending Approval_? - -If reports are marked **"Pending Approval"** instead of **"Approved"**, adjust NetSuite approval settings. - -**For Journal Entries/Vendor Bills:** -- Go to **Setup > Accounting > Accounting Preferences** in NetSuite. -- Under the **General** tab, uncheck **Require Approvals on Journal Entries**. -- Under the **Approval Routing** tab, disable approval for **Journal Entries/Vendor Bills**. - -**Note:** This applies to all Journal Entries, not just Expensify reports. - -**For Expense Reports:** -- Go to **Setup > Company > Enable Features**. -- Under the **Employee** tab, uncheck **Approval Routing** to remove approval for Expense Reports. - -**Note:** This also affects purchase orders. - ---- - -## How to Change the Default Payable Account for Reimbursable Expenses in NetSuite - -When exporting reimbursable expenses, NetSuite uses a default payable account. To change this: - -**For OneWorld Accounts:** -- Go to **Setup > Company > Subsidiaries**. -- Click **Edit** next to the subsidiary. -- Under **Preferences**, update the **Default Payable Account for Expense Reports**. -- Click **Save**. - -**For Non-OneWorld Accounts:** -- Go to **Setup > Accounting > Accounting Preferences**. -- Under the **Time & Expenses** tab, update the **Default Payable Account for Expense Reports**. -- Click **Save**. - - diff --git a/docs/articles/new-expensify/connections/netsuite/Troubleshooting/Authentication-and-Login-errors/Overview.md b/docs/articles/new-expensify/connections/netsuite/Troubleshooting/Authentication-and-Login-errors/Overview.md deleted file mode 100644 index c91ae3dba3e0c..0000000000000 --- a/docs/articles/new-expensify/connections/netsuite/Troubleshooting/Authentication-and-Login-errors/Overview.md +++ /dev/null @@ -1,9 +0,0 @@ ---- -title: Overview -description: This section is under construction. Content will be added in a follow-up PR. ---- - -# Overview - -This section is under construction. Content will be added in a follow-up PR. - diff --git a/docs/articles/new-expensify/connections/netsuite/Troubleshooting/Connection-errors/Overview.md b/docs/articles/new-expensify/connections/netsuite/Troubleshooting/Connection-errors/Overview.md deleted file mode 100644 index c91ae3dba3e0c..0000000000000 --- a/docs/articles/new-expensify/connections/netsuite/Troubleshooting/Connection-errors/Overview.md +++ /dev/null @@ -1,9 +0,0 @@ ---- -title: Overview -description: This section is under construction. Content will be added in a follow-up PR. ---- - -# Overview - -This section is under construction. Content will be added in a follow-up PR. - diff --git a/docs/articles/new-expensify/connections/netsuite/Troubleshooting/Export-Errors/Overview.md b/docs/articles/new-expensify/connections/netsuite/Troubleshooting/Export-Errors/Overview.md deleted file mode 100644 index c91ae3dba3e0c..0000000000000 --- a/docs/articles/new-expensify/connections/netsuite/Troubleshooting/Export-Errors/Overview.md +++ /dev/null @@ -1,9 +0,0 @@ ---- -title: Overview -description: This section is under construction. Content will be added in a follow-up PR. ---- - -# Overview - -This section is under construction. Content will be added in a follow-up PR. - diff --git a/docs/articles/new-expensify/connections/netsuite/Troubleshooting/Sync-Errors/Overview.md b/docs/articles/new-expensify/connections/netsuite/Troubleshooting/Sync-Errors/Overview.md deleted file mode 100644 index c91ae3dba3e0c..0000000000000 --- a/docs/articles/new-expensify/connections/netsuite/Troubleshooting/Sync-Errors/Overview.md +++ /dev/null @@ -1,9 +0,0 @@ ---- -title: Overview -description: This section is under construction. Content will be added in a follow-up PR. ---- - -# Overview - -This section is under construction. Content will be added in a follow-up PR. - diff --git a/docs/articles/new-expensify/connections/quickbooks-desktop/QuickBooks-Desktop-Troubleshooting.md b/docs/articles/new-expensify/connections/quickbooks-desktop/QuickBooks-Desktop-Troubleshooting.md deleted file mode 100644 index c6fd08bb59e53..0000000000000 --- a/docs/articles/new-expensify/connections/quickbooks-desktop/QuickBooks-Desktop-Troubleshooting.md +++ /dev/null @@ -1,116 +0,0 @@ ---- -title: QuickBooks Desktop Troubleshooting -description: Resolve common QuickBooks Desktop integration issues with Expensify, including Web Connector, authentication, import, and export errors. -keywords: [New Expensify, QuickBooks Desktop, Web Connector, export error, sync issues, import missing categories, authentication issues] -order: 3 ---- - - -This guide provides step-by-step solutions for the most common issues, including Web Connector errors, authentication problems, and data import/export failures. - ---- - -# Web Connector cannot be reached - -If you're seeing connection errors, it's likely due to an issue between QuickBooks and the Web Connector. - -## Steps to Fix - -1. Make sure both QuickBooks Desktop and the Web Connector are running. -2. Confirm that the Web Connector is installed in the same environment as QuickBooks (either local desktop or remote server). -3. If the error persists: - - Close the Web Connector completely (use Task Manager if necessary). - - Right-click the Web Connector and choose **Run as administrator**. - - Try syncing your Expensify workspace again. -4. Still not working? - - Quit and reopen QuickBooks Desktop. - - From the navigation tabs (on the left on web, and at the bottom on mobile), go to **Workspaces > [Workspace Name] > Accounting**. - - Click the three dots next to **QuickBooks Desktop**, then select **Sync now**. - - If none of the above works, reinstall the Web Connector using the official link from QuickBooks. - ---- - -# Connection or authentication issues - -These typically occur when QuickBooks can't authenticate the Web Connector or Expensify. - -## Steps to Fix - -1. Open QuickBooks Desktop with the correct company file. -2. Make sure the QuickBooks Web Connector is online. -3. Close any open dialog boxes in QuickBooks and try syncing again. -4. Log in as Admin in single-user mode. -5. Go to **Edit > Preferences > Integrated Applications > Company Preferences**. -6. Select **Web Connector**, then click **Properties**. -7. Enable **Allow this application to login automatically**, then click **OK**. -8. Close all QuickBooks windows. - -**If issues persist, contact Concierge with the following details:** -- QuickBooks Desktop version -- Location of QuickBooks and company file (local or remote) -- Location of Web Connector -- Name of hosting provider (if remote, e.g., RightNetworks) - ---- - -# Import issues or missing categories, or tags - -These issues usually signal that the integration is outdated or not fully compatible. - -## Steps to Fix - -1. Re-sync from **Workspaces > [Workspace Name] > Accounting**. -2. Check your QuickBooks configuration: - - Chart of accounts = categories/export accounts - - Projects, customers, and classes = tags in Expensify - -If issues persist, contact Concierge support with screenshots of your QuickBooks setup and error details. - ---- - -# Export errors or missing categories, classes, or accounts - -These errors often show up in Expense Chat during report export. - -## Steps to Fix - -1. Re-sync from **Workspaces > [Workspace Name] > Accounting > QuickBooks Desktop**. -2. Re-apply the coding on your expenses and re-export the report. -3. Make sure your QuickBooks Desktop version supports the export feature you’re using ([check compatibility](https://quickbooks.intuit.com/desktop/)). - -**If issues persist, contact Concierge support with the following details:** -- The Report ID -- Screenshot of the error in Expensify -- Details about the export issue - ---- - -# Error: “Oops!” error when syncing or exporting - -This message may appear even if the sync or export worked. - -## Steps to Fix - -1. Check whether the action actually succeeded. -2. Retry syncing or exporting if needed. - -If the error keeps showing: -- Open the Web Connector -- Click **View Log** to download the QuickBooks Desktop logs -- Contact Concierge and share the logs - -**Note:** If you're using a remote server (e.g., RightNetworks), contact their support for help retrieving logs. - ---- - -# Reports not exporting to QuickBooks Desktop - -This usually means QuickBooks or the Web Connector was closed during the export attempt. - -## Steps to Fix - -1. Ensure QuickBooks Desktop and the Web Connector are both open. -2. In Web Connector, confirm the **Last Status** reads “Ok”. -3. Check the associated Expense Chat in Expensify to verify if the export was successful. - -Still not exporting? Share the Report ID and a screenshot of your Web Connector with Concierge. diff --git a/docs/articles/new-expensify/connections/quickbooks-desktop/Troubleshooting/Authentication-and-Login-errors/Overview.md b/docs/articles/new-expensify/connections/quickbooks-desktop/Troubleshooting/Authentication-and-Login-errors/Overview.md deleted file mode 100644 index c91ae3dba3e0c..0000000000000 --- a/docs/articles/new-expensify/connections/quickbooks-desktop/Troubleshooting/Authentication-and-Login-errors/Overview.md +++ /dev/null @@ -1,9 +0,0 @@ ---- -title: Overview -description: This section is under construction. Content will be added in a follow-up PR. ---- - -# Overview - -This section is under construction. Content will be added in a follow-up PR. - diff --git a/docs/articles/new-expensify/connections/quickbooks-desktop/Troubleshooting/Connection-errors/Overview.md b/docs/articles/new-expensify/connections/quickbooks-desktop/Troubleshooting/Connection-errors/Overview.md deleted file mode 100644 index c91ae3dba3e0c..0000000000000 --- a/docs/articles/new-expensify/connections/quickbooks-desktop/Troubleshooting/Connection-errors/Overview.md +++ /dev/null @@ -1,9 +0,0 @@ ---- -title: Overview -description: This section is under construction. Content will be added in a follow-up PR. ---- - -# Overview - -This section is under construction. Content will be added in a follow-up PR. - diff --git a/docs/articles/new-expensify/connections/quickbooks-desktop/Troubleshooting/Export-Errors/Overview.md b/docs/articles/new-expensify/connections/quickbooks-desktop/Troubleshooting/Export-Errors/Overview.md deleted file mode 100644 index c91ae3dba3e0c..0000000000000 --- a/docs/articles/new-expensify/connections/quickbooks-desktop/Troubleshooting/Export-Errors/Overview.md +++ /dev/null @@ -1,9 +0,0 @@ ---- -title: Overview -description: This section is under construction. Content will be added in a follow-up PR. ---- - -# Overview - -This section is under construction. Content will be added in a follow-up PR. - diff --git a/docs/articles/new-expensify/connections/quickbooks-desktop/Troubleshooting/Sync-Errors/Overview.md b/docs/articles/new-expensify/connections/quickbooks-desktop/Troubleshooting/Sync-Errors/Overview.md deleted file mode 100644 index c91ae3dba3e0c..0000000000000 --- a/docs/articles/new-expensify/connections/quickbooks-desktop/Troubleshooting/Sync-Errors/Overview.md +++ /dev/null @@ -1,9 +0,0 @@ ---- -title: Overview -description: This section is under construction. Content will be added in a follow-up PR. ---- - -# Overview - -This section is under construction. Content will be added in a follow-up PR. - diff --git a/docs/articles/new-expensify/connections/quickbooks-online/Quickbooks-Online-Troubleshooting.md b/docs/articles/new-expensify/connections/quickbooks-online/Quickbooks-Online-Troubleshooting.md deleted file mode 100644 index 5c67ed6204285..0000000000000 --- a/docs/articles/new-expensify/connections/quickbooks-online/Quickbooks-Online-Troubleshooting.md +++ /dev/null @@ -1,204 +0,0 @@ ---- -title: QuickBooks Online Troubleshooting -description: A list of common QuickBooks Online errors and how to resolve them -keywords: [New Expensify, QuickBooks Online errors, QBO export error, accounting sync, export failed] ---- - - -Sometimes reports may fail to export or sync with QuickBooks Online. This guide outlines common errors and how to resolve them. - ---- - -# Issue: Report won’t automatically export to QuickBooks Online - -If an error occurs during automatic export: - -- You’ll receive an email with error details -- The error will appear in the related Expense Chat (red dot next to report) -- Auto-sync errors also appear in the related **#admins** room with a link to the accounting settings - -Errors will prevent automatic export until resolved. - -## How to resolve - -1. Open the expense -2. Make the required corrections -3. An admin must go to the report’s **Details** tab and click **Export** - ---- - -# Issue: Unable to manually export a report - -Only reports in **Approved**, **Done**, or **Paid** status can be exported. If the report is a **Draft**, the export button will load an empty screen. - -## How to resolve - -1. Submit the report (if it's a Draft) -2. Have an approver approve it (if it's Outstanding) -3. Then, a Workspace Admin can manually export the report - ---- - -# Error: When exporting billable expenses, please make sure the account in QuickBooks Online has been marked as billable - -This happens when the category used is not marked as billable. - -## How to resolve - -1. Log in to QuickBooks Online -2. Go to **Gear > Company Settings > Expenses** -3. Enable **Make expenses and items billable** -4. If “In multiple accounts” is selected: - - Go to **Chart of Accounts** - - Click **Edit** on the relevant account - - Mark as billable and assign an income account -5. Sync the connection in Expensify under **Workspaces > [Workspace Name] > Accounting > QuickBooks Online** -6. Open the report and re-export - ---- - -# Error: Feature Not Included in Subscription - -This occurs when your QuickBooks subscription doesn’t support a selected feature. - -## How to resolve - -Turn off the unsupported feature in Expensify or upgrade your QuickBooks Online plan. - -**Note:** QuickBooks Self-Employed is not supported in Expensify. - ---- - -# Error: Error Creating Vendor - -Occurs when a matching Employee Record already exists in QBO with the same name. - -## How to resolve - -**Option 1**: - -1. Log in to QuickBooks Online -2. Go to **Employee Records** and edit the name -3. Sync your QuickBooks Online connection -4. Re-export the report - -**Option 2**: - -1. Manually create vendor records in QBO with matching email addresses -2. In Expensify, turn off **Automatically Create Entities** under **Workspaces > [Workspace Name] > Accounting > Advanced** - ---- - -# Error: When You Use Accounts Payable, You Must Choose a Vendor in the Name Field - -Occurs when exporting reimbursable expenses as Journal Entries to an A/P account. - -## How to resolve - -- **Option 1**: Change export type in **Accounting > Export** to something other than Journal Entry -- **Option 2**: Enable **Automatically Create Entities** -- **Option 3**: Manually create vendor records in QBO - ---- - -# Error: Items marked as billable must have sales information checked - -Occurs when an item used does not have sales info enabled. - -## How to resolve - -1. Log in to QuickBooks Online -2. Go to your **Items list** -3. Click **Edit** on the relevant item -4. Check **Sales**, assign an income account, and save -5. Sync the connection in Expensify under **Workspaces > [Workspace Name] > Accounting > QuickBooks Online** -6. Re-export the report - ---- - -# Error: Couldn't Connect to QuickBooks Online - -Occurs when your QBO credentials have changed or expired - -Also appears as: **OAuth Token Rejected** - -## How to resolve - -1. Go to **Workspaces > [Workspace Name] > Accounting > QuickBooks Online** -2. Click **Sync Now** -3. In the pop-up, click **Reconnect** and log in with your current QBO credentials - -If using new credentials, reconfigure settings after reconnecting. Take a screenshot of the settings beforehand. - ---- - -# Error: Duplicate Document Number - -This occurs if QBO is set to flag duplicate bill numbers. - -## How to resolve - -1. Log in to **QuickBooks Online** -2. Head to **Settings > Advanced** -3. Under **Other Preferences**, set “Warn if duplicate bill number is used” to **Off** -4. Sync the connection -5. Re-export the report - ---- - -# Error: Currency mismatch with A/R or A/P accounts - -Occurs when the currency of the vendor record doesn’t match the currency on the A/P account. - -## How to resolve - -1. Log in to QuickBooks Online -2. Open the **Vendor Record** -3. Confirm: - - Correct currency - - Associated A/P account - - Email matches Expensify user - -**If you have duplicate vendors with the same email and different currencies**: - -1. Remove the email from the unwanted vendor -2. Sync Expensify -3. Re-export the report - -**If issues persist**: - -- In Expensify, go to **Accounting > Export** -- Check that the selected A/P accounts use the correct currency - ---- - -# FAQ - -## Why are company card expenses exporting to the wrong account? - -1. Go to **Settings > Domains > Company Cards** -2. Click **Edit Export** for the affected card and confirm the correct account -3. Verify that expenses have the **Card + Lock** icon (to be mapped correctly) - -**Is the exporter a domain admin?** - -- The preferred exporter (used by Concierge) must be a domain admin -- If not, exports will default to the fallback company card account - -Check the exporter's role in **Workspaces > [Workspace Name] > Accounting > QuickBooks Online > Export** - -## How do I disconnect the QuickBooks Online connection? - -1. Click your profile image in the bottom-left menu -2. Go to **Workspaces** -3. Select your workspace -4. Click **Accounting** -5. Click the **three-dot icon** next to QuickBooks Online and select **Disconnect** -6. Confirm to disconnect - -**Note:** This clears all imported options from Expensify - -## Can I export negative expenses? - -Yes — QuickBooks Online accepts negative expenses across all export types. - diff --git a/docs/articles/new-expensify/connections/quickbooks-online/Troubleshooting/Authentication-and-Login-errors/Overview.md b/docs/articles/new-expensify/connections/quickbooks-online/Troubleshooting/Authentication-and-Login-errors/Overview.md deleted file mode 100644 index c91ae3dba3e0c..0000000000000 --- a/docs/articles/new-expensify/connections/quickbooks-online/Troubleshooting/Authentication-and-Login-errors/Overview.md +++ /dev/null @@ -1,9 +0,0 @@ ---- -title: Overview -description: This section is under construction. Content will be added in a follow-up PR. ---- - -# Overview - -This section is under construction. Content will be added in a follow-up PR. - diff --git a/docs/articles/new-expensify/connections/quickbooks-online/Troubleshooting/Connection-errors/Overview.md b/docs/articles/new-expensify/connections/quickbooks-online/Troubleshooting/Connection-errors/Overview.md deleted file mode 100644 index c91ae3dba3e0c..0000000000000 --- a/docs/articles/new-expensify/connections/quickbooks-online/Troubleshooting/Connection-errors/Overview.md +++ /dev/null @@ -1,9 +0,0 @@ ---- -title: Overview -description: This section is under construction. Content will be added in a follow-up PR. ---- - -# Overview - -This section is under construction. Content will be added in a follow-up PR. - diff --git a/docs/articles/new-expensify/connections/quickbooks-online/Troubleshooting/Sync-Errors/Overview.md b/docs/articles/new-expensify/connections/quickbooks-online/Troubleshooting/Sync-Errors/Overview.md deleted file mode 100644 index c91ae3dba3e0c..0000000000000 --- a/docs/articles/new-expensify/connections/quickbooks-online/Troubleshooting/Sync-Errors/Overview.md +++ /dev/null @@ -1,9 +0,0 @@ ---- -title: Overview -description: This section is under construction. Content will be added in a follow-up PR. ---- - -# Overview - -This section is under construction. Content will be added in a follow-up PR. - diff --git a/docs/articles/new-expensify/connections/sage-intacct/Sage-Intacct-Troubleshooting.md b/docs/articles/new-expensify/connections/sage-intacct/Sage-Intacct-Troubleshooting.md deleted file mode 100644 index 573d116033dda..0000000000000 --- a/docs/articles/new-expensify/connections/sage-intacct/Sage-Intacct-Troubleshooting.md +++ /dev/null @@ -1,206 +0,0 @@ ---- -title: Sage Intacct Troubleshooting -description: Learn how to troubleshoot common synchronization and export errors between Expensify and Sage Intacct. -keywords: [Sage Intacct, troubleshooting, sync errors, export errors, Expensify Classic] ---- - - -Synchronizing and exporting data between Expensify and Sage Intacct streamlines financial processes, but errors can occasionally occur due to incorrect settings, missing data, or configuration issues. This guide outlines solutions to common issues, ensuring a seamless connection between your systems. - ---- - -# Common Sage Intacct Sync & Export Errors - -# Authentication Error - -**Error Message:** -*Sage Intacct experienced the following error trying to synchronize your workspace: Authentication error.* - -## Why This Happens -This error occurs when Expensify cannot authenticate the Sage Intacct connection due to incorrect credentials. - -## How to Fix It -1. **Verify Credentials** - - Ensure you are using the correct credentials for your `xmlgateway_expensify` web services user. - -2. **Add Expensify to Web Services Authorizations** - - In **Sage Intacct**, go to **Company > Setup > Company > Security > Edit**. - - Scroll to **Web Services Authorizations** and add `expensify` (all lowercase) as a **Sender ID**. - - Click **Save**. - -3. **Retry Connection** - - Attempt to sync again after making these changes. - -**Note:** If the error persists, remove and re-add Expensify from the Web Services authorizations list. - ---- - -# Company Card Expenses Exporting to the Wrong Account - -**Behavior:** -Company card transactions are exporting to the wrong account. - -## Why This Happens -This can be caused by incorrect account mapping, export settings, or user permissions. - -## How to Fix It - -1. **Check How the Expense Was Imported** - - **Company Card Import:** Only expenses with the locked card icon follow export mapping settings configured in **Domain Control**. - - **Other Imports:** Expenses from individually linked cards, SmartScanned receipts, or manually created cash expenses export to the **default account** in your connection settings. - -2. **Confirm Card Mapping in Domain Control** - - Ensure company cards are mapped to the correct accounts. - -3. **Merge SmartScanned Receipts** - - If SmartScanned receipts should have merged with company card transactions, verify and manually merge them if necessary. - -4. **Verify Export Options** - - Go to **Settings > Workspaces > [Workspace Name] > Accounting > Configure**. - - Select **"Credit Card"** as the non-reimbursable export option if mapping to specific credit card accounts. - -5. **Ensure the Exporter Has Domain Admin Permissions** - - Check the **Report Comments** section to see who exported the report. - - Ensure the **Preferred Exporter** in **Settings > Workspaces > [Workspace Name] > Accounting > Configure** is a **Domain Admin**. - -6. **Check Workspace Mapping** - - If multiple workspaces connect to the same accounting system, ensure expenses export under the correct workspace. - ---- - -# Credit Card Configuration is Missing - -**Error Message:** -*Sage Intacct: Credit Card Configuration is Missing / You haven't yet set up credit cards in Sage Intacct.* - -## Why This Happens -Sage Intacct requires a configured credit card account to process non-reimbursable expenses. - -## How to Fix It - -1. **Set Up a Credit Card Account in Sage Intacct** - - Go to **Cash Management > Setup > + Charge Card Accounts**. - - Fill in mandatory fields: - - **ID:** Recognizable name for the account. - - **Payment Method:** Select **Credit**. - - **Credit-card offset account:** Account credited when expenses post. - - **Expiration:** Required but not crucial for roll-up card accounts. - - **Vendor ID:** Typically, the bank or card provider. - -2. **Link the Account in Expensify** - - Go to **Expensify > Settings > Workspaces > [Workspace Name] > Accounting > Configure > Export**. - - Select the newly created credit card account. - - Click **Save**. - ---- - -# Expensify Not Displaying Customers/Projects - -**Behavior:** Customers or projects from Sage Intacct are not appearing in Expensify. - -## Why This Happens -The Sage Intacct web services user lacks the required permissions. - -## How to Fix It - -1. **Verify Permissions** - - In **Sage Intacct**, go to **Company > Users > Subscriptions**. - - Ensure the web services user has **Read-Only** permissions for the **Accounts Receivable (AR)** module. - -2. **Sync the Connection** - - In **Expensify**, go to **Settings > Workspaces > [Workspace Name] > Accounting > Sync Now**. - ---- - -# ExpensiError INT009: Employee Manager Does Not Have a User Associated - -## Why This Happens -This error occurs when an employee's manager in Sage Intacct lacks a user account. - -## How to Fix It - -- **If Not Using Approvals** - 1. Disable **Expense Report Approval** in **Sage Intacct > Time & Expenses > Configure Time & Expenses**. - 2. Sync Expensify: **Settings > Workspaces > [Workspace Name] > Accounting > Sync Now**. - -- **If Using Approvals** - 1. Set the **First Approver** in **Sage Intacct > Time & Expenses > Configure Time & Expenses**. - 2. Ensure the **First Approver** is a Sage Intacct admin. - ---- - -# ExpensiError INT012: "Reason for Expense" Note is Invalid - -## Why This Happens -Sage Intacct requires a "Reason for Expense" note, preventing export. - -## How to Fix It - -1. **Disable Requirement in Sage Intacct** - - Go to **Time & Expenses > Configure Time & Expenses**. - - Under **Expense Report Requirements**, uncheck **Reason for Expense**. - ---- - -# ExpensiError INT028: Use of an Empty Location is Invalid - -## Why This Happens -Sage Intacct requires a **Location** for employees, which is missing. - -## How to Fix It - -1. **Specify a Location in Sage Intacct** - - Locate the employee profile and add a Location. - -2. **Sync Expensify** - - Go to **Settings > Workspaces > [Workspace Name] > Accounting > Sync Now**. - -3. **Re-export the Report** - - Retry the export after syncing. - ---- - -# ExpensiError INT043: Not Authorized to Execute This Function - -## Why This Happens -The `xml_gateway` user lacks the necessary permissions in Sage Intacct. - -## How to Fix It - -1. **Enable Required Permissions** - - **User-Based Permissions:** Go to **Company > Users > Subscriptions**. - - **Role-Based Permissions:** Go to **Company > Roles > Subscriptions**. - - Ensure the following permissions are set: - - **Administration:** All - - **Company:** Read-only - - **Cash Management:** All - - **Time and Expense:** All - - **General Ledger:** All - - **Projects:** Read-only - - **Accounts Payable:** All - -2. **Sync Connection in Expensify** - - Go to **Settings > Workspaces > [Workspace Name] > Accounting > Sync Now**. - -3. **Retry Export** - - Attempt to export again. - ---- - -# ExpensiError INT054: No Sage Intacct Employee Found - -## Why This Happens -Expensify cannot find a matching employee record in Sage Intacct. - -## How to Fix It - -1. **Ensure the Employee Exists in Sage Intacct** - - Go to **Time & Expenses > + Employee**. - - Verify the email matches Expensify. - -2. **Check for Duplicate Employee Records** - - Delete duplicates if they exist. - -3. **Sync Expensify** - - Go to **Settings > Workspaces > [Workspace Name] > Accounting > Sync Now**. - diff --git a/docs/articles/new-expensify/connections/sage-intacct/Troubleshooting/Export-Errors/Overview.md b/docs/articles/new-expensify/connections/sage-intacct/Troubleshooting/Export-Errors/Overview.md deleted file mode 100644 index c91ae3dba3e0c..0000000000000 --- a/docs/articles/new-expensify/connections/sage-intacct/Troubleshooting/Export-Errors/Overview.md +++ /dev/null @@ -1,9 +0,0 @@ ---- -title: Overview -description: This section is under construction. Content will be added in a follow-up PR. ---- - -# Overview - -This section is under construction. Content will be added in a follow-up PR. - diff --git a/docs/articles/new-expensify/connections/sage-intacct/Troubleshooting/Sync-Errors/Overview.md b/docs/articles/new-expensify/connections/sage-intacct/Troubleshooting/Sync-Errors/Overview.md deleted file mode 100644 index c91ae3dba3e0c..0000000000000 --- a/docs/articles/new-expensify/connections/sage-intacct/Troubleshooting/Sync-Errors/Overview.md +++ /dev/null @@ -1,9 +0,0 @@ ---- -title: Overview -description: This section is under construction. Content will be added in a follow-up PR. ---- - -# Overview - -This section is under construction. Content will be added in a follow-up PR. - diff --git a/docs/articles/new-expensify/connections/xero/Troubleshooting/Authentication-and-Login-errors/Overview.md b/docs/articles/new-expensify/connections/xero/Troubleshooting/Authentication-and-Login-errors/Overview.md deleted file mode 100644 index c91ae3dba3e0c..0000000000000 --- a/docs/articles/new-expensify/connections/xero/Troubleshooting/Authentication-and-Login-errors/Overview.md +++ /dev/null @@ -1,9 +0,0 @@ ---- -title: Overview -description: This section is under construction. Content will be added in a follow-up PR. ---- - -# Overview - -This section is under construction. Content will be added in a follow-up PR. - diff --git a/docs/articles/new-expensify/connections/xero/Troubleshooting/Export-Errors/Overview.md b/docs/articles/new-expensify/connections/xero/Troubleshooting/Export-Errors/Overview.md deleted file mode 100644 index c91ae3dba3e0c..0000000000000 --- a/docs/articles/new-expensify/connections/xero/Troubleshooting/Export-Errors/Overview.md +++ /dev/null @@ -1,9 +0,0 @@ ---- -title: Overview -description: This section is under construction. Content will be added in a follow-up PR. ---- - -# Overview - -This section is under construction. Content will be added in a follow-up PR. - diff --git a/docs/articles/new-expensify/connections/xero/Troubleshooting/Sync-Errors/Overview.md b/docs/articles/new-expensify/connections/xero/Troubleshooting/Sync-Errors/Overview.md deleted file mode 100644 index c91ae3dba3e0c..0000000000000 --- a/docs/articles/new-expensify/connections/xero/Troubleshooting/Sync-Errors/Overview.md +++ /dev/null @@ -1,9 +0,0 @@ ---- -title: Overview -description: This section is under construction. Content will be added in a follow-up PR. ---- - -# Overview - -This section is under construction. Content will be added in a follow-up PR. - diff --git a/docs/articles/new-expensify/connections/xero/Xero-Troubleshooting.md b/docs/articles/new-expensify/connections/xero/Xero-Troubleshooting.md deleted file mode 100644 index 2d608536566e6..0000000000000 --- a/docs/articles/new-expensify/connections/xero/Xero-Troubleshooting.md +++ /dev/null @@ -1,44 +0,0 @@ ---- -title: Xero Troubleshooting -description: Learn how to resolve common errors that prevent reports from exporting to Xero. -keywords: [New Expensify, Xero errors, export failure, troubleshoot Xero, manual export] ---- - - -If your expense reports aren’t exporting to Xero, this guide covers common causes and how to fix them. - -# Report didn’t export automatically to Xero - -When an error occurs during an auto-export: - -- You'll receive an email with details about the error -- The report will show a red dot in the related **Chat** thread -- A message will post in the Workspace’s **#admins** chat, linking to the **Accounting** settings with the error reason - -These errors prevent automatic exports. You’ll need to correct the issue and export the report manually. - -## How to resolve it - -1. Open the expense and fix any required details. -2. From the top of the report, select **Export**. -3. Choose **Xero** to manually export the report. - ---- - -# Can't manually export a report - -You can only export reports that are in one of these states: - -- **Approved** -- **Done** -- **Paid** - -If a report is still a **Draft**, you’ll see a message indicating the data isn’t ready for export. - -## How to resolve it - -1. Open the report and review its status. -2. If the report is a **Draft**, submit it. -3. If the report is **Outstanding**, it must be approved by an admin or approver. -4. Once approved, go to the top of the report, select **Export**, and choose **Xero**. - diff --git a/docs/articles/new-expensify/workspaces/Create-expense-tags.md b/docs/articles/new-expensify/workspaces/Create-expense-tags.md deleted file mode 100644 index 37edeafb488bf..0000000000000 --- a/docs/articles/new-expensify/workspaces/Create-expense-tags.md +++ /dev/null @@ -1,170 +0,0 @@ ---- -title: Create Expense Tags -description: Add tags to use for coding expenses. -keywords: [New Expensify, expense tags, class tracking, cost center, import tags, coding expenses, tag GL code] -internalScope: Audience is Workspace Admins. Covers enabling, creating, importing, activating, and managing expense tags, including multi-level tags and tag GL codes. Does not cover personal expense rules or accounting system configuration. ---- - -In Expensify, **tags** represent attributes like classes, projects, cost centers, locations, customers, or jobs. They help code expenses for accounting and reporting. - -Workspace Admins can create tags manually, import them from a spreadsheet, or sync them from an accounting system like QuickBooks Online, Intacct, Xero, or NetSuite. Once created, tags can be enabled or disabled as needed. Over time, Expensify also learns your tag preferences and applies them automatically. - -The Tags table displays the tag **Name**, **GL Code** (if assigned), and whether it's **Required** for expenses. - -![The Tags tab]({{site.url}}/assets/images/NewExpensify_ManageTags_3.png){:width="100%"} - ---- - -# How to enable expense tags - -Before you can manage tags, you need to enable the **Tags** feature for your workspace. - -1. In the **navigation tabs** (on the left on web, and at the bottom on mobile), click **Workspaces**. -2. Select your **workspace name**. -3. Select **More Features**. -4. In the **Organize** section, toggle **Tags** on. - ---- - -# How to add expense Tags - -## Manually Add A Single Tag - -1. Go to **Workspaces > [Workspace Name] > Tags**. -2. Click **Add Tag** at the top of the page. -3. Enter a name and click **Save**. - -## Import A Single Level Of Tags From A Spreadsheet - -1. Go to **Workspaces > [Workspace Name] > Tags**. -2. Click **More > Import spreadsheet** (or if you haven't added any tags yet, just click **Import** from the main Tags settings page). -3. Click **Single level of tags**. -4. Click **Choose File** and select the file to import. -5. Toggle the "File contains column headers" on or off accordingly, then select which spreadsheet column should be mapped to which tag field. We require columns Name and Enabled, and you can optionally include a column for Tag GL Code. GL codes will be visible to Workspace Admins in the Tags table. -6. Click **Import** to finish importing the tags. - -1. In the **navigation tabs** (on the left on web, and at the bottom on mobile), click **Workspaces**. -2. Select your **workspace name**. -3. Select **Tags**. -4. Click **Add Tag**. -5. Enter a name and click **Save**. - -## How to import a single level of expense tags using a spreadsheet - -1. In the **navigation tabs** (on the left on web, and at the bottom on mobile), click **Workspaces**. -2. Select your **workspace name**. -3. Select **Tags**. -4. Click **More > Import spreadsheet** - - If no tags exist yet, select Import from the Tags page. -5. Select **Single level of tags**. -6. Click **Choose File** and upload your spreadsheet. -7. Map the required columns: - - Name - - Enabled - - (Optional) Tag GL Code -8. Select **Import**. - -## How to import multi-level expense tags using a spreadsheet - -1. In the **navigation tabs** (on the left on web, and at the bottom on mobile), click **Workspaces**. -2. Select your **workspace name**. -3. Select **Tags**. -4. Click **More > Import spreadsheet** - - If no tags exist yet, select Import from the Tags page. -5. Select **Multi-level tags**. -6. Click **Choose File** and upload your spreadsheet. -7. Configure the import options: - - Whether the first row contains tag level names - - Whether tag levels are dependent or independent - - Whether each level includes a GL code column -8. Select **Import**. - -You can use one of these template files to build your tags list: - -- [Dependent tags with GL codes](https://help.expensify.com/assets/Files/Dependent+with+GL+codes+format.csv) -- [Dependent tags without GL codes](https://help.expensify.com/assets/Files/Dependent+without+GL+codes+format.csv) -- [Independent tags with GL codes](https://help.expensify.com/assets/Files/Independent+with+GL+codes+format.csv) -- [Independent tags without GL codes](https://help.expensify.com/assets/Files/Independent+without+GL+codes+format.csv) - -**Notes:** - - Only CSV and TSV files are supported for multi-level tag imports. - - A single file can include up to 50,000 tags. - - Each import replaces the existing tag list. Update and re-upload the original file to preserve tags. - -## How to delete expense tags - -1. In the **navigation tabs** (on the left on web, and at the bottom on mobile), click **Workspaces**. -2. Select your **workspace name**. -3. Select **Tags**. -4. Select one or more tags. -5. Click **Selected** in the top right corner. -6. Click **Delete Tag**. - -**Note:** For multi-level tags, individual tags can’t be deleted manually. To remove them, upload a new spreadsheet without the tags you no longer need. For single-level tags, individual tags can be deleted manually - ---- - -## How to enable or disable expense tags - -Workspace Admins can turn tags on or off at any time to control which options are available to members. - -1. In the **navigation tabs** (on the left on web, and at the bottom on mobile), click **Workspaces**. -2. Select your **workspace name**. -3. Select **Tags**. -4. Use the toggle to enable or disable the tag. - -**Note:** Tags imported from an accounting system are added as **inactive** by default and must be enabled on manually. - ---- - -## How to add or edit a tag GL code - -Workspaces on the Control plan can assign a GL code to each tag for exporting purposes. Tag GL codes are not visible to members. - -1. In the **navigation tabs** (on the left on web, and at the bottom on mobile), click **Workspaces**. -2. Select your **workspace name**. -3. Select **Tags**. -4. Click a tag to open its detail panel. -5. Click the **GL Code** field, enter or update the code, then click **Save**. - ---- - -# How to apply expense tags automatically - -Expensify provides two ways to apply tags automatically based on merchant behavior. - -## Learned Tag Suggestions - -Expensify learns how tags are applied over time and suggests them automatically. - -- Manual corrections are remembered over time to improve future suggestions. -- Tags that were manually applied to expenses aren’t overwritten automatically. -- These suggestions are based on patterns and may vary by user. - ---- - -# FAQ - -## Can I edit expense tags on a submitted expense report? - -Yes. You can edit tags until the expense is approved or reimbursed. - -Approvers can also edit tags, even post-approval, by taking control of the report. - -## Can I see an audit trail of tag changes? - -Yes. When a tag is manually changed, the update is logged in the associated expense chat. - -## What happens if a tag is disabled in my accounting system? - -It will be removed from the workspace’s tag list. However, it will still appear on any expenses or reports where it was already applied. - -## Why can’t I enable multi-level tags? - -If you are connected to an accounting integration, you will not see this feature. You will need to add those tags in your accounting system first, then sync the connection. - -## How can my Employees see the GL Codes? - -GL codes are visible to Workspace Admins in the Tags table but are not visible to workspace members. If you need members to see GL codes, consider including the GL code in the tag -name itself. - diff --git a/src/components/Deferred.tsx b/src/components/Deferred.tsx deleted file mode 100644 index c2703ae78113b..0000000000000 --- a/src/components/Deferred.tsx +++ /dev/null @@ -1,30 +0,0 @@ -import type {PropsWithChildren} from 'react'; -import {startTransition, use, useLayoutEffect, useState} from 'react'; - -/** - * This is a wrapper component that allows us to defer rendering children and do it in the background with the use of startTransition. - * Caution: To achieve performance benefits from this component you have to wrap it in a Suspense component. - */ -function Deferred({children}: PropsWithChildren) { - const [{promise, resolve}] = useState(() => Promise.withResolvers()); - const [isMounted, setIsMounted] = useState(false); - - useLayoutEffect(() => { - setIsMounted(true); - - startTransition(() => { - resolve(); - }); - }, [resolve]); - - if (!isMounted) { - // Don't suspend on the first render so the layout effect can run - return null; - } - - // Suspend rendering children until the callback resolves. This promise will be caught by the parent Suspense component. - use(promise); - return children; -} - -export default Deferred; diff --git a/src/components/Lightbox/numberOfConcurrentLightboxes/types.ts b/src/components/Lightbox/numberOfConcurrentLightboxes/types.ts deleted file mode 100644 index 32738c1f2285b..0000000000000 --- a/src/components/Lightbox/numberOfConcurrentLightboxes/types.ts +++ /dev/null @@ -1,5 +0,0 @@ -// Increase/decrease this number to change the number of concurrent lightboxes -// The more concurrent lightboxes, the worse performance gets (especially on low-end devices) -type LightboxConcurrencyLimit = number | 'UNLIMITED'; - -export default LightboxConcurrencyLimit; diff --git a/src/components/SelectionListWithSections/Search/ActionCell/BadgeActionCell.tsx b/src/components/SelectionListWithSections/Search/ActionCell/BadgeActionCell.tsx deleted file mode 100644 index 0dcb058e74060..0000000000000 --- a/src/components/SelectionListWithSections/Search/ActionCell/BadgeActionCell.tsx +++ /dev/null @@ -1,50 +0,0 @@ -import React from 'react'; -import {View} from 'react-native'; -import Badge from '@components/Badge'; -import useLocalize from '@hooks/useLocalize'; -import useStyleUtils from '@hooks/useStyleUtils'; -import useTheme from '@hooks/useTheme'; -import useThemeStyles from '@hooks/useThemeStyles'; -import variables from '@styles/variables'; -import CONST from '@src/CONST'; -import type {SearchTransactionAction} from '@src/types/onyx/SearchResults'; -import actionTranslationsMap from './actionTranslationsMap'; - -type BadgeActionCellProps = { - action: SearchTransactionAction; - isLargeScreenWidth: boolean; - shouldDisablePointerEvents?: boolean; -}; - -function BadgeActionCell({action, isLargeScreenWidth, shouldDisablePointerEvents}: BadgeActionCellProps) { - const {translate} = useLocalize(); - const theme = useTheme(); - const styles = useThemeStyles(); - const StyleUtils = useStyleUtils(); - const text = translate(actionTranslationsMap[action]); - - const badgeTheme = action === CONST.SEARCH.ACTION_TYPES.PAID ? theme.reportStatusBadge.paid : theme.reportStatusBadge.approved; - - return ( - - - - ); -} - -export type {BadgeActionCellProps}; -export default BadgeActionCell; diff --git a/src/components/TabSelector/ScrollableTabSelector/ScrollableTabSelector.tsx b/src/components/TabSelector/ScrollableTabSelector/ScrollableTabSelector.tsx deleted file mode 100644 index 27cc4a9dd2f39..0000000000000 --- a/src/components/TabSelector/ScrollableTabSelector/ScrollableTabSelector.tsx +++ /dev/null @@ -1,76 +0,0 @@ -import {TabActions} from '@react-navigation/native'; -import React from 'react'; -import FocusTrapContainerElement from '@components/FocusTrap/FocusTrapContainerElement'; -import {getIconTitleAndTestID, MEMOIZED_LAZY_TAB_SELECTOR_ICONS} from '@components/TabSelector/getIconTitleAndTestID'; -import type {TabSelectorBaseItem, TabSelectorProps} from '@components/TabSelector/types'; -import {useMemoizedLazyExpensifyIcons} from '@hooks/useLazyAsset'; -import useLocalize from '@hooks/useLocalize'; -import ScrollableTabSelectorBase from './ScrollableTabSelectorBase'; -import ScrollableTabSelectorContextProvider from './ScrollableTabSelectorContext'; - -function ScrollableTabSelector({ - state, - navigation, - onTabPress = () => {}, - position, - onFocusTrapContainerElementChanged, - shouldShowLabelWhenInactive = true, - equalWidth = false, -}: TabSelectorProps) { - const icons = useMemoizedLazyExpensifyIcons(MEMOIZED_LAZY_TAB_SELECTOR_ICONS); - const {translate} = useLocalize(); - - const tabs: TabSelectorBaseItem[] = state.routes.map((route) => { - const {icon, title, testID, sentryLabel} = getIconTitleAndTestID(icons, route.name, translate); - return { - key: route.name, - icon, - title, - testID, - sentryLabel, - }; - }); - - const activeRouteName = state.routes[state.index]?.name ?? ''; - - const handleTabPress = (tabKey: string) => { - const route = state.routes.find((candidateRoute) => candidateRoute.name === tabKey); - if (!route) { - return; - } - - const isActive = route.key === state.routes[state.index]?.key; - if (isActive) { - return; - } - - const event = navigation.emit({ - type: 'tabPress', - target: route.key, - canPreventDefault: true, - }); - - if (!event.defaultPrevented) { - navigation.dispatch(TabActions.jumpTo(route.name)); - } - - onTabPress(route.name); - }; - - return ( - - - - - - ); -} - -export default ScrollableTabSelector; diff --git a/src/components/TabSelector/ScrollableTabSelector/ScrollableTabSelectorBase.tsx b/src/components/TabSelector/ScrollableTabSelector/ScrollableTabSelectorBase.tsx deleted file mode 100644 index 38d30b5006e46..0000000000000 --- a/src/components/TabSelector/ScrollableTabSelector/ScrollableTabSelectorBase.tsx +++ /dev/null @@ -1,108 +0,0 @@ -import React, {useContext, useState} from 'react'; -import ScrollView from '@components/ScrollView'; -import getBackgroundColor from '@components/TabSelector/getBackground'; -import getOpacity from '@components/TabSelector/getOpacity'; -import type {TabSelectorBaseProps} from '@components/TabSelector/types'; -import useTheme from '@hooks/useTheme'; -import useThemeStyles from '@hooks/useThemeStyles'; -import {ScrollableTabSelectorContext} from './ScrollableTabSelectorContext'; -import ScrollableTabSelectorItem from './ScrollableTabSelectorItem'; - -const MIN_SMOOTH_SCROLL_EVENT_THROTTLE = 16; - -/** - * Navigation-agnostic tab selector UI that renders a row of ScrollableTabSelectorItem components. - * - * This component owns the shared layout, width/position measurements, and animation helpers - * (getOpacity / getBackgroundColor). It is reused by both navigation-based TabSelector and - * inline tab selectors like SplitExpensePage. - */ -function ScrollableTabSelectorBase({tabs, activeTabKey, onTabPress = () => {}, position, shouldShowLabelWhenInactive = true, equalWidth = false}: TabSelectorBaseProps) { - const theme = useTheme(); - const styles = useThemeStyles(); - - const routesLength = tabs.length; - - const defaultAffectedAnimatedTabs = Array.from({length: routesLength}, (_v, i) => i); - const [affectedAnimatedTabs, setAffectedAnimatedTabs] = useState(defaultAffectedAnimatedTabs); - - const activeIndex = tabs.findIndex((tab) => tab.key === activeTabKey); - - const {containerRef, onContainerLayout, onContainerScroll} = useContext(ScrollableTabSelectorContext); - - return ( - - {tabs.map((tab, index) => { - const isActive = index === activeIndex; - const activeOpacity = getOpacity({ - routesLength, - tabIndex: index, - active: true, - affectedTabs: affectedAnimatedTabs, - position, - isActive, - }); - const inactiveOpacity = getOpacity({ - routesLength, - tabIndex: index, - active: false, - affectedTabs: affectedAnimatedTabs, - position, - isActive, - }); - const backgroundColor = getBackgroundColor({ - routesLength, - tabIndex: index, - affectedTabs: affectedAnimatedTabs, - theme, - position, - isActive, - }); - - const handlePress = () => { - if (isActive) { - return; - } - - setAffectedAnimatedTabs([activeIndex, index]); - onTabPress(tab.key); - }; - - return ( - - ); - })} - - ); -} - -ScrollableTabSelectorBase.displayName = 'ScrollableTabSelectorBase'; - -export default ScrollableTabSelectorBase; diff --git a/src/components/TabSelector/ScrollableTabSelector/ScrollableTabSelectorContext.tsx b/src/components/TabSelector/ScrollableTabSelector/ScrollableTabSelectorContext.tsx deleted file mode 100644 index d71a6892fdb59..0000000000000 --- a/src/components/TabSelector/ScrollableTabSelector/ScrollableTabSelectorContext.tsx +++ /dev/null @@ -1,85 +0,0 @@ -import React, {createContext, useRef} from 'react'; -// eslint-disable-next-line no-restricted-imports -import type {LayoutChangeEvent, NativeScrollEvent, NativeSyntheticEvent, ScrollView as RNScrollView, View} from 'react-native'; -import scrollToTabUtil from './scrollToTab'; - -type ScrollableTabSelectorContextValue = { - containerRef: React.RefObject; - onContainerLayout: (event: LayoutChangeEvent) => void; - onContainerScroll: (event: NativeSyntheticEvent) => void; - scrollToTab: (tabKey: string) => void; - registerTab: (tabKey: string, ref: HTMLDivElement | View | null) => void; - onTabLayout: (tabKey: string, event: LayoutChangeEvent) => void; -}; - -type ScrollableTabSelectorContextProviderProps = { - activeTabKey: string; - children: React.ReactNode; -}; - -const defaultValue: ScrollableTabSelectorContextValue = { - containerRef: {current: null}, - onContainerLayout: () => {}, - onContainerScroll: () => {}, - scrollToTab: () => {}, - registerTab: () => {}, - onTabLayout: () => {}, -}; - -const ScrollableTabSelectorContext = createContext(defaultValue); - -function ScrollableTabSelectorContextProvider({children, activeTabKey}: ScrollableTabSelectorContextProviderProps) { - const containerRef = useRef(null); - const containerLayoutRef = useRef<{x: number; width: number}>({x: 0, width: 0}); - const tabsRef = useRef>({}); - - const onContainerLayout = (event: LayoutChangeEvent) => { - const width = event.nativeEvent.layout.width; - containerLayoutRef.current.width = width; - }; - - const onContainerScroll = (event: NativeSyntheticEvent) => { - const x = event.nativeEvent.contentOffset.x; - containerLayoutRef.current.x = x; - }; - - const registerTab = (tabKey: string, ref: HTMLDivElement | View | null) => { - if (ref === null) { - return; - } - - tabsRef.current[tabKey] = {...tabsRef.current[tabKey], ref}; - }; - - const onTabLayout = (tabKey: string, event: LayoutChangeEvent) => { - const {x, width} = event.nativeEvent.layout; - tabsRef.current[tabKey] = {...tabsRef.current[tabKey], x, width}; - - if (tabKey === activeTabKey) { - const {ref: tabRef} = tabsRef.current[tabKey]; - scrollToTabUtil({tabX: x, tabWidth: width, tabRef, containerRef, containerWidth: containerLayoutRef.current.width, containerX: containerLayoutRef.current.x, animated: false}); - } - }; - - const scrollToTab = (tabKey: string) => { - const tabData = tabsRef.current[tabKey]; - - if (!tabData) { - return; - } - - const {x: tabX, width: tabWidth, ref: tabRef} = tabData; - - scrollToTabUtil({tabX, tabWidth, tabRef, containerRef, containerWidth: containerLayoutRef.current.width, containerX: containerLayoutRef.current.x}); - }; - - // React Compiler auto-memoization - // eslint-disable-next-line react/jsx-no-constructed-context-values - const contextValue = {containerRef, registerTab, onTabLayout, onContainerLayout, onContainerScroll, scrollToTab}; - - return {children}; -} - -export default ScrollableTabSelectorContextProvider; - -export {ScrollableTabSelectorContext}; diff --git a/src/components/TabSelector/ScrollableTabSelector/ScrollableTabSelectorItem.tsx b/src/components/TabSelector/ScrollableTabSelector/ScrollableTabSelectorItem.tsx deleted file mode 100644 index 2609c8939d2ad..0000000000000 --- a/src/components/TabSelector/ScrollableTabSelector/ScrollableTabSelectorItem.tsx +++ /dev/null @@ -1,74 +0,0 @@ -import React, {useContext, useState} from 'react'; -// eslint-disable-next-line no-restricted-imports -import type {View} from 'react-native'; -// eslint-disable-next-line no-restricted-imports -import {Animated} from 'react-native'; -import PressableWithFeedback from '@components/Pressable/PressableWithFeedback'; -import TabIcon from '@components/TabSelector/TabIcon'; -import TabLabel from '@components/TabSelector/TabLabel'; -import type {TabSelectorItemProps} from '@components/TabSelector/types'; -import useThemeStyles from '@hooks/useThemeStyles'; -import CONST from '@src/CONST'; -import {ScrollableTabSelectorContext} from './ScrollableTabSelectorContext'; - -const AnimatedPressableWithFeedback = Animated.createAnimatedComponent(PressableWithFeedback); - -type ScrollableTabSelectorItemProps = TabSelectorItemProps & {tabKey: string}; - -function ScrollableTabSelectorItem({ - icon, - tabKey, - title = '', - onPress = () => {}, - backgroundColor = '', - activeOpacity = 0, - inactiveOpacity = 1, - isActive = false, - shouldShowLabelWhenInactive = true, - testID, - equalWidth = false, - sentryLabel, -}: ScrollableTabSelectorItemProps) { - const styles = useThemeStyles(); - const [isHovered, setIsHovered] = useState(false); - - const {onTabLayout, registerTab, scrollToTab} = useContext(ScrollableTabSelectorContext); - - return ( - registerTab(tabKey, ref)} - accessibilityLabel={title} - accessibilityState={{selected: isActive}} - accessibilityRole={CONST.ROLE.TAB} - sentryLabel={sentryLabel} - style={[styles.tabSelectorButton, styles.tabBackground(isHovered, isActive, backgroundColor), styles.userSelectNone]} - wrapperStyle={[equalWidth ? styles.flex1 : styles.flexGrow1]} - onPress={() => { - scrollToTab(tabKey); - onPress(); - }} - onWrapperLayout={(event) => onTabLayout(tabKey, event)} - onHoverIn={() => setIsHovered(true)} - onHoverOut={() => setIsHovered(false)} - role={CONST.ROLE.TAB} - dataSet={{[CONST.SELECTION_SCRAPER_HIDDEN_ELEMENT]: true}} - testID={testID} - > - - {(shouldShowLabelWhenInactive || isActive) && ( - - )} - - ); -} - -export default ScrollableTabSelectorItem; diff --git a/src/components/TabSelector/ScrollableTabSelector/scrollToTab/index.native.ts b/src/components/TabSelector/ScrollableTabSelector/scrollToTab/index.native.ts deleted file mode 100644 index cf0c3f3b106e5..0000000000000 --- a/src/components/TabSelector/ScrollableTabSelector/scrollToTab/index.native.ts +++ /dev/null @@ -1,24 +0,0 @@ -import variables from '@styles/variables'; -import type {ScrollToTabProps} from './types'; - -function scrollToTab({containerX, tabX, tabWidth, animated = true, containerRef, containerWidth}: ScrollToTabProps) { - if (!containerRef.current) { - return; - } - - const isTabLeftSideCut = containerX > tabX; - const isTabRightSideCut = tabX + tabWidth >= containerX + containerWidth - variables.tabSelectorScrollMarginInline; - if (!isTabLeftSideCut && !isTabRightSideCut) { - return; - } - - if (isTabRightSideCut) { - const tabCutLengthOnRight = tabX + tabWidth - (containerWidth + containerX); - containerRef.current.scrollTo({x: containerX + tabCutLengthOnRight + variables.tabSelectorScrollMarginInline, animated}); - return; - } - - containerRef.current.scrollTo({x: tabX - variables.tabSelectorScrollMarginInline, animated}); -} - -export default scrollToTab; diff --git a/src/components/TabSelector/ScrollableTabSelector/scrollToTab/index.ts b/src/components/TabSelector/ScrollableTabSelector/scrollToTab/index.ts deleted file mode 100644 index 4899a01c01b87..0000000000000 --- a/src/components/TabSelector/ScrollableTabSelector/scrollToTab/index.ts +++ /dev/null @@ -1,11 +0,0 @@ -import type {ScrollToTabProps} from './types'; - -function scrollToTab({tabRef, animated = true}: ScrollToTabProps) { - if (!tabRef || !('scrollIntoView' in tabRef)) { - return; - } - - tabRef.scrollIntoView({block: 'nearest', behavior: animated ? 'smooth' : 'instant'}); -} - -export default scrollToTab; diff --git a/src/components/TabSelector/ScrollableTabSelector/scrollToTab/types.ts b/src/components/TabSelector/ScrollableTabSelector/scrollToTab/types.ts deleted file mode 100644 index 5aaa949f04ab1..0000000000000 --- a/src/components/TabSelector/ScrollableTabSelector/scrollToTab/types.ts +++ /dev/null @@ -1,15 +0,0 @@ -// eslint-disable-next-line no-restricted-imports -import type {ScrollView as RNScrollView, View} from 'react-native'; - -type ScrollToTabProps = { - animated?: boolean; - tabRef: HTMLDivElement | View | null; - containerRef: React.RefObject; - containerX: number; - containerWidth: number; - tabX: number; - tabWidth: number; -}; - -// eslint-disable-next-line import/prefer-default-export -export type {ScrollToTabProps}; diff --git a/src/components/utils/useFormHelpMessageAccessibilityAnnouncement.ios.ts b/src/components/utils/useFormHelpMessageAccessibilityAnnouncement.ios.ts deleted file mode 100644 index b891fbbd96b0e..0000000000000 --- a/src/components/utils/useFormHelpMessageAccessibilityAnnouncement.ios.ts +++ /dev/null @@ -1,31 +0,0 @@ -import type {ReactNode} from 'react'; -import {useEffect, useRef} from 'react'; -import {AccessibilityInfo} from 'react-native'; - -const DELAY_FOR_ACCESSIBILITY_TREE_SYNC = 100; - -function useFormHelpMessageAccessibilityAnnouncement(message: string | ReactNode, shouldAnnounceError: boolean) { - const previousAnnouncedMessageRef = useRef(''); - - useEffect(() => { - if (!shouldAnnounceError || typeof message !== 'string' || !message.trim()) { - previousAnnouncedMessageRef.current = ''; - return; - } - - if (previousAnnouncedMessageRef.current === message) { - return; - } - - previousAnnouncedMessageRef.current = message; - - // On iOS real devices, a brief delay helps the accessibility tree sync before announcing. - const timeout = setTimeout(() => { - AccessibilityInfo.announceForAccessibility(message); - }, DELAY_FOR_ACCESSIBILITY_TREE_SYNC); - - return () => clearTimeout(timeout); - }, [message, shouldAnnounceError]); -} - -export default useFormHelpMessageAccessibilityAnnouncement; diff --git a/src/components/utils/useFormHelpMessageAccessibilityAnnouncement.ts b/src/components/utils/useFormHelpMessageAccessibilityAnnouncement.ts deleted file mode 100644 index 2183a4d407753..0000000000000 --- a/src/components/utils/useFormHelpMessageAccessibilityAnnouncement.ts +++ /dev/null @@ -1,6 +0,0 @@ -import type {ReactNode} from 'react'; - -// eslint-disable-next-line @typescript-eslint/no-unused-vars -function useFormHelpMessageAccessibilityAnnouncement(_message: string | ReactNode, _shouldAnnounceError: boolean) {} - -export default useFormHelpMessageAccessibilityAnnouncement; diff --git a/src/hooks/useDismissModalForUSD.tsx b/src/hooks/useDismissModalForUSD.tsx deleted file mode 100644 index ceb98a9d683a7..0000000000000 --- a/src/hooks/useDismissModalForUSD.tsx +++ /dev/null @@ -1,19 +0,0 @@ -import type {Dispatch, SetStateAction} from 'react'; -import {useEffect, useState} from 'react'; -import CONST from '@src/CONST'; - -function useDismissModalForUSD(workspaceCurrency: string | undefined): [isCurrencyModalOpen: boolean, setIsCurrencyModalOpen: Dispatch>] { - const [isCurrencyModalOpen, setIsCurrencyModalOpen] = useState(false); - - useEffect(() => { - if (!isCurrencyModalOpen || workspaceCurrency !== CONST.CURRENCY.USD) { - return; - } - - setIsCurrencyModalOpen(false); - }, [workspaceCurrency, isCurrencyModalOpen, setIsCurrencyModalOpen]); - - return [isCurrencyModalOpen, setIsCurrencyModalOpen]; -} - -export default useDismissModalForUSD; diff --git a/src/hooks/useExportedToAutocompleteList.ts b/src/hooks/useExportedToAutocompleteList.ts deleted file mode 100644 index ee7f416725949..0000000000000 --- a/src/hooks/useExportedToAutocompleteList.ts +++ /dev/null @@ -1,30 +0,0 @@ -import {useMemo} from 'react'; -import {getStandardExportTemplateDisplayName} from '@libs/AccountingUtils'; -import {getExportTemplates} from '@libs/actions/Search'; -import CONST from '@src/CONST'; -import ONYXKEYS from '@src/ONYXKEYS'; -import useLocalize from './useLocalize'; -import useOnyx from './useOnyx'; - -/** - * Hook that returns the list of export template names for the "exported-to:" search autocomplete. - * Combines predefined integration names EXPORTED_TO_INTEGRATION_DISPLAY_NAMES with custom export template names. - */ -export default function useExportedToAutocompleteList(): string[] { - const {translate} = useLocalize(); - const [integrationsExportTemplates] = useOnyx(ONYXKEYS.NVP_INTEGRATION_SERVER_EXPORT_TEMPLATES); - const [csvExportLayouts] = useOnyx(ONYXKEYS.NVP_CSV_EXPORT_LAYOUTS); - - return useMemo(() => { - const exportTemplates = getExportTemplates(integrationsExportTemplates ?? [], csvExportLayouts ?? {}, translate, undefined, true); - const customNames = exportTemplates.flatMap((template) => { - const templateDisplayName = getStandardExportTemplateDisplayName(template.templateName); - if (templateDisplayName !== template.templateName) { - return [templateDisplayName]; - } - return [template.templateName].filter(Boolean); - }); - - return Array.from(new Set([...CONST.POLICY.CONNECTIONS.EXPORTED_TO_INTEGRATION_DISPLAY_NAMES, ...customNames])); - }, [integrationsExportTemplates, csvExportLayouts, translate]); -} diff --git a/src/libs/API/parameters/SetPersonalDetailsAndRevealExpensifyCardParams.ts b/src/libs/API/parameters/SetPersonalDetailsAndRevealExpensifyCardParams.ts deleted file mode 100644 index a10bb96bc3059..0000000000000 --- a/src/libs/API/parameters/SetPersonalDetailsAndRevealExpensifyCardParams.ts +++ /dev/null @@ -1,16 +0,0 @@ -type SetPersonalDetailsAndRevealExpensifyCardParams = { - legalFirstName: string; - legalLastName: string; - phoneNumber: string; - addressCity: string; - addressStreet: string; - addressStreet2: string; - addressZip: string; - addressCountry: string; - addressState: string; - dob: string; - validateCode: string; - cardID: number; -}; - -export default SetPersonalDetailsAndRevealExpensifyCardParams; diff --git a/src/libs/Navigation/guards/TestDriveModalGuard.ts b/src/libs/Navigation/guards/TestDriveModalGuard.ts deleted file mode 100644 index 5adb7146824b1..0000000000000 --- a/src/libs/Navigation/guards/TestDriveModalGuard.ts +++ /dev/null @@ -1,163 +0,0 @@ -import type {NavigationAction, NavigationState} from '@react-navigation/native'; -import {findFocusedRoute} from '@react-navigation/native'; -import {hasCompletedGuidedSetupFlowSelector} from '@selectors/Onboarding'; -import Onyx from 'react-native-onyx'; -import type {OnyxEntry} from 'react-native-onyx'; -import Log from '@libs/Log'; -import CONST from '@src/CONST'; -import NAVIGATORS from '@src/NAVIGATORS'; -import ONYXKEYS from '@src/ONYXKEYS'; -import ROUTES from '@src/ROUTES'; -import SCREENS from '@src/SCREENS'; -import type Onboarding from '@src/types/onyx/Onboarding'; -import type {GuardResult, NavigationGuard} from './types'; - -/** - * Module-level Onyx subscriptions for TestDriveModalGuard - */ -let onboarding: OnyxEntry; -let onboardingPolicyID: OnyxEntry; -let hasNonPersonalPolicy: OnyxEntry; - -let hasRedirectedToTestDriveModal = false; - -/** - * Reset the session flag (for testing purposes) - */ -function resetSessionFlag() { - hasRedirectedToTestDriveModal = false; -} - -Onyx.connectWithoutView({ - key: ONYXKEYS.NVP_ONBOARDING, - callback: (value) => { - onboarding = value; - - // Reset the session flag when modal is dismissed - if (value?.testDriveModalDismissed === true) { - hasRedirectedToTestDriveModal = false; - } - }, -}); - -Onyx.connectWithoutView({ - key: ONYXKEYS.ONBOARDING_POLICY_ID, - callback: (value) => { - onboardingPolicyID = value; - }, -}); - -Onyx.connectWithoutView({ - key: ONYXKEYS.HAS_NON_PERSONAL_POLICY, - callback: (value) => { - hasNonPersonalPolicy = value; - }, -}); - -/** - * Check if navigation should be blocked while the test drive modal is active. - * After the guard redirects to the modal, there's a delay before the native Modal overlay becomes visible - * During this window, tab switches can push screens on top of the modal navigator, - * causing DISMISS_MODAL to fail since it only checks the last route. - */ -function shouldBlockWhileModalActive(state: NavigationState, action: NavigationAction): boolean { - const isModalDismissed = onboarding?.testDriveModalDismissed === true; - if (!hasRedirectedToTestDriveModal || isModalDismissed) { - return false; - } - - // Only block when the test drive modal is the LAST route (on top of the stack). - // If something was already pushed on top (broken state), don't block — the user - // needs to be able to navigate to recover from the error. - const lastRoute = state.routes.at(-1); - if (lastRoute?.name !== NAVIGATORS.TEST_DRIVE_MODAL_NAVIGATOR) { - return false; - } - - // Allow DISMISS_MODAL (Skip button) and GO_BACK (close/X button, confirm flow) - if (action.type === CONST.NAVIGATION.ACTION_TYPE.DISMISS_MODAL || action.type === CONST.NAVIGATION.ACTION_TYPE.GO_BACK) { - return false; - } - - return true; -} - -/** - * Check if we're already on or navigating to the test drive modal - * This prevents redirect loops where our redirect creates new navigation actions - */ -function isNavigatingToTestDriveModal(state: NavigationState, action: NavigationAction): boolean { - const currentRoute = findFocusedRoute(state); - if (currentRoute?.name === SCREENS.TEST_DRIVE_MODAL.ROOT) { - return true; - } - - if (action.type === 'RESET' && action.payload) { - const targetRoute = findFocusedRoute(action.payload as NavigationState); - if (targetRoute?.name === SCREENS.TEST_DRIVE_MODAL.ROOT) { - return true; - } - } - - return false; -} - -/** - * TestDriveModalGuard handles the test drive modal flow - * This modal appears after a user completes the guided setup flow but hasn't dismissed the test drive modal yet - */ -const TestDriveModalGuard: NavigationGuard = { - name: 'TestDriveModalGuard', - - evaluate: (state: NavigationState, action: NavigationAction, context): GuardResult => { - if (context.isLoading) { - return {type: 'ALLOW'}; - } - - if (shouldBlockWhileModalActive(state, action)) { - return {type: 'BLOCK', reason: '[TestDriveModalGuard] Blocking navigation while test drive modal is active'}; - } - - const isModalDismissed = onboarding?.testDriveModalDismissed === true; - const isNavigatingToModal = isNavigatingToTestDriveModal(state, action); - - // Redirect to home if trying to access dismissed test drive modal (prevent URL navigation) - if (isNavigatingToModal && isModalDismissed) { - Log.info('[TestDriveModalGuard] Redirecting to home - test drive modal has been dismissed'); - return {type: 'REDIRECT', route: ROUTES.HOME}; - } - - // Allow if we're already navigating to the modal (prevents redirect loops) - if (isNavigatingToModal) { - return {type: 'ALLOW'}; - } - - // Skip if already redirected or user has accessible policy - if (hasRedirectedToTestDriveModal || (onboardingPolicyID && hasNonPersonalPolicy)) { - Log.info('[TestDriveModalGuard] Already redirected or user has accessible policy, allowing'); - return {type: 'ALLOW'}; - } - - // Check if user has completed the guided setup flow - const hasCompletedGuidedSetup = hasCompletedGuidedSetupFlowSelector(onboarding) ?? false; - - // Check if test drive modal should be shown - const shouldShowTestDriveModal = onboarding?.testDriveModalDismissed === false; - - // If user completed setup and modal should be shown, redirect to it once - if (hasCompletedGuidedSetup && shouldShowTestDriveModal) { - Log.info('[TestDriveModalGuard] Redirecting to test drive modal'); - hasRedirectedToTestDriveModal = true; - - return { - type: 'REDIRECT', - route: ROUTES.TEST_DRIVE_MODAL_ROOT.route, - }; - } - - return {type: 'ALLOW'}; - }, -}; - -export default TestDriveModalGuard; -export {resetSessionFlag}; diff --git a/src/libs/Navigation/helpers/createDynamicRoute.ts b/src/libs/Navigation/helpers/createDynamicRoute.ts deleted file mode 100644 index 51b62ac3bb71e..0000000000000 --- a/src/libs/Navigation/helpers/createDynamicRoute.ts +++ /dev/null @@ -1,35 +0,0 @@ -import Log from '@libs/Log'; -import Navigation from '@libs/Navigation/Navigation'; -import type {DynamicRouteSuffix, Route} from '@src/ROUTES'; -import isDynamicRouteSuffix from './isDynamicRouteSuffix'; -import splitPathAndQuery from './splitPathAndQuery'; - -const combinePathAndSuffix = (path: string, suffix: string): Route => { - const [normalizedPath, query] = splitPathAndQuery(path); - - // This should never happen as the path should always be defined - if (!normalizedPath) { - Log.warn('[createDynamicRoute.ts] Path is undefined or empty, returning suffix only', {path, suffix}); - return suffix as Route; - } - - let newPath = normalizedPath === '/' ? `/${suffix}` : `${normalizedPath}/${suffix}`; - - if (query) { - newPath += `?${query}`; - } - return newPath as Route; -}; - -/** Adds dynamic route name to the current URL and returns it */ -const createDynamicRoute = (dynamicRouteSuffix: DynamicRouteSuffix): Route => { - if (!isDynamicRouteSuffix(dynamicRouteSuffix)) { - // eslint-disable-next-line @typescript-eslint/restrict-template-expressions - throw new Error(`The route name ${dynamicRouteSuffix} is not supported in createDynamicRoute`); - } - - const activeRoute = Navigation.getActiveRoute(); - return combinePathAndSuffix(activeRoute, dynamicRouteSuffix); -}; - -export default createDynamicRoute; diff --git a/src/libs/Navigation/helpers/getLastSuffixFromPath.ts b/src/libs/Navigation/helpers/getLastSuffixFromPath.ts deleted file mode 100644 index edbac08958697..0000000000000 --- a/src/libs/Navigation/helpers/getLastSuffixFromPath.ts +++ /dev/null @@ -1,23 +0,0 @@ -import Log from '@libs/Log'; -import splitPathAndQuery from './splitPathAndQuery'; - -/** - * Extracts the last segment from a URL path, removing query parameters and trailing slashes. - * - * @param path - The URL path to extract the suffix from (can be undefined) - * @returns The last segment of the path as a string - */ -function getLastSuffixFromPath(path: string | undefined): string { - const [normalizedPath] = splitPathAndQuery(path ?? ''); - - if (!normalizedPath) { - Log.warn('[getLastSuffixFromPath.ts] Failed to parse the path, path is empty'); - return ''; - } - - const lastSuffix = normalizedPath.split('/').pop() ?? ''; - - return lastSuffix; -} - -export default getLastSuffixFromPath; diff --git a/src/libs/Navigation/helpers/getStateForDynamicRoute.ts b/src/libs/Navigation/helpers/getStateForDynamicRoute.ts deleted file mode 100644 index fc9fb1a378b1f..0000000000000 --- a/src/libs/Navigation/helpers/getStateForDynamicRoute.ts +++ /dev/null @@ -1,69 +0,0 @@ -import {normalizedConfigs} from '@libs/Navigation/linkingConfig/config'; -import {DYNAMIC_ROUTES} from '@src/ROUTES'; -import type {DynamicRouteSuffix} from '@src/ROUTES'; - -type LeafRoute = { - name: string; - path: string; -}; - -type NestedRoute = { - name: string; - state: { - routes: [RouteNode]; - index: 0; // Always 0 since routes array contains exactly one element - }; -}; - -type RouteNode = LeafRoute | NestedRoute; - -const configEntries = Object.entries(normalizedConfigs); - -function getRouteNamesForDynamicRoute(dynamicRouteName: DynamicRouteSuffix): string[] | null { - // Search through normalized configs to find matching path and extract navigation hierarchy - // routeNames contains the sequence of screen/navigator names that should be present in the navigation state - for (const [, config] of configEntries) { - if (config.path === dynamicRouteName) { - return config.routeNames; - } - } - - return null; -} - -function getStateForDynamicRoute(path: string, dynamicRouteName: keyof typeof DYNAMIC_ROUTES) { - const routeConfig = getRouteNamesForDynamicRoute(DYNAMIC_ROUTES[dynamicRouteName].path); - - if (!routeConfig) { - throw new Error(`No route configuration found for dynamic route '${dynamicRouteName}'`); - } - - // Build navigation state by creating nested structure - const buildNestedState = (routes: string[], currentIndex: number): RouteNode => { - const currentRoute = routes.at(currentIndex); - - // If this is the last route, create leaf node with path - if (currentIndex === routes.length - 1) { - return { - name: currentRoute ?? '', - path, - }; - } - - // Create intermediate node with nested state - return { - name: currentRoute ?? '', - state: { - routes: [buildNestedState(routes, currentIndex + 1)], - index: 0, - }, - }; - }; - - // Start building from the first route - const rootRoute = {routes: [buildNestedState(routeConfig, 0)]}; - - return rootRoute; -} - -export default getStateForDynamicRoute; diff --git a/src/libs/Navigation/helpers/isDynamicRouteSuffix.ts b/src/libs/Navigation/helpers/isDynamicRouteSuffix.ts deleted file mode 100644 index 1e3a758bedc8c..0000000000000 --- a/src/libs/Navigation/helpers/isDynamicRouteSuffix.ts +++ /dev/null @@ -1,11 +0,0 @@ -import {DYNAMIC_ROUTES} from '@src/ROUTES'; -import type {DynamicRouteSuffix} from '@src/ROUTES'; - -/** - * Checks if a suffix matches any dynamic route path in DYNAMIC_ROUTES. - */ -function isDynamicRouteSuffix(suffix: string): suffix is DynamicRouteSuffix { - return Object.values(DYNAMIC_ROUTES).some((route) => route.path === suffix); -} - -export default isDynamicRouteSuffix; diff --git a/src/libs/Navigation/helpers/splitPathAndQuery.ts b/src/libs/Navigation/helpers/splitPathAndQuery.ts deleted file mode 100644 index f1dc2c487362b..0000000000000 --- a/src/libs/Navigation/helpers/splitPathAndQuery.ts +++ /dev/null @@ -1,13 +0,0 @@ -/** - * Splits a full path into its path and query components. - * @param fullPath - The full URL path (e.g., '/settings/wallet?param=value') - * @returns A tuple where the first element is the path without trailing slash - * and the second element is the query string (if any). - */ -function splitPathAndQuery(fullPath: string | undefined): [string | undefined, string | undefined] { - const [path, query] = fullPath?.split('?', 2) ?? [undefined, undefined]; - const normalizedPath = path?.endsWith('/') && path.length > 1 ? path.slice(0, -1) : path; - return [normalizedPath, query]; -} - -export default splitPathAndQuery; diff --git a/src/libs/migrations/RenameEmojiSkinTone.ts b/src/libs/migrations/RenameEmojiSkinTone.ts deleted file mode 100644 index 81c813b7b70e9..0000000000000 --- a/src/libs/migrations/RenameEmojiSkinTone.ts +++ /dev/null @@ -1,36 +0,0 @@ -import Onyx from 'react-native-onyx'; -import type {OnyxEntry} from 'react-native-onyx'; -import Log from '@libs/Log'; -import ONYXKEYS from '@src/ONYXKEYS'; - -// This migration fixes the value of preferred skin tone to use number only. -export default function () { - return new Promise((resolve) => { - // Connect to the PREFERRED_EMOJI_SKIN_TONE key in Onyx to get the value of PREFERRED_EMOJI_SKIN_TONE. - // This will change the value of default to -1 - const connection = Onyx.connectWithoutView({ - key: ONYXKEYS.PREFERRED_EMOJI_SKIN_TONE, - callback: (value: OnyxEntry) => { - Onyx.disconnect(connection); - - if (!value) { - Log.info('[Migrate Onyx] Skipped migration RenameEmojiSkinTone because there is no value'); - return resolve(); - } - - if (typeof value === 'number') { - Log.info('[Migrate Onyx] Skipped migration RenameEmojiSkinTone because the value is correct'); - return resolve(); - } - - Log.info('[Migrate Onyx] Running RenameEmojiSkinTone migration'); - - // eslint-disable-next-line rulesdir/prefer-actions-set-data - Onyx.merge(ONYXKEYS.PREFERRED_EMOJI_SKIN_TONE, -1).then(() => { - Log.info('[Migrate Onyx] Ran migration RenameEmojiSkinTone'); - resolve(); - }); - }, - }); - }); -} diff --git a/src/pages/RequireTwoFactorAuthenticationPage.tsx b/src/pages/RequireTwoFactorAuthenticationPage.tsx deleted file mode 100644 index b058a76301367..0000000000000 --- a/src/pages/RequireTwoFactorAuthenticationPage.tsx +++ /dev/null @@ -1,90 +0,0 @@ -import {isUserValidatedSelector} from '@selectors/Account'; -import React, {useCallback} from 'react'; -import {StyleSheet, View} from 'react-native'; -import type {OnyxCollection} from 'react-native-onyx'; -import Button from '@components/Button'; -import FocusTrapForModal from '@components/FocusTrap/FocusTrapForModal'; -import Icon from '@components/Icon'; -import Text from '@components/Text'; -import {useMemoizedLazyIllustrations} from '@hooks/useLazyAsset'; -import useLocalize from '@hooks/useLocalize'; -import useOnyx from '@hooks/useOnyx'; -import useThemeStyles from '@hooks/useThemeStyles'; -import Navigation from '@libs/Navigation/Navigation'; -import variables from '@styles/variables'; -import CONST from '@src/CONST'; -import ONYXKEYS from '@src/ONYXKEYS'; -import ROUTES from '@src/ROUTES'; -import {emailSelector} from '@src/selectors/Session'; -import type {Policy} from '@src/types/onyx'; - -/** - * Checks if the 2FA is required because of Xero. - * - User is an admin of a workspace - * - Xero connection is enabled in the workspace - */ -const is2FARequiredBecauseOfXeroSelector = (email?: string) => { - return (workspaces: OnyxCollection) => { - return Object.values(workspaces ?? {})?.some((workspace) => { - const isXeroConnectionEnabled = workspace?.connections?.xero; - const isAdmin = email && workspace?.employeeList?.[email]?.role === CONST.POLICY.ROLE.ADMIN; - return !!isXeroConnectionEnabled && !!isAdmin; - }); - }; -}; - -function RequireTwoFactorAuthenticationPage() { - const illustrations = useMemoizedLazyIllustrations(['Encryption']); - const styles = useThemeStyles(); - const {translate} = useLocalize(); - const [isUserValidated = false] = useOnyx(ONYXKEYS.ACCOUNT, {selector: isUserValidatedSelector}); - const [email] = useOnyx(ONYXKEYS.SESSION, {selector: emailSelector}); - const requires2FAForXeroSelector = useCallback((workspaces: OnyxCollection) => is2FARequiredBecauseOfXeroSelector(email)(workspaces), [email]); - const [is2FARequiredBecauseOfXero = false] = useOnyx(ONYXKEYS.COLLECTION.POLICY, {selector: requires2FAForXeroSelector}); - - const handleOnPress = useCallback(() => { - if (isUserValidated) { - Navigation.navigate(ROUTES.SETTINGS_2FA_ROOT.getRoute()); - return; - } - Navigation.navigate(ROUTES.SETTINGS_2FA_VERIFY_ACCOUNT.getRoute({forwardTo: ROUTES.SETTINGS_2FA_ROOT.getRoute()})); - }, [isUserValidated]); - - return ( - - - - - - - - - - {translate('twoFactorAuth.twoFactorAuthIsRequiredForAdminsHeader')} - - {translate(is2FARequiredBecauseOfXero ? 'twoFactorAuth.twoFactorAuthIsRequiredXero' : 'twoFactorAuth.twoFactorAuthIsRequiredCompany')} - - -