diff --git a/src/CONST.ts b/src/CONST.ts index ab5a67274955b..c0463ce52bc96 100755 --- a/src/CONST.ts +++ b/src/CONST.ts @@ -553,6 +553,7 @@ const CONST = { CONCIERGE_ICON_URL_2021: `${CLOUDFRONT_URL}/images/icons/concierge_2021.png`, CONCIERGE_ICON_URL: `${CLOUDFRONT_URL}/images/icons/concierge_2022.png`, UPWORK_URL: 'https://github.com/Expensify/App/issues?q=is%3Aopen+is%3Aissue+label%3A%22Help+Wanted%22', + DEEP_DIVE_EXPENSIFY_CARD: 'https://community.expensify.com/discussion/4848/deep-dive-expensify-card-and-quickbooks-online-auto-reconciliation-how-it-works', GITHUB_URL: 'https://github.com/Expensify/App', TERMS_URL: `${USE_EXPENSIFY_URL}/terms`, PRIVACY_URL: `${USE_EXPENSIFY_URL}/privacy`, @@ -1220,12 +1221,25 @@ const CONST = { }, QUICKBOOKS_ONLINE: 'quickbooksOnline', - QUICKBOOKS_IMPORTS: { + QUICK_BOOKS_CONFIG: { SYNC_CLASSES: 'syncClasses', ENABLE_NEW_CATEGORIES: 'enableNewCategories', SYNC_CUSTOMERS: 'syncCustomers', SYNC_LOCATIONS: 'syncLocations', SYNC_TAXES: 'syncTaxes', + PREFERRED_EXPORTER: 'exporter', + EXPORT_DATE: 'exportDate', + OUT_OF_POCKET_EXPENSES: 'outOfPocketExpenses', + EXPORT_INVOICE: 'exportInvoice', + EXPORT_ENTITY: 'exportEntity', + EXPORT_ACCOUNT: 'exportAccount', + EXPORT_COMPANY_CARD: 'exportCompanyCard', + }, + + QUICKBOOKS_EXPORT_ENTITY: { + VENDOR_BILL: 'vendorBill', + CHECK: 'check', + JOURNAL_ENTRY: 'journalEntry', }, ACCOUNT_ID: { @@ -4588,6 +4602,12 @@ const CONST = { }, }, + QUICKBOOKS_EXPORT_DATE: { + LAST_EXPENSE: 'lastExpense', + EXPORTED_DATE: 'exportedDate', + SUBMITTED_DATA: 'submittedData', + }, + SESSION_STORAGE_KEYS: { INITIAL_URL: 'INITIAL_URL', }, diff --git a/src/ROUTES.ts b/src/ROUTES.ts index ac12fc5de5218..17dc62ca9f30e 100644 --- a/src/ROUTES.ts +++ b/src/ROUTES.ts @@ -477,10 +477,46 @@ const ROUTES = { route: 'settings/workspaces/:policyID/profile', getRoute: (policyID: string) => `settings/workspaces/${policyID}/profile` as const, }, + WORKSPACE_ACCOUNTING: { + route: 'settings/workspaces/:policyID/accounting', + getRoute: (policyID: string) => `settings/workspaces/${policyID}/accounting` as const, + }, WORKSPACE_PROFILE_CURRENCY: { route: 'settings/workspaces/:policyID/profile/currency', getRoute: (policyID: string) => `settings/workspaces/${policyID}/profile/currency` as const, }, + POLICY_ACCOUNTING_QUICKBOOKS_ONLINE_EXPORT: { + route: 'settings/workspaces/:policyID/accounting/quickbooks-online/export', + getRoute: (policyID: string) => `settings/workspaces/${policyID}/accounting/quickbooks-online/export` as const, + }, + POLICY_ACCOUNTING_QUICKBOOKS_ONLINE_COMPANY_CARD_EXPENSE_ACCOUNT_SELECT: { + route: 'settings/workspaces/:policyID/accounting/quickbooks-online/company-card-expense-account-select', + getRoute: (policyID: string) => `settings/workspaces/${policyID}/accounting/quickbooks-online/company-card-expense-account-select` as const, + }, + POLICY_ACCOUNTING_QUICKBOOKS_ONLINE_INVOICE_ACCOUNT_SELECT: { + route: 'settings/workspaces/:policyID/accounting/quickbooks-online/export/invoice-account-select', + getRoute: (policyID: string) => `settings/workspaces/${policyID}/accounting/quickbooks-online/export/invoice-account-select` as const, + }, + POLICY_ACCOUNTING_QUICKBOOKS_ONLINE_PREFERRED_EXPORTER: { + route: 'settings/workspaces/:policyID/accounting/quickbooks-online/preferred-exporter', + getRoute: (policyID: string) => `settings/workspaces/${policyID}/accounting/quickbooks-online/preferred-exporter` as const, + }, + POLICY_ACCOUNTING_QUICKBOOKS_ONLINE_EXPORT_OUT_OF_POCKET_EXPENSES: { + route: 'settings/workspaces/:policyID/accounting/quickbooks-online/export/out-of-pocket-expense', + getRoute: (policyID: string) => `settings/workspaces/${policyID}/accounting/quickbooks-online/export/out-of-pocket-expense` as const, + }, + POLICY_ACCOUNTING_QUICKBOOKS_ONLINE_EXPORT_OUT_OF_POCKET_EXPENSES_ACCOUNT_SELECT: { + route: 'settings/workspaces/:policyID/accounting/quickbooks-online/export/out-of-pocket-expense/account-select', + getRoute: (policyID: string) => `settings/workspaces/${policyID}/accounting/quickbooks-online/export/out-of-pocket-expense/account-select` as const, + }, + POLICY_ACCOUNTING_QUICKBOOKS_ONLINE_EXPORT_OUT_OF_POCKET_EXPENSES_SELECT: { + route: 'settings/workspaces/:policyID/accounting/quickbooks-online/export/out-of-pocket-expense/entity-select', + getRoute: (policyID: string) => `settings/workspaces/${policyID}/accounting/quickbooks-online/export/out-of-pocket-expense/entity-select` as const, + }, + POLICY_ACCOUNTING_QUICKBOOKS_ONLINE_EXPORT_DATE_SELECT: { + route: 'settings/workspaces/:policyID/accounting/quickbooks-online/export/date-select', + getRoute: (policyID: string) => `settings/workspaces/${policyID}/accounting/quickbooks-online/export/date-select` as const, + }, WORKSPACE_PROFILE_NAME: { route: 'settings/workspaces/:policyID/profile/name', getRoute: (policyID: string) => `settings/workspaces/${policyID}/profile/name` as const, diff --git a/src/SCREENS.ts b/src/SCREENS.ts index aed70dc1e9498..70df9b016e3f1 100644 --- a/src/SCREENS.ts +++ b/src/SCREENS.ts @@ -215,6 +215,14 @@ const SCREENS = { QUICKBOOKS_ONLINE_CUSTOMERS: 'Policy_Accounting_Quickbooks_Online_Import_Customers', QUICKBOOKS_ONLINE_LOCATIONS: 'Policy_Accounting_Quickbooks_Online_Import_Locations', QUICKBOOKS_ONLINE_TAXES: 'Policy_Accounting_Quickbooks_Online_Import_Taxes', + QUICKBOOKS_ONLINE_EXPORT: 'Workspace_Accounting_Quickbooks_Online_Export', + QUICKBOOKS_ONLINE_EXPORT_DATE_SELECT: 'Workspace_Accounting_Quickbooks_Online_Export_Date_Select', + QUICKBOOKS_ONLINE_EXPORT_INVOICE_ACCOUNT_SELECT: 'Workspace_Accounting_Quickbooks_Online_Export_Invoice_Account_Select', + QUICKBOOKS_ONLINE_COMPANY_CARD_EXPENSE_ACCOUNT_SELECT: 'Workspace_Accounting_Quickbooks_Online_Export_Company_Card_Expense_Select', + QUICKBOOKS_ONLINE_EXPORT_PREFERRED_EXPORTER: 'Workspace_Accounting_Quickbooks_Online_Export_Preferred_Exporter', + QUICKBOOKS_ONLINE_EXPORT_OUT_OF_POCKET_EXPENSES: 'Workspace_Accounting_Quickbooks_Online_Export_Out_Of_Pocket_Expenses', + QUICKBOOKS_ONLINE_EXPORT_OUT_OF_POCKET_EXPENSES_SELECT: 'Workspace_Accounting_Quickbooks_Online_Export_Out_Of_Pocket_Expenses_Select', + QUICKBOOKS_ONLINE_EXPORT_OUT_OF_POCKET_EXPENSES_ACCOUNT_SELECT: 'Workspace_Accounting_Quickbooks_Online_Export_Out_Of_Pocket_Expenses_Account_Select', }, INITIAL: 'Workspace_Initial', PROFILE: 'Workspace_Profile', diff --git a/src/languages/en.ts b/src/languages/en.ts index 1ca1feaba0482..437ed309c0f54 100755 --- a/src/languages/en.ts +++ b/src/languages/en.ts @@ -1872,6 +1872,50 @@ export default { taxesDescription: 'Choose whether to import tax rates and tax defaults from your accounting integration.', locationsAdditionalDescription: 'Locations are imported as Tags. This limits exporting expense reports as Vendor Bills or Checks to QuickBooks Online. To unlock these export options, either disable Locations import or upgrade to the Control Plan to export Locations encoded as a Report Field.', + export: 'Export', + exportAs: 'Export as', + exportDescription: 'Configure how data in Expensify gets exported to QuickBooks Online.', + preferredExporter: 'Preferred exporter', + date: 'Date', + exportExpenses: 'Export out-of-pocket expenses as', + exportInvoices: 'Export invoices to', + exportCompany: 'Export company cards as', + exportExpensifyCard: 'Export Expensify Card transactions as', + deepDiveExpensifyCard: 'Expensify Card transactions automatically export to a "Expensify Card Liability Account" created with', + deepDiveExpensifyCardIntegration: 'our integration.', + exportDate: 'Export date', + exportDateDescription: 'Use this date when exporting reports to QuickBooks Online.', + lastExpense: {label: 'Date of last expense', description: 'The date of the most recent expense on the report'}, + exportedDate: {label: 'Export date', description: 'The date the report was exported to QuickBooks Online'}, + submittedData: {label: 'Submitted date', description: 'The date the report was submitted for approval'}, + receivable: 'Accounts receivable', // This is an account name that will come directly from QBO, so I don't know why we need a translation for it. It should take whatever the name of the account is in QBO. Leaving this note for CS. + archive: 'Accounts receivable archive', // This is an account name that will come directly from QBO, so I don't know why we need a translation for it. It should take whatever the name of the account is in QBO. Leaving this note for CS. + exportInvoicesDescription: 'Invoices will be exported to this account in QuickBooks Online.', + exportCompanyCardsDescription: 'Set how company card purchases export to QuickBooks Online.', + creditCard: 'Credit Card', + debitCard: 'Debit Card', + vendorBill: 'Vendor Bill', + exportPreferredExporterNote: 'This can be any workspace admin, but must be a Domain Admin if you set different export accounts for individual company cards in Domain Settings.', + exportPreferredExporterSubNote: 'Once set, the preferred exporter will see reports for export in their account.', + exportOutOfPocketExpensesDescription: 'Set how out-of-pocket expenses export to QuickBooks Online.', + exportVendorBillDescription: + "We'll create a single itemized vendor bill for each Expensify report. If the period of the bill is closed, we'll post to the 1st of the next open period. You can add the vendor bill to your A/P account of choice (below).", + check: 'Check', + accountsPayable: 'Accounts Payable', + accountsPayableDescription: 'This is your chosen A/P account, against which vendor bills for each report are created.', + journalEntry: 'Journal Entry', + optionBelow: 'Choose an option below:', + vendorBillError: 'Vendor Bills are not available when locations are enabled. Please select a different export option.', + checkError: 'Check is not available when locations are enabled. Please select a different export option.', + journalEntryError: 'Journal entry is not available when taxes enabled. please select a different export option.', + companyCardsLocationEnabledDescription: + 'Note: QuickBooks Online does not support a field for Locations as Tags on Vendor Bills exports. As you import Locations from, this this export option is unavailable.', + outOfPocketTaxEnabledDescription: + "Note: QuickBooks Online doesn't support a field for tax on Journal Entry exports. Because you have tax tracking enabled on your workspace, this export option is unavailable.", + outOfPocketTaxEnabledError: 'Journal entry is not available when taxes enabled. please select a different export option.', + outOfPocketLocationEnabledError: 'Vendor Bills are not available when locations are enabled. Please select a different export option.', + outOfPocketLocationEnabledDescription: + 'Note: QuickBooks Online does not support a field for Locations as Tags on Vendor Bills exports. As you import Locations as Tags, this export option is unavailable.', }, type: { free: 'Free', diff --git a/src/languages/es.ts b/src/languages/es.ts index 112993f848f6e..5a3a9c230f58e 100644 --- a/src/languages/es.ts +++ b/src/languages/es.ts @@ -1896,6 +1896,51 @@ export default { taxesDescription: 'Elige si quires importar las tasas de impuestos y los impuestos por defecto de tu integración de contaduría.', locationsAdditionalDescription: 'Los lugares son importados como Etiquegas. Esto limita a exportar los informes de gastos como Factura del Proveedor o Cheques a Quicbooks Online. Para desbloquear estas opciones de exportación desactiva la importación de Lugares o cambia al Plan Control para exportar Lugares como Campos de Informes.', + export: 'Exportar', + exportAs: 'Exportar cómo', + exportExpenses: 'Exportar gastos de bolsillo como', + exportInvoices: 'Exportar facturas a', + exportCompany: 'Exportar tarjetas de empresa como', + exportDescription: 'Configura cómo se exportan los datos de Expensify a QuickBooks Online.', + preferredExporter: 'Exportador preferido', + date: 'Fecha', + deepDiveExpensifyCard: 'Las transacciones de la Tarjeta Expensify se exportan automáticamente a una "Cuenta de Responsabilidad de la Tarjeta Expensify" creada con', + deepDiveExpensifyCardIntegration: 'nuestra integración.', + exportExpensifyCard: 'Exportar las transacciones de las tarjetas Expensify como', + exportDate: 'Fecha de exportación', + exportDateDescription: 'Use this date when exporting reports to QuickBooks Online.', + lastExpense: {label: 'Date of last expense', description: 'The date of the most recent expense on the report'}, + exportedDate: {label: 'Fecha de exportación', description: 'Fecha de exportación del informe a QuickBooks Online'}, + submittedData: {label: 'Fecha de envío', description: 'Fecha en la que el informe se envió para su aprobación'}, + receivable: 'Cuentas por cobrar', // This is an account name that will come directly from QBO, so I don't know why we need a translation for it. It should take whatever the name of the account is in QBO. Leaving this note for CS. + archive: 'Archivo de cuentas por cobrar', // This is an account name that will come directly from QBO, so I don't know why we need a translation for it. It should take whatever the name of the account is in QBO. Leaving this note for CS. + exportInvoicesDescription: 'Las facturas se exportarán a esta cuenta en QuickBooks Online.', + exportCompanyCardsDescription: 'Establece cómo se exportan las compras con tarjeta de empresa a QuickBooks Online.', + debitCard: 'Tarjeta de débito', + check: 'Cheque', + optionBelow: 'Elija una opción a continuación:', + creditCard: 'Tarjeta de crédito', + vendorBill: 'Factura del proveedor', + accountsPayable: 'Cuentas por pagar', + accountsPayableDescription: 'Esta es la cuenta de cuentas por pagar elegida, contra la cual se crean las facturas de proveedores para cada informe.', + companyCardsLocationEnabledDescription: + 'Nota: QuickBooks Online no admite un campo para Ubicaciones como etiquetas en las exportaciones de facturas de proveedores. A medida que importa ubicaciones, esta opción de exportación no está disponible.', + exportPreferredExporterNote: + 'Puede ser cualquier administrador del espacio de trabajo, pero debe ser un administrador de dominio si configura diferentes cuentas de exportación para tarjetas de empresa individuales en la configuración del dominio.', + exportPreferredExporterSubNote: 'Una vez configurado, el exportador preferido verá los informes para exportar en su cuenta.', + journalEntry: 'Asiento contable', + vendorBillError: 'Las facturas de proveedores no están disponibles cuando las ubicaciones están habilitadas. Seleccione una opción de exportación diferente.', + checkError: 'La verificación no está disponible cuando las ubicaciones están habilitadas. Seleccione una opción de exportación diferente.', + journalEntryError: 'El asiento de diario no está disponible cuando los impuestos están habilitados. seleccione una opción de exportación diferente.', + exportOutOfPocketExpensesDescription: 'Establezca cómo se exportan los gastos de bolsillo a QuickBooks Online.', + exportVendorBillDescription: + 'Crearemos una única factura de proveedor detallada para cada informe de Expensify. Si el período de la factura está cerrado, lo publicaremos en el día 1 del siguiente período abierto. Puede agregar la factura del proveedor a la cuenta A/P de su elección (a continuación).', + outOfPocketTaxEnabledDescription: + 'Nota: QuickBooks Online no admite un campo para impuestos en las exportaciones de Anotación en el diario. Debido a que tienes habilitado el seguimiento de impuestos en tu área de trabajo, esta opción de exportación no está disponible.', + outOfPocketTaxEnabledError: 'La Anotacion en el diario no está disponible cuando los impuestos están activados. Por favor, selecciona una opción de exportación diferente.', + outOfPocketLocationEnabledError: 'Las facturas de proveedores no están disponibles cuando las ubicaciones están activadas. Seleccione otra opción de exportación.', + outOfPocketLocationEnabledDescription: + 'Nota: QuickBooks Online no admite un campo para Ubicaciones como Etiquetas en las exportaciones de Facturas de Proveedor. Al importar Ubicaciones como Etiquetas, esta opción de exportación no está disponible.', }, type: { free: 'Gratis', diff --git a/src/libs/API/parameters/UpdatePolicyConnectionConfigParams.ts b/src/libs/API/parameters/UpdatePolicyConnectionConfigParams.ts index c720fe0059c17..dd1a2edec089a 100644 --- a/src/libs/API/parameters/UpdatePolicyConnectionConfigParams.ts +++ b/src/libs/API/parameters/UpdatePolicyConnectionConfigParams.ts @@ -4,7 +4,7 @@ type UpdatePolicyConnectionConfigParams require('../../../../pages/settings/Profile/Contacts/ContactMethodDetailsPage').default as React.ComponentType, [SCREENS.SETTINGS.PROFILE.NEW_CONTACT_METHOD]: () => require('../../../../pages/settings/Profile/Contacts/NewContactMethodPage').default as React.ComponentType, [SCREENS.SETTINGS.PREFERENCES.PRIORITY_MODE]: () => require('../../../../pages/settings/Preferences/PriorityModePage').default as React.ComponentType, + [SCREENS.WORKSPACE.ACCOUNTING.ROOT]: () => require('../../../../pages/workspace/accounting/PolicyAccountingPage').default as React.ComponentType, [SCREENS.SETTINGS.PREFERENCES.LANGUAGE]: () => require('../../../../pages/settings/Preferences/LanguagePage').default as React.ComponentType, [SCREENS.SETTINGS.PREFERENCES.THEME]: () => require('../../../../pages/settings/Preferences/ThemePage').default as React.ComponentType, [SCREENS.SETTINGS.CLOSE]: () => require('../../../../pages/settings/Security/CloseAccountPage').default as React.ComponentType, @@ -254,6 +255,22 @@ const SettingsModalStackNavigator = createModalStackNavigator require('../../../../pages/workspace/taxes/WorkspaceTaxesSettingsCustomTaxName').default as React.ComponentType, [SCREENS.WORKSPACE.TAXES_SETTINGS_FOREIGN_CURRENCY_DEFAULT]: () => require('../../../../pages/workspace/taxes/WorkspaceTaxesSettingsForeignCurrency').default as React.ComponentType, [SCREENS.WORKSPACE.TAXES_SETTINGS_WORKSPACE_CURRENCY_DEFAULT]: () => require('../../../../pages/workspace/taxes/WorkspaceTaxesSettingsWorkspaceCurrency').default as React.ComponentType, + [SCREENS.WORKSPACE.ACCOUNTING.QUICKBOOKS_ONLINE_EXPORT]: () => + require('../../../../pages/workspace/accounting/qbo/export/QuickbooksExportConfigurationPage').default as React.ComponentType, + [SCREENS.WORKSPACE.ACCOUNTING.QUICKBOOKS_ONLINE_EXPORT_DATE_SELECT]: () => + require('../../../../pages/workspace/accounting/qbo/export/QuickbooksExportDateSelectPage').default as React.ComponentType, + [SCREENS.WORKSPACE.ACCOUNTING.QUICKBOOKS_ONLINE_EXPORT_INVOICE_ACCOUNT_SELECT]: () => + require('../../../../pages/workspace/accounting/qbo/export/QuickbooksExportInvoiceAccountSelectPage').default as React.ComponentType, + [SCREENS.WORKSPACE.ACCOUNTING.QUICKBOOKS_ONLINE_EXPORT_OUT_OF_POCKET_EXPENSES_ACCOUNT_SELECT]: () => + require('../../../../pages/workspace/accounting/qbo/export/QuickbooksOutOfPocketExpenseAccountSelectPage').default as React.ComponentType, + [SCREENS.WORKSPACE.ACCOUNTING.QUICKBOOKS_ONLINE_EXPORT_OUT_OF_POCKET_EXPENSES]: () => + require('../../../../pages/workspace/accounting/qbo/export/QuickbooksOutOfPocketExpenseConfigurationPage').default as React.ComponentType, + [SCREENS.WORKSPACE.ACCOUNTING.QUICKBOOKS_ONLINE_EXPORT_OUT_OF_POCKET_EXPENSES_SELECT]: () => + require('../../../../pages/workspace/accounting/qbo/export/QuickbooksOutOfPocketExpenseEntitySelectPage').default as React.ComponentType, + [SCREENS.WORKSPACE.ACCOUNTING.QUICKBOOKS_ONLINE_COMPANY_CARD_EXPENSE_ACCOUNT_SELECT]: () => + require('../../../../pages/workspace/accounting/qbo/export/QuickbooksCompanyCardExpenseAccountSelectPage').default as React.ComponentType, + [SCREENS.WORKSPACE.ACCOUNTING.QUICKBOOKS_ONLINE_EXPORT_PREFERRED_EXPORTER]: () => + require('../../../../pages/workspace/accounting/qbo/export/QuickbooksPreferredExporterConfigurationPage').default as React.ComponentType, [SCREENS.REIMBURSEMENT_ACCOUNT]: () => require('../../../../pages/ReimbursementAccount/ReimbursementAccountPage').default as React.ComponentType, [SCREENS.GET_ASSISTANCE]: () => require('../../../../pages/GetAssistancePage').default as React.ComponentType, [SCREENS.SETTINGS.TWO_FACTOR_AUTH]: () => require('../../../../pages/settings/Security/TwoFactorAuth/TwoFactorAuthPage').default as React.ComponentType, diff --git a/src/libs/Navigation/linkingConfig/FULL_SCREEN_TO_RHP_MAPPING.ts b/src/libs/Navigation/linkingConfig/FULL_SCREEN_TO_RHP_MAPPING.ts index af57b4e776936..7bb1a82fc4651 100755 --- a/src/libs/Navigation/linkingConfig/FULL_SCREEN_TO_RHP_MAPPING.ts +++ b/src/libs/Navigation/linkingConfig/FULL_SCREEN_TO_RHP_MAPPING.ts @@ -25,6 +25,14 @@ const FULL_SCREEN_TO_RHP_MAPPING: Partial> = { SCREENS.WORKSPACE.ACCOUNTING.QUICKBOOKS_ONLINE_TAXES, SCREENS.WORKSPACE.ACCOUNTING.QUICKBOOKS_ONLINE_LOCATIONS, SCREENS.WORKSPACE.ACCOUNTING.QUICKBOOKS_ONLINE_CUSTOMERS, + SCREENS.WORKSPACE.ACCOUNTING.QUICKBOOKS_ONLINE_EXPORT, + SCREENS.WORKSPACE.ACCOUNTING.QUICKBOOKS_ONLINE_EXPORT_DATE_SELECT, + SCREENS.WORKSPACE.ACCOUNTING.QUICKBOOKS_ONLINE_EXPORT_INVOICE_ACCOUNT_SELECT, + SCREENS.WORKSPACE.ACCOUNTING.QUICKBOOKS_ONLINE_EXPORT_OUT_OF_POCKET_EXPENSES_ACCOUNT_SELECT, + SCREENS.WORKSPACE.ACCOUNTING.QUICKBOOKS_ONLINE_COMPANY_CARD_EXPENSE_ACCOUNT_SELECT, + SCREENS.WORKSPACE.ACCOUNTING.QUICKBOOKS_ONLINE_EXPORT_PREFERRED_EXPORTER, + SCREENS.WORKSPACE.ACCOUNTING.QUICKBOOKS_ONLINE_EXPORT_OUT_OF_POCKET_EXPENSES, + SCREENS.WORKSPACE.ACCOUNTING.QUICKBOOKS_ONLINE_EXPORT_OUT_OF_POCKET_EXPENSES_SELECT, ], [SCREENS.WORKSPACE.TAXES]: [ SCREENS.WORKSPACE.TAXES_SETTINGS, diff --git a/src/libs/Navigation/linkingConfig/config.ts b/src/libs/Navigation/linkingConfig/config.ts index 3964b7dcd0740..f87922102c685 100644 --- a/src/libs/Navigation/linkingConfig/config.ts +++ b/src/libs/Navigation/linkingConfig/config.ts @@ -274,6 +274,22 @@ const config: LinkingOptions['config'] = { [SCREENS.WORKSPACE.ACCOUNTING.QUICKBOOKS_ONLINE_CUSTOMERS]: {path: ROUTES.POLICY_ACCOUNTING_QUICKBOOKS_ONLINE_CUSTOMERS.route}, [SCREENS.WORKSPACE.ACCOUNTING.QUICKBOOKS_ONLINE_LOCATIONS]: {path: ROUTES.POLICY_ACCOUNTING_QUICKBOOKS_ONLINE_LOCATIONS.route}, [SCREENS.WORKSPACE.ACCOUNTING.QUICKBOOKS_ONLINE_TAXES]: {path: ROUTES.POLICY_ACCOUNTING_QUICKBOOKS_ONLINE_TAXES.route}, + [SCREENS.WORKSPACE.ACCOUNTING.QUICKBOOKS_ONLINE_EXPORT]: {path: ROUTES.POLICY_ACCOUNTING_QUICKBOOKS_ONLINE_EXPORT.route}, + [SCREENS.WORKSPACE.ACCOUNTING.QUICKBOOKS_ONLINE_EXPORT_DATE_SELECT]: {path: ROUTES.POLICY_ACCOUNTING_QUICKBOOKS_ONLINE_EXPORT_DATE_SELECT.route}, + [SCREENS.WORKSPACE.ACCOUNTING.QUICKBOOKS_ONLINE_EXPORT_INVOICE_ACCOUNT_SELECT]: {path: ROUTES.POLICY_ACCOUNTING_QUICKBOOKS_ONLINE_INVOICE_ACCOUNT_SELECT.route}, + [SCREENS.WORKSPACE.ACCOUNTING.QUICKBOOKS_ONLINE_EXPORT_OUT_OF_POCKET_EXPENSES_ACCOUNT_SELECT]: { + path: ROUTES.POLICY_ACCOUNTING_QUICKBOOKS_ONLINE_EXPORT_OUT_OF_POCKET_EXPENSES_ACCOUNT_SELECT.route, + }, + [SCREENS.WORKSPACE.ACCOUNTING.QUICKBOOKS_ONLINE_EXPORT_OUT_OF_POCKET_EXPENSES]: { + path: ROUTES.POLICY_ACCOUNTING_QUICKBOOKS_ONLINE_EXPORT_OUT_OF_POCKET_EXPENSES.route, + }, + [SCREENS.WORKSPACE.ACCOUNTING.QUICKBOOKS_ONLINE_EXPORT_OUT_OF_POCKET_EXPENSES_SELECT]: { + path: ROUTES.POLICY_ACCOUNTING_QUICKBOOKS_ONLINE_EXPORT_OUT_OF_POCKET_EXPENSES_SELECT.route, + }, + [SCREENS.WORKSPACE.ACCOUNTING.QUICKBOOKS_ONLINE_COMPANY_CARD_EXPENSE_ACCOUNT_SELECT]: { + path: ROUTES.POLICY_ACCOUNTING_QUICKBOOKS_ONLINE_COMPANY_CARD_EXPENSE_ACCOUNT_SELECT.route, + }, + [SCREENS.WORKSPACE.ACCOUNTING.QUICKBOOKS_ONLINE_EXPORT_PREFERRED_EXPORTER]: {path: ROUTES.POLICY_ACCOUNTING_QUICKBOOKS_ONLINE_PREFERRED_EXPORTER.route}, [SCREENS.WORKSPACE.DESCRIPTION]: { path: ROUTES.WORKSPACE_PROFILE_DESCRIPTION.route, }, diff --git a/src/libs/Navigation/types.ts b/src/libs/Navigation/types.ts index f564ee01cbf79..b3e702bbdceee 100644 --- a/src/libs/Navigation/types.ts +++ b/src/libs/Navigation/types.ts @@ -265,6 +265,30 @@ type SettingsNavigatorParamList = { [SCREENS.WORKSPACE.ACCOUNTING.QUICKBOOKS_ONLINE_TAXES]: { policyID: string; }; + [SCREENS.WORKSPACE.ACCOUNTING.QUICKBOOKS_ONLINE_EXPORT]: { + policyID: string; + }; + [SCREENS.WORKSPACE.ACCOUNTING.QUICKBOOKS_ONLINE_EXPORT_DATE_SELECT]: { + policyID: string; + }; + [SCREENS.WORKSPACE.ACCOUNTING.QUICKBOOKS_ONLINE_EXPORT_INVOICE_ACCOUNT_SELECT]: { + policyID: string; + }; + [SCREENS.WORKSPACE.ACCOUNTING.QUICKBOOKS_ONLINE_EXPORT_OUT_OF_POCKET_EXPENSES_ACCOUNT_SELECT]: { + policyID: string; + }; + [SCREENS.WORKSPACE.ACCOUNTING.QUICKBOOKS_ONLINE_EXPORT_OUT_OF_POCKET_EXPENSES]: { + policyID: string; + }; + [SCREENS.WORKSPACE.ACCOUNTING.QUICKBOOKS_ONLINE_EXPORT_OUT_OF_POCKET_EXPENSES_SELECT]: { + policyID: string; + }; + [SCREENS.WORKSPACE.ACCOUNTING.QUICKBOOKS_ONLINE_COMPANY_CARD_EXPENSE_ACCOUNT_SELECT]: { + policyID: string; + }; + [SCREENS.WORKSPACE.ACCOUNTING.QUICKBOOKS_ONLINE_EXPORT_PREFERRED_EXPORTER]: { + policyID: string; + }; [SCREENS.GET_ASSISTANCE]: { backTo: Routes; }; @@ -687,9 +711,6 @@ type WorkspacesCentralPaneNavigatorParamList = { [SCREENS.WORKSPACE.MEMBERS]: { policyID: string; }; - [SCREENS.WORKSPACE.ACCOUNTING.ROOT]: { - policyID: string; - }; [SCREENS.WORKSPACE.CATEGORIES]: { policyID: string; }; diff --git a/src/libs/PolicyUtils.ts b/src/libs/PolicyUtils.ts index b9774949e2d97..cf6726ef11291 100644 --- a/src/libs/PolicyUtils.ts +++ b/src/libs/PolicyUtils.ts @@ -7,6 +7,7 @@ import ONYXKEYS from '@src/ONYXKEYS'; import ROUTES from '@src/ROUTES'; import type {Policy, PolicyCategories, PolicyEmployeeList, PolicyTagList, PolicyTags, TaxRate} from '@src/types/onyx'; import type {PolicyFeatureName, Rate} from '@src/types/onyx/Policy'; +import type PolicyEmployee from '@src/types/onyx/PolicyEmployee'; import type {EmptyObject} from '@src/types/utils/EmptyObject'; import {isEmptyObject} from '@src/types/utils/EmptyObject'; import getPolicyIDFromState from './Navigation/getPolicyIDFromState'; @@ -331,6 +332,10 @@ function getPolicyIDFromNavigationState() { return getPolicyIDFromState(navigationRef.getRootState() as State); } +function getAdminEmployees(policy: OnyxEntry): PolicyEmployee[] { + return Object.values(policy?.employeeList ?? {}).filter((employee) => employee.role === CONST.POLICY.ROLE.ADMIN); +} + /** * Returns the policy of the report */ @@ -381,6 +386,7 @@ export { getTaxByID, hasPolicyCategoriesError, getPolicyIDFromNavigationState, + getAdminEmployees, getPolicy, }; diff --git a/src/libs/actions/connections/index.ts b/src/libs/actions/connections/index.ts index 154036ba70e18..95a1280c9f992 100644 --- a/src/libs/actions/connections/index.ts +++ b/src/libs/actions/connections/index.ts @@ -46,7 +46,7 @@ function updatePolicyConnectionConfig {}, + onPress: () => Navigation.navigate(ROUTES.POLICY_ACCOUNTING_QUICKBOOKS_ONLINE_EXPORT.getRoute(policyID)), }, { icon: Expensicons.Gear, diff --git a/src/pages/workspace/accounting/qbo/QuickbooksChartOfAccountsPage.tsx b/src/pages/workspace/accounting/qbo/QuickbooksChartOfAccountsPage.tsx index 10f7500b3ca1a..723ac48224249 100644 --- a/src/pages/workspace/accounting/qbo/QuickbooksChartOfAccountsPage.tsx +++ b/src/pages/workspace/accounting/qbo/QuickbooksChartOfAccountsPage.tsx @@ -50,7 +50,7 @@ function QuickbooksChartOfAccountsPage({policy}: WithPolicyProps) { Connections.updatePolicyConnectionConfig( policyID, CONST.POLICY.CONNECTIONS.NAME.QBO, - CONST.QUICKBOOKS_IMPORTS.ENABLE_NEW_CATEGORIES, + CONST.QUICK_BOOKS_CONFIG.ENABLE_NEW_CATEGORIES, isSwitchOn ? CONST.INTEGRATION_ENTITY_MAP_TYPES.NONE : CONST.INTEGRATION_ENTITY_MAP_TYPES.TAG, ) } diff --git a/src/pages/workspace/accounting/qbo/QuickbooksClassesPage.tsx b/src/pages/workspace/accounting/qbo/QuickbooksClassesPage.tsx index 62a0a65ac91ca..42f4e7e3f728d 100644 --- a/src/pages/workspace/accounting/qbo/QuickbooksClassesPage.tsx +++ b/src/pages/workspace/accounting/qbo/QuickbooksClassesPage.tsx @@ -52,7 +52,7 @@ function QuickbooksClassesPage({policy}: WithPolicyProps) { Connections.updatePolicyConnectionConfig( policyID, CONST.POLICY.CONNECTIONS.NAME.QBO, - CONST.QUICKBOOKS_IMPORTS.SYNC_CLASSES, + CONST.QUICK_BOOKS_CONFIG.SYNC_CLASSES, isSwitchOn ? CONST.INTEGRATION_ENTITY_MAP_TYPES.NONE : CONST.INTEGRATION_ENTITY_MAP_TYPES.TAG, ) } diff --git a/src/pages/workspace/accounting/qbo/QuickbooksCustomersPage.tsx b/src/pages/workspace/accounting/qbo/QuickbooksCustomersPage.tsx index 3192ff4d83a9b..644bd070327c8 100644 --- a/src/pages/workspace/accounting/qbo/QuickbooksCustomersPage.tsx +++ b/src/pages/workspace/accounting/qbo/QuickbooksCustomersPage.tsx @@ -51,7 +51,7 @@ function QuickbooksCustomersPage({policy}: WithPolicyProps) { Connections.updatePolicyConnectionConfig( policyID, CONST.POLICY.CONNECTIONS.NAME.QBO, - CONST.QUICKBOOKS_IMPORTS.SYNC_CUSTOMERS, + CONST.QUICK_BOOKS_CONFIG.SYNC_CUSTOMERS, isSwitchOn ? CONST.INTEGRATION_ENTITY_MAP_TYPES.NONE : CONST.INTEGRATION_ENTITY_MAP_TYPES.TAG, ) } diff --git a/src/pages/workspace/accounting/qbo/QuickbooksLocationsPage.tsx b/src/pages/workspace/accounting/qbo/QuickbooksLocationsPage.tsx index fa573b813585a..06635b1fe7dbe 100644 --- a/src/pages/workspace/accounting/qbo/QuickbooksLocationsPage.tsx +++ b/src/pages/workspace/accounting/qbo/QuickbooksLocationsPage.tsx @@ -52,7 +52,7 @@ function QuickbooksLocationsPage({policy}: WithPolicyProps) { Connections.updatePolicyConnectionConfig( policyID, CONST.POLICY.CONNECTIONS.NAME.QBO, - CONST.QUICKBOOKS_IMPORTS.SYNC_LOCATIONS, + CONST.QUICK_BOOKS_CONFIG.SYNC_LOCATIONS, isSwitchOn ? CONST.INTEGRATION_ENTITY_MAP_TYPES.NONE : CONST.INTEGRATION_ENTITY_MAP_TYPES.TAG, ) } diff --git a/src/pages/workspace/accounting/qbo/QuickbooksTaxesPage.tsx b/src/pages/workspace/accounting/qbo/QuickbooksTaxesPage.tsx index 215d8397b7ec9..714e2638583e1 100644 --- a/src/pages/workspace/accounting/qbo/QuickbooksTaxesPage.tsx +++ b/src/pages/workspace/accounting/qbo/QuickbooksTaxesPage.tsx @@ -49,7 +49,7 @@ function QuickbooksTaxesPage({policy}: WithPolicyProps) { Connections.updatePolicyConnectionConfig( policyID, CONST.POLICY.CONNECTIONS.NAME.QBO, - CONST.QUICKBOOKS_IMPORTS.SYNC_TAXES, + CONST.QUICK_BOOKS_CONFIG.SYNC_TAXES, isSwitchOn ? CONST.INTEGRATION_ENTITY_MAP_TYPES.NONE : CONST.INTEGRATION_ENTITY_MAP_TYPES.TAG, ) } diff --git a/src/pages/workspace/accounting/qbo/export/QuickbooksCompanyCardExpenseAccountSelectPage.tsx b/src/pages/workspace/accounting/qbo/export/QuickbooksCompanyCardExpenseAccountSelectPage.tsx new file mode 100644 index 0000000000000..d105a3c73ddee --- /dev/null +++ b/src/pages/workspace/accounting/qbo/export/QuickbooksCompanyCardExpenseAccountSelectPage.tsx @@ -0,0 +1,109 @@ +import React, {useCallback, useMemo} from 'react'; +import {View} from 'react-native'; +import type {SectionListData} from 'react-native'; +import HeaderWithBackButton from '@components/HeaderWithBackButton'; +import ScreenWrapper from '@components/ScreenWrapper'; +import SelectionList from '@components/SelectionList'; +import RadioListItem from '@components/SelectionList/RadioListItem'; +import type {ListItem, Section} from '@components/SelectionList/types'; +import Text from '@components/Text'; +import useLocalize from '@hooks/useLocalize'; +import useThemeStyles from '@hooks/useThemeStyles'; +import * as Connections from '@libs/actions/connections'; +import Navigation from '@navigation/Navigation'; +import AdminPolicyAccessOrNotFoundWrapper from '@pages/workspace/AdminPolicyAccessOrNotFoundWrapper'; +import FeatureEnabledAccessOrNotFoundWrapper from '@pages/workspace/FeatureEnabledAccessOrNotFoundWrapper'; +import withPolicy from '@pages/workspace/withPolicy'; +import type {WithPolicyProps} from '@pages/workspace/withPolicy'; +import CONST from '@src/CONST'; +import ROUTES from '@src/ROUTES'; + +type CardListItem = ListItem & { + value: string; +}; +type CardsSection = SectionListData>; +type Card = {name: string}; + +function QuickbooksCompanyCardExpenseAccountSelectPage({policy}: WithPolicyProps) { + const {translate} = useLocalize(); + const styles = useThemeStyles(); + const {creditCards} = policy?.connections?.quickbooksOnline?.data ?? {}; + + const {exportCompanyCard, syncLocations} = policy?.connections?.quickbooksOnline?.config ?? {}; + const isLocationEnabled = Boolean(syncLocations && syncLocations !== CONST.INTEGRATION_ENTITY_MAP_TYPES.NONE); + + const defaultCards = useMemo( + () => [ + { + name: translate(`workspace.qbo.creditCard`), + }, + { + name: translate(`workspace.qbo.debitCard`), + }, + { + name: translate(`workspace.qbo.vendorBill`), + }, + ], + [translate], + ); + const cards = useMemo(() => { + if (creditCards?.length) { + return creditCards; + } + return isLocationEnabled ? defaultCards.slice(0, -1) : defaultCards; + }, [creditCards, isLocationEnabled, defaultCards]); + + const data = useMemo( + () => + cards.map((card) => ({ + value: card.name, + text: card.name, + keyForList: card.name, + isSelected: card.name === exportCompanyCard, + })), + [cards, exportCompanyCard], + ); + + const sections = useMemo(() => [{data}], [data]); + const policyID = policy?.id ?? ''; + + const onSelectRow = useCallback( + (row: CardListItem) => { + if (row.value !== exportCompanyCard) { + Connections.updatePolicyConnectionConfig(policyID, CONST.POLICY.CONNECTIONS.NAME.QBO, CONST.QUICK_BOOKS_CONFIG.EXPORT_COMPANY_CARD, row.value); + } + Navigation.goBack(ROUTES.POLICY_ACCOUNTING_QUICKBOOKS_ONLINE_EXPORT.getRoute(policyID)); + }, + [exportCompanyCard, policyID], + ); + + return ( + + + + + + {translate('workspace.qbo.exportCompanyCardsDescription')}} + sections={sections} + ListItem={RadioListItem} + onSelectRow={onSelectRow} + initiallyFocusedOptionKey={data.find((mode) => mode.isSelected)?.keyForList} + footerContent={ + isLocationEnabled && {translate('workspace.qbo.companyCardsLocationEnabledDescription')} + } + /> + + + + + ); +} + +QuickbooksCompanyCardExpenseAccountSelectPage.displayName = 'QuickbooksCompanyCardExpenseAccountSelectPage'; + +export default withPolicy(QuickbooksCompanyCardExpenseAccountSelectPage); diff --git a/src/pages/workspace/accounting/qbo/export/QuickbooksExportConfigurationPage.tsx b/src/pages/workspace/accounting/qbo/export/QuickbooksExportConfigurationPage.tsx new file mode 100644 index 0000000000000..429e7afddd32c --- /dev/null +++ b/src/pages/workspace/accounting/qbo/export/QuickbooksExportConfigurationPage.tsx @@ -0,0 +1,128 @@ +import React from 'react'; +import HeaderWithBackButton from '@components/HeaderWithBackButton'; +import type {MenuItemProps} from '@components/MenuItem'; +import MenuItemWithTopDescription from '@components/MenuItemWithTopDescription'; +import OfflineWithFeedback from '@components/OfflineWithFeedback'; +import type {OfflineWithFeedbackProps} from '@components/OfflineWithFeedback'; +import ScreenWrapper from '@components/ScreenWrapper'; +import ScrollView from '@components/ScrollView'; +import Text from '@components/Text'; +import TextLink from '@components/TextLink'; +import useLocalize from '@hooks/useLocalize'; +import useThemeStyles from '@hooks/useThemeStyles'; +import Navigation from '@navigation/Navigation'; +import AdminPolicyAccessOrNotFoundWrapper from '@pages/workspace/AdminPolicyAccessOrNotFoundWrapper'; +import FeatureEnabledAccessOrNotFoundWrapper from '@pages/workspace/FeatureEnabledAccessOrNotFoundWrapper'; +import withPolicy from '@pages/workspace/withPolicy'; +import type {WithPolicyProps} from '@pages/workspace/withPolicy'; +import * as Link from '@userActions/Link'; +import CONST from '@src/CONST'; +import ROUTES from '@src/ROUTES'; + +type MenuItem = MenuItemProps & {pendingAction?: OfflineWithFeedbackProps['pendingAction']}; + +function QuickbooksExportConfigurationPage({policy}: WithPolicyProps) { + const {translate} = useLocalize(); + const styles = useThemeStyles(); + const policyID = policy?.id ?? ''; + const policyOwner = policy?.owner ?? ''; + const {exporter, exportDate, exportEntity, exportInvoice, exportCompanyCard, errorFields, pendingFields} = policy?.connections?.quickbooksOnline?.config ?? {}; + const menuItems: MenuItem[] = [ + { + description: translate('workspace.qbo.preferredExporter'), + onPress: () => Navigation.navigate(ROUTES.POLICY_ACCOUNTING_QUICKBOOKS_ONLINE_PREFERRED_EXPORTER.getRoute(policyID)), + brickRoadIndicator: errorFields?.exporter ? CONST.BRICK_ROAD_INDICATOR_STATUS.ERROR : undefined, + title: exporter ?? policyOwner, + pendingAction: pendingFields?.exporter, + error: errorFields?.exporter ? translate('common.genericErrorMessage') : undefined, + }, + { + description: translate('workspace.qbo.date'), + onPress: () => Navigation.navigate(ROUTES.POLICY_ACCOUNTING_QUICKBOOKS_ONLINE_EXPORT_DATE_SELECT.getRoute(policyID)), + brickRoadIndicator: errorFields?.exportDate ? CONST.BRICK_ROAD_INDICATOR_STATUS.ERROR : undefined, + title: exportDate ? translate(`workspace.qbo.${exportDate}.label`) : undefined, + pendingAction: pendingFields?.exportDate, + error: errorFields?.exportDate ? translate('common.genericErrorMessage') : undefined, + }, + { + description: translate('workspace.qbo.exportExpenses'), + onPress: () => Navigation.navigate(ROUTES.POLICY_ACCOUNTING_QUICKBOOKS_ONLINE_EXPORT_OUT_OF_POCKET_EXPENSES.getRoute(policyID)), + brickRoadIndicator: Boolean(errorFields?.exportEntity) || Boolean(errorFields?.exportAccount) ? CONST.BRICK_ROAD_INDICATOR_STATUS.ERROR : undefined, + title: exportEntity ? translate(`workspace.qbo.${exportEntity}`) : undefined, + // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing + pendingAction: pendingFields?.exportEntity || pendingFields?.exportAccount, + }, + { + description: translate('workspace.qbo.exportInvoices'), + onPress: () => Navigation.navigate(ROUTES.POLICY_ACCOUNTING_QUICKBOOKS_ONLINE_INVOICE_ACCOUNT_SELECT.getRoute(policyID)), + brickRoadIndicator: errorFields?.exportInvoice ? CONST.BRICK_ROAD_INDICATOR_STATUS.ERROR : undefined, + title: exportInvoice, + pendingAction: pendingFields?.exportInvoice, + error: errorFields?.exportInvoice ? translate('common.genericErrorMessage') : undefined, + }, + { + description: translate('workspace.qbo.exportCompany'), + onPress: () => Navigation.navigate(ROUTES.POLICY_ACCOUNTING_QUICKBOOKS_ONLINE_COMPANY_CARD_EXPENSE_ACCOUNT_SELECT.getRoute(policyID)), + brickRoadIndicator: errorFields?.exportCompanyCard ? CONST.BRICK_ROAD_INDICATOR_STATUS.ERROR : undefined, + title: exportCompanyCard, + pendingAction: pendingFields?.exportCompanyCard, + error: errorFields?.exportCompanyCard ? translate('common.genericErrorMessage') : undefined, + }, + { + description: translate('workspace.qbo.exportExpensifyCard'), + title: translate('workspace.qbo.creditCard'), + shouldShowRightIcon: false, + interactive: false, + }, + ]; + + return ( + + + + + + {translate('workspace.qbo.exportDescription')} + {menuItems.map((menuItem) => ( + + + + ))} + + {`${translate('workspace.qbo.deepDiveExpensifyCard')} `} + Link.openExternalLink(CONST.DEEP_DIVE_EXPENSIFY_CARD)} + style={[styles.mutedNormalTextLabel, styles.link]} + > + {translate('workspace.qbo.deepDiveExpensifyCardIntegration')} + + + + + + + ); +} + +QuickbooksExportConfigurationPage.displayName = 'QuickbooksExportConfigurationPage'; + +export default withPolicy(QuickbooksExportConfigurationPage); diff --git a/src/pages/workspace/accounting/qbo/export/QuickbooksExportDateSelectPage.tsx b/src/pages/workspace/accounting/qbo/export/QuickbooksExportDateSelectPage.tsx new file mode 100644 index 0000000000000..5db9126f18604 --- /dev/null +++ b/src/pages/workspace/accounting/qbo/export/QuickbooksExportDateSelectPage.tsx @@ -0,0 +1,72 @@ +import React, {useCallback} from 'react'; +import type {ValueOf} from 'type-fest'; +import HeaderWithBackButton from '@components/HeaderWithBackButton'; +import ScreenWrapper from '@components/ScreenWrapper'; +import SelectionList from '@components/SelectionList'; +import RadioListItem from '@components/SelectionList/RadioListItem'; +import type {ListItem} from '@components/SelectionList/types'; +import Text from '@components/Text'; +import useLocalize from '@hooks/useLocalize'; +import useThemeStyles from '@hooks/useThemeStyles'; +import * as Connections from '@libs/actions/connections'; +import Navigation from '@navigation/Navigation'; +import AdminPolicyAccessOrNotFoundWrapper from '@pages/workspace/AdminPolicyAccessOrNotFoundWrapper'; +import FeatureEnabledAccessOrNotFoundWrapper from '@pages/workspace/FeatureEnabledAccessOrNotFoundWrapper'; +import withPolicy from '@pages/workspace/withPolicy'; +import type {WithPolicyProps} from '@pages/workspace/withPolicy'; +import CONST from '@src/CONST'; +import ROUTES from '@src/ROUTES'; + +type CardListItem = ListItem & { + value: ValueOf; +}; +function QuickbooksExportDateSelectPage({policy}: WithPolicyProps) { + const {translate} = useLocalize(); + const styles = useThemeStyles(); + const policyID = policy?.id ?? ''; + const {exportDate} = policy?.connections?.quickbooksOnline?.config ?? {}; + const data: CardListItem[] = Object.values(CONST.QUICKBOOKS_EXPORT_DATE).map((dateType) => ({ + value: dateType, + text: translate(`workspace.qbo.${dateType}.label`), + alternateText: translate(`workspace.qbo.${dateType}.description`), + keyForList: dateType, + isSelected: exportDate === dateType, + })); + + const onSelectRow = useCallback( + (row: CardListItem) => { + if (row.value !== exportDate) { + Connections.updatePolicyConnectionConfig(policyID, CONST.POLICY.CONNECTIONS.NAME.QBO, CONST.QUICK_BOOKS_CONFIG.EXPORT_DATE, row.value); + } + Navigation.goBack(ROUTES.POLICY_ACCOUNTING_QUICKBOOKS_ONLINE_EXPORT_DATE_SELECT.getRoute(policyID)); + }, + [exportDate, policyID], + ); + + return ( + + + + + {translate('workspace.qbo.exportDateDescription')}} + sections={[{data}]} + ListItem={RadioListItem} + onSelectRow={onSelectRow} + initiallyFocusedOptionKey={data.find((mode) => mode.isSelected)?.keyForList} + /> + + + + ); +} + +QuickbooksExportDateSelectPage.displayName = 'QuickbooksExportDateSelectPage'; + +export default withPolicy(QuickbooksExportDateSelectPage); diff --git a/src/pages/workspace/accounting/qbo/export/QuickbooksExportInvoiceAccountSelectPage.tsx b/src/pages/workspace/accounting/qbo/export/QuickbooksExportInvoiceAccountSelectPage.tsx new file mode 100644 index 0000000000000..de47ca90527e9 --- /dev/null +++ b/src/pages/workspace/accounting/qbo/export/QuickbooksExportInvoiceAccountSelectPage.tsx @@ -0,0 +1,84 @@ +import React, {useCallback, useMemo} from 'react'; +import HeaderWithBackButton from '@components/HeaderWithBackButton'; +import ScreenWrapper from '@components/ScreenWrapper'; +import SelectionList from '@components/SelectionList'; +import RadioListItem from '@components/SelectionList/RadioListItem'; +import type {ListItem} from '@components/SelectionList/types'; +import Text from '@components/Text'; +import useLocalize from '@hooks/useLocalize'; +import useThemeStyles from '@hooks/useThemeStyles'; +import * as Connections from '@libs/actions/connections'; +import Navigation from '@navigation/Navigation'; +import AdminPolicyAccessOrNotFoundWrapper from '@pages/workspace/AdminPolicyAccessOrNotFoundWrapper'; +import FeatureEnabledAccessOrNotFoundWrapper from '@pages/workspace/FeatureEnabledAccessOrNotFoundWrapper'; +import withPolicy from '@pages/workspace/withPolicy'; +import type {WithPolicyProps} from '@pages/workspace/withPolicy'; +import CONST from '@src/CONST'; +import ROUTES from '@src/ROUTES'; + +type CardListItem = ListItem & { + value: string; +}; + +function QuickbooksExportInvoiceAccountSelectPage({policy}: WithPolicyProps) { + const {translate} = useLocalize(); + const styles = useThemeStyles(); + const {accountsReceivable} = policy?.connections?.quickbooksOnline?.data ?? {}; + const {exportInvoice} = policy?.connections?.quickbooksOnline?.config ?? {}; + // TODO - should be removed after API fully working + const draft = [ + { + name: translate(`workspace.qbo.receivable`), + }, + { + name: translate(`workspace.qbo.archive`), + }, + ]; + const result = accountsReceivable?.length ? accountsReceivable : draft; + + const policyID = policy?.id ?? ''; + const data: CardListItem[] = useMemo( + () => + result?.map((account) => ({ + value: account.name, + text: account.name, + keyForList: account.name, + isSelected: account.name === exportInvoice, + })), + [exportInvoice, result], + ); + + const onSelectRow = useCallback( + (row: CardListItem) => { + if (row.value !== exportInvoice) { + Connections.updatePolicyConnectionConfig(policyID, CONST.POLICY.CONNECTIONS.NAME.QBO, CONST.QUICK_BOOKS_CONFIG.EXPORT_INVOICE, row.value); + } + Navigation.goBack(ROUTES.POLICY_ACCOUNTING_QUICKBOOKS_ONLINE_INVOICE_ACCOUNT_SELECT.getRoute(policyID)); + }, + [exportInvoice, policyID], + ); + + return ( + + + + + {translate('workspace.qbo.exportInvoicesDescription')}} + sections={[{data}]} + ListItem={RadioListItem} + onSelectRow={onSelectRow} + initiallyFocusedOptionKey={data.find((mode) => mode.isSelected)?.keyForList} + /> + + + + ); +} + +QuickbooksExportInvoiceAccountSelectPage.displayName = 'QuickbooksExportInvoiceAccountSelectPage'; + +export default withPolicy(QuickbooksExportInvoiceAccountSelectPage); diff --git a/src/pages/workspace/accounting/qbo/export/QuickbooksOutOfPocketExpenseAccountSelectPage.tsx b/src/pages/workspace/accounting/qbo/export/QuickbooksOutOfPocketExpenseAccountSelectPage.tsx new file mode 100644 index 0000000000000..659e42556fcc4 --- /dev/null +++ b/src/pages/workspace/accounting/qbo/export/QuickbooksOutOfPocketExpenseAccountSelectPage.tsx @@ -0,0 +1,99 @@ +import React, {useCallback, useMemo} from 'react'; +import HeaderWithBackButton from '@components/HeaderWithBackButton'; +import ScreenWrapper from '@components/ScreenWrapper'; +import SelectionList from '@components/SelectionList'; +import RadioListItem from '@components/SelectionList/RadioListItem'; +import type {ListItem} from '@components/SelectionList/types'; +import Text from '@components/Text'; +import useLocalize from '@hooks/useLocalize'; +import useThemeStyles from '@hooks/useThemeStyles'; +import * as Connections from '@libs/actions/connections'; +import Navigation from '@navigation/Navigation'; +import AdminPolicyAccessOrNotFoundWrapper from '@pages/workspace/AdminPolicyAccessOrNotFoundWrapper'; +import FeatureEnabledAccessOrNotFoundWrapper from '@pages/workspace/FeatureEnabledAccessOrNotFoundWrapper'; +import withPolicy from '@pages/workspace/withPolicy'; +import type {WithPolicyProps} from '@pages/workspace/withPolicy'; +import CONST from '@src/CONST'; +import ROUTES from '@src/ROUTES'; + +// TODO - should be removed after API fully working +const draft = [ + { + name: 'Accounts Payable (A/P)', + }, + { + name: 'Payroll Accounts', + }, +]; + +type CardListItem = ListItem & { + value: string; +}; + +function QuickbooksOutOfPocketExpenseAccountSelectPage({policy}: WithPolicyProps) { + const {translate} = useLocalize(); + const styles = useThemeStyles(); + const {bankAccounts, journalEntryAccounts, accountsPayable} = policy?.connections?.quickbooksOnline?.data ?? {}; + + const {exportEntity, exportAccount} = policy?.connections?.quickbooksOnline?.config ?? {}; + + const data: CardListItem[] = useMemo(() => { + let result; + switch (exportEntity) { + case CONST.QUICKBOOKS_EXPORT_ENTITY.CHECK: + result = bankAccounts ?? []; + break; + case CONST.QUICKBOOKS_EXPORT_ENTITY.VENDOR_BILL: + result = accountsPayable ?? []; + break; + case CONST.QUICKBOOKS_EXPORT_ENTITY.JOURNAL_ENTRY: + result = journalEntryAccounts ?? []; + break; + default: + result = draft; + } + + return (draft ?? result)?.map((card) => ({ + value: card.name, + text: card.name, + keyForList: card.name, + isSelected: card.name === exportAccount, + })); + }, [accountsPayable, bankAccounts, exportAccount, exportEntity, journalEntryAccounts]); + + const policyID = policy?.id ?? ''; + + const onSelectRow = useCallback( + (row: CardListItem) => { + if (row.value !== exportAccount) { + Connections.updatePolicyConnectionConfig(policyID, CONST.POLICY.CONNECTIONS.NAME.QBO, CONST.QUICK_BOOKS_CONFIG.EXPORT_ACCOUNT, row.value); + } + Navigation.goBack(ROUTES.POLICY_ACCOUNTING_QUICKBOOKS_ONLINE_EXPORT_OUT_OF_POCKET_EXPENSES.getRoute(policyID)); + }, + [exportAccount, policyID], + ); + + return ( + + + + + {translate('workspace.qbo.accountsPayableDescription')}} + sections={[{data}]} + ListItem={RadioListItem} + onSelectRow={onSelectRow} + initiallyFocusedOptionKey={data.find((mode) => mode.isSelected)?.keyForList} + /> + + + + ); +} + +QuickbooksOutOfPocketExpenseAccountSelectPage.displayName = 'QuickbooksOutOfPocketExpenseAccountSelectPage'; + +export default withPolicy(QuickbooksOutOfPocketExpenseAccountSelectPage); diff --git a/src/pages/workspace/accounting/qbo/export/QuickbooksOutOfPocketExpenseConfigurationPage.tsx b/src/pages/workspace/accounting/qbo/export/QuickbooksOutOfPocketExpenseConfigurationPage.tsx new file mode 100644 index 0000000000000..8ee94e675141e --- /dev/null +++ b/src/pages/workspace/accounting/qbo/export/QuickbooksOutOfPocketExpenseConfigurationPage.tsx @@ -0,0 +1,79 @@ +import React from 'react'; +import HeaderWithBackButton from '@components/HeaderWithBackButton'; +import MenuItemWithTopDescription from '@components/MenuItemWithTopDescription'; +import OfflineWithFeedback from '@components/OfflineWithFeedback'; +import ScreenWrapper from '@components/ScreenWrapper'; +import ScrollView from '@components/ScrollView'; +import Text from '@components/Text'; +import useLocalize from '@hooks/useLocalize'; +import useThemeStyles from '@hooks/useThemeStyles'; +import Navigation from '@navigation/Navigation'; +import AdminPolicyAccessOrNotFoundWrapper from '@pages/workspace/AdminPolicyAccessOrNotFoundWrapper'; +import FeatureEnabledAccessOrNotFoundWrapper from '@pages/workspace/FeatureEnabledAccessOrNotFoundWrapper'; +import withPolicy from '@pages/workspace/withPolicy'; +import type {WithPolicyProps} from '@pages/workspace/withPolicy'; +import CONST from '@src/CONST'; +import ROUTES from '@src/ROUTES'; + +function QuickbooksOutOfPocketExpenseConfigurationPage({policy}: WithPolicyProps) { + const {translate} = useLocalize(); + const styles = useThemeStyles(); + const policyID = policy?.id ?? ''; + const {syncLocations, exportAccount, exportEntity, errorFields, syncTaxes, pendingFields} = policy?.connections?.quickbooksOnline?.config ?? {}; + const isLocationEnabled = Boolean(syncLocations && syncLocations !== CONST.INTEGRATION_ENTITY_MAP_TYPES.NONE); + const isTaxesEnabled = Boolean(syncTaxes && syncTaxes !== CONST.INTEGRATION_ENTITY_MAP_TYPES.NONE); + const shouldShowTaxError = isTaxesEnabled && exportEntity === CONST.QUICKBOOKS_EXPORT_ENTITY.JOURNAL_ENTRY; + const shouldShowLocationError = isLocationEnabled && exportEntity !== CONST.QUICKBOOKS_EXPORT_ENTITY.JOURNAL_ENTRY; + const hasErrors = Boolean(errorFields?.exportEntity) || shouldShowTaxError || shouldShowLocationError; + + return ( + + + + + + {!isLocationEnabled && {translate('workspace.qbo.exportOutOfPocketExpensesDescription')}} + + Navigation.navigate(ROUTES.POLICY_ACCOUNTING_QUICKBOOKS_ONLINE_EXPORT_OUT_OF_POCKET_EXPENSES_SELECT.getRoute(policyID))} + brickRoadIndicator={hasErrors ? CONST.BRICK_ROAD_INDICATOR_STATUS.ERROR : undefined} + shouldShowRightIcon + /> + + {exportEntity === CONST.QUICKBOOKS_EXPORT_ENTITY.VENDOR_BILL && !isLocationEnabled && ( + {translate('workspace.qbo.exportVendorBillDescription')} + )} + {isLocationEnabled && {translate('workspace.qbo.outOfPocketLocationEnabledDescription')}} + {!isLocationEnabled && ( + + Navigation.navigate(ROUTES.POLICY_ACCOUNTING_QUICKBOOKS_ONLINE_EXPORT_OUT_OF_POCKET_EXPENSES_ACCOUNT_SELECT.getRoute(policyID))} + brickRoadIndicator={errorFields?.exportAccount ? CONST.BRICK_ROAD_INDICATOR_STATUS.ERROR : undefined} + shouldShowRightIcon + error={errorFields?.exportAccount ? translate('common.genericErrorMessage') : undefined} + // TODO uncomment when errorText will be fixed + // errorText={errors?.exportAccount} + /> + + )} + + + + + ); +} + +QuickbooksOutOfPocketExpenseConfigurationPage.displayName = 'QuickbooksExportOutOfPocketExpensesPage'; + +export default withPolicy(QuickbooksOutOfPocketExpenseConfigurationPage); diff --git a/src/pages/workspace/accounting/qbo/export/QuickbooksOutOfPocketExpenseEntitySelectPage.tsx b/src/pages/workspace/accounting/qbo/export/QuickbooksOutOfPocketExpenseEntitySelectPage.tsx new file mode 100644 index 0000000000000..ee191a9575cac --- /dev/null +++ b/src/pages/workspace/accounting/qbo/export/QuickbooksOutOfPocketExpenseEntitySelectPage.tsx @@ -0,0 +1,114 @@ +import React, {useCallback, useEffect, useMemo} from 'react'; +import {View} from 'react-native'; +import type {SectionListData} from 'react-native'; +import type {ValueOf} from 'type-fest'; +import HeaderWithBackButton from '@components/HeaderWithBackButton'; +import ScreenWrapper from '@components/ScreenWrapper'; +import SelectionList from '@components/SelectionList'; +import RadioListItem from '@components/SelectionList/RadioListItem'; +import type {ListItem, Section} from '@components/SelectionList/types'; +import Text from '@components/Text'; +import useLocalize from '@hooks/useLocalize'; +import useThemeStyles from '@hooks/useThemeStyles'; +import * as Connections from '@libs/actions/connections'; +import Navigation from '@navigation/Navigation'; +import AdminPolicyAccessOrNotFoundWrapper from '@pages/workspace/AdminPolicyAccessOrNotFoundWrapper'; +import FeatureEnabledAccessOrNotFoundWrapper from '@pages/workspace/FeatureEnabledAccessOrNotFoundWrapper'; +import withPolicy from '@pages/workspace/withPolicy'; +import type {WithPolicyProps} from '@pages/workspace/withPolicy'; +import CONST from '@src/CONST'; +import ROUTES from '@src/ROUTES'; + +type CardListItem = ListItem & { + value: ValueOf; + isShown: boolean; +}; +type CardsSection = SectionListData>; + +function QuickbooksOutOfPocketExpenseEntitySelectPage({policy}: WithPolicyProps) { + const {translate} = useLocalize(); + const styles = useThemeStyles(); + const {exportEntity, syncTaxes, syncLocations} = policy?.connections?.quickbooksOnline?.config ?? {}; + const isLocationsEnabled = Boolean(syncLocations && syncLocations !== CONST.INTEGRATION_ENTITY_MAP_TYPES.NONE); + const isTaxesEnabled = Boolean(syncTaxes && syncTaxes !== CONST.INTEGRATION_ENTITY_MAP_TYPES.NONE); + const isTaxError = isTaxesEnabled && exportEntity === CONST.QUICKBOOKS_EXPORT_ENTITY.JOURNAL_ENTRY; + const isLocationError = isLocationsEnabled && exportEntity !== CONST.QUICKBOOKS_EXPORT_ENTITY.JOURNAL_ENTRY; + const policyID = policy?.id ?? ''; + + useEffect(() => { + if (!isTaxError && !isLocationError) { + return; + } + Connections.updatePolicyConnectionConfig(policyID, CONST.POLICY.CONNECTIONS.NAME.QBO, CONST.QUICK_BOOKS_CONFIG.EXPORT_ENTITY); + }, [policyID, isTaxError, isLocationError]); + + const data: CardListItem[] = useMemo( + () => [ + { + value: CONST.QUICKBOOKS_EXPORT_ENTITY.CHECK, + text: translate(`workspace.qbo.check`), + keyForList: CONST.QUICKBOOKS_EXPORT_ENTITY.CHECK, + isSelected: exportEntity === CONST.QUICKBOOKS_EXPORT_ENTITY.CHECK, + isShown: !isLocationsEnabled, + }, + { + value: CONST.QUICKBOOKS_EXPORT_ENTITY.JOURNAL_ENTRY, + text: translate(`workspace.qbo.journalEntry`), + keyForList: CONST.QUICKBOOKS_EXPORT_ENTITY.JOURNAL_ENTRY, + isSelected: exportEntity === CONST.QUICKBOOKS_EXPORT_ENTITY.JOURNAL_ENTRY, + isShown: !isTaxesEnabled || isLocationsEnabled, + }, + { + value: CONST.QUICKBOOKS_EXPORT_ENTITY.VENDOR_BILL, + text: translate(`workspace.qbo.vendorBill`), + keyForList: CONST.QUICKBOOKS_EXPORT_ENTITY.VENDOR_BILL, + isSelected: exportEntity === CONST.QUICKBOOKS_EXPORT_ENTITY.VENDOR_BILL, + isShown: !isLocationsEnabled, + }, + ], + [exportEntity, isTaxesEnabled, translate, isLocationsEnabled], + ); + + const sections: CardsSection[] = useMemo(() => [{data: data.filter((item) => item.isShown)}], [data]); + + const onSelectRow = useCallback( + (row: CardListItem) => { + if (row.value !== exportEntity) { + Connections.updatePolicyConnectionConfig(policyID, CONST.POLICY.CONNECTIONS.NAME.QBO, CONST.QUICK_BOOKS_CONFIG.EXPORT_ENTITY, row.value); + } + Navigation.goBack(ROUTES.POLICY_ACCOUNTING_QUICKBOOKS_ONLINE_EXPORT_OUT_OF_POCKET_EXPENSES.getRoute(policyID)); + }, + [exportEntity, policyID], + ); + + return ( + + + + + + {translate('workspace.qbo.optionBelow')}} + sections={sections} + ListItem={RadioListItem} + onSelectRow={onSelectRow} + initiallyFocusedOptionKey={data.find((mode) => mode.isSelected)?.keyForList} + footerContent={isTaxesEnabled && {translate('workspace.qbo.outOfPocketTaxEnabledDescription')}} + /> + + + + + ); +} + +QuickbooksOutOfPocketExpenseEntitySelectPage.displayName = 'QuickbooksOutOfPocketExpenseEntitySelectPage'; + +export default withPolicy(QuickbooksOutOfPocketExpenseEntitySelectPage); diff --git a/src/pages/workspace/accounting/qbo/export/QuickbooksPreferredExporterConfigurationPage.tsx b/src/pages/workspace/accounting/qbo/export/QuickbooksPreferredExporterConfigurationPage.tsx new file mode 100644 index 0000000000000..5bad9caca7066 --- /dev/null +++ b/src/pages/workspace/accounting/qbo/export/QuickbooksPreferredExporterConfigurationPage.tsx @@ -0,0 +1,95 @@ +import React, {useCallback, useMemo} from 'react'; +import HeaderWithBackButton from '@components/HeaderWithBackButton'; +import ScreenWrapper from '@components/ScreenWrapper'; +import SelectionList from '@components/SelectionList'; +import RadioListItem from '@components/SelectionList/RadioListItem'; +import type {ListItem} from '@components/SelectionList/types'; +import Text from '@components/Text'; +import useLocalize from '@hooks/useLocalize'; +import useThemeStyles from '@hooks/useThemeStyles'; +import * as Connections from '@libs/actions/connections'; +import {getAdminEmployees} from '@libs/PolicyUtils'; +import Navigation from '@navigation/Navigation'; +import AdminPolicyAccessOrNotFoundWrapper from '@pages/workspace/AdminPolicyAccessOrNotFoundWrapper'; +import FeatureEnabledAccessOrNotFoundWrapper from '@pages/workspace/FeatureEnabledAccessOrNotFoundWrapper'; +import withPolicy from '@pages/workspace/withPolicy'; +import type {WithPolicyProps} from '@pages/workspace/withPolicy'; +import CONST from '@src/CONST'; +import ROUTES from '@src/ROUTES'; + +// TODO - should be removed after API fully working +const draft = [ + {name: '+14153166423@expensify.sms', currency: 'USD', id: '94', email: '+14153166423@expensify.sms'}, + {name: 'Account Maintenance Fee', currency: 'USD', id: '141', email: 'alberto@expensify213.com'}, + {name: 'Admin Test', currency: 'USD', id: '119', email: 'admin@qbocard.com'}, + {name: 'Alberto Gonzalez-Cela', currency: 'USD', id: '104', email: 'alberto@expensify.com'}, + {name: 'Aldo test QBO2 QBO2 Last name', currency: 'USD', id: '140', email: 'admin@qbo.com'}, +]; + +type CardListItem = ListItem & { + value: string; +}; + +function QuickBooksExportPreferredExporterPage({policy}: WithPolicyProps) { + const {translate} = useLocalize(); + const styles = useThemeStyles(); + const {exporter} = policy?.connections?.quickbooksOnline?.config ?? {}; + const exporters = getAdminEmployees(policy); + const result = exporters?.length ? exporters : draft; + + const policyID = policy?.id ?? ''; + const data: CardListItem[] = useMemo( + () => + result.reduce((vendors, vendor) => { + if (vendor.email) { + vendors.push({ + value: vendor.email, + text: vendor.email, + keyForList: vendor.email, + isSelected: exporter === vendor.email, + }); + } + return vendors; + }, []), + [result, exporter], + ); + + const onSelectRow = useCallback( + (row: CardListItem) => { + if (row.value !== exporter) { + Connections.updatePolicyConnectionConfig(policyID, CONST.POLICY.CONNECTIONS.NAME.QBO, CONST.QUICK_BOOKS_CONFIG.PREFERRED_EXPORTER, row.value); + } + Navigation.goBack(ROUTES.POLICY_ACCOUNTING_QUICKBOOKS_ONLINE_PREFERRED_EXPORTER.getRoute(policyID)); + }, + [policyID, exporter], + ); + + return ( + + + + + + {translate('workspace.qbo.exportPreferredExporterNote')} + {translate('workspace.qbo.exportPreferredExporterSubNote')} + + } + sections={[{data}]} + ListItem={RadioListItem} + onSelectRow={onSelectRow} + initiallyFocusedOptionKey={data.find((mode) => mode.isSelected)?.keyForList} + /> + + + + ); +} + +QuickBooksExportPreferredExporterPage.displayName = 'QuickBooksExportPreferredExporterPage'; + +export default withPolicy(QuickBooksExportPreferredExporterPage); diff --git a/src/styles/index.ts b/src/styles/index.ts index 2220d86956df3..05defcf8b12c3 100644 --- a/src/styles/index.ts +++ b/src/styles/index.ts @@ -378,6 +378,12 @@ const styles = (theme: ThemeColors) => lineHeight: variables.lineHeightLarge, }, + mutedNormalTextLabel: { + color: theme.textSupporting, + fontSize: variables.fontSizeLabel, + lineHeight: variables.lineHeightNormal, + }, + textMicro: { fontFamily: FontUtils.fontFamily.platform.EXP_NEUE, fontSize: variables.fontSizeSmall, diff --git a/src/types/onyx/Policy.ts b/src/types/onyx/Policy.ts index c55d6359c68fe..4071625c683d4 100644 --- a/src/types/onyx/Policy.ts +++ b/src/types/onyx/Policy.ts @@ -168,15 +168,18 @@ type QBOConnectionConfig = OnyxCommon.OnyxValueWithOfflineFeedback<{ syncLocations: IntegrationEntityMap; syncAccounts: IntegrationEntityMap; syncTaxes: IntegrationEntityMap; - exportDate: string; lastConfigurationTime: number; syncTax: boolean; enableNewCategories: IntegrationEntityMap; errors?: OnyxCommon.Errors; + exporter: string; + exportDate: ValueOf; + outOfPocketExpenses: string; + exportInvoice: string; + exportAccount: string; + exportEntity?: ValueOf; + exportCompanyCard: string; errorFields?: OnyxCommon.ErrorFields; - export: { - exporter: string; - }; }>; type Connection = { lastSync?: ConnectionLastSync;