diff --git a/src/CONST.ts b/src/CONST.ts index 9b884c1fc3b6..66b9b8127500 100755 --- a/src/CONST.ts +++ b/src/CONST.ts @@ -2036,6 +2036,7 @@ const CONST = { AUTO_CREATE_VENDOR: 'autoCreateVendor', REIMBURSEMENT_ACCOUNT_ID: 'reimbursementAccountID', COLLECTION_ACCOUNT_ID: 'collectionAccountID', + ACCOUNTING_METHOD: 'accountingMethod', }, XERO_CONFIG: { diff --git a/src/ROUTES.ts b/src/ROUTES.ts index 203abf7cb0a8..01bd3e5549e1 100644 --- a/src/ROUTES.ts +++ b/src/ROUTES.ts @@ -1247,11 +1247,19 @@ const ROUTES = { }, WORKSPACE_ACCOUNTING_QUICKBOOKS_ONLINE_ACCOUNT_SELECTOR: { route: 'settings/workspaces/:policyID/accounting/quickbooks-online/account-selector', - getRoute: (policyID: string) => `settings/workspaces/${policyID}/accounting/quickbooks-online/account-selector` as const, + getRoute: (policyID: string | undefined) => `settings/workspaces/${policyID}/accounting/quickbooks-online/account-selector` as const, }, WORKSPACE_ACCOUNTING_QUICKBOOKS_ONLINE_INVOICE_ACCOUNT_SELECTOR: { route: 'settings/workspaces/:policyID/accounting/quickbooks-online/invoice-account-selector', - getRoute: (policyID: string) => `settings/workspaces/${policyID}/accounting/quickbooks-online/invoice-account-selector` as const, + getRoute: (policyID: string | undefined) => `settings/workspaces/${policyID}/accounting/quickbooks-online/invoice-account-selector` as const, + }, + WORKSPACE_ACCOUNTING_QUICKBOOKS_ONLINE_AUTO_SYNC: { + route: 'settings/workspaces/:policyID/connections/quickbooks-online/advanced/autosync', + getRoute: (policyID: string | undefined) => `settings/workspaces/${policyID}/connections/quickbooks-online/advanced/autosync` as const, + }, + WORKSPACE_ACCOUNTING_QUICKBOOKS_ONLINE_ACCOUNTING_METHOD: { + route: 'settings/workspaces/:policyID/connections/quickbooks-online/advanced/autosync/accounting-method', + getRoute: (policyID: string | undefined) => `settings/workspaces/${policyID}/connections/quickbooks-online/advanced/autosync/accounting-method` as const, }, WORKSPACE_ACCOUNTING_CARD_RECONCILIATION: { route: 'settings/workspaces/:policyID/accounting/:connection/card-reconciliation', diff --git a/src/SCREENS.ts b/src/SCREENS.ts index 562b047efe97..e12221994b61 100644 --- a/src/SCREENS.ts +++ b/src/SCREENS.ts @@ -382,6 +382,8 @@ const SCREENS = { QUICKBOOKS_ONLINE_CLASSES_DISPLAYED_AS: 'Policy_Accounting_Quickbooks_Online_Import_Classes_Displayed_As', QUICKBOOKS_ONLINE_CUSTOMERS_DISPLAYED_AS: 'Policy_Accounting_Quickbooks_Online_Import_Customers_Displayed_As', QUICKBOOKS_ONLINE_LOCATIONS_DISPLAYED_AS: 'Policy_Accounting_Quickbooks_Online_Import_Locations_Displayed_As', + QUICKBOOKS_ONLINE_AUTO_SYNC: 'Policy_Accounting_Quickbooks_Online_Auto_Sync', + QUICKBOOKS_ONLINE_ACCOUNTING_METHOD: 'Policy_Accounting_Quickbooks_Online_Accounting_Method', QUICKBOOKS_DESKTOP_COMPANY_CARD_EXPENSE_ACCOUNT_SELECT: 'Workspace_Accounting_Quickbooks_Desktop_Export_Company_Card_Expense_Account_Select', QUICKBOOKS_DESKTOP_COMPANY_CARD_EXPENSE_ACCOUNT_COMPANY_CARD_SELECT: 'Workspace_Accounting_Quickbooks_Desktop_Export_Company_Card_Expense_Select', QUICKBOOKS_DESKTOP_COMPANY_CARD_EXPENSE_ACCOUNT: 'Workspace_Accounting_Quickbooks_Desktop_Export_Company_Card_Expense', diff --git a/src/languages/en.ts b/src/languages/en.ts index 9a9b06b5b85d..992e2e65be09 100755 --- a/src/languages/en.ts +++ b/src/languages/en.ts @@ -3176,7 +3176,19 @@ const translations = { [CONST.QUICKBOOKS_REIMBURSABLE_ACCOUNT_TYPE.CHECK]: 'To use check export, set up a bank account in QuickBooks Online', }, noAccountsFound: 'No accounts found', - noAccountsFoundDescription: 'Add the account in QuickBooks Online and sync the connection again', + noAccountsFoundDescription: 'Add the account in QuickBooks Online and sync the connection again.', + accountingMethods: { + label: 'When to Export', + description: 'Choose when to export the expenses:', + values: { + [COMMON_CONST.INTEGRATIONS.ACCOUNTING_METHOD.ACCRUAL]: 'Accrual', + [COMMON_CONST.INTEGRATIONS.ACCOUNTING_METHOD.CASH]: 'Cash', + }, + alternateText: { + [COMMON_CONST.INTEGRATIONS.ACCOUNTING_METHOD.ACCRUAL]: 'Out-of-pocket expenses will export when final approved', + [COMMON_CONST.INTEGRATIONS.ACCOUNTING_METHOD.CASH]: 'Out-of-pocket expenses will export when paid', + }, + }, }, workspaceList: { joinNow: 'Join now', diff --git a/src/languages/es.ts b/src/languages/es.ts index ce368de65c6f..9987e46b7821 100644 --- a/src/languages/es.ts +++ b/src/languages/es.ts @@ -3206,7 +3206,19 @@ const translations = { [CONST.QUICKBOOKS_REIMBURSABLE_ACCOUNT_TYPE.CHECK]: 'Para usar la exportación de cheques, configura una cuenta bancaria en QuickBooks Online', }, noAccountsFound: 'No se ha encontrado ninguna cuenta', - noAccountsFoundDescription: 'Añade la cuenta en QuickBooks Online y sincroniza de nuevo la conexión', + noAccountsFoundDescription: 'Añade la cuenta en QuickBooks Online y sincroniza de nuevo la conexión.', + accountingMethods: { + label: 'Cuándo Exportar', + description: 'Elige cuándo exportar los gastos:', + values: { + [COMMON_CONST.INTEGRATIONS.ACCOUNTING_METHOD.ACCRUAL]: 'Devengo', + [COMMON_CONST.INTEGRATIONS.ACCOUNTING_METHOD.CASH]: 'Efectivo', + }, + alternateText: { + [COMMON_CONST.INTEGRATIONS.ACCOUNTING_METHOD.ACCRUAL]: 'Los gastos por cuenta propia se exportarán cuando estén aprobados definitivamente', + [COMMON_CONST.INTEGRATIONS.ACCOUNTING_METHOD.CASH]: 'Los gastos por cuenta propia se exportarán cuando estén pagados', + }, + }, }, workspaceList: { joinNow: 'Únete ahora', diff --git a/src/libs/API/parameters/UpdateQuickbooksOnlineAccountingMethodParams.ts b/src/libs/API/parameters/UpdateQuickbooksOnlineAccountingMethodParams.ts new file mode 100644 index 000000000000..617570d5c365 --- /dev/null +++ b/src/libs/API/parameters/UpdateQuickbooksOnlineAccountingMethodParams.ts @@ -0,0 +1,9 @@ +import type {CONST as COMMON_CONST} from 'expensify-common'; +import type {ValueOf} from 'type-fest'; + +type UpdateQuickbooksOnlineAccountingMethodParams = { + policyID: string; + accountingMethod: ValueOf; +}; + +export default UpdateQuickbooksOnlineAccountingMethodParams; diff --git a/src/libs/API/parameters/index.ts b/src/libs/API/parameters/index.ts index a70093c83b11..5b4390fa69c0 100644 --- a/src/libs/API/parameters/index.ts +++ b/src/libs/API/parameters/index.ts @@ -20,6 +20,7 @@ export type {default as SyncPolicyToQuickbooksOnlineParams} from './SyncPolicyTo export type {default as SyncPolicyToXeroParams} from './SyncPolicyToXeroParams'; export type {default as SyncPolicyToNetSuiteParams} from './SyncPolicyToNetSuiteParams'; export type {default as UpdateNetSuiteAccountingMethodParams} from './UpdateNetSuiteAccountingMethodParams'; +export type {default as UpdateQuickbooksOnlineAccountingMethodParams} from './UpdateQuickbooksOnlineAccountingMethodParams'; export type {default as SyncPolicyToQuickbooksDesktopParams} from './SyncPolicyToQuickbooksDesktopParams'; export type {default as DeleteContactMethodParams} from './DeleteContactMethodParams'; export type {default as DeletePaymentBankAccountParams} from './DeletePaymentBankAccountParams'; diff --git a/src/libs/API/types.ts b/src/libs/API/types.ts index a96b93931949..ea90cc67ac53 100644 --- a/src/libs/API/types.ts +++ b/src/libs/API/types.ts @@ -261,6 +261,7 @@ const WRITE_COMMANDS = { UPDATE_QUICKBOOKS_ONLINE_REIMBURSABLE_EXPENSES_ACCOUNT: 'UpdateQuickbooksOnlineReimbursableExpensesAccount', UPDATE_QUICKBOOKS_ONLINE_RECEIVABLE_ACCOUNT: 'UpdateQuickbooksOnlineReceivableAccount', UPDATE_QUICKBOOKS_ONLINE_EXPORT_DATE: 'UpdateQuickbooksOnlineExportDate', + UPDATE_QUICKBOOKS_ONLINE_ACCOUNTING_METHOD: 'UpdateQuickbooksOnlineAccountingMethod', UPDATE_QUICKBOOKS_ONLINE_NON_REIMBURSABLE_EXPENSES_ACCOUNT: 'UpdateQuickbooksOnlineNonReimbursableExpensesAccount', UPDATE_QUICKBOOKS_ONLINE_COLLECTION_ACCOUNT_ID: 'UpdateQuickbooksOnlineCollectionAccountID', UPDATE_QUICKBOOKS_ONLINE_SYNC_TAX: 'UpdateQuickbooksOnlineSyncTax', @@ -754,6 +755,7 @@ type WriteCommandParameters = { [WRITE_COMMANDS.UPDATE_QUICKBOOKS_ONLINE_EXPORT_DATE]: Parameters.UpdateQuickbooksOnlineGenericTypeParams; [WRITE_COMMANDS.UPDATE_QUICKBOOKS_ONLINE_NON_REIMBURSABLE_EXPENSES_ACCOUNT]: Parameters.UpdateQuickbooksOnlineGenericTypeParams; [WRITE_COMMANDS.UPDATE_QUICKBOOKS_ONLINE_COLLECTION_ACCOUNT_ID]: Parameters.UpdateQuickbooksOnlineGenericTypeParams; + [WRITE_COMMANDS.UPDATE_QUICKBOOKS_ONLINE_ACCOUNTING_METHOD]: Parameters.UpdateQuickbooksOnlineAccountingMethodParams; [WRITE_COMMANDS.UPDATE_QUICKBOOKS_DESKTOP_EXPORT_DATE]: Parameters.UpdateQuickbooksDesktopGenericTypeParams; [WRITE_COMMANDS.UPDATE_QUICKBOOKS_DESKTOP_MARK_CHECKS_TO_BE_PRINTED]: Parameters.UpdateQuickbooksDesktopGenericTypeParams; [WRITE_COMMANDS.UPDATE_QUICKBOOKS_DESKTOP_AUTO_CREATE_VENDOR]: Parameters.UpdateQuickbooksDesktopGenericTypeParams; @@ -878,6 +880,7 @@ type WriteCommandParameters = { [WRITE_COMMANDS.UPDATE_NETSUITE_EXPORT_REPORTS_TO]: Parameters.UpdateNetSuiteGenericTypeParams<'value', ValueOf>; [WRITE_COMMANDS.UPDATE_NETSUITE_VENDOR_BILLS_TO]: Parameters.UpdateNetSuiteGenericTypeParams<'value', ValueOf>; [WRITE_COMMANDS.UPDATE_NETSUITE_ACCOUNTING_METHOD]: Parameters.UpdateNetSuiteAccountingMethodParams; + [WRITE_COMMANDS.UPDATE_NETSUITE_JOURNALS_TO]: Parameters.UpdateNetSuiteGenericTypeParams<'value', ValueOf>; [WRITE_COMMANDS.UPDATE_NETSUITE_APPROVAL_ACCOUNT]: Parameters.UpdateNetSuiteGenericTypeParams<'value', string>; [WRITE_COMMANDS.UPDATE_NETSUITE_CUSTOM_FORM_ID_OPTIONS_REIMBURSABLE]: Parameters.UpdateNetSuiteCustomFormIDParams; diff --git a/src/libs/Navigation/AppNavigator/ModalStackNavigators/index.tsx b/src/libs/Navigation/AppNavigator/ModalStackNavigators/index.tsx index 416e5160fafe..e9026bb41e22 100644 --- a/src/libs/Navigation/AppNavigator/ModalStackNavigators/index.tsx +++ b/src/libs/Navigation/AppNavigator/ModalStackNavigators/index.tsx @@ -362,6 +362,9 @@ const SettingsModalStackNavigator = createModalStackNavigator('@pages/workspace/accounting/qbo/export/QuickbooksCompanyCardExpenseAccountSelectPage').default, [SCREENS.WORKSPACE.ACCOUNTING.QUICKBOOKS_ONLINE_COMPANY_CARD_EXPENSE_ACCOUNT_COMPANY_CARD_SELECT]: () => require('../../../../pages/workspace/accounting/qbo/export/QuickbooksCompanyCardExpenseAccountSelectCardPage').default, + [SCREENS.WORKSPACE.ACCOUNTING.QUICKBOOKS_ONLINE_AUTO_SYNC]: () => require('../../../../pages/workspace/accounting/qbo/advanced/QuickbooksAutoSyncPage').default, + [SCREENS.WORKSPACE.ACCOUNTING.QUICKBOOKS_ONLINE_ACCOUNTING_METHOD]: () => + require('../../../../pages/workspace/accounting/qbo/advanced/QuickbooksAccountingMethodPage').default, [SCREENS.WORKSPACE.ACCOUNTING.QUICKBOOKS_ONLINE_COMPANY_CARD_EXPENSE_ACCOUNT]: () => require('../../../../pages/workspace/accounting/qbo/export/QuickbooksCompanyCardExpenseAccountPage').default, [SCREENS.WORKSPACE.ACCOUNTING.QUICKBOOKS_ONLINE_EXPORT_PREFERRED_EXPORTER]: () => diff --git a/src/libs/Navigation/linkingConfig/RELATIONS/WORKSPACE_TO_RHP.ts b/src/libs/Navigation/linkingConfig/RELATIONS/WORKSPACE_TO_RHP.ts index 5654777e003a..109f9d0cf37a 100755 --- a/src/libs/Navigation/linkingConfig/RELATIONS/WORKSPACE_TO_RHP.ts +++ b/src/libs/Navigation/linkingConfig/RELATIONS/WORKSPACE_TO_RHP.ts @@ -55,6 +55,8 @@ const WORKSPACE_TO_RHP: Partial['config'] = { [SCREENS.WORKSPACE.ACCOUNTING.QUICKBOOKS_ONLINE_LOCATIONS_DISPLAYED_AS]: { path: ROUTES.POLICY_ACCOUNTING_QUICKBOOKS_ONLINE_LOCATIONS_DISPLAYED_AS.route, }, + [SCREENS.WORKSPACE.ACCOUNTING.QUICKBOOKS_ONLINE_AUTO_SYNC]: { + path: ROUTES.WORKSPACE_ACCOUNTING_QUICKBOOKS_ONLINE_AUTO_SYNC.route, + }, + [SCREENS.WORKSPACE.ACCOUNTING.QUICKBOOKS_ONLINE_ACCOUNTING_METHOD]: { + path: ROUTES.WORKSPACE_ACCOUNTING_QUICKBOOKS_ONLINE_ACCOUNTING_METHOD.route, + }, [SCREENS.WORKSPACE.ACCOUNTING.QUICKBOOKS_DESKTOP_COMPANY_CARD_EXPENSE_ACCOUNT_SELECT]: { path: ROUTES.POLICY_ACCOUNTING_QUICKBOOKS_DESKTOP_COMPANY_CARD_EXPENSE_ACCOUNT_SELECT.route, }, diff --git a/src/libs/actions/Policy/Policy.ts b/src/libs/actions/Policy/Policy.ts index e74164eb0acd..11ee65b61acd 100644 --- a/src/libs/actions/Policy/Policy.ts +++ b/src/libs/actions/Policy/Policy.ts @@ -738,10 +738,14 @@ function clearSageIntacctErrorField(policyID: string | undefined, fieldName: str Onyx.merge(`${ONYXKEYS.COLLECTION.POLICY}${policyID}`, {connections: {intacct: {config: {errorFields: {[fieldName]: null}}}}}); } -function clearNetSuiteAutoSyncErrorField(policyID: string) { +function clearNetSuiteAutoSyncErrorField(policyID: string | undefined) { Onyx.merge(`${ONYXKEYS.COLLECTION.POLICY}${policyID}`, {connections: {netsuite: {config: {errorFields: {autoSync: null}}}}}); } +function clearQuickbooksOnlineAutoSyncErrorField(policyID: string | undefined) { + Onyx.merge(`${ONYXKEYS.COLLECTION.POLICY}${policyID}`, {connections: {quickbooksOnline: {config: {errorFields: {autoSync: null}}}}}); +} + function setWorkspaceReimbursement(policyID: string, reimbursementChoice: ValueOf, reimburserEmail: string) { const policy = getPolicy(policyID); @@ -5169,6 +5173,7 @@ export { updateDefaultPolicy, getAssignedSupportData, downgradeToTeam, + clearQuickbooksOnlineAutoSyncErrorField, updateLastAccessedWorkspaceSwitcher, }; diff --git a/src/libs/actions/connections/QuickbooksOnline.ts b/src/libs/actions/connections/QuickbooksOnline.ts index 0ed0c814271e..ab23855bbb7a 100644 --- a/src/libs/actions/connections/QuickbooksOnline.ts +++ b/src/libs/actions/connections/QuickbooksOnline.ts @@ -1,7 +1,9 @@ +import type {CONST as COMMON_CONST} from 'expensify-common'; import type {OnyxEntry, OnyxUpdate} from 'react-native-onyx'; import Onyx from 'react-native-onyx'; +import type {ValueOf} from 'type-fest'; import * as API from '@libs/API'; -import type {ConnectPolicyToAccountingIntegrationParams} from '@libs/API/parameters'; +import type {ConnectPolicyToAccountingIntegrationParams, UpdateQuickbooksOnlineAccountingMethodParams} from '@libs/API/parameters'; import type UpdateQuickbooksOnlineAutoCreateVendorParams from '@libs/API/parameters/UpdateQuickbooksOnlineAutoCreateVendorParams'; import type UpdateQuickbooksOnlineGenericTypeParams from '@libs/API/parameters/UpdateQuickbooksOnlineGenericTypeParams'; import {READ_COMMANDS, WRITE_COMMANDS} from '@libs/API/types'; @@ -171,7 +173,10 @@ function buildOnyxDataForQuickbooksConfiguration(policyID: string, settingValue: TSettingValue) { +function updateQuickbooksOnlineAutoSync(policyID: string | undefined, settingValue: TSettingValue) { + if (!policyID) { + return; + } const onyxData = buildOnyxDataForQuickbooksConfiguration(policyID, CONST.QUICKBOOKS_CONFIG.AUTO_SYNC, {enabled: settingValue}, {enabled: !settingValue}); const parameters: UpdateQuickbooksOnlineGenericTypeParams = { @@ -194,10 +199,13 @@ function updateQuickbooksOnlineEnableNewCategories>( - policyID: string, + policyID: string | undefined, configUpdate: TConfigUpdate, configCurrentData: TConfigUpdate, ) { + if (!policyID) { + return; + } const onyxData = buildOnyxDataForMultipleQuickbooksConfigurations(policyID, configUpdate, configCurrentData); const parameters: UpdateQuickbooksOnlineAutoCreateVendorParams = { @@ -210,7 +218,10 @@ function updateQuickbooksOnlineAutoCreateVendor(policyID: string, settingValue: TSettingValue) { +function updateQuickbooksOnlineSyncPeople(policyID: string | undefined, settingValue: TSettingValue) { + if (!policyID) { + return; + } const onyxData = buildOnyxDataForQuickbooksConfiguration(policyID, CONST.QUICKBOOKS_CONFIG.SYNC_PEOPLE, settingValue, !settingValue); const parameters: UpdateQuickbooksOnlineGenericTypeParams = { @@ -345,11 +356,11 @@ function updateQuickbooksOnlineNonReimbursableExpensesAccount( - policyID: string, + policyID: string | undefined, settingValue: TSettingValue, oldSettingValue?: TSettingValue, ) { - if (settingValue === oldSettingValue) { + if (settingValue === oldSettingValue || !policyID) { return; } @@ -363,6 +374,24 @@ function updateQuickbooksOnlineCollectionAccountID, + oldAccountingMethod: ValueOf, +) { + if (!policyID) { + return; + } + const onyxData = buildOnyxDataForQuickbooksConfiguration(policyID, CONST.QUICKBOOKS_CONFIG.ACCOUNTING_METHOD, accountingMethod, oldAccountingMethod); + + const parameters: UpdateQuickbooksOnlineAccountingMethodParams = { + policyID, + accountingMethod, + }; + + API.write(WRITE_COMMANDS.UPDATE_QUICKBOOKS_ONLINE_ACCOUNTING_METHOD, parameters, onyxData); +} + function updateQuickbooksOnlineSyncTax(policyID: string, settingValue: TSettingValue) { const onyxData = buildOnyxDataForQuickbooksConfiguration(policyID, CONST.QUICKBOOKS_CONFIG.SYNC_TAX, settingValue, !settingValue); @@ -429,4 +458,5 @@ export { updateQuickbooksOnlineSyncClasses, updateQuickbooksOnlineSyncLocations, updateQuickbooksOnlineSyncCustomers, + updateQuickbooksOnlineAccountingMethod, }; diff --git a/src/pages/workspace/accounting/qbo/advanced/QuickbooksAccountingMethodPage.tsx b/src/pages/workspace/accounting/qbo/advanced/QuickbooksAccountingMethodPage.tsx new file mode 100644 index 000000000000..5b997b59b9f9 --- /dev/null +++ b/src/pages/workspace/accounting/qbo/advanced/QuickbooksAccountingMethodPage.tsx @@ -0,0 +1,82 @@ +import {CONST as COMMON_CONST} from 'expensify-common'; +import React, {useCallback, useMemo} from 'react'; +import {View} from 'react-native'; +import type {ValueOf} from 'type-fest'; +import RadioListItem from '@components/SelectionList/RadioListItem'; +import type {ListItem} from '@components/SelectionList/types'; +import SelectionScreen from '@components/SelectionScreen'; +import type {SelectorType} from '@components/SelectionScreen'; +import Text from '@components/Text'; +import useLocalize from '@hooks/useLocalize'; +import useThemeStyles from '@hooks/useThemeStyles'; +import {updateQuickbooksOnlineAccountingMethod} from '@libs/actions/connections/QuickbooksOnline'; +import {settingsPendingAction} from '@libs/PolicyUtils'; +import Navigation from '@navigation/Navigation'; +import type {WithPolicyConnectionsProps} from '@pages/workspace/withPolicyConnections'; +import withPolicyConnections from '@pages/workspace/withPolicyConnections'; +import CONST from '@src/CONST'; +import type {TranslationPaths} from '@src/languages/types'; +import ROUTES from '@src/ROUTES'; + +type MenuListItem = ListItem & { + value: ValueOf; +}; + +function QuickbooksAccountingMethodPage({policy}: WithPolicyConnectionsProps) { + const {translate} = useLocalize(); + const policyID = policy?.id; + const styles = useThemeStyles(); + const config = policy?.connections?.quickbooksOnline?.config; + const accountingMethod = config?.accountingMethod ?? COMMON_CONST.INTEGRATIONS.ACCOUNTING_METHOD.CASH; + const data: MenuListItem[] = Object.values(COMMON_CONST.INTEGRATIONS.ACCOUNTING_METHOD).map((accountingMethodType) => ({ + value: accountingMethodType, + text: translate(`workspace.qbo.accountingMethods.values.${accountingMethodType}` as TranslationPaths), + alternateText: translate(`workspace.qbo.accountingMethods.alternateText.${accountingMethodType}` as TranslationPaths), + keyForList: accountingMethodType, + isSelected: accountingMethod === accountingMethodType, + })); + + const pendingAction = + settingsPendingAction([CONST.QUICKBOOKS_CONFIG.AUTO_SYNC], config?.pendingFields) ?? settingsPendingAction([CONST.QUICKBOOKS_CONFIG.ACCOUNTING_METHOD], config?.pendingFields); + + const headerContent = useMemo( + () => ( + + {translate('workspace.qbo.accountingMethods.description')} + + ), + [translate, styles.pb5, styles.ph5], + ); + + const selectExpenseReportApprovalLevel = useCallback( + (row: MenuListItem) => { + if (row.value !== config?.accountingMethod) { + updateQuickbooksOnlineAccountingMethod(policyID, row.value, config?.accountingMethod ?? COMMON_CONST.INTEGRATIONS.ACCOUNTING_METHOD.CASH); + } + Navigation.goBack(ROUTES.WORKSPACE_ACCOUNTING_QUICKBOOKS_ONLINE_AUTO_SYNC.getRoute(policyID)); + }, + [config?.accountingMethod, policyID], + ); + + return ( + selectExpenseReportApprovalLevel(selection as MenuListItem)} + initiallyFocusedOptionKey={data.find((mode) => mode.isSelected)?.keyForList} + policyID={policyID} + accessVariants={[CONST.POLICY.ACCESS_VARIANTS.ADMIN]} + featureName={CONST.POLICY.MORE_FEATURES.ARE_CONNECTIONS_ENABLED} + onBackButtonPress={() => Navigation.goBack(ROUTES.WORKSPACE_ACCOUNTING_QUICKBOOKS_ONLINE_AUTO_SYNC.getRoute(policyID))} + connectionName={CONST.POLICY.CONNECTIONS.NAME.QBO} + pendingAction={pendingAction} + /> + ); +} + +QuickbooksAccountingMethodPage.displayName = 'QuickbooksAccountingMethodPage'; + +export default withPolicyConnections(QuickbooksAccountingMethodPage); diff --git a/src/pages/workspace/accounting/qbo/advanced/QuickbooksAdvancedPage.tsx b/src/pages/workspace/accounting/qbo/advanced/QuickbooksAdvancedPage.tsx index 14be50461112..650ac8726b2c 100644 --- a/src/pages/workspace/accounting/qbo/advanced/QuickbooksAdvancedPage.tsx +++ b/src/pages/workspace/accounting/qbo/advanced/QuickbooksAdvancedPage.tsx @@ -1,3 +1,4 @@ +import {CONST as COMMON_CONST} from 'expensify-common'; import React, {useMemo} from 'react'; import {View} from 'react-native'; import Accordion from '@components/Accordion'; @@ -8,16 +9,16 @@ import useAccordionAnimation from '@hooks/useAccordionAnimation'; import useLocalize from '@hooks/useLocalize'; import useThemeStyles from '@hooks/useThemeStyles'; import useWaitForNavigation from '@hooks/useWaitForNavigation'; -import * as QuickbooksOnline from '@libs/actions/connections/QuickbooksOnline'; -import * as ErrorUtils from '@libs/ErrorUtils'; +import {updateQuickbooksOnlineAutoCreateVendor, updateQuickbooksOnlineCollectionAccountID, updateQuickbooksOnlineSyncPeople} from '@libs/actions/connections/QuickbooksOnline'; +import {getLatestErrorField} from '@libs/ErrorUtils'; import Navigation from '@libs/Navigation/Navigation'; -import * as PolicyUtils from '@libs/PolicyUtils'; -import {settingsPendingAction} from '@libs/PolicyUtils'; +import {areSettingsInErrorFields, settingsPendingAction} from '@libs/PolicyUtils'; import type {WithPolicyConnectionsProps} from '@pages/workspace/withPolicyConnections'; import withPolicyConnections from '@pages/workspace/withPolicyConnections'; import ToggleSettingOptionRow from '@pages/workspace/workflows/ToggleSettingsOptionRow'; import {clearQBOErrorField} from '@userActions/Policy/Policy'; import CONST from '@src/CONST'; +import type {TranslationPaths} from '@src/languages/types'; import ROUTES from '@src/ROUTES'; const reimbursementOrCollectionAccountIDs = [CONST.QUICKBOOKS_CONFIG.REIMBURSEMENT_ACCOUNT_ID, CONST.QUICKBOOKS_CONFIG.COLLECTION_ACCOUNT_ID]; @@ -28,8 +29,9 @@ function QuickbooksAdvancedPage({policy}: WithPolicyConnectionsProps) { const waitForNavigate = useWaitForNavigation(); const {translate} = useLocalize(); - const policyID = policy?.id ?? '-1'; + const policyID = policy?.id; const qboConfig = policy?.connections?.quickbooksOnline?.config; + const accountingMethod = policy?.connections?.quickbooksOnline?.config?.accountingMethod; const {bankAccounts, creditCards, otherCurrentAssetAccounts, vendors} = policy?.connections?.quickbooksOnline?.data ?? {}; const nonReimbursableBillDefaultVendorObject = vendors?.find((vendor) => vendor.id === qboConfig?.nonReimbursableBillDefaultVendor); @@ -57,16 +59,16 @@ function QuickbooksAdvancedPage({policy}: WithPolicyConnectionsProps) { description: translate('workspace.qbo.advancedConfig.qboBillPaymentAccount'), onPress: waitForNavigate(() => Navigation.navigate(ROUTES.WORKSPACE_ACCOUNTING_QUICKBOOKS_ONLINE_ACCOUNT_SELECTOR.getRoute(policyID))), subscribedSettings: reimbursementOrCollectionAccountIDs, - brickRoadIndicator: PolicyUtils.areSettingsInErrorFields(reimbursementOrCollectionAccountIDs, qboConfig?.errorFields) ? CONST.BRICK_ROAD_INDICATOR_STATUS.ERROR : undefined, - pendingAction: PolicyUtils.settingsPendingAction(reimbursementOrCollectionAccountIDs, qboConfig?.pendingFields), + brickRoadIndicator: areSettingsInErrorFields(reimbursementOrCollectionAccountIDs, qboConfig?.errorFields) ? CONST.BRICK_ROAD_INDICATOR_STATUS.ERROR : undefined, + pendingAction: settingsPendingAction(reimbursementOrCollectionAccountIDs, qboConfig?.pendingFields), }, { title: selectedInvoiceCollectionAccountName, description: translate('workspace.qbo.advancedConfig.qboInvoiceCollectionAccount'), onPress: waitForNavigate(() => Navigation.navigate(ROUTES.WORKSPACE_ACCOUNTING_QUICKBOOKS_ONLINE_INVOICE_ACCOUNT_SELECTOR.getRoute(policyID))), subscribedSettings: collectionAccountIDs, - brickRoadIndicator: PolicyUtils.areSettingsInErrorFields(collectionAccountIDs, qboConfig?.errorFields) ? CONST.BRICK_ROAD_INDICATOR_STATUS.ERROR : undefined, - pendingAction: PolicyUtils.settingsPendingAction(collectionAccountIDs, qboConfig?.pendingFields), + brickRoadIndicator: areSettingsInErrorFields(collectionAccountIDs, qboConfig?.errorFields) ? CONST.BRICK_ROAD_INDICATOR_STATUS.ERROR : undefined, + pendingAction: settingsPendingAction(collectionAccountIDs, qboConfig?.pendingFields), }, ]; @@ -88,24 +90,14 @@ function QuickbooksAdvancedPage({policy}: WithPolicyConnectionsProps) { ); const qboToggleSettingItems = [ - { - title: translate('workspace.accounting.autoSync'), - subtitle: translate('workspace.qbo.advancedConfig.autoSyncDescription'), - switchAccessibilityLabel: translate('workspace.qbo.advancedConfig.autoSyncDescription'), - isActive: !!qboConfig?.autoSync?.enabled, - onToggle: () => QuickbooksOnline.updateQuickbooksOnlineAutoSync(policyID, !qboConfig?.autoSync?.enabled), - subscribedSetting: CONST.QUICKBOOKS_CONFIG.AUTO_SYNC, - errors: ErrorUtils.getLatestErrorField(qboConfig, CONST.QUICKBOOKS_CONFIG.AUTO_SYNC), - pendingAction: settingsPendingAction([CONST.QUICKBOOKS_CONFIG.AUTO_SYNC], qboConfig?.pendingFields), - }, { title: translate('workspace.qbo.advancedConfig.inviteEmployees'), subtitle: translate('workspace.qbo.advancedConfig.inviteEmployeesDescription'), switchAccessibilityLabel: translate('workspace.qbo.advancedConfig.inviteEmployeesDescription'), isActive: !!qboConfig?.syncPeople, - onToggle: () => QuickbooksOnline.updateQuickbooksOnlineSyncPeople(policyID, !qboConfig?.syncPeople), + onToggle: () => updateQuickbooksOnlineSyncPeople(policyID, !qboConfig?.syncPeople), subscribedSetting: CONST.QUICKBOOKS_CONFIG.SYNC_PEOPLE, - errors: ErrorUtils.getLatestErrorField(qboConfig, CONST.QUICKBOOKS_CONFIG.SYNC_PEOPLE), + errors: getLatestErrorField(qboConfig, CONST.QUICKBOOKS_CONFIG.SYNC_PEOPLE), pendingAction: settingsPendingAction([CONST.QUICKBOOKS_CONFIG.SYNC_PEOPLE], qboConfig?.pendingFields), }, { @@ -119,7 +111,7 @@ function QuickbooksAdvancedPage({policy}: WithPolicyConnectionsProps) { : CONST.INTEGRATION_ENTITY_MAP_TYPES.NONE; const nonReimbursableVendorCurrentValue = nonReimbursableBillDefaultVendorObject?.id ?? CONST.INTEGRATION_ENTITY_MAP_TYPES.NONE; - QuickbooksOnline.updateQuickbooksOnlineAutoCreateVendor( + updateQuickbooksOnlineAutoCreateVendor( policyID, { [autoCreateVendorConst]: isOn, @@ -132,7 +124,7 @@ function QuickbooksAdvancedPage({policy}: WithPolicyConnectionsProps) { ); }, subscribedSetting: CONST.QUICKBOOKS_CONFIG.AUTO_CREATE_VENDOR, - errors: ErrorUtils.getLatestErrorField(qboConfig, CONST.QUICKBOOKS_CONFIG.AUTO_CREATE_VENDOR), + errors: getLatestErrorField(qboConfig, CONST.QUICKBOOKS_CONFIG.AUTO_CREATE_VENDOR), pendingAction: settingsPendingAction([CONST.QUICKBOOKS_CONFIG.AUTO_CREATE_VENDOR], qboConfig?.pendingFields), }, { @@ -141,13 +133,13 @@ function QuickbooksAdvancedPage({policy}: WithPolicyConnectionsProps) { switchAccessibilityLabel: translate('workspace.qbo.advancedConfig.reimbursedReportsDescription'), isActive: isSyncReimbursedSwitchOn, onToggle: () => - QuickbooksOnline.updateQuickbooksOnlineCollectionAccountID( + updateQuickbooksOnlineCollectionAccountID( policyID, isSyncReimbursedSwitchOn ? '' : [...qboAccountOptions, ...invoiceAccountCollectionOptions].at(0)?.id, qboConfig?.collectionAccountID, ), subscribedSetting: CONST.QUICKBOOKS_CONFIG.COLLECTION_ACCOUNT_ID, - errors: ErrorUtils.getLatestErrorField(qboConfig, CONST.QUICKBOOKS_CONFIG.COLLECTION_ACCOUNT_ID), + errors: getLatestErrorField(qboConfig, CONST.QUICKBOOKS_CONFIG.COLLECTION_ACCOUNT_ID), pendingAction: settingsPendingAction([CONST.QUICKBOOKS_CONFIG.COLLECTION_ACCOUNT_ID], qboConfig?.pendingFields), }, ]; @@ -162,6 +154,26 @@ function QuickbooksAdvancedPage({policy}: WithPolicyConnectionsProps) { contentContainerStyle={[styles.pb2, styles.ph5]} connectionName={CONST.POLICY.CONNECTIONS.NAME.QBO} > + + Navigation.navigate(ROUTES.WORKSPACE_ACCOUNTING_QUICKBOOKS_ONLINE_AUTO_SYNC.getRoute(policyID))} + brickRoadIndicator={ + areSettingsInErrorFields([CONST.QUICKBOOKS_CONFIG.AUTO_SYNC, CONST.QUICKBOOKS_CONFIG.ACCOUNTING_METHOD], qboConfig?.errorFields) + ? CONST.BRICK_ROAD_INDICATOR_STATUS.ERROR + : undefined + } + hintText={(() => { + if (!qboConfig?.autoSync?.enabled) { + return undefined; + } + return translate(`workspace.qbo.accountingMethods.alternateText.${accountingMethod ?? COMMON_CONST.INTEGRATIONS.ACCOUNTING_METHOD.CASH}` as TranslationPaths); + })()} + /> + {qboToggleSettingItems.map((item) => ( + + Navigation.goBack(ROUTES.WORKSPACE_ACCOUNTING_QUICKBOOKS_ONLINE_ADVANCED.getRoute(policyID))} + /> + clearQuickbooksOnlineAutoSyncErrorField(policyID)} + onToggle={(isEnabled) => updateQuickbooksOnlineAutoSync(policyID, isEnabled)} + pendingAction={pendingAction} + errors={getLatestErrorField(config, CONST.QUICKBOOKS_CONFIG.AUTO_SYNC)} + /> + {!!config?.autoSync?.enabled && ( + + Navigation.navigate(ROUTES.WORKSPACE_ACCOUNTING_QUICKBOOKS_ONLINE_ACCOUNTING_METHOD.getRoute(policyID))} + /> + + )} + + + ); +} + +QuickbooksAutoSyncPage.displayName = 'QuickbooksAutoSyncPage'; + +export default withPolicyConnections(QuickbooksAutoSyncPage); diff --git a/src/types/onyx/Policy.ts b/src/types/onyx/Policy.ts index 3bb080cbcd97..f3b4aefe72b3 100644 --- a/src/types/onyx/Policy.ts +++ b/src/types/onyx/Policy.ts @@ -476,6 +476,9 @@ type QBOConnectionConfig = OnyxCommon.OnyxValueWithOfflineFeedback<{ /** Credentials of the current QBO connection */ credentials: QBOCredentials; + + /** The accounting Method for NetSuite conenction config */ + accountingMethod?: ValueOf; }>; /**