From ccd51eddba0dd79c30daaf595e4619c06ec1b0e8 Mon Sep 17 00:00:00 2001 From: VH Date: Thu, 3 Oct 2024 23:33:02 +0700 Subject: [PATCH 01/17] Show QBD option in accounting page --- .../integrationicons/qbd-icon-square.svg | 1 + src/CONST.ts | 2 ++ src/components/Icon/Expensicons.ts | 2 ++ src/languages/en.ts | 1 + src/languages/es.ts | 1 + src/pages/workspace/accounting/utils.tsx | 18 ++++++++++ src/types/onyx/Policy.ts | 36 ++++++++++++++++++- 7 files changed, 60 insertions(+), 1 deletion(-) create mode 100644 assets/images/integrationicons/qbd-icon-square.svg diff --git a/assets/images/integrationicons/qbd-icon-square.svg b/assets/images/integrationicons/qbd-icon-square.svg new file mode 100644 index 000000000000..e297b597f980 --- /dev/null +++ b/assets/images/integrationicons/qbd-icon-square.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/CONST.ts b/src/CONST.ts index 2af183d9d751..364d85e29c5b 100755 --- a/src/CONST.ts +++ b/src/CONST.ts @@ -2294,12 +2294,14 @@ const CONST = { XERO: 'xero', NETSUITE: 'netsuite', SAGE_INTACCT: 'intacct', + QBD: 'quickbooksDesktop', }, ROUTE: { QBO: 'quickbooks-online', XERO: 'xero', NETSUITE: 'netsuite', SAGE_INTACCT: 'sage-intacct', + QBD: 'quickbooks-desktop', }, NAME_USER_FRIENDLY: { netsuite: 'NetSuite', diff --git a/src/components/Icon/Expensicons.ts b/src/components/Icon/Expensicons.ts index 569e467dfad7..485e80399d9d 100644 --- a/src/components/Icon/Expensicons.ts +++ b/src/components/Icon/Expensicons.ts @@ -108,6 +108,7 @@ import Info from '@assets/images/info.svg'; import NetSuiteSquare from '@assets/images/integrationicons/netsuite-icon-square.svg'; import QBOCircle from '@assets/images/integrationicons/qbo-icon-circle.svg'; import QBOSquare from '@assets/images/integrationicons/qbo-icon-square.svg'; +import QBDSquare from '@assets/images/integrationicons/qbd-icon-square.svg'; import SageIntacctSquare from '@assets/images/integrationicons/sage-intacct-icon-square.svg'; import XeroCircle from '@assets/images/integrationicons/xero-icon-circle.svg'; import XeroSquare from '@assets/images/integrationicons/xero-icon-square.svg'; @@ -402,4 +403,5 @@ export { SpreadsheetComputer, Bookmark, Star, + QBDSquare, }; diff --git a/src/languages/en.ts b/src/languages/en.ts index f15e5c97d037..025950e9cabb 100755 --- a/src/languages/en.ts +++ b/src/languages/en.ts @@ -3421,6 +3421,7 @@ const translations = { title: 'Connections', subtitle: 'Connect to your accounting system to code transactions with your chart of accounts, auto-match payments, and keep your finances in sync.', qbo: 'Quickbooks Online', + qbd: 'Quickbooks Desktop', xero: 'Xero', netsuite: 'NetSuite', intacct: 'Sage Intacct', diff --git a/src/languages/es.ts b/src/languages/es.ts index 413084aa8286..b43fc42e9539 100644 --- a/src/languages/es.ts +++ b/src/languages/es.ts @@ -3425,6 +3425,7 @@ const translations = { title: 'Conexiones', subtitle: 'Conecta a tu sistema de contabilidad para codificar transacciones con tu plan de cuentas, auto-cotejar pagos, y mantener tus finanzas sincronizadas.', qbo: 'Quickbooks Online', + qbd: 'Quickbooks Desktop', xero: 'Xero', netsuite: 'NetSuite', intacct: 'Sage Intacct', diff --git a/src/pages/workspace/accounting/utils.tsx b/src/pages/workspace/accounting/utils.tsx index cceb2ea09423..b22202415c8b 100644 --- a/src/pages/workspace/accounting/utils.tsx +++ b/src/pages/workspace/accounting/utils.tsx @@ -245,6 +245,24 @@ function getAccountingIntegrationData( pendingFields: policy?.connections?.intacct?.config?.pendingFields, errorFields: policy?.connections?.intacct?.config?.errorFields, }; + case CONST.POLICY.CONNECTIONS.NAME.QBD: + return { + title: translate('workspace.accounting.qbd'), + icon: Expensicons.QBDSquare, + setupConnectionFlow: ( + + ), + onImportPagePress: () => {}, + onExportPagePress: () => {}, + onCardReconciliationPagePress: () => {}, + onAdvancedPagePress: () => {}, + subscribedImportSettings: [], + subscribedExportSettings: [], + subscribedAdvancedSettings: [], + }; default: return undefined; } diff --git a/src/types/onyx/Policy.ts b/src/types/onyx/Policy.ts index 693f49f35eb0..85e19d6a6138 100644 --- a/src/types/onyx/Policy.ts +++ b/src/types/onyx/Policy.ts @@ -1205,6 +1205,37 @@ type SageIntacctConnectionsConfig = OnyxCommon.OnyxValueWithOfflineFeedback< SageIntacctOfflineStateKeys | keyof SageIntacctSyncConfig | keyof SageIntacctAutoSyncConfig | keyof SageIntacctExportConfig >; +/** + * Data imported from QuickBooks Desktop. + */ +type QBDConnectionData = { + /** Collection of cash accounts */ + cashAccounts: Account[]; + + /** Collection of credit cards */ + creditCardAccounts: Account[]; + + /** Collection of journal entry accounts */ + journalEntryAccounts: Account[]; + + /** Collection of payable accounts */ + payableAccounts: Account[]; + + /** Collection of bank accounts */ + bankAccounts: Account[]; + + /** Collections of vendors */ + vendors: Vendor[]; +}; + +/** + * User configuration for the QuickBooks Desktop accounting integration. + */ +type QBDConnectionConfig = OnyxCommon.OnyxValueWithOfflineFeedback<{ + /** API provider */ + apiProvider: string; +}>; + /** State of integration connection */ type Connection = { /** State of the last synchronization */ @@ -1219,7 +1250,7 @@ type Connection = { /** Available integration connections */ type Connections = { - /** QuickBooks integration connection */ + /** QuickBooks Online integration connection */ [CONST.POLICY.CONNECTIONS.NAME.QBO]: Connection; /** Xero integration connection */ @@ -1230,6 +1261,9 @@ type Connections = { /** Sage Intacct integration connection */ [CONST.POLICY.CONNECTIONS.NAME.SAGE_INTACCT]: Connection; + + /** QuickBooks Desktop integration connection */ + [CONST.POLICY.CONNECTIONS.NAME.QBD]: Connection; }; /** All integration connections, including unsupported ones */ From 7eb13019effca97a78d7d8ea30dc6392ec1b9ad7 Mon Sep 17 00:00:00 2001 From: VH Date: Fri, 4 Oct 2024 00:54:29 +0700 Subject: [PATCH 02/17] Required setup QBD page --- src/ROUTES.ts | 8 +++ src/SCREENS.ts | 2 + .../index.native.tsx | 18 ++++++ .../ConnectToQuickbooksDesktopFlow/index.tsx | 26 ++++++++ .../ConnectToQuickbooksDesktopFlow/types.ts | 6 ++ src/languages/en.ts | 8 +++ src/languages/es.ts | 8 +++ .../ModalStackNavigators/index.tsx | 3 + .../FULL_SCREEN_TO_RHP_MAPPING.ts | 2 + src/libs/Navigation/linkingConfig/config.ts | 6 ++ src/libs/Navigation/types.ts | 6 ++ .../qbd/RequireQuickBooksDesktopPage.tsx | 61 +++++++++++++++++++ src/pages/workspace/accounting/utils.tsx | 3 +- 13 files changed, 156 insertions(+), 1 deletion(-) create mode 100644 src/components/ConnectToQuickbooksDesktopFlow/index.native.tsx create mode 100644 src/components/ConnectToQuickbooksDesktopFlow/index.tsx create mode 100644 src/components/ConnectToQuickbooksDesktopFlow/types.ts create mode 100644 src/pages/workspace/accounting/qbd/RequireQuickBooksDesktopPage.tsx diff --git a/src/ROUTES.ts b/src/ROUTES.ts index 9c429dd3e909..a621a0f5decd 100644 --- a/src/ROUTES.ts +++ b/src/ROUTES.ts @@ -1502,6 +1502,14 @@ const ROUTES = { route: 'settings/workspaces/:policyID/accounting/sage-intacct/advanced/payment-account', getRoute: (policyID: string) => `settings/workspaces/${policyID}/accounting/sage-intacct/advanced/payment-account` as const, }, + POLICY_ACCOUNTING_QUICKBOOKS_DESKTOP_SETUP_MODAL: { + route: 'settings/workspaces/:policyID/accounting/quickbooks-desktop/setup-modal', + getRoute: (policyID: string) => `settings/workspaces/${policyID}/accounting/quickbooks-desktop/setup-modal` as const, + }, + POLICY_ACCOUNTING_QUICKBOOKS_DESKTOP_SETUP_REQUIRED_DEVICE_MODAL: { + route: 'settings/workspaces/:policyID/accounting/quickbooks-desktop/setup-required-device', + getRoute: (policyID: string) => `settings/workspaces/${policyID}/accounting/quickbooks-desktop/setup-required-device` as const, + }, DEBUG_REPORT: { route: 'debug/report/:reportID', getRoute: (reportID: string) => `debug/report/${reportID}` as const, diff --git a/src/SCREENS.ts b/src/SCREENS.ts index 9a94d612dc80..452da9d6ebd3 100644 --- a/src/SCREENS.ts +++ b/src/SCREENS.ts @@ -372,6 +372,8 @@ const SCREENS = { SAGE_INTACCT_NON_REIMBURSABLE_CREDIT_CARD_ACCOUNT: 'Policy_Accounting_Sage_Intacct_Non_Reimbursable_Credit_Card_Account', SAGE_INTACCT_ADVANCED: 'Policy_Accounting_Sage_Intacct_Advanced', SAGE_INTACCT_PAYMENT_ACCOUNT: 'Policy_Accounting_Sage_Intacct_Payment_Account', + QUICKBOOKS_DESKTOP_SETUP_MODAL: 'Policy_Accouting_Quickbooks_Desktop_Setup_Modal', + QUICKBOOKS_DESKTOP_SETUP_REQUIRED_DEVICE_MODAL: 'Policy_Accouting_Quickbooks_Desktop_Setup_Required_Device_Modal', CARD_RECONCILIATION: 'Policy_Accounting_Card_Reconciliation', RECONCILIATION_ACCOUNT_SETTINGS: 'Policy_Accounting_Reconciliation_Account_Settings', }, diff --git a/src/components/ConnectToQuickbooksDesktopFlow/index.native.tsx b/src/components/ConnectToQuickbooksDesktopFlow/index.native.tsx new file mode 100644 index 000000000000..96c2c75183d9 --- /dev/null +++ b/src/components/ConnectToQuickbooksDesktopFlow/index.native.tsx @@ -0,0 +1,18 @@ +import {useEffect} from 'react'; +import Navigation from '@libs/Navigation/Navigation'; +import ROUTES from '@src/ROUTES'; +import type {ConnectToQuickbooksDesktopFlowProps} from './types'; + +function ConnectToQuickbooksDesktopFlow({policyID}: ConnectToQuickbooksDesktopFlowProps) { + useEffect(() => { + Navigation.navigate(ROUTES.POLICY_ACCOUNTING_QUICKBOOKS_DESKTOP_SETUP_REQUIRED_DEVICE_MODAL.getRoute(policyID)); + // eslint-disable-next-line react-compiler/react-compiler + // eslint-disable-next-line react-hooks/exhaustive-deps + }, []); + + return null; +} + +ConnectToQuickbooksDesktopFlow.displayName = 'ConnectToQuickbooksDesktopFlow'; + +export default ConnectToQuickbooksDesktopFlow; diff --git a/src/components/ConnectToQuickbooksDesktopFlow/index.tsx b/src/components/ConnectToQuickbooksDesktopFlow/index.tsx new file mode 100644 index 000000000000..a0ec7f2394d7 --- /dev/null +++ b/src/components/ConnectToQuickbooksDesktopFlow/index.tsx @@ -0,0 +1,26 @@ +import {useEffect} from 'react'; +import useResponsiveLayout from '@hooks/useResponsiveLayout'; +import Navigation from '@libs/Navigation/Navigation'; +import * as PolicyAction from '@userActions/Policy/Policy'; +import ROUTES from '@src/ROUTES'; +import type {ConnectToQuickbooksDesktopFlowProps} from './types'; + +function ConnectToQuickbooksDesktopFlow({policyID}: ConnectToQuickbooksDesktopFlowProps) { + const {isSmallScreenWidth} = useResponsiveLayout(); + + useEffect(() => { + if (isSmallScreenWidth) { + Navigation.navigate(ROUTES.POLICY_ACCOUNTING_QUICKBOOKS_DESKTOP_SETUP_REQUIRED_DEVICE_MODAL.getRoute(policyID)); + } else { + // Since QBO doesn't support Taxes, we should disable them from the LHN when connecting to QBO + PolicyAction.enablePolicyTaxes(policyID, false); + Navigation.navigate(ROUTES.POLICY_ACCOUNTING_QUICKBOOKS_DESKTOP_SETUP_MODAL.getRoute(policyID)); + } + }, [isSmallScreenWidth, policyID]); + + return null; +} + +ConnectToQuickbooksDesktopFlow.displayName = 'ConnectToQuickbooksDesktopFlow'; + +export default ConnectToQuickbooksDesktopFlow; diff --git a/src/components/ConnectToQuickbooksDesktopFlow/types.ts b/src/components/ConnectToQuickbooksDesktopFlow/types.ts new file mode 100644 index 000000000000..81971047a72a --- /dev/null +++ b/src/components/ConnectToQuickbooksDesktopFlow/types.ts @@ -0,0 +1,6 @@ +type ConnectToQuickbooksDesktopFlowProps = { + policyID: string; +}; + +// eslint-disable-next-line import/prefer-default-export +export type {ConnectToQuickbooksDesktopFlowProps}; diff --git a/src/languages/en.ts b/src/languages/en.ts index 025950e9cabb..328ce7fa4049 100755 --- a/src/languages/en.ts +++ b/src/languages/en.ts @@ -2919,6 +2919,14 @@ const translations = { } }, }, + qbd: { + qbdSetup: 'QuickBooks Desktop setup', + requiredSetupDevice: { + title: "Can't connect from this device", + body1: "You'll need to setup this connection from the computer that hosts your QuickBooks Desktop company file.", + body2: "Once you're connected, you'll be able to sync and export from anywhere.", + }, + }, type: { free: 'Free', control: 'Control', diff --git a/src/languages/es.ts b/src/languages/es.ts index b43fc42e9539..c78a92835450 100644 --- a/src/languages/es.ts +++ b/src/languages/es.ts @@ -2954,6 +2954,14 @@ const translations = { } }, }, + qbd: { + qbdSetup: 'QuickBooks Desktop configuración', + requiredSetupDevice: { + title: "Can't connect from this device", + body1: "You'll need to setup this connection from the computer that hosts your QuickBooks Desktop company file.", + body2: "Once you're connected, you'll be able to sync and export from anywhere.", + }, + }, type: { free: 'Gratis', control: 'Control', diff --git a/src/libs/Navigation/AppNavigator/ModalStackNavigators/index.tsx b/src/libs/Navigation/AppNavigator/ModalStackNavigators/index.tsx index 2be410ad8803..7a2668b26748 100644 --- a/src/libs/Navigation/AppNavigator/ModalStackNavigators/index.tsx +++ b/src/libs/Navigation/AppNavigator/ModalStackNavigators/index.tsx @@ -426,6 +426,9 @@ const SettingsModalStackNavigator = createModalStackNavigator require('../../../../pages/workspace/accounting/intacct/advanced/SageIntacctAdvancedPage').default, [SCREENS.WORKSPACE.ACCOUNTING.SAGE_INTACCT_PAYMENT_ACCOUNT]: () => require('../../../../pages/workspace/accounting/intacct/advanced/SageIntacctPaymentAccountPage').default, + [SCREENS.WORKSPACE.ACCOUNTING.QUICKBOOKS_DESKTOP_SETUP_MODAL]: () => require('../../../../pages/workspace/accounting/qbd/RequireQuickBooksDesktopPage').default, + [SCREENS.WORKSPACE.ACCOUNTING.QUICKBOOKS_DESKTOP_SETUP_REQUIRED_DEVICE_MODAL]: () => + require('../../../../pages/workspace/accounting/qbd/RequireQuickBooksDesktopPage').default, [SCREENS.WORKSPACE.ACCOUNTING.CARD_RECONCILIATION]: () => require('../../../../pages/workspace/accounting/reconciliation/CardReconciliationPage').default, [SCREENS.WORKSPACE.ACCOUNTING.RECONCILIATION_ACCOUNT_SETTINGS]: () => require('../../../../pages/workspace/accounting/reconciliation/ReconciliationAccountSettingsPage').default, 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 6d8871e5a38a..a8249c55fea2 100755 --- a/src/libs/Navigation/linkingConfig/FULL_SCREEN_TO_RHP_MAPPING.ts +++ b/src/libs/Navigation/linkingConfig/FULL_SCREEN_TO_RHP_MAPPING.ts @@ -114,6 +114,8 @@ const FULL_SCREEN_TO_RHP_MAPPING: Partial> = { SCREENS.WORKSPACE.ACCOUNTING.SAGE_INTACCT_NON_REIMBURSABLE_CREDIT_CARD_ACCOUNT, SCREENS.WORKSPACE.ACCOUNTING.SAGE_INTACCT_ADVANCED, SCREENS.WORKSPACE.ACCOUNTING.SAGE_INTACCT_PAYMENT_ACCOUNT, + SCREENS.WORKSPACE.ACCOUNTING.QUICKBOOKS_DESKTOP_SETUP_MODAL, + SCREENS.WORKSPACE.ACCOUNTING.QUICKBOOKS_DESKTOP_SETUP_REQUIRED_DEVICE_MODAL, SCREENS.WORKSPACE.ACCOUNTING.CARD_RECONCILIATION, SCREENS.WORKSPACE.ACCOUNTING.RECONCILIATION_ACCOUNT_SETTINGS, ], diff --git a/src/libs/Navigation/linkingConfig/config.ts b/src/libs/Navigation/linkingConfig/config.ts index 114e89ff2bf5..734892beb905 100644 --- a/src/libs/Navigation/linkingConfig/config.ts +++ b/src/libs/Navigation/linkingConfig/config.ts @@ -490,6 +490,12 @@ const config: LinkingOptions['config'] = { }, [SCREENS.WORKSPACE.ACCOUNTING.SAGE_INTACCT_ADVANCED]: {path: ROUTES.POLICY_ACCOUNTING_SAGE_INTACCT_ADVANCED.route}, [SCREENS.WORKSPACE.ACCOUNTING.SAGE_INTACCT_PAYMENT_ACCOUNT]: {path: ROUTES.POLICY_ACCOUNTING_SAGE_INTACCT_PAYMENT_ACCOUNT.route}, + [SCREENS.WORKSPACE.ACCOUNTING.QUICKBOOKS_DESKTOP_SETUP_MODAL]: { + path: ROUTES.POLICY_ACCOUNTING_QUICKBOOKS_DESKTOP_SETUP_MODAL.route, + }, + [SCREENS.WORKSPACE.ACCOUNTING.QUICKBOOKS_DESKTOP_SETUP_REQUIRED_DEVICE_MODAL]: { + path: ROUTES.POLICY_ACCOUNTING_QUICKBOOKS_DESKTOP_SETUP_REQUIRED_DEVICE_MODAL.route, + }, [SCREENS.WORKSPACE.ACCOUNTING.CARD_RECONCILIATION]: {path: ROUTES.WORKSPACE_ACCOUNTING_CARD_RECONCILIATION.route}, [SCREENS.WORKSPACE.ACCOUNTING.RECONCILIATION_ACCOUNT_SETTINGS]: {path: ROUTES.WORKSPACE_ACCOUNTING_RECONCILIATION_ACCOUNT_SETTINGS.route}, [SCREENS.WORKSPACE.DESCRIPTION]: { diff --git a/src/libs/Navigation/types.ts b/src/libs/Navigation/types.ts index b698681966e2..52694b2569ed 100644 --- a/src/libs/Navigation/types.ts +++ b/src/libs/Navigation/types.ts @@ -660,6 +660,12 @@ type SettingsNavigatorParamList = { [SCREENS.WORKSPACE.ACCOUNTING.SAGE_INTACCT_PAYMENT_ACCOUNT]: { policyID: string; }; + [SCREENS.WORKSPACE.ACCOUNTING.QUICKBOOKS_DESKTOP_SETUP_MODAL]: { + policyID: string; + }; + [SCREENS.WORKSPACE.ACCOUNTING.QUICKBOOKS_DESKTOP_SETUP_REQUIRED_DEVICE_MODAL]: { + policyID: string; + }; [SCREENS.WORKSPACE.ACCOUNTING.CARD_RECONCILIATION]: { policyID: string; connection: ValueOf; diff --git a/src/pages/workspace/accounting/qbd/RequireQuickBooksDesktopPage.tsx b/src/pages/workspace/accounting/qbd/RequireQuickBooksDesktopPage.tsx new file mode 100644 index 000000000000..4e15b8d8062c --- /dev/null +++ b/src/pages/workspace/accounting/qbd/RequireQuickBooksDesktopPage.tsx @@ -0,0 +1,61 @@ +import type {StackScreenProps} from '@react-navigation/stack'; +import React from 'react'; +import {View} from 'react-native'; +import Computer from '@assets/images/computer.svg'; +import Button from '@components/Button'; +import FixedFooter from '@components/FixedFooter'; +import HeaderWithBackButton from '@components/HeaderWithBackButton'; +import ImageSVG from '@components/ImageSVG'; +import ScreenWrapper from '@components/ScreenWrapper'; +import Text from '@components/Text'; +import useLocalize from '@hooks/useLocalize'; +import useThemeStyles from '@hooks/useThemeStyles'; +import Navigation from '@libs/Navigation/Navigation'; +import type {SettingsNavigatorParamList} from '@libs/Navigation/types'; +import ROUTES from '@src/ROUTES'; +import type SCREENS from '@src/SCREENS'; + +type RequireQuickBooksDesktopModalProps = StackScreenProps; + +function RequireQuickBooksDesktopModal({route}: RequireQuickBooksDesktopModalProps) { + const {translate} = useLocalize(); + const styles = useThemeStyles(); + const policyID: string = route.params.policyID; + + return ( + + Navigation.dismissModal()} + /> + + + + + + {translate('workspace.qbd.requiredSetupDevice.title')} + {translate('workspace.qbd.requiredSetupDevice.body1')} + {translate('workspace.qbd.requiredSetupDevice.body2')} + + +